/* * Copyright (C) 2014 Pavel Kirienko */ #pragma once #include #include #include #ifndef UAVCAN_CPP_VERSION # error UAVCAN_CPP_VERSION #endif namespace uavcan { 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 is not constructed"); } } void ensureNotConstructed() const { if (ptr_) { handleFatalError("LazyConstructor is already constructed"); } } 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) { std::fill(data_.pool, data_.pool + sizeof(T), 0); } LazyConstructor(const LazyConstructor& rhs) : ptr_(NULL) { std::fill(data_.pool, data_.pool + sizeof(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; std::fill(data_.pool, data_.pool + sizeof(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); } }; }