libAlgAudio  v1.99-440-g08538e5-dirty
The development library for AlgAudio framework.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
LateReturn.hpp
Go to the documentation of this file.
1 #ifndef LATERETURN_HPP
2 #define LATERETURN_HPP
3 /*
4 This file is part of AlgAudio.
5 
6 AlgAudio, Copyright (C) 2015 CeTA - Audiovisual Technology Center
7 
8 AlgAudio is free software: you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as
10 published by the Free Software Foundation, either version 3 of the
11 License, or (at your option) any later version.
12 
13 AlgAudio is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public License
19 along with AlgAudio. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include <map>
23 #include <unordered_map>
24 #include <functional>
25 #include <tuple>
26 #include <iostream>
27 #include <typeinfo>
28 #include <typeindex>
29 #include <memory>
30 #include "Exception.hpp"
31 
32 namespace AlgAudio{
33 
34 template <typename... Types>
35 class LateReturn;
36 template <typename... Types>
37 class Relay;
38 
62 class Sync{
63 public:
67  Sync(int count);
72  void WhenAll(std::function<void()> func) const;
74  void Trigger() const;
75 private:
76  const unsigned int id;
77  struct SyncEntry{
78  SyncEntry(int c) : count(c) {}
79  int count = 2;
80  bool stored = false;
81  std::function<void()> stored_func;
82  };
83  static std::map<unsigned int, SyncEntry*> entries;
84  static unsigned int id_counter;
85 };
86 
87 template <typename T>
88 std::function<void()> bind_tuple(std::function<void(T)> f, std::tuple<T> t){
89  return std::bind(f, std::get<0>(t));
90 }
91 template <typename T, typename S>
92 std::function<void()> bind_tuple(std::function<void(T, S)> f, std::tuple<T, S> t){
93  return std::bind(f, std::get<0>(t), std::get<1>(t));
94 }
95 template <typename T, typename S, typename R>
96 std::function<void()> bind_tuple(std::function<void(T, S, R)> f, std::tuple<T, S, R> t){
97  return std::bind(f, std::get<0>(t), std::get<1>(t), std::get<2>(t));
98 }
99 inline std::function<void()> bind_tuple(std::function<void()> f, std::tuple<>){
100  return f;
101 }
102 
107 protected:
109  bool triggered = false;
110 public:
111  static std::map<int, LateReturnEntryBase*> entries;
112  static int id_counter;
113 };
120 template <typename... Types>
122 public:
123  friend class LateReturn<Types...>;
124  friend class Relay<Types...>;
125 private:
126  LateReturnEntry(){};
128  void Invoke(){
129  std::function<void()> f = bind_tuple(stored_func, stored_args);
130  try{
131  f();
132  }catch(...){
133  std::cout << "Exception while invoking a latereturn continuation" << std::endl;
134  }
135  }
137  std::function<void(Types...)> stored_func;
139  std::tuple<Types...> stored_args;
141  std::unordered_map<std::type_index, std::function<void(std::shared_ptr<Exceptions::Exception>)>> catchers;
143  std::shared_ptr<Exceptions::Exception> stored_exception;
145  std::function<void(std::shared_ptr<Exceptions::Exception>)> default_catcher;
147  bool stored = false;
148 };
149 
236 template <typename... Types>
237 class LateReturn{
238 public:
246  const LateReturn& Then(std::function<void(Types...)> f) const{
247  auto it = LateReturnEntryBase::entries.find(id);
248  if(it == LateReturnEntryBase::entries.end()){
249  std::cout << "ERROR: LateReturn Then called, but it is not in the base!" << std::endl;
250  return *this;
251  }
252  LateReturnEntry<Types...>* entry = dynamic_cast<LateReturnEntry<Types...>*>(it->second);
253  if(!entry->triggered){
254  entry->stored_func = f;
255  entry->stored = true;
256  }else{
257  // The Relay has already returned, but it was not bound until now.
258  entry->stored_func = f;
259  entry->Invoke();
260  delete entry;
262  }
263  return *this;
264  }
265 
271  template<typename Ex>
272  const LateReturn& Catch(std::function<void(std::shared_ptr<Exceptions::Exception>)> func) const{
273  auto it = LateReturnEntryBase::entries.find(id);
274  if(it == LateReturnEntryBase::entries.end()){
275  // Catch is called, but the entry has already returned. Therefore, ignore the catcher.
276  return *this;
277  }
278  LateReturnEntry<Types...>* entry = dynamic_cast<LateReturnEntry<Types...>*>(it->second);
279  if(entry->stored_exception){
280  std::cout << "There is a stored exception already" << std::endl;
281  func(entry->stored_exception);
282  }else{
283  entry->catchers[typeid(Ex)] = func;
284  }
285  return *this;
286  }
287 
294  template<typename Ex>
295  const LateReturn& CatchAll(std::function<void(std::shared_ptr<Exceptions::Exception>)> func) const{
296  auto it = LateReturnEntryBase::entries.find(id);
297  if(it == LateReturnEntryBase::entries.end()){
298  // Catch is called, but the entry has already returned. Therefore, ignore the catcher.
299  return *this;
300  }
301  LateReturnEntry<Types...>* entry = dynamic_cast<LateReturnEntry<Types...>*>(it->second);
302  if(entry->default_catcher){
303  std::cout << "ERROR: Cannot add another default cather to the same latereturn" << std::endl;
304  return;
305  }
306  if(entry->stored_exception){
307  std::cout << "There is a stored exception already" << std::endl;
308  func(entry->stored_exception);
309  }else{
310  entry->default_catcher = func;
311  }
312  return *this;
313  }
314 
320  template<typename... X>
321  const LateReturn& Catch(const Relay<X...>& r) const{
322  auto it = LateReturnEntryBase::entries.find(id);
323  if(it == LateReturnEntryBase::entries.end()){
324  // Catch is called, but the entry has already returned. Therefore, ignore the catcher.
325  return *this;
326  }
327  LateReturnEntry<Types...>* entry = dynamic_cast<LateReturnEntry<Types...>*>(it->second);
328  if(entry->default_catcher){
329  std::cout << "ERROR: Cannot add another default cather to the same latereturn" << std::endl;
330  return *this;
331  }
332  if(entry->stored_exception){
333  std::cout << "There is a stored exception already" << std::endl;
334  // Pass the exception to that parent relay
335  r.PassException(entry->stored_exception);
336  }else{
337  // Pass all exceptions to parent relay
338  entry->default_catcher = [r](std::shared_ptr<Exceptions::Exception> ex){
339  r.PassException(ex);
340  };
341  }
342  return *this;
343  }
344 
349  const LateReturn& ThenSync(Sync& s) const{
350  Then([=](Types...)mutable{
351  s.Trigger();
352  });
353  return *this;
354  }
361  Then([r](Types... result){
362  r.Return(result...);
363  });
364  return *this;
365  }
367  LateReturn(const Relay<Types...>& r) : id(r.id) {}
368  LateReturn(const LateReturn& other) = delete;
369  LateReturn& operator=(const LateReturn& other) = delete;
370  LateReturn(LateReturn&& other) : id(other.id) {}
371  LateReturn& operator=(LateReturn&& other) {id = other.id;}
372  friend class Relay<Types...>;
373 private:
374  LateReturn(int i) : id(i) {};
375  const int id;
376 };
377 
425 template <typename... Types>
426 class Relay{
427 public:
429  Relay(){
430  int newid = LateReturnEntryBase::id_counter++;
431  LateReturnEntryBase::entries[newid] = new LateReturnEntry<Types...>();
432  id = newid;
433  }
437  const Relay& Return(Types... args) const{
438  auto it = LateReturnEntryBase::entries.find(id);
439  //std::cout << "Returning " << id << std::endl;
440  if(it == LateReturnEntryBase::entries.end()){
441  std::cout << "ERROR: Return() used on the same relay " << id << " twice!" << std::endl;
442  std::cout << "Did you remember to capture the relay by-value?" << std::endl;
443  return *this;
444  }
445  LateReturnEntry<Types...>* entry = dynamic_cast<LateReturnEntry<Types...>*>(it->second);
446  if(entry->stored){
447  entry->stored_args = std::tuple<Types...>(args...);
448  entry->Invoke();
449  delete entry;
451  }else{
452  entry->stored_args = std::tuple<Types...>(args...);
453  entry->triggered = true;
454  }
455  return *this;
456  }
471  template<typename Ex, typename... ConstructArgs>
472  const Relay& LateThrow(ConstructArgs... args) const{
473  std::shared_ptr<Ex> exception = std::make_shared<Ex>(args...);
474  PassException(exception);
475  return *this;
476  }
478  const Relay& PassException(std::shared_ptr<Exceptions::Exception> ex) const{
479  auto it = LateReturnEntryBase::entries.find(id);
480  if(it != LateReturnEntryBase::entries.end()){
481  LateReturnEntry<Types...>* entry = dynamic_cast<LateReturnEntry<Types...>*>(it->second);
482  // Check if there is a catcher registered for this exception.
483  auto it2 = entry->catchers.find(typeid(*ex));
484  if(it2 != entry->catchers.end()){
485  // If so, call the cather.
486  (it2->second)(ex);
487  }else{
488  if(entry->default_catcher){
489  // Use the default catcher.
490  (entry->default_catcher)(ex);
491  }else{
492  // Otherwise store it for later.
493  entry->stored_exception = ex;
494 
495  if(entry->stored){
496  // There is a stored then entry, but no catcher. This ususally means trouble.
497  // TODO : Detect when the last referencet to LastReturn is lost. If
498  // there are no references, and no catcher, there is no chance it could
499  // be aded later. Warn about this.
500  std::cout << "WARNING: A LateThrow cannot be caught and is ignored: " << ex->what() << std::endl;
501  }
502  }
503  }
504  }else{
505  std::cout << "ERROR: A relay may not PassException(...) after Return(...)ing." << std::endl;
506  }
507  return *this;
508  }
510  LateReturn<Types...> GetLateReturn() const{
511  return LateReturn<Types...>(id);
512  }
513  friend class LateReturn<Types...>;
514  int GetID() const {return id;}
515 private:
516  int id = -42;
517  Relay(int i) : id(i) {};
518 };
519 
524 template <typename T>
526  Relay<> r;
527  lr.Then([r,&to_set](T val)mutable{
528  to_set = val;
529  r.Return();
530  });
531  return r;
532 }
533 
534 
535 template <typename T> struct identity
536 {
537  typedef T type;
538 };
539 template <typename... X>
540 void operator>>=(LateReturn<X...>&& first, typename identity<std::function<void(X...)>>::type then){
541  first.Then(then);
542 }
543 
544 template <typename... X, typename Y>
545 LateReturn<Y> operator>>=(LateReturn<X...>&& first, typename identity<std::function<Y(X...)>>::type then){
546  Relay<Y> r;
547  first.Then([=](X... args){
548  r.Return( then(args...) );
549  });
550  return r;
551 }
552 
553 template <typename... X, typename... Y>
554 LateReturn<Y...> operator>>=(LateReturn<X...>&& first, typename identity<std::function<LateReturn<Y...>(X...)>>::type then){
555  Relay<Y...> r;
556  first.Then([=](X... args){
557  then(args...).ThenReturn(r);
558  });
559  return r;
560 }
561 
562 } // namespace AlgAudio
563 
564 #endif // LATERETURN_HPP
LateReturn(const Relay< Types...> &r)
Definition: LateReturn.hpp:367
LateReturn< Types...> GetLateReturn() const
Definition: LateReturn.hpp:510
Sync(int count)
const LateReturn & Catch(const Relay< X...> &r) const
Definition: LateReturn.hpp:321
const Relay & LateThrow(ConstructArgs...args) const
Definition: LateReturn.hpp:472
virtual ~LateReturnEntryBase()
Definition: LateReturn.hpp:108
const LateReturn & ThenReturn(Relay< Types...> r) const
Definition: LateReturn.hpp:360
LateReturn LateAssign(T &to_set, LateReturn< T > lr)
Definition: LateReturn.hpp:525
void operator>>=(LateReturn< X...> &&first, typename identity< std::function< void(X...)>>::type then)
Definition: LateReturn.hpp:540
Definition: LateReturn.hpp:62
const Relay & Return(Types...args) const
Definition: LateReturn.hpp:437
Relay()
Definition: LateReturn.hpp:429
Definition: LateReturn.hpp:37
Definition: LateReturn.hpp:121
static std::map< int, LateReturnEntryBase * > entries
Definition: LateReturn.hpp:111
const LateReturn & Catch(std::function< void(std::shared_ptr< Exceptions::Exception >)> func) const
Definition: LateReturn.hpp:272
Definition: LateReturn.hpp:106
const LateReturn & ThenSync(Sync &s) const
Definition: LateReturn.hpp:349
int GetID() const
Definition: LateReturn.hpp:514
void Trigger() const
void WhenAll(std::function< void()> func) const
Definition: Alertable.hpp:26
bool triggered
Definition: LateReturn.hpp:109
LateReturn(LateReturn &&other)
Definition: LateReturn.hpp:370
static int id_counter
Definition: LateReturn.hpp:112
LateReturn & operator=(const LateReturn &other)=delete
LateReturn & operator=(LateReturn &&other)
Definition: LateReturn.hpp:371
Definition: LateReturn.hpp:35
const Relay & PassException(std::shared_ptr< Exceptions::Exception > ex) const
Definition: LateReturn.hpp:478
std::function< void()> bind_tuple(std::function< void(T)> f, std::tuple< T > t)
Definition: LateReturn.hpp:88
const LateReturn & CatchAll(std::function< void(std::shared_ptr< Exceptions::Exception >)> func) const
Definition: LateReturn.hpp:295
T type
Definition: LateReturn.hpp:537
const LateReturn & Then(std::function< void(Types...)> f) const
Definition: LateReturn.hpp:246
Definition: LateReturn.hpp:535