mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-04-14 10:07:39 +08:00
LazyConstructor
This commit is contained in:
parent
bc065ee3c4
commit
fd454a77f8
145
libuavcan/include/uavcan/internal/lazy_constructor.hpp
Normal file
145
libuavcan/include/uavcan/internal/lazy_constructor.hpp
Normal file
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
61
libuavcan/test/lazy_constructor.cpp
Normal file
61
libuavcan/test/lazy_constructor.cpp
Normal file
@ -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);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user