mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-24 03:53:33 +08:00
LazyConstructor
This commit is contained in:
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cassert>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace uavcan
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class LazyConstructor
|
||||||
|
{
|
||||||
|
unsigned char data_[sizeof(T)] __attribute__((aligned(16))); // TODO: compiler-independent alignment
|
||||||
|
T* ptr_;
|
||||||
|
|
||||||
|
void failure() const
|
||||||
|
{
|
||||||
|
#if UAVCAN_EXCEPTIONS
|
||||||
|
throw std::logic_error(typeid(*this).name());
|
||||||
|
#else
|
||||||
|
assert(0);
|
||||||
|
std::abort();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ensureConstructed() const
|
||||||
|
{
|
||||||
|
if (!ptr_)
|
||||||
|
failure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ensureNotConstructed() const
|
||||||
|
{
|
||||||
|
if (ptr_)
|
||||||
|
failure();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
LazyConstructor()
|
||||||
|
: ptr_(NULL)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
LazyConstructor(const LazyConstructor<T>& rhs)
|
||||||
|
: ptr_(NULL)
|
||||||
|
{
|
||||||
|
if (rhs)
|
||||||
|
construct(*rhs); // Invoke copy constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
~LazyConstructor() { destroy(); }
|
||||||
|
|
||||||
|
LazyConstructor<T>& operator=(const LazyConstructor<T>& 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void construct()
|
||||||
|
{
|
||||||
|
ensureNotConstructed();
|
||||||
|
ptr_ = new (static_cast<void*>(data_)) T();
|
||||||
|
}
|
||||||
|
|
||||||
|
// MAX_ARGS = 6
|
||||||
|
// TEMPLATE = '''
|
||||||
|
// template <%s>
|
||||||
|
// void construct(%s)
|
||||||
|
// {
|
||||||
|
// ensureNotConstructed();
|
||||||
|
// ptr_ = new (static_cast<void*>(data_)) 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 = ['P%d 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 <typename P1>
|
||||||
|
void construct(P1 p1)
|
||||||
|
{
|
||||||
|
ensureNotConstructed();
|
||||||
|
ptr_ = new (static_cast<void*>(data_)) T(p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P1, typename P2>
|
||||||
|
void construct(P1 p1, P2 p2)
|
||||||
|
{
|
||||||
|
ensureNotConstructed();
|
||||||
|
ptr_ = new (static_cast<void*>(data_)) T(p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P1, typename P2, typename P3>
|
||||||
|
void construct(P1 p1, P2 p2, P3 p3)
|
||||||
|
{
|
||||||
|
ensureNotConstructed();
|
||||||
|
ptr_ = new (static_cast<void*>(data_)) T(p1, p2, p3);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P1, typename P2, typename P3, typename P4>
|
||||||
|
void construct(P1 p1, P2 p2, P3 p3, P4 p4)
|
||||||
|
{
|
||||||
|
ensureNotConstructed();
|
||||||
|
ptr_ = new (static_cast<void*>(data_)) T(p1, p2, p3, p4);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P1, typename P2, typename P3, typename P4, typename P5>
|
||||||
|
void construct(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
|
||||||
|
{
|
||||||
|
ensureNotConstructed();
|
||||||
|
ptr_ = new (static_cast<void*>(data_)) T(p1, p2, p3, p4, p5);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
|
||||||
|
void construct(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
|
||||||
|
{
|
||||||
|
ensureNotConstructed();
|
||||||
|
ptr_ = new (static_cast<void*>(data_)) T(p1, p2, p3, p4, p5, p6);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <uavcan/internal/lazy_constructor.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
TEST(LazyConstructor, Basic)
|
||||||
|
{
|
||||||
|
using ::uavcan::LazyConstructor;
|
||||||
|
|
||||||
|
LazyConstructor<std::string> a;
|
||||||
|
LazyConstructor<std::string> b;
|
||||||
|
|
||||||
|
ASSERT_FALSE(a);
|
||||||
|
ASSERT_FALSE(b.isConstructed());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Construction
|
||||||
|
*/
|
||||||
|
a.destroy(); // no-op
|
||||||
|
a.construct();
|
||||||
|
b.construct("Hello world");
|
||||||
|
|
||||||
|
ASSERT_TRUE(a);
|
||||||
|
ASSERT_TRUE(b.isConstructed());
|
||||||
|
|
||||||
|
ASSERT_NE(*a, *b);
|
||||||
|
ASSERT_STRNE(a->c_str(), b->c_str());
|
||||||
|
|
||||||
|
ASSERT_EQ(*a, "");
|
||||||
|
ASSERT_EQ(*b, "Hello world");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copying
|
||||||
|
*/
|
||||||
|
a = b; // Assignment operator performs destruction and immediate copy construction
|
||||||
|
ASSERT_EQ(*a, *b);
|
||||||
|
ASSERT_EQ(*a, "Hello world");
|
||||||
|
|
||||||
|
LazyConstructor<std::string> c(a); // Copy constructor call is forwarded to std::string
|
||||||
|
|
||||||
|
ASSERT_EQ(*c, *a);
|
||||||
|
|
||||||
|
*a = "123";
|
||||||
|
ASSERT_NE(*c, *a);
|
||||||
|
ASSERT_EQ(*c, *b);
|
||||||
|
|
||||||
|
*c = "456";
|
||||||
|
ASSERT_NE(*a, *c);
|
||||||
|
ASSERT_NE(*b, *a);
|
||||||
|
ASSERT_NE(*c, *b);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Destruction
|
||||||
|
*/
|
||||||
|
ASSERT_TRUE(c);
|
||||||
|
c.destroy();
|
||||||
|
ASSERT_FALSE(c);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user