FastArduino  v1.9 alpha
C++ library to build fast but small Arduino/AVR projects
lifecycle.h
Go to the documentation of this file.
1 // Copyright 2016-2022 Jean-Francois Poilpret
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
24 #ifndef LIFECYCLE_HH
25 #define LIFECYCLE_HH
26 
27 #include <string.h>
28 #include "move.h"
29 #include "types_traits.h"
30 
48 namespace lifecycle
49 {
51  // Forward declaration
52  class AbstractLifeCycleManager;
53  template<typename T> class LifeCycle;
55 
68  {
69  public:
71  AbstractLifeCycle() = default;
74  AbstractLifeCycle& operator=(AbstractLifeCycle&& that);
75 
76  AbstractLifeCycle(const AbstractLifeCycle&) = delete;
77  AbstractLifeCycle& operator=(const AbstractLifeCycle&) = delete;
79 
94  uint8_t id() const
95  {
96  return id_;
97  }
98 
113  {
114  return manager_;
115  }
116 
117  private:
118  uint8_t id_ = 0;
119  AbstractLifeCycleManager* manager_ = nullptr;
120 
121  friend class AbstractLifeCycleManager;
122  };
123 
132  {
133  public:
156  template<typename T> uint8_t register_(LifeCycle<T>& instance)
157  {
158  return register_impl_(instance);
159  }
160 
178  bool unregister_(uint8_t id)
179  {
180  AbstractLifeCycle** slot = find_slot_(id);
181  if ((slot == nullptr) || (*slot == nullptr))
182  return false;
183  AbstractLifeCycle& source = **slot;
184  source.id_ = 0;
185  source.manager_ = nullptr;
186  *slot = nullptr;
187  ++free_slots_;
188  return true;
189  }
190 
198  uint8_t available_() const
199  {
200  return free_slots_;
201  }
202 
224  bool move_(uint8_t id, AbstractLifeCycle& dest)
225  {
226  // Check this instance is managed
227  AbstractLifeCycle** slot = find_slot_(id);
228  if ((slot == nullptr) || (*slot == nullptr)) return false;
229  // Perform move
230  AbstractLifeCycle& source = **slot;
231  dest.id_ = source.id_;
232  dest.manager_ = this;
233  source.id_ = 0;
234  source.manager_ = nullptr;
235  *slot = &dest;
236  return true;
237  }
238 
263  template<typename T> LifeCycle<T>* find_(uint8_t id) const
264  {
265  return static_cast<LifeCycle<T>*>(find_impl_(id));
266  }
267 
268  protected:
270  AbstractLifeCycleManager(AbstractLifeCycle** slots, uint8_t size)
271  : size_{size}, slots_{slots}, free_slots_{size}
272  {
273  memset(slots, 0, size * sizeof(AbstractLifeCycle*));
274  }
275  ~AbstractLifeCycleManager() = default;
276  AbstractLifeCycleManager(const AbstractLifeCycleManager&) = delete;
277  AbstractLifeCycleManager& operator=(const AbstractLifeCycleManager&) = delete;
279 
280  private:
281  uint8_t register_impl_(AbstractLifeCycle& instance)
282  {
283  // You cannot register any instance if there are no free slots remaining
284  if (free_slots_ == 0) return 0;
285  // You cannot register an already registered future
286  if (instance.id_ != 0) return 0;
287  // Find first free slot for registration
288  AbstractLifeCycle** slot = &slots_[0];
289  for (uint8_t i = 0; i < size_; ++i)
290  {
291  if (*slot == nullptr)
292  {
293  const uint8_t id = i + 1;
294  instance.id_ = id;
295  instance.manager_ = this;
296  *slot = &instance;
297  --free_slots_;
298  return id;
299  }
300  ++slot;
301  }
302  // No free slot found; should never come here since we checked free_slots_ first
303  return 0;
304  }
305 
306  AbstractLifeCycle* find_impl_(uint8_t id) const
307  {
308  AbstractLifeCycle** slot = find_slot_(id);
309  if (slot == nullptr)
310  return nullptr;
311  else
312  return *slot;
313  }
314 
315  AbstractLifeCycle** find_slot_(uint8_t id) const
316  {
317  if ((id == 0) || (id > size_))
318  return nullptr;
319  else
320  return &slots_[id - 1];
321  }
322 
323  const uint8_t size_;
324  AbstractLifeCycle** slots_;
325  uint8_t free_slots_;
326  };
327 
340  template<uint8_t SIZE> class LifeCycleManager : public AbstractLifeCycleManager
341  {
342  public:
343  LifeCycleManager() : AbstractLifeCycleManager{slots_buffer_, SIZE} {}
344 
345  private:
346  AbstractLifeCycle* slots_buffer_[SIZE];
347  };
348 
356  template<typename T> class LifeCycle : public AbstractLifeCycle, public T
357  {
358  public:
368 
379  explicit LifeCycle(const T& value) : AbstractLifeCycle{}, T{value} {}
380 
391  explicit LifeCycle(T&& value) : AbstractLifeCycle{}, T{std::move(value)} {}
392 
405  LifeCycle(LifeCycle&& that) = default;
406 
412  ~LifeCycle() = default;
413 
428  LifeCycle& operator=(LifeCycle&& that) = default;
429  };
430 
431  // Forward declarations for Proxy and LightProxy classes
433  template<typename T> class Proxy;
434  template<typename T> bool operator==(const Proxy<T>& a, const Proxy<T>& b);
435  template<typename T> bool operator!=(const Proxy<T>& a, const Proxy<T>& b);
436  template<typename T> class LightProxy;
437  template<typename T> bool operator==(const LightProxy<T>& a, const LightProxy<T>& b);
438  template<typename T> bool operator!=(const LightProxy<T>& a, const LightProxy<T>& b);
439  template<typename T> class DirectProxy;
440  template<typename T> bool operator==(const DirectProxy<T>& a, const DirectProxy<T>& b);
441  template<typename T> bool operator!=(const DirectProxy<T>& a, const DirectProxy<T>& b);
443 
444  //TODO define AbstractProxy to factor out common code?
458  template<typename T> class Proxy
459  {
460  public:
465  Proxy(const T& dest)
466  : ptr_{reinterpret_cast<uintptr_t>(&dest)}, is_dynamic_{false} {}
467 
478  template<typename U>
479  Proxy(const LifeCycle<U>& dest)
480  : id_{dest.id()}, ptr_{reinterpret_cast<uintptr_t>(dest.manager())}, is_dynamic_{true}
481  {
482  // Statically check (at compile-time) that U is a subclass of T
484  }
485 
487  constexpr Proxy() = default;
488  template<typename U> Proxy(const Proxy<U>& that)
489  : id_{that.id_}, ptr_{that.ptr_}, is_dynamic_{that.is_dynamic_}
490  {
491  // Statically check (at compile-time) that U is a subclass of T
493 
494  }
495  template<typename U> Proxy& operator=(const Proxy<U>& that)
496  {
497  // Statically check (at compile-time) that U is a subclass of T
499  if (this == &that) return *this;
500  id_ = that.id_;
501  ptr_ = that.ptr_;
502  is_dynamic_ = that.is_dynamic_;
503  return *this;
504  }
506 
511  {
512  return *target();
513  }
514 
520  {
521  return target();
522  }
523 
532  bool is_dynamic() const
533  {
534  return is_dynamic_;
535  }
536 
541  uint8_t id() const
542  {
543  return id_;
544  }
545 
550  T* destination() const
551  {
552  return (is_dynamic_ ? nullptr : reinterpret_cast<T*>(ptr_));
553  }
554 
560  {
561  return (is_dynamic_ ? reinterpret_cast<AbstractLifeCycleManager*>(ptr_) : nullptr);
562  }
563 
564  private:
565  T* target() const
566  {
567  if (is_dynamic_)
568  return reinterpret_cast<AbstractLifeCycleManager*>(ptr_)->find_<T>(id_);
569  else
570  return reinterpret_cast<T*>(ptr_);
571  }
572 
573  struct
574  {
575  uint8_t id_ = 0;
576  uintptr_t ptr_ : 15;
577  bool is_dynamic_ : 1;
578  };
579 
580  template<typename U> friend class Proxy;
581  friend bool operator==<T>(const Proxy<T>&, const Proxy<T>&);
582  friend bool operator!=<T>(const Proxy<T>&, const Proxy<T>&);
583  };
584 
593  template<typename T> Proxy<T> make_proxy(const T& dest)
594  {
595  return Proxy<T>{dest};
596  }
597 
606  template<typename T> Proxy<T> make_proxy(const LifeCycle<T>& dest)
607  {
608  return Proxy<T>{dest};
609  }
610 
612  template<typename T>
613  bool operator==(const Proxy<T>& a, const Proxy<T>& b)
614  {
615  if (&a == &b) return true;
616  return (a.is_dynamic_ == b.is_dynamic_) && (a.ptr_ == b.ptr_) && (a.id_ == b.id_);
617  }
618 
619  template<typename T>
620  bool operator!=(const Proxy<T>& a, const Proxy<T>& b)
621  {
622  if (&a == &b) return false;
623  return (a.is_dynamic_ != b.is_dynamic_) || (a.ptr_ != b.ptr_) || (a.id_ != b.id_);
624  }
626 
642  template<typename T> class LightProxy
643  {
644  public:
649  LightProxy(const T& dest) : ptr_{reinterpret_cast<uintptr_t>(&dest)}, is_dynamic_{false} {}
650 
661  template<typename U>
662  LightProxy(const LifeCycle<U>& dest) : id_{dest.id()}, is_dynamic2_{true}
663  {
664  // Statically check (at compile-time) that U is a subclass of T
666  }
667 
674  explicit LightProxy(const Proxy<T>& proxy)
675  {
676  if (proxy.is_dynamic())
677  {
678  id_ = proxy.id();
679  is_dynamic2_ = true;
680  }
681  else
682  {
683  ptr_ = reinterpret_cast<uintptr_t>(proxy.destination());
684  is_dynamic_ = false;
685  }
686  }
687 
689  constexpr LightProxy() : content_{} {}
690  template<typename U> LightProxy(const LightProxy<U>& that) : content_{that.content_}
691  {
692  // Statically check (at compile-time) that U is a subclass of T
694  }
695  template<typename U> LightProxy& operator=(const LightProxy<U>& that)
696  {
697  // Statically check (at compile-time) that U is a subclass of T
699  if (this == (const LightProxy<T>*) &that) return *this;
700  content_ = that.content_;
701  return *this;
702  }
704 
712  T* operator()(const AbstractLifeCycleManager* manager = nullptr) const
713  {
714  if (is_dynamic_)
715  return manager->find_<T>(id_);
716  else
717  return reinterpret_cast<T*>(ptr_);
718  }
719 
728  bool is_dynamic() const
729  {
730  return is_dynamic_;
731  }
732 
737  uint8_t id() const
738  {
739  return id_;
740  }
741 
746  T* destination() const
747  {
748  return (is_dynamic_ ? nullptr : reinterpret_cast<T*>(ptr_));
749  }
750 
751  private:
752  union
753  {
754  uint16_t content_;
755  struct
756  {
757  uintptr_t ptr_ : 15;
758  uint16_t is_dynamic_ : 1;
759  };
760  struct
761  {
762  uint8_t id_;
763  uint8_t reserved_ : 7;
764  uint8_t is_dynamic2_ : 1;
765  };
766  };
767 
768  template<typename U> friend class LightProxy;
769  friend bool operator==<T>(const LightProxy<T>&, const LightProxy<T>&);
770  friend bool operator!=<T>(const LightProxy<T>&, const LightProxy<T>&);
771  };
772 
781  template<typename T> LightProxy<T> make_light_proxy(const T& dest)
782  {
783  return LightProxy<T>{dest};
784  }
785 
794  template<typename T> LightProxy<T> make_light_proxy(const LifeCycle<T>& dest)
795  {
796  return LightProxy<T>{dest};
797  }
798 
800  template<typename T>
801  bool operator==(const LightProxy<T>& a, const LightProxy<T>& b)
802  {
803  if (&a == &b) return true;
804  return (a.is_dynamic_ == b.is_dynamic_) && (a.ptr_ == b.ptr_);
805  }
806 
807  template<typename T>
808  bool operator!=(const LightProxy<T>& a, const LightProxy<T>& b)
809  {
810  if (&a == &b) return false;
811  return (a.is_dynamic_ != b.is_dynamic_) || (a.ptr_ != b.ptr_);
812  }
814 
825  template<typename T> class DirectProxy
826  {
827  public:
832  DirectProxy(const T& dest) : ptr_{reinterpret_cast<uintptr_t>(&dest)} {}
833 
835  constexpr DirectProxy() = default;
836  template<typename U> DirectProxy(const DirectProxy<U>& that) : ptr_{that.ptr_}
837  {
838  // Statically check (at compile-time) that U is a subclass of T
840  }
841  template<typename U> DirectProxy& operator=(const DirectProxy<U>& that)
842  {
843  // Statically check (at compile-time) that U is a subclass of T
845  if (this == &that) return *this;
846  ptr_ = that.ptr_;
847  return *this;
848  }
850 
856  T* operator()(UNUSED const AbstractLifeCycleManager* manager = nullptr) const
857  {
858  return reinterpret_cast<T*>(ptr_);
859  }
860 
866  bool is_dynamic() const
867  {
868  return false;
869  }
870 
876  uint8_t id() const
877  {
878  return 0;
879  }
880 
884  T* destination() const
885  {
886  return reinterpret_cast<T*>(ptr_);
887  }
888 
889  private:
890  uintptr_t ptr_ = 0;
891 
892  template<typename U> friend class DirectProxy;
893  friend bool operator==<T>(const DirectProxy<T>&, const DirectProxy<T>&);
894  friend bool operator!=<T>(const DirectProxy<T>&, const DirectProxy<T>&);
895  };
896 
905  template<typename T> DirectProxy<T> make_direct_proxy(const T& dest)
906  {
907  return DirectProxy<T>{dest};
908  }
909 
911  template<typename T>
912  bool operator==(const DirectProxy<T>& a, const DirectProxy<T>& b)
913  {
914  if (&a == &b) return true;
915  return (a.ptr_ == b.ptr_);
916  }
917 
918  template<typename T>
919  bool operator!=(const DirectProxy<T>& a, const DirectProxy<T>& b)
920  {
921  if (&a == &b) return false;
922  return (a.ptr_ != b.ptr_);
923  }
925 }
926 
927 #endif /* LIFECYCLE_HH */
The abstract base class of all LifeCycle<T>.
Definition: lifecycle.h:68
AbstractLifeCycleManager * manager() const
A pointer to the AbstractLifeCycleManager handling this instance.
Definition: lifecycle.h:112
uint8_t id() const
The unique identifier of this lifecycle-managed instance, as provided by the LifeCycleManager it was ...
Definition: lifecycle.h:94
The abstract base class of all LifeCycleManager.
Definition: lifecycle.h:132
bool move_(uint8_t id, AbstractLifeCycle &dest)
Move an already registered LifeCycle<T> instance (identified by id) to a new location,...
Definition: lifecycle.h:224
LifeCycle< T > * find_(uint8_t id) const
Find an existing LifeCycle<T> registered with this LifeCycleManager and identified by id.
Definition: lifecycle.h:263
bool unregister_(uint8_t id)
Unregisters a LifeCycle<T> instance, identified by id, already registered with this LifeCycleManager.
Definition: lifecycle.h:178
uint8_t register_(LifeCycle< T > &instance)
Register a LifeCycle<T> instance with this LifeCycleManager.
Definition: lifecycle.h:156
uint8_t available_() const
Return the number of available "slots" for registration of new LifeCycle<T> instances.
Definition: lifecycle.h:198
A kind of proxy class that encapsulates access to a fixed T instance.
Definition: lifecycle.h:826
DirectProxy(const T &dest)
Create a DirectProxy<T> to a static reference.
Definition: lifecycle.h:832
bool is_dynamic() const
Tell if this DirectProxy is dynamic or static.
Definition: lifecycle.h:866
T * destination() const
A pointer to the static instance proxified.
Definition: lifecycle.h:884
uint8_t id() const
The identifier of the proxified LifeCycle<U> or 0 if a static instance was proxified.
Definition: lifecycle.h:876
T * operator()(UNUSED const AbstractLifeCycleManager *manager=nullptr) const
Return a pointer to the proxified T instance.
Definition: lifecycle.h:856
A mixin class allowing lifecycle management of any object of any type T.
Definition: lifecycle.h:357
LifeCycle & operator=(LifeCycle &&that)=default
Assign this LifeCycle<T> with that, by moving that already existing LifeCycle<T> instance.
LifeCycle()
Create a new LifeCycle<T> mixin for an object of type T.
Definition: lifecycle.h:367
LifeCycle(LifeCycle &&that)=default
Crate a new LifeCycle<T> mixin object of type T, by moving an already existing LifeCycle<T> instance ...
LifeCycle(const T &value)
Create a new LifeCycle<T> mixin for object value of type T.
Definition: lifecycle.h:379
LifeCycle(T &&value)
Create a new LifeCycle<T> mixin for object value of type T.
Definition: lifecycle.h:391
~LifeCycle()=default
Destroy this LifeCycle<T> instance.
An actual LifeCycleManager implementation, based on AbstractLifeCycleManager, adding static storage f...
Definition: lifecycle.h:341
A light proxy class that encapsulates access to a fixed T instance, or to a dynamic LifeCycle<T> inst...
Definition: lifecycle.h:643
uint8_t id() const
The identifier of the proxified LifeCycle<U> or 0 if a static instance was proxified.
Definition: lifecycle.h:737
bool is_dynamic() const
Tell if this LightProxy is dynamic or static.
Definition: lifecycle.h:728
LightProxy(const Proxy< T > &proxy)
Create a LightProxy<T> from a Proxy<T>.
Definition: lifecycle.h:674
T * destination() const
A pointer to the static instance proxified, or nullptr if a dynamic instance (a LifeCycle<U>) was pro...
Definition: lifecycle.h:746
T * operator()(const AbstractLifeCycleManager *manager=nullptr) const
Return a pointer to the proxified T instance.
Definition: lifecycle.h:712
LightProxy(const LifeCycle< U > &dest)
Create a LightProxy<T> to a LifeCycle<U> instance (dynamic reference).
Definition: lifecycle.h:662
LightProxy(const T &dest)
Create a LightProxy<T> to a static reference.
Definition: lifecycle.h:649
A proxy class that encapsulates access to a fixed T instance, or to a dynamic LifeCycle<T> instance.
Definition: lifecycle.h:459
Proxy(const T &dest)
Create a Proxy<T> to a static reference.
Definition: lifecycle.h:465
Proxy(const LifeCycle< U > &dest)
Create a Proxy<T> to a LifeCycle<U> instance (dynamic reference).
Definition: lifecycle.h:479
bool is_dynamic() const
Tell if this Proxy is dynamic or static.
Definition: lifecycle.h:532
uint8_t id() const
The identifier of the proxified LifeCycle<U> or 0 if a static instance was proxified.
Definition: lifecycle.h:541
T * destination() const
A pointer to the static instance proxified, or nullptr if a dynamic instance (a LifeCycle<U>) was pro...
Definition: lifecycle.h:550
T * operator->()
Overloaded -> operator, allowing access to proxified type T instance members.
Definition: lifecycle.h:519
AbstractLifeCycleManager * manager() const
The LifeCycleManager managing the proxified LifeCycle<U>, or nullptr if a static instance was proxifi...
Definition: lifecycle.h:559
T & operator*()
Return a reference to the proxified T instance.
Definition: lifecycle.h:510
#define UNUSED
Specific GCC attribute to declare an argument or variable unused, so that the compiler does not emit ...
Definition: defines.h:45
Contains the API around LifeCycle management implementation.
Definition: lifecycle.cpp:18
DirectProxy< T > make_direct_proxy(const T &dest)
Utility template function to create a DirectProxy<T> from dest without the need to speicify T.
Definition: lifecycle.h:905
LightProxy< T > make_light_proxy(const T &dest)
Utility template function to create a LightProxy<T> from dest without the need to speicify T.
Definition: lifecycle.h:781
Proxy< T > make_proxy(const T &dest)
Utility template function to create a Proxy<T> from dest without the need to speicify T.
Definition: lifecycle.h:593
Similar to standard C++ std namespace, this namespace is used by FastArduino library to implement var...
bool operator==(const RTTTime &a, const RTTTime &b)
Compare 2 RTTTime instances.
Definition: time.h:204
bool operator!=(const RTTTime &a, const RTTTime &b)
Compare 2 RTTTime instances.
Definition: time.h:216
Utility class that checks, at compile-time, that type T is a subtype of type B.
Definition: types_traits.h:93
Useful traits for common types.