fork download
  1. #include <list>
  2. #include <map>
  3. #include <iostream>
  4. #include <string>
  5. #include <memory>
  6. #include <stdexcept>
  7.  
  8. namespace mem=std;//::tr1;
  9. namespace fun=std;//::tr1;
  10.  
  11. //Original of the non-templatized version: http://w...content-available-to-author-only...k.com/index.php?title=Design_pattern_memento
  12. //continued here: https://g...content-available-to-author-only...b.com/d-led/undoredo-cpp
  13.  
  14. /// to be able to talk undoables uniformly
  15. struct Undoable
  16. {
  17. virtual void Undo()=0;
  18. virtual ~Undoable() {}
  19. };
  20.  
  21. /// Memento for the encapsulation of the state and its handling
  22. template <class T>
  23. class Memento
  24. {
  25.  
  26. private:
  27.  
  28. T state_;
  29.  
  30. public:
  31.  
  32. Memento(const T& stateToSave) : state_(stateToSave) { }
  33. const T& getSavedState()
  34. {
  35. return state_;
  36. }
  37. };
  38.  
  39. /// A convenience class for storage of mementos
  40. template <class T, class TMemento = typename T::MementoType>
  41. struct MementoStore : public Undoable
  42. {
  43. virtual void Save(T* t)=0;
  44. virtual void Undo(T* t)=0;
  45. virtual void Undo()=0;
  46. virtual ~MementoStore() {}
  47. };
  48.  
  49. /// the default implementation of the store
  50. template<class T, class TMemento = typename T::MementoType>
  51. class StlMementoStore : public MementoStore<T, TMemento>
  52. {
  53. private:
  54. typedef std::map<T*,std::list<mem::shared_ptr<TMemento> > > StoreType;
  55. StoreType Store;
  56.  
  57. public:
  58.  
  59. void PushState(T* t,mem::shared_ptr<TMemento> m)
  60. {
  61. if (t)
  62. {
  63. Store[t].push_back(m);
  64. }
  65. }
  66.  
  67. mem::shared_ptr<TMemento> PopState(T* t)
  68. {
  69. if (!t || Store[t].size()<1) throw std::runtime_error("No more undo states");
  70. mem::shared_ptr<TMemento> res=Store[t].back();
  71. Store[t].pop_back();
  72. return res;
  73. }
  74.  
  75. virtual void Save(T* t)
  76. {
  77. PushState(t,t->SaveState());
  78. }
  79.  
  80. virtual void Undo(T* t)
  81. {
  82. t->RestoreState(PopState(t));
  83. }
  84.  
  85. /// tries to undo 1 state change per object for all objects
  86. virtual void Undo()
  87. {
  88. TryUndoAll();
  89. }
  90.  
  91. private:
  92. void TryUndoAll()
  93. {
  94. for (typename StoreType::iterator it=Store.begin(); it!=Store.end(); ++it)
  95. {
  96. try
  97. {
  98. it->first->RestoreState(PopState(it->first));
  99. }
  100. catch(std::exception& e)
  101. {
  102. /*trying, anyway*/ e;
  103. }
  104. }
  105. }
  106. };
  107.  
  108. /// A container of undoables that undos all
  109. class UndoableAggregate : public Undoable
  110. {
  111. typedef std::list<mem::shared_ptr<Undoable> > Container;
  112. private:
  113. Container list_;
  114.  
  115. public:
  116. virtual void Undo()
  117. {
  118. for (Container::iterator it=list_.begin(); it!=list_.end(); ++it)
  119. {
  120. (*it)->Undo();
  121. }
  122. }
  123.  
  124. public:
  125. void AddUndoable(mem::shared_ptr<Undoable> instance)
  126. {
  127. list_.push_back(instance);
  128. }
  129. };
  130.  
  131. /// example state-undoable class
  132. class MyOriginator
  133. {
  134. private:
  135. struct State
  136. {
  137. std::string s;
  138. };
  139. State state_;
  140.  
  141. public:
  142.  
  143. void Set(const std::string& state)
  144. {
  145. std::cout << "MyOriginator::Setting state to: " << state << std::endl;
  146. state_.s = state;
  147. }
  148.  
  149. //--- class-specific memento
  150.  
  151. public:
  152. typedef Memento<State> MementoType;
  153. typedef MementoStore<MyOriginator> MementoStoreType;
  154.  
  155. mem::shared_ptr<MementoType> SaveState()
  156. {
  157. std::cout << "MyOriginator::Saving state to Memento." << std::endl;
  158. return mem::shared_ptr<MementoType>(new MementoType(state_));
  159. }
  160.  
  161. void RestoreState(mem::shared_ptr<MementoType> memento)
  162. {
  163. state_ = memento->getSavedState();
  164. std::cout << "MyOriginator::Restoring state from Memento: " << state_.s << std::endl;
  165. }
  166. };
  167.  
  168. /// the other example class
  169. class MySecondOriginator
  170. {
  171. private:
  172. int s;
  173.  
  174. public:
  175.  
  176. void Set(int state)
  177. {
  178. std::cout << "MySecondOriginator::Setting state to: " << state << std::endl;
  179. s = state;
  180. }
  181.  
  182. MySecondOriginator():s(0){}
  183.  
  184. //--- class-specific memento
  185.  
  186. public:
  187. typedef Memento<int> MementoType;
  188. typedef MementoStore<MySecondOriginator> MementoStoreType;
  189.  
  190. mem::shared_ptr<MementoType> SaveState()
  191. {
  192. std::cout << "MySecondOriginator::Saving state to Memento." << std::endl;
  193. return mem::shared_ptr<MementoType>(new MementoType(s));
  194. }
  195.  
  196. void RestoreState(mem::shared_ptr<MementoType> memento)
  197. {
  198. s = memento->getSavedState();
  199. std::cout << "MySecondOriginator::Restoring state from Memento: " << s << std::endl;
  200. }
  201. };
  202.  
  203. template <class T>
  204. mem::shared_ptr<typename T::MementoStoreType> NewMementoStore()
  205. {
  206. return mem::shared_ptr<typename T::MementoStoreType>(new StlMementoStore<T>);
  207. }
  208.  
  209. //----- Prototype for transaction based undo
  210.  
  211. typedef fun::function<void ()> Action;
  212. typedef std::pair<Action/*Undo*/,Action/*Redo*/> Transaction;
  213.  
  214.  
  215. /// Storage of transactions
  216. class TransactionStore
  217. {
  218. private:
  219. std::list<Transaction> Undo_;
  220. std::list<Transaction> Redo_;
  221.  
  222. public:
  223.  
  224. void AddTransaction(Transaction t)
  225. {
  226. if (t.first && t.second)
  227. {
  228. Undo_.push_back(t);
  229. Redo_.clear();
  230. }
  231. }
  232.  
  233. void UndoLastTransaction()
  234. {
  235. if (Undo_.size()<1) throw std::runtime_error("No more undo transactions");
  236. Undo_.back().first();
  237. Redo_.push_back(Undo_.back());
  238. Undo_.pop_back();
  239. }
  240.  
  241. void RedoLastTransaction()
  242. {
  243. if (Redo_.size()<1) throw std::runtime_error("No more redo transactions");
  244. Redo_.back().second();
  245. Undo_.push_back(Redo_.back());
  246. Redo_.pop_back();
  247. }
  248.  
  249. void Purge()
  250. {
  251. Undo_.clear();
  252. Redo_.clear();
  253. }
  254. };
  255.  
  256. class CompositeTransaction : public fun::enable_shared_from_this<CompositeTransaction>
  257. {
  258. private:
  259. std::list<Transaction> Undo_;
  260. std::list<Transaction> Redo_;
  261.  
  262. public:
  263.  
  264. void AddTransaction(Transaction t)
  265. {
  266. if (t.first && t.second)
  267. {
  268. Undo_.push_back(t);
  269. Redo_.clear();
  270. }
  271. }
  272.  
  273. void UndoAll()
  274. {
  275. while (Undo_.size())
  276. {
  277. Undo_.back().first();
  278. Redo_.push_back(Undo_.back());
  279. Undo_.pop_back();
  280. }
  281. }
  282.  
  283. void RedoAll()
  284. {
  285. while (Redo_.size())
  286. {
  287. Redo_.back().second();
  288. Undo_.push_back(Redo_.back());
  289. Redo_.pop_back();
  290. }
  291. }
  292.  
  293. /// a composite transaction, instance must be in shared_ptr
  294. Transaction Get()
  295. {
  296. return std::make_pair(fun::bind(&CompositeTransaction::UndoAll,shared_from_this()),
  297. fun::bind(&CompositeTransaction::RedoAll,shared_from_this()));
  298. }
  299. };
  300.  
  301.  
  302. /// Transaction-undoable example class
  303. class MyThirdOriginator : public mem::enable_shared_from_this<MyThirdOriginator>
  304. {
  305. private:
  306. int state;
  307. std::string name;
  308.  
  309. public:
  310.  
  311. void Set(int s)
  312. {
  313. std::cout << "MyThirdOriginator("<<name<<")::Setting state to: " << s << std::endl;
  314. state=s;
  315. }
  316.  
  317. void SetName(std::string n)
  318. {
  319. std::cout << "MyThirdOriginator("<<name<<")::Setting name to: " << n << std::endl;
  320. name=n;
  321. }
  322.  
  323. //---- class-specific transaction
  324.  
  325. Transaction UndoableSet(int s,std::string n)
  326. {
  327. mem::shared_ptr<CompositeTransaction> res(new CompositeTransaction);
  328. if (n!=name)
  329. {
  330. res->AddTransaction(std::make_pair(
  331. fun::bind(&MyThirdOriginator::SetName,shared_from_this(),name),
  332. fun::bind(&MyThirdOriginator::SetName,shared_from_this(),n)
  333. ));
  334. SetName(n);
  335. }
  336. if (s!=state)
  337. {
  338. res->AddTransaction(std::make_pair(
  339. fun::bind(&MyThirdOriginator::Set,shared_from_this(),state),
  340. fun::bind(&MyThirdOriginator::Set,shared_from_this(),s)
  341. ));
  342. Set(s);
  343. }
  344. return res->Get();
  345. }
  346.  
  347. public:
  348.  
  349. MyThirdOriginator(std::string n):state(0),name(n) {}
  350.  
  351. ~MyThirdOriginator()
  352. {
  353. std::cout<<"Destroying MyThirdOriginator("<<name<<")" << std::endl;
  354. }
  355. };
  356.  
  357. static void Print(const char * t)
  358. {
  359. std::cout<<t;
  360. }
  361.  
  362. static Transaction RepeatedPrint(const char * t)
  363. {
  364. Print(t);
  365. return std::make_pair(fun::bind(Print,t),fun::bind(Print,t));
  366. }
  367.  
  368. /// the default implementation of the store
  369. template<class T, class TMemento = typename T::MementoType>
  370. class DelayedTransaction : public mem::enable_shared_from_this<DelayedTransaction<T,typename T::MementoType> >
  371. {
  372. private:
  373. mem::shared_ptr<TMemento> Undo_;
  374. mem::shared_ptr<TMemento> Redo_;
  375. T* Object_;
  376.  
  377. public:
  378.  
  379. DelayedTransaction(T* t)
  380. {
  381. Object_=t;
  382. }
  383.  
  384. void BeginTransaction()
  385. {
  386. Undo_=Object_->SaveState();
  387. }
  388.  
  389. Transaction EndTransaction()
  390. {
  391. Redo_=Object_->SaveState();
  392. return Get();
  393. }
  394.  
  395. Transaction Get()
  396. {
  397. return std::make_pair(fun::bind(&DelayedTransaction<T>::Undo,this->shared_from_this()),
  398. fun::bind(&DelayedTransaction<T>::Redo,this->shared_from_this()));
  399. }
  400.  
  401. private:
  402.  
  403. virtual void Undo()
  404. {
  405. Object_->RestoreState(Undo_);
  406. }
  407.  
  408. virtual void Redo()
  409. {
  410. Object_->RestoreState(Redo_);
  411. }
  412. };
  413.  
  414. int main()
  415. {
  416. std::auto_ptr<UndoableAggregate> allStores(new UndoableAggregate);
  417.  
  418. //example class 1
  419. MyOriginator originator;
  420. mem::shared_ptr<MyOriginator::MementoStoreType> savedStates(NewMementoStore<MyOriginator>()); //without c++0x
  421. //auto savedStates=NewMementoStore<MyOriginator>();
  422. allStores->AddUndoable(savedStates);
  423. //
  424. originator.Set("StateA");
  425. originator.Set("StateB");
  426. savedStates->Save(&originator);
  427. originator.Set("StateC");
  428. savedStates->Save(&originator);
  429. originator.Set("StateD");
  430. savedStates->Save(&originator);
  431. //
  432. MyOriginator originator2;
  433. originator2.Set("StateA(2)");
  434. savedStates->Save(&originator2);
  435. originator2.Set("StateB(2)");
  436. savedStates->Save(&originator2);
  437.  
  438. //example class 2
  439. MySecondOriginator originator3;
  440. mem::shared_ptr<MySecondOriginator::MementoStoreType> savedStates2(NewMementoStore<MySecondOriginator>());
  441. //auto savedStates2=NewMementoStore<MySecondOriginator>();
  442. allStores->AddUndoable(savedStates2);
  443. //
  444. originator3.Set(1);
  445. savedStates2->Save(&originator3);
  446. originator3.Set(2);
  447. savedStates2->Save(&originator3);
  448.  
  449. try
  450. {
  451. allStores->Undo(); //try to undo all objects in all stores
  452. allStores->Undo();
  453.  
  454. savedStates->Undo(&originator);
  455. savedStates->Undo(&originator);
  456. savedStates->Undo(&originator);
  457. savedStates->Undo(&originator);
  458. }
  459. catch (std::exception& e)
  460. {
  461. std::cout<<e.what()<<std::endl;
  462. }
  463.  
  464.  
  465. // transaction-based undo prototype
  466. mem::shared_ptr<MyThirdOriginator> o1(new MyThirdOriginator("o1")),o2(new MyThirdOriginator("o2"));
  467. TransactionStore ts;
  468. ts.AddTransaction(RepeatedPrint("-----------------\n"));
  469. ts.AddTransaction(o1->UndoableSet(1,"o1"));
  470. ts.AddTransaction(o1->UndoableSet(2,"o1"));
  471. ts.AddTransaction(o1->UndoableSet(3,"o1->1"));
  472. ts.AddTransaction(o1->UndoableSet(4,"o1->2"));
  473. ts.AddTransaction(RepeatedPrint("-----------------\n"));
  474. ts.AddTransaction(o2->UndoableSet(4,"o2"));
  475. ts.AddTransaction(o2->UndoableSet(5,"o2"));
  476. ts.AddTransaction(RepeatedPrint("-----------------\n"));
  477.  
  478. ts.UndoLastTransaction();
  479. std::cout<<"Undo : ";
  480. ts.UndoLastTransaction();
  481. std::cout<<"Undo : ";
  482. ts.UndoLastTransaction();
  483. std::cout<<"Redo : ";
  484. ts.RedoLastTransaction();
  485. std::cout<<"Redo : ";
  486. ts.RedoLastTransaction();
  487. ts.RedoLastTransaction();
  488.  
  489. while (true)
  490. {
  491. try
  492. {
  493. ts.UndoLastTransaction();
  494. }
  495. catch(std::exception& e)
  496. {
  497. std::cout<<e.what()<<std::endl;
  498. break;
  499. }
  500. }
  501.  
  502. Print("-----------------\n");
  503. std::cout<<"Redo test : "<<std::endl;
  504.  
  505.  
  506. ts.AddTransaction(RepeatedPrint("Action 1\n"));
  507.  
  508. mem::shared_ptr<CompositeTransaction> A2(new CompositeTransaction);
  509. A2->AddTransaction(RepeatedPrint("Action 2.1\n"));
  510. A2->AddTransaction(RepeatedPrint("Action 2.2\n"));
  511.  
  512. ts.AddTransaction(A2->Get());
  513.  
  514. ts.AddTransaction(RepeatedPrint("Action 3\n"));
  515.  
  516. std::cout<<"Undo : ";
  517. ts.UndoLastTransaction();
  518. std::cout<<"Undo : ";
  519. ts.UndoLastTransaction();
  520.  
  521. ts.AddTransaction(RepeatedPrint("Action 4\n"));
  522.  
  523.  
  524. while (true)
  525. {
  526. try
  527. {
  528. ts.RedoLastTransaction();
  529. }
  530. catch(std::exception& e)
  531. {
  532. std::cout<<e.what()<<std::endl;
  533. break;
  534. }
  535. }
  536.  
  537. Print("-----------------\n");
  538. std::cout<<"Lifetime test : "<<std::endl;
  539.  
  540. ts.Purge();
  541.  
  542. {
  543. mem::shared_ptr<MyThirdOriginator> O3(new MyThirdOriginator("O3"));
  544. ts.AddTransaction(O3->UndoableSet(1,"O3.1"));
  545. ts.AddTransaction(O3->UndoableSet(2,"O3.2"));
  546. }
  547.  
  548. std::cout<<"Undo : ";
  549. ts.UndoLastTransaction();
  550. std::cout<<"Undo : ";
  551. ts.UndoLastTransaction();
  552. std::cout<<"Redo : ";
  553. ts.RedoLastTransaction();
  554. std::cout<<"Redo : ";
  555. ts.RedoLastTransaction();
  556.  
  557. Print("-----------------\n");
  558. std::cout<<"Purging undo history ..."<<std::endl;
  559. ts.Purge();
  560. std::cout<<"Purged undo history"<<std::endl;
  561.  
  562.  
  563. Print("-----------------\n");
  564. std::cout<<"Memento transaction test : "<<std::endl;
  565. mem::shared_ptr<MySecondOriginator> MSO(new MySecondOriginator);
  566.  
  567. mem::shared_ptr<DelayedTransaction<MySecondOriginator> > DT(new DelayedTransaction<MySecondOriginator>(MSO.get()));
  568.  
  569. DT.reset(new DelayedTransaction<MySecondOriginator>(MSO.get()));
  570. DT->BeginTransaction();
  571. MSO->Set(1);
  572. ts.AddTransaction(DT->EndTransaction());
  573.  
  574. DT.reset(new DelayedTransaction<MySecondOriginator>(MSO.get()));
  575. DT->BeginTransaction();
  576. MSO->Set(2);
  577. ts.AddTransaction(DT->EndTransaction());
  578.  
  579. DT.reset(new DelayedTransaction<MySecondOriginator>(MSO.get()));
  580. DT->BeginTransaction();
  581. MSO->Set(3);
  582. MSO->Set(4);
  583. ts.AddTransaction(DT->EndTransaction());
  584.  
  585. DT.reset(new DelayedTransaction<MySecondOriginator>(MSO.get()));
  586. DT->BeginTransaction();
  587. MSO->Set(5);
  588. ts.AddTransaction(DT->EndTransaction());
  589.  
  590. std::cout<<"Undo : ";
  591. ts.UndoLastTransaction();
  592. std::cout<<"Undo : ";
  593. ts.UndoLastTransaction();
  594. std::cout<<"Undo : ";
  595. ts.UndoLastTransaction();
  596. std::cout<<"Redo : ";
  597. ts.RedoLastTransaction();
  598. std::cout<<"Redo : ";
  599. ts.RedoLastTransaction();
  600. std::cout<<"Redo : ";
  601. ts.RedoLastTransaction();
  602.  
  603. ts.Purge();
  604.  
  605. //todo: lifetime management in the combination of memento and transactions
  606. return 0;
  607. }
Success #stdin #stdout 0s 3028KB
stdin
Standard input is empty
stdout
MyOriginator::Setting state to: StateA
MyOriginator::Setting state to: StateB
MyOriginator::Saving state to Memento.
MyOriginator::Setting state to: StateC
MyOriginator::Saving state to Memento.
MyOriginator::Setting state to: StateD
MyOriginator::Saving state to Memento.
MyOriginator::Setting state to: StateA(2)
MyOriginator::Saving state to Memento.
MyOriginator::Setting state to: StateB(2)
MyOriginator::Saving state to Memento.
MySecondOriginator::Setting state to: 1
MySecondOriginator::Saving state to Memento.
MySecondOriginator::Setting state to: 2
MySecondOriginator::Saving state to Memento.
MyOriginator::Restoring state from Memento: StateB(2)
MyOriginator::Restoring state from Memento: StateD
MySecondOriginator::Restoring state from Memento: 2
MyOriginator::Restoring state from Memento: StateA(2)
MyOriginator::Restoring state from Memento: StateC
MySecondOriginator::Restoring state from Memento: 1
MyOriginator::Restoring state from Memento: StateB
No more undo states
-----------------
MyThirdOriginator(o1)::Setting state to: 1
MyThirdOriginator(o1)::Setting state to: 2
MyThirdOriginator(o1)::Setting name to: o1->1
MyThirdOriginator(o1->1)::Setting state to: 3
MyThirdOriginator(o1->1)::Setting name to: o1->2
MyThirdOriginator(o1->2)::Setting state to: 4
-----------------
MyThirdOriginator(o2)::Setting state to: 4
MyThirdOriginator(o2)::Setting state to: 5
-----------------
-----------------
Undo : MyThirdOriginator(o2)::Setting state to: 4
Undo : MyThirdOriginator(o2)::Setting state to: 0
Redo : MyThirdOriginator(o2)::Setting state to: 4
Redo : MyThirdOriginator(o2)::Setting state to: 5
-----------------
-----------------
MyThirdOriginator(o2)::Setting state to: 4
MyThirdOriginator(o2)::Setting state to: 0
-----------------
MyThirdOriginator(o1->2)::Setting state to: 3
MyThirdOriginator(o1->2)::Setting name to: o1->1
MyThirdOriginator(o1->1)::Setting state to: 2
MyThirdOriginator(o1->1)::Setting name to: o1
MyThirdOriginator(o1)::Setting state to: 1
MyThirdOriginator(o1)::Setting state to: 0
-----------------
No more undo transactions
-----------------
Redo test : 
Action 1
Action 2.1
Action 2.2
Action 3
Undo : Action 3
Undo : Action 2.2
Action 2.1
Action 4
No more redo transactions
-----------------
Lifetime test : 
MyThirdOriginator(O3)::Setting name to: O3.1
MyThirdOriginator(O3.1)::Setting state to: 1
MyThirdOriginator(O3.1)::Setting name to: O3.2
MyThirdOriginator(O3.2)::Setting state to: 2
Undo : MyThirdOriginator(O3.2)::Setting state to: 1
MyThirdOriginator(O3.2)::Setting name to: O3.1
Undo : MyThirdOriginator(O3.1)::Setting state to: 0
MyThirdOriginator(O3.1)::Setting name to: O3
Redo : MyThirdOriginator(O3)::Setting name to: O3.1
MyThirdOriginator(O3.1)::Setting state to: 1
Redo : MyThirdOriginator(O3.1)::Setting name to: O3.2
MyThirdOriginator(O3.2)::Setting state to: 2
-----------------
Purging undo history ...
Destroying MyThirdOriginator(O3.2)
Purged undo history
-----------------
Memento transaction test : 
MySecondOriginator::Saving state to Memento.
MySecondOriginator::Setting state to: 1
MySecondOriginator::Saving state to Memento.
MySecondOriginator::Saving state to Memento.
MySecondOriginator::Setting state to: 2
MySecondOriginator::Saving state to Memento.
MySecondOriginator::Saving state to Memento.
MySecondOriginator::Setting state to: 3
MySecondOriginator::Setting state to: 4
MySecondOriginator::Saving state to Memento.
MySecondOriginator::Saving state to Memento.
MySecondOriginator::Setting state to: 5
MySecondOriginator::Saving state to Memento.
Undo : MySecondOriginator::Restoring state from Memento: 4
Undo : MySecondOriginator::Restoring state from Memento: 2
Undo : MySecondOriginator::Restoring state from Memento: 1
Redo : MySecondOriginator::Restoring state from Memento: 2
Redo : MySecondOriginator::Restoring state from Memento: 4
Redo : MySecondOriginator::Restoring state from Memento: 5
Destroying MyThirdOriginator(o2)
Destroying MyThirdOriginator(o1)