/* * Copyright (C) 2014 Pavel Kirienko */ #ifndef UAVCAN_UTIL_LAZY_CONSTRUCTOR_HPP_INCLUDED #define UAVCAN_UTIL_LAZY_CONSTRUCTOR_HPP_INCLUDED #include #include #include #include #ifndef UAVCAN_CPP_VERSION # error UAVCAN_CPP_VERSION #endif namespace uavcan { /** * This class allows to postpone the object contruction. * It statically allocates a pool of memory of just enough size to fit the object being constructed. * Later call to construct<>() calls the constructor of the object. * The object will be destroyed automatically when the container class destructor is called. * The memory pool is aligned at the size of the largest primitive type (long double or long long int). */ template class UAVCAN_EXPORT LazyConstructor { union { unsigned char pool[sizeof(T)]; long double _aligner1; long long _aligner2; } data_; T* ptr_; void ensureConstructed() const { if (!ptr_) { handleFatalError("LazyConstructor"); } } void ensureNotConstructed() const { if (ptr_) { handleFatalError("LazyConstructor"); } } template struct ParamType { typedef const U& Type; }; template struct ParamType { typedef U& Type; }; #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11 template struct ParamType { typedef U&& Type; }; #endif public: LazyConstructor() : ptr_(NULL) { fill(data_.pool, data_.pool + sizeof(T), uint8_t(0)); } LazyConstructor(const LazyConstructor& rhs) // Implicit : ptr_(NULL) { fill(data_.pool, data_.pool + sizeof(T), uint8_t(0)); if (rhs) { construct(*rhs); // Invoke copy constructor } } ~LazyConstructor() { destroy(); } LazyConstructor& operator=(const LazyConstructor& rhs) { destroy(); if (rhs) { construct(*rhs); // Invoke copy constructor } return *this; } bool isConstructed() const { return ptr_ != NULL; } operator T*() const { return ptr_; } const T* operator->() const { ensureConstructed(); return ptr_; } T* operator->() { ensureConstructed(); return ptr_; } const T& operator*() const { ensureConstructed(); return *ptr_; } T& operator*() { ensureConstructed(); return *ptr_; } void destroy() { if (ptr_) { ptr_->~T(); } ptr_ = NULL; fill(data_.pool, data_.pool + sizeof(T), uint8_t(0)); } void construct() { ensureNotConstructed(); ptr_ = new (static_cast(data_.pool)) T(); } // MAX_ARGS = 6 // TEMPLATE = ''' // template <%s> // void construct(%s) // { // ensureNotConstructed(); // ptr_ = new (static_cast(data_.pool)) T(%s); // }''' // for nargs in range(1, MAX_ARGS + 1): // nums = [(x + 1) for x in range(nargs)] // l1 = ['typename P%d' % x for x in nums] // l2 = ['typename ParamType::Type p%d' % (x, x) for x in nums] // l3 = ['p%d' % x for x in nums] // print(TEMPLATE % (', '.join(l1), ', '.join(l2), ', '.join(l3))) template void construct(typename ParamType::Type p1) { ensureNotConstructed(); ptr_ = new (static_cast(data_.pool)) T(p1); } template void construct(typename ParamType::Type p1, typename ParamType::Type p2) { ensureNotConstructed(); ptr_ = new (static_cast(data_.pool)) T(p1, p2); } template void construct(typename ParamType::Type p1, typename ParamType::Type p2, typename ParamType::Type p3) { ensureNotConstructed(); ptr_ = new (static_cast(data_.pool)) T(p1, p2, p3); } template void construct(typename ParamType::Type p1, typename ParamType::Type p2, typename ParamType::Type p3, typename ParamType::Type p4) { ensureNotConstructed(); ptr_ = new (static_cast(data_.pool)) T(p1, p2, p3, p4); } template void construct(typename ParamType::Type p1, typename ParamType::Type p2, typename ParamType::Type p3, typename ParamType::Type p4, typename ParamType::Type p5) { ensureNotConstructed(); ptr_ = new (static_cast(data_.pool)) T(p1, p2, p3, p4, p5); } template void construct(typename ParamType::Type p1, typename ParamType::Type p2, typename ParamType::Type p3, typename ParamType::Type p4, typename ParamType::Type p5, typename ParamType::Type p6) { ensureNotConstructed(); ptr_ = new (static_cast(data_.pool)) T(p1, p2, p3, p4, p5, p6); } }; } #endif // UAVCAN_UTIL_LAZY_CONSTRUCTOR_HPP_INCLUDED