Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
document_session.hpp
Go to the documentation of this file.
1#pragma once
2
6
7#include <atomic>
8#include <cstddef>
9#include <cstdint>
10#include <limits>
11#include <memory>
12#include <optional>
13#include <type_traits>
14
15namespace pulp::timeline {
16
20
21namespace detail {
22class DocumentSessionPreviewAccess;
23class WriterTokenTestAccess;
24} // namespace detail
25
37
78
80inline constexpr std::size_t kCommandClassCount = 11;
81
86enum class CommandIntent : std::uint8_t {
93};
94
96inline constexpr std::size_t kCommandIntentCount = 3;
97
107
108namespace detail {
109template <class> inline constexpr bool unclassified_command_v = false;
110} // namespace detail
111
121template <class T> constexpr CommandAuthority command_authority_of() noexcept {
122 using Class = CommandClass;
123 using Intent = CommandIntent;
124 if constexpr (std::is_same_v<T, InsertClip>)
125 return {Class::Clip, Intent::Create};
126 else if constexpr (std::is_same_v<T, RemoveClip>)
127 return {Class::Clip, Intent::Remove};
128 else if constexpr (std::is_same_v<T, MoveClip>)
129 return {Class::Clip, Intent::Modify};
130 else if constexpr (std::is_same_v<T, SetClipPlaybackProperties>)
131 return {Class::Clip, Intent::Modify};
132 else if constexpr (std::is_same_v<T, SetClipSequenceRef>)
133 return {Class::Clip, Intent::Modify};
134 else if constexpr (std::is_same_v<T, InsertNotes>)
135 return {Class::Note, Intent::Create};
136 else if constexpr (std::is_same_v<T, RemoveNotes>)
137 return {Class::Note, Intent::Remove};
138 else if constexpr (std::is_same_v<T, SetNoteVelocity>)
139 return {Class::Note, Intent::Modify};
140 else if constexpr (std::is_same_v<T, ReplaceNoteContent>)
141 return {Class::Note, Intent::Modify};
142 else if constexpr (std::is_same_v<T, SetNoteEvents>)
143 return {Class::Note, Intent::Modify};
144 else if constexpr (std::is_same_v<T, InsertMidiExpressionLane>)
145 return {Class::Note, Intent::Create};
146 else if constexpr (std::is_same_v<T, RemoveMidiExpressionLane>)
147 return {Class::Note, Intent::Remove};
148 else if constexpr (std::is_same_v<T, SetMidiExpressionLanePoints>)
149 return {Class::Note, Intent::Modify};
150 else if constexpr (std::is_same_v<T, InsertAutomationLane>)
151 return {Class::Automation, Intent::Create};
152 else if constexpr (std::is_same_v<T, RemoveAutomationLane>)
153 return {Class::Automation, Intent::Remove};
154 else if constexpr (std::is_same_v<T, InsertTrack>)
155 return {Class::Track, Intent::Create};
156 else if constexpr (std::is_same_v<T, RemoveTrack>)
157 return {Class::Track, Intent::Remove};
158 else if constexpr (std::is_same_v<T, SetTrackName>)
159 return {Class::Track, Intent::Modify};
160 else if constexpr (std::is_same_v<T, MoveTrack>)
161 return {Class::Track, Intent::Modify};
162 else if constexpr (std::is_same_v<T, SetTrackMixer>)
163 return {Class::Track, Intent::Modify};
164 else if constexpr (std::is_same_v<T, SetRecordArm>)
165 return {Class::Track, Intent::Modify};
166 else if constexpr (std::is_same_v<T, SetTrackFreeze>)
167 return {Class::Track, Intent::Modify};
168 else if constexpr (std::is_same_v<T, InsertTakeLane>)
169 return {Class::Take, Intent::Create};
170 else if constexpr (std::is_same_v<T, RemoveTakeLane>)
171 return {Class::Take, Intent::Remove};
172 else if constexpr (std::is_same_v<T, InsertTake>)
173 return {Class::Take, Intent::Create};
174 else if constexpr (std::is_same_v<T, RemoveTake>)
175 return {Class::Take, Intent::Remove};
176 else if constexpr (std::is_same_v<T, SetActiveTakeLane>)
177 return {Class::Take, Intent::Modify};
178 else if constexpr (std::is_same_v<T, SetTakeComp>)
179 return {Class::Take, Intent::Modify};
180 else if constexpr (std::is_same_v<T, InsertScene>)
181 return {Class::Scene, Intent::Create};
182 else if constexpr (std::is_same_v<T, RemoveScene>)
183 return {Class::Scene, Intent::Remove};
184 else if constexpr (std::is_same_v<T, InsertSlot>)
185 return {Class::Scene, Intent::Create};
186 else if constexpr (std::is_same_v<T, RemoveSlot>)
187 return {Class::Scene, Intent::Remove};
188 else if constexpr (std::is_same_v<T, InsertSequence>)
189 return {Class::Sequence, Intent::Create};
190 else if constexpr (std::is_same_v<T, CloneSequence>)
191 return {Class::Sequence, Intent::Create};
192 else if constexpr (std::is_same_v<T, RemoveSequence>)
193 return {Class::Sequence, Intent::Remove};
194 else if constexpr (std::is_same_v<T, InsertDevice>)
195 return {Class::Device, Intent::Create};
196 else if constexpr (std::is_same_v<T, RemoveDevice>)
197 return {Class::Device, Intent::Remove};
198 else if constexpr (std::is_same_v<T, MoveDevice>)
199 return {Class::Device, Intent::Modify};
200 else if constexpr (std::is_same_v<T, RetargetDevice>)
201 return {Class::Device, Intent::Modify};
202 else if constexpr (std::is_same_v<T, SetDeviceState>)
203 return {Class::Device, Intent::Modify};
204 else if constexpr (std::is_same_v<T, InsertMarker>)
205 return {Class::Annotation, Intent::Create};
206 else if constexpr (std::is_same_v<T, RemoveMarker>)
207 return {Class::Annotation, Intent::Remove};
208 else if constexpr (std::is_same_v<T, InsertRegion>)
209 return {Class::Annotation, Intent::Create};
210 else if constexpr (std::is_same_v<T, RemoveRegion>)
211 return {Class::Annotation, Intent::Remove};
212 else if constexpr (std::is_same_v<T, SetChordScaleLane>)
213 return {Class::Annotation, Intent::Modify};
214 else if constexpr (std::is_same_v<T, SetGroove>)
215 return {Class::Annotation, Intent::Modify};
216 else if constexpr (std::is_same_v<T, SetDynamicsLane>)
217 return {Class::Annotation, Intent::Modify};
218 else if constexpr (std::is_same_v<T, SetRegion>)
219 return {Class::Annotation, Intent::Modify};
220 else if constexpr (std::is_same_v<T, SetTempoMap>)
221 return {Class::Timing, Intent::Modify};
222 else if constexpr (std::is_same_v<T, SetMeterMap>)
223 return {Class::Timing, Intent::Modify};
224 else if constexpr (std::is_same_v<T, SetProjectTuning>)
225 return {Class::Timing, Intent::Modify};
226 else if constexpr (std::is_same_v<T, SetTrackTuning>)
227 return {Class::Timing, Intent::Modify};
228 else if constexpr (std::is_same_v<T, InsertModulator>)
229 return {Class::Automation, Intent::Create};
230 else if constexpr (std::is_same_v<T, RemoveModulator>)
231 return {Class::Automation, Intent::Remove};
232 else if constexpr (std::is_same_v<T, SetModulator>)
233 return {Class::Automation, Intent::Modify};
234 else if constexpr (std::is_same_v<T, InsertMacro>)
235 return {Class::Automation, Intent::Create};
236 else if constexpr (std::is_same_v<T, RemoveMacro>)
237 return {Class::Automation, Intent::Remove};
238 else if constexpr (std::is_same_v<T, SetMacro>)
239 return {Class::Automation, Intent::Modify};
240 else if constexpr (std::is_same_v<T, SetMacroValue>)
241 return {Class::Automation, Intent::Modify};
242 else if constexpr (std::is_same_v<T, InsertModulationRoute>)
243 return {Class::Automation, Intent::Create};
244 else if constexpr (std::is_same_v<T, RemoveModulationRoute>)
245 return {Class::Automation, Intent::Remove};
246 else if constexpr (std::is_same_v<T, SetModulationRoute>)
247 return {Class::Automation, Intent::Modify};
248 else if constexpr (std::is_same_v<T, CreateAsset>)
249 return {Class::Asset, Intent::Create};
250 else if constexpr (std::is_same_v<T, RemoveAsset>)
251 return {Class::Asset, Intent::Remove};
252 else
254 "every Command alternative needs a CommandAuthority");
255}
256
259
261constexpr std::uint64_t capability_bit(CommandAuthority authority) noexcept {
262 return std::uint64_t{1} << (static_cast<std::size_t>(authority.command_class) *
264 static_cast<std::size_t>(authority.intent));
265}
266
268inline constexpr std::uint64_t kAllCommandAuthorities =
269 (std::uint64_t{1} << (kCommandClassCount * kCommandIntentCount)) - 1;
270static_assert(kCommandClassCount * kCommandIntentCount < 64,
271 "writer capability pairs must fit in the mask");
272
284 std::uint64_t allowed = [] {
285 auto value = kAllCommandAuthorities;
286 for (std::size_t index = 0; index < kCommandClassCount; ++index)
287 value &= ~capability_bit(
288 {static_cast<CommandClass>(index), CommandIntent::Remove});
289 return value;
290 }();
291
292 std::size_t max_transaction_retained_bytes = std::numeric_limits<std::size_t>::max();
294 std::size_t max_session_retained_bytes = std::numeric_limits<std::size_t>::max();
295};
296
298constexpr bool allows(const WriterCapabilityMask& mask, CommandAuthority authority) noexcept {
299 return (mask.allowed & capability_bit(authority)) != 0;
300}
301
304 CommandIntent intent) noexcept {
305 mask.allowed &= ~capability_bit({command_class, intent});
306 return mask;
307}
308
311 CommandIntent intent) noexcept {
312 mask.allowed |= capability_bit({command_class, intent});
313 return mask;
314}
315
320 return mask;
321}
322
327
335 public:
341 public:
343 constexpr Provenance() noexcept = default;
344
346 constexpr bool valid() const noexcept {
347 return writer_.valid() && owner_nonce_ != 0;
348 }
349
351 constexpr bool operator==(const Provenance&) const noexcept = default;
352
353 private:
354 friend class WriterToken;
355 friend class DocumentSession;
356 constexpr Provenance(WriterId writer, std::uint64_t owner_nonce) noexcept
357 : writer_(writer), owner_nonce_(owner_nonce) {}
358
359 WriterId writer_;
360 std::uint64_t owner_nonce_ = 0;
361 };
362
364 WriterToken() = default;
365 WriterToken(const WriterToken&) = delete;
368 WriterToken(WriterToken&& other) noexcept;
371
373 WriterId id() const noexcept {
374 return id_;
375 }
376
377 [[nodiscard]] Provenance provenance() const noexcept {
378 return Provenance(id_, owner_nonce_);
379 }
380
386
387 private:
388 friend class DocumentSession;
390 WriterId id_;
391 std::uint64_t owner_nonce_ = 0;
392 std::atomic<std::uint64_t> next_transaction_{1};
393 std::atomic<std::uint64_t> next_command_{1};
394 std::atomic<std::uint64_t> next_undo_group_{1};
395};
396
402 std::shared_ptr<const Project> snapshot;
404};
405
415 public:
423 create(Project initial, SessionLimits limits = {});
433 create(Project initial, SessionLimits limits, std::shared_ptr<JournalSink> journal_sink);
443 std::shared_ptr<JournalSink> journal_sink);
448
451
473 std::optional<WriterCapabilityMask>
476 DocumentView current() const noexcept;
478 std::shared_ptr<const Project> snapshot() const noexcept;
480 DocumentRevision revision() const noexcept;
484 bool is_current_publication(const CommitResult& result) const noexcept;
489 bool is_gesture_open(WriterToken::Provenance provenance, UndoGroupId group) const noexcept;
504 Transaction transaction);
516 bool can_undo() const noexcept;
518 bool can_redo() const noexcept;
526 bool checkpoint(DocumentRevision durable_revision);
527
528 private:
530 enum class SinkAttachment : std::uint8_t { Initialize, Restore };
531
533 create_impl(Project checkpoint, DocumentRevision checkpoint_revision, SessionLimits limits,
534 std::shared_ptr<JournalSink> journal_sink, SinkAttachment attachment);
535
536 struct Impl;
537 explicit DocumentSession(std::unique_ptr<Impl> impl);
538 std::unique_ptr<Impl> impl_;
539};
540
542
543} // namespace pulp::timeline
Result<T, E> — either holds a T or an E, never both.
Definition result.hpp:76
Immutable identity-bearing placement of one ClipContent value.
Definition clip.hpp:466
Bounded, replayable in-memory log of contiguous document revisions.
Definition journal.hpp:112
static runtime::Result< std::unique_ptr< DocumentSession >, TransactionError > create(Project initial, SessionLimits limits, std::shared_ptr< JournalSink > journal_sink)
Creates a session at revision zero and initializes a durable sink.
runtime::Result< WriterToken, TransactionError > register_writer()
Registers a distinct writer until max_writers or ID space is exhausted.
bool can_redo() const noexcept
Reports whether a redo group is currently available.
runtime::Result< CommitResult, TransactionError > undo(WriterToken &writer)
Applies the newest closed undo group as a durable history transaction.
friend class detail::DocumentSessionPreviewAccess
Definition document_session.hpp:529
runtime::Result< WriterToken, TransactionError > register_writer(WriterCapabilityMask mask)
Registers a distinct writer whose authority is fixed at mask.
DocumentRevision revision() const noexcept
Returns the revision paired with the currently published snapshot.
bool can_undo() const noexcept
Reports whether a closed undo group is currently available.
DocumentView current() const noexcept
Returns one atomic snapshot/revision observation without taking the writer lock.
runtime::Result< CommitResult, TransactionError > submit(WriterToken &writer, Transaction transaction)
Applies and, when configured, durably journals one transaction.
bool is_current_publication(const CommitResult &result) const noexcept
Reports whether result is the session's exact current publication.
static runtime::Result< std::unique_ptr< DocumentSession >, TransactionError > create(Project initial, SessionLimits limits={})
Creates a session at revision zero without an external durable sink.
CommandJournal journal() const
Returns a locked copy of the bounded in-memory command journal.
DocumentSession & operator=(const DocumentSession &)=delete
bool is_gesture_open(WriterToken::Provenance provenance, UndoGroupId group) const noexcept
Reports whether provenance/group owns the session's current open gesture.
DocumentSession(const DocumentSession &)=delete
static runtime::Result< std::unique_ptr< DocumentSession >, TransactionError > restore(Project checkpoint, DocumentRevision checkpoint_revision, SessionLimits limits, std::shared_ptr< JournalSink > journal_sink)
Restores a session from a checkpoint already present in a durable sink.
std::shared_ptr< const Project > snapshot() const noexcept
Returns the currently published immutable snapshot.
bool checkpoint(DocumentRevision durable_revision)
Advances the journal checkpoint through an existing revision.
~DocumentSession()
Releases the session and its retained sink.
std::optional< WriterCapabilityMask > writer_capabilities(WriterToken::Provenance provenance) const noexcept
Returns the authority fixed at registration for provenance.
runtime::Result< CommitResult, TransactionError > redo(WriterToken &writer)
Reapplies the newest redo group as a durable history transaction.
Immutable root of a Timeline document and its monotonic identity domain.
Definition model.hpp:1079
Immutable identity-bearing arrangement with tracks, annotations, context, and launch scenes.
Definition model.hpp:692
Immutable sample-anchored recording take referencing a project media asset.
Definition recording.hpp:29
Immutable identity-bearing arrangement track.
Definition model.hpp:83
Opaque identity of one writer authority within one document session.
Definition document_session.hpp:340
constexpr bool operator==(const Provenance &) const noexcept=default
Compares both the session and writer identity without exposing either.
friend class DocumentSession
Definition document_session.hpp:355
friend class WriterToken
Definition document_session.hpp:354
constexpr Provenance() noexcept=default
Constructs an invalid provenance value.
constexpr bool valid() const noexcept
Returns whether this value identifies a writer authority.
Definition document_session.hpp:346
Move-only authority for submitting transactions to one DocumentSession.
Definition document_session.hpp:334
WriterToken & operator=(const WriterToken &)=delete
UndoGroupId allocate_undo_group_id() noexcept
Allocates the next undo-group ID, or an invalid ID after exhaustion.
WriterToken(WriterToken &&other) noexcept
Transfers writer authority and invalidates other.
CommandId allocate_command_id() noexcept
Allocates the next command ID, or an invalid ID after exhaustion.
WriterToken()=default
Constructs an invalid token that cannot authorize submissions.
WriterToken(const WriterToken &)=delete
friend class DocumentSession
Definition document_session.hpp:388
friend class detail::WriterTokenTestAccess
Definition document_session.hpp:389
WriterToken & operator=(WriterToken &&other) noexcept
Replaces this authority with other and invalidates other.
Provenance provenance() const noexcept
Returns an opaque fingerprint that remains stable when this token moves.
Definition document_session.hpp:377
WriterId id() const noexcept
Returns the writer identity carried by this token.
Definition document_session.hpp:373
TransactionId allocate_transaction_id() noexcept
Allocates the next transaction ID, or an invalid ID after exhaustion.
constexpr CommandAuthority command_authority_of() noexcept
Returns the primary authority command type T requires.
Definition document_session.hpp:121
constexpr WriterCapabilityMask allow(WriterCapabilityMask mask, CommandClass command_class, CommandIntent intent) noexcept
Returns mask with one class/intent pair permitted.
Definition document_session.hpp:310
constexpr WriterCapabilityMask unrestricted_capabilities() noexcept
Returns the legacy authority carried by writers registered without a mask.
Definition document_session.hpp:317
constexpr bool allows(const WriterCapabilityMask &mask, CommandAuthority authority) noexcept
Reports whether mask permits authority.
Definition document_session.hpp:298
constexpr std::size_t kCommandClassCount
Number of distinct command classes.
Definition document_session.hpp:80
constexpr std::uint64_t capability_bit(CommandAuthority authority) noexcept
Returns the single mask bit representing authority.
Definition document_session.hpp:261
constexpr std::size_t kCommandIntentCount
Number of distinct command intents.
Definition document_session.hpp:96
constexpr WriterCapabilityMask deny(WriterCapabilityMask mask, CommandClass command_class, CommandIntent intent) noexcept
Returns mask with one class/intent pair denied.
Definition document_session.hpp:303
CommandClass
The part of the document one command governs.
Definition document_session.hpp:42
std::variant< InsertClip, RemoveClip, InsertAutomationLane, RemoveAutomationLane, MoveClip, SetNoteVelocity, ReplaceNoteContent, SetClipPlaybackProperties, SetTempoMap, SetMeterMap, CreateAsset, RemoveAsset, InsertTakeLane, RemoveTakeLane, SetRecordArm, InsertTake, RemoveTake, SetActiveTakeLane, SetTakeComp, SetTrackFreeze, InsertMarker, RemoveMarker, InsertRegion, RemoveRegion, SetChordScaleLane, SetGroove, InsertScene, RemoveScene, InsertSlot, RemoveSlot, InsertSequence, CloneSequence, RemoveSequence, SetClipSequenceRef, SetTrackMixer, InsertTrack, RemoveTrack, SetTrackName, MoveTrack, SetNoteEvents, InsertNotes, RemoveNotes, InsertDevice, RemoveDevice, MoveDevice, RetargetDevice, SetDeviceState, SetDynamicsLane, InsertMidiExpressionLane, RemoveMidiExpressionLane, SetMidiExpressionLanePoints, SetProjectTuning, SetTrackTuning, SetRegion, InsertModulator, RemoveModulator, SetModulator, InsertMacro, RemoveMacro, SetMacro, SetMacroValue, InsertModulationRoute, RemoveModulationRoute, SetModulationRoute > Command
Exhaustive set of durable Timeline document mutations.
Definition command.hpp:800
constexpr std::uint64_t kAllCommandAuthorities
Every class/intent pair set.
Definition document_session.hpp:268
CommandAuthority command_authority(const Command &command) noexcept
Returns the primary authority command requires.
CommandIntent
What a command does to the entity its class names.
Definition document_session.hpp:86
constexpr WriterCapabilityMask non_destructive_capabilities() noexcept
Returns a mask permitting every class but denying every destructive intent.
Definition document_session.hpp:324
@ Asset
Project-owned media assets.
Definition document_session.hpp:76
@ Note
Note content within a clip.
Definition document_session.hpp:46
@ Annotation
Markers, regions, chord/scale lane, and groove.
Definition document_session.hpp:69
@ Clip
Clip placement, timing, and playback properties on a track.
Definition document_session.hpp:44
@ Automation
Non-performed control of parameter values on a track: automation lanes, modulation sources,...
Definition document_session.hpp:57
@ Timing
How the document is interpreted musically: the project tempo and meter maps, and the tuning a project...
Definition document_session.hpp:74
@ Device
Device placement, ordering, retargeting, and state.
Definition document_session.hpp:67
@ Remove
Takes an existing entity out of the document.
Definition document_session.hpp:92
@ Create
Brings a new entity into the document.
Definition document_session.hpp:88
@ Modify
Changes an existing entity in place.
Definition document_session.hpp:90
Definition generated_event_source.hpp:33
Definition clip_launch.hpp:30
constexpr bool unclassified_command_v
Definition document_session.hpp:109
Definition program_compiler.hpp:18
STL namespace.
The authority one command requires, as a class and intent pair.
Definition document_session.hpp:99
constexpr bool operator==(const CommandAuthority &) const noexcept=default
CommandClass command_class
The part of the document the command governs.
Definition document_session.hpp:101
CommandIntent intent
What the command does to that part.
Definition document_session.hpp:103
Writer-scoped, monotonically assigned command identity.
Definition command.hpp:32
Immutable state published by a successful session commit.
Definition transaction.hpp:187
Monotonic document snapshot revision used for optimistic admission.
Definition command.hpp:54
Atomically observed immutable project snapshot and its matching revision.
Definition document_session.hpp:401
DocumentRevision revision
Definition document_session.hpp:403
std::shared_ptr< const Project > snapshot
Definition document_session.hpp:402
In-memory command-journal quotas.
Definition journal.hpp:24
Authored grouping of slots presented as one launchable column.
Definition clip_launch.hpp:247
Resource ceilings for one mutable document session.
Definition document_session.hpp:31
JournalLimits journal
Definition document_session.hpp:32
UndoLimits undo
Definition document_session.hpp:33
std::size_t max_cached_results
Definition document_session.hpp:35
std::size_t max_writers
Definition document_session.hpp:34
Structured transaction rejection.
Definition transaction.hpp:160
Writer-scoped, monotonically assigned transaction identity.
Definition command.hpp:43
Atomically admitted ordered command batch.
Definition command.hpp:824
Writer-scoped identity joining gesture transactions into one undo unit.
Definition command.hpp:60
Bounds the number and retained memory of undo groups in a session.
Definition undo.hpp:18
Fixed authority of one writer over command classes and retained size.
Definition document_session.hpp:282
std::size_t max_session_retained_bytes
Largest cumulative retained size this writer may commit to the session.
Definition document_session.hpp:294
std::uint64_t allowed
One bit per class/intent pair, indexed by capability_bit.
Definition document_session.hpp:284
std::size_t max_transaction_retained_bytes
Largest retained size a single transaction from this writer may carry.
Definition document_session.hpp:292
Stable non-zero identity of a document writer.
Definition command.hpp:22