opynsim
Unofficial C++ Documentation
Loading...
Searching...
No Matches
undo_redo.h
Go to the documentation of this file.
1#pragma once
2
5
6#include <chrono>
7#include <concepts>
8#include <cstddef>
9#include <memory>
10#include <string>
11#include <string_view>
12#include <utility>
13#include <vector>
14
15// undo/redo algorithm support
16//
17// snapshot-based, rather than command-pattern based. Designed to be reference-counted, and
18// type-erasable, so that generic downstream code doesn't necessarily need to know what,
19// or how, the data is actually stored in memory
20namespace osc
21{
22 template<typename T>
23 concept Undoable = std::destructible<T> and std::copy_constructible<T>;
24
25 // internal storage details
26 namespace detail
27 {
28 // a base class for storing undo/redo metadata
30 protected:
31 explicit UndoRedoEntryMetadata(std::string_view message) :
32 message_{message}
33 {}
38 public:
40
41 UID id() const { return id_; }
42 CStringView message() const { return message_; }
43
44 private:
45 UID id_;
46 std::string message_;
47 };
48
49 // concrete implementation of storage for a complete undo/redo entry (metadata + value)
50 template<Undoable T>
52 public:
53 template<typename... Args>
54 requires std::constructible_from<T, Args&&...>
55 explicit UndoRedoEntryData(std::string_view message, Args&&... args) :
57 value_{std::forward<Args>(args)...}
58 {}
59
60 const T& value() const { return value_; }
61
62 private:
63 T value_;
64 };
65 }
66
67 // type-erased, const, and reference-counted storage for undo/redo entry data
68 //
69 // can be safely copied, sliced, etc. from the derived class, enabling type-erased
70 // implementation code
72 protected:
73 explicit UndoRedoEntryBase(std::shared_ptr<const detail::UndoRedoEntryMetadata> data) :
74 data_{std::move(data)}
75 {}
76
77 const detail::UndoRedoEntryMetadata& metadata() const { return *data_; }
78 public:
79 UID id() const { return data_->id(); }
80 CStringView message() const { return data_->message(); }
81
82 private:
83 std::shared_ptr<const detail::UndoRedoEntryMetadata> data_;
84 };
85
86 // concrete, known-to-hold-type-T version of `UndoRedoEntry`
87 template<Undoable T>
89 public:
90 template<typename... Args>
91 requires std::constructible_from<T, Args&&...>
92 explicit UndoRedoEntry(std::string_view message, Args&&... args) :
93 UndoRedoEntryBase{std::make_shared<detail::UndoRedoEntryData<T>>(std::move(message), std::forward<Args>(args)...)}
94 {}
95
96 const T& value() const { return static_cast<const detail::UndoRedoEntryData<T>&>(metadata()).value(); }
97 };
98
99 // type-erased base class for undo/redo storage
100 //
101 // this base class stores undo/redo entries as type-erased pointers, so that the
102 // code here, and in other generic downstream classes, doesn't need to know what's
103 // actually being stored
105 protected:
111
112 public:
114
115 // Moves the current head to the undo entries, creates a new head from
116 // the current scratch space, and clears the redo entries.
117 void commit_scratch(std::string_view commit_message);
118
121
122 // Copy-assigns the current head over the scratch space.
123 void rollback();
124
127 void undo_to(size_t pos);
129 void undo();
130
134 void redo_to(size_t pos);
135 void redo();
136
137 private:
140
141 std::vector<UndoRedoEntryBase> undo_;
142 std::vector<UndoRedoEntryBase> redo_;
143 UndoRedoEntryBase head_;
144 };
145
146 // concrete class for undo/redo storage
147 //
148 // - there is a "scratch" space that other code can edit
149 // - other code can "commit" the scratch space to storage via `commit(message)`
150 // - there is always at least one commit (the "head") in storage, for rollback support
153 public:
154 template<typename... Args>
155 requires std::constructible_from<T, Args&&...>
156 explicit UndoRedo(Args&&... args) :
157 UndoRedoBase(UndoRedoEntry<T>{"created document", std::forward<Args>(args)...}),
158 scratch_{static_cast<const UndoRedoEntry<T>&>(head()).value()}
159 {}
160
161 const T& scratch() const { return scratch_; }
162
163 T& upd_scratch() { return scratch_; }
164
165 const UndoRedoEntry<T>& undo_entry_at(size_t pos) const
166 {
167 return static_cast<const UndoRedoEntry<T>&>(static_cast<const UndoRedoBase&>(*this).undo_entry_at(pos));
168 }
169
170 const UndoRedoEntry<T>& redo_entry_at(size_t pos) const
171 {
172 return static_cast<const UndoRedoEntry<T>&>(static_cast<const UndoRedoBase&>(*this).redo_entry_at(pos));
173 }
174
175 private:
177 {
178 return UndoRedoEntry<T>{std::move(commit_message), scratch_};
179 }
180
182 {
183 scratch_ = static_cast<const UndoRedoEntry<T>&>(commit).value();
184 }
185
186 T scratch_;
187 };
188}
Definition c_string_view.h:12
Definition uid.h:14
Definition undo_redo.h:104
virtual void impl_copy_assign_scratch_from_commit(const UndoRedoEntryBase &)=0
bool can_undo() const
const UndoRedoEntryBase & redo_entry_at(size_t pos) const
UndoRedoBase(UndoRedoEntryBase initial_commit)
void commit_scratch(std::string_view commit_message)
const UndoRedoEntryBase & undo_entry_at(size_t pos) const
size_t num_undo_entries() const
const UndoRedoEntryBase & head() const
size_t num_redo_entries() const
bool can_redo() const
void undo_to(size_t pos)
UndoRedoBase(UndoRedoBase &&) noexcept
virtual UndoRedoEntryBase impl_construct_commit_from_scratch(std::string_view commit_message)=0
UID head_id() const
void redo_to(size_t pos)
UndoRedoBase(const UndoRedoBase &)
Definition undo_redo.h:71
CStringView message() const
Definition undo_redo.h:80
UndoRedoEntryBase(std::shared_ptr< const detail::UndoRedoEntryMetadata > data)
Definition undo_redo.h:73
const detail::UndoRedoEntryMetadata & metadata() const
Definition undo_redo.h:77
UID id() const
Definition undo_redo.h:79
Definition undo_redo.h:88
UndoRedoEntry(std::string_view message, Args &&... args)
Definition undo_redo.h:92
const T & value() const
Definition undo_redo.h:96
Definition undo_redo.h:152
const UndoRedoEntry< T > & undo_entry_at(size_t pos) const
Definition undo_redo.h:165
const T & scratch() const
Definition undo_redo.h:161
UndoRedoEntryBase impl_construct_commit_from_scratch(std::string_view commit_message) final
Definition undo_redo.h:176
UndoRedo(Args &&... args)
Definition undo_redo.h:156
void impl_copy_assign_scratch_from_commit(const UndoRedoEntryBase &commit) final
Definition undo_redo.h:181
T & upd_scratch()
Definition undo_redo.h:163
const UndoRedoEntry< T > & redo_entry_at(size_t pos) const
Definition undo_redo.h:170
Definition undo_redo.h:51
const T & value() const
Definition undo_redo.h:60
UndoRedoEntryData(std::string_view message, Args &&... args)
Definition undo_redo.h:55
Definition undo_redo.h:29
UndoRedoEntryMetadata(const UndoRedoEntryMetadata &)=default
UndoRedoEntryMetadata(UndoRedoEntryMetadata &&) noexcept=default
CStringView message() const
Definition undo_redo.h:42
UndoRedoEntryMetadata(std::string_view message)
Definition undo_redo.h:31
Definition undo_redo.h:23
Definition custom_decoration_generator.h:5
constexpr U to(T &&value)
Definition conversion.h:56
and
Definition algorithms.h:158