#ifndef _C4_CTOR_DTOR_H_ #define _C4_CTOR_DTOR_H_ #include "c4/preprocessor.hpp" #include "c4/language.hpp" #include "c4/memory_util.hpp" #include "c4/error.hpp" #include #include // std::forward /** @file ctor_dtor.hpp object construction and destruction facilities. * Some of these are not yet available in C++11. */ C4_BEGIN_NAMESPACE(c4) #define _C4REQUIRE(cond) \ C4_ALWAYS_INLINE typename std::enable_if::type /** default-construct an object, trivial version */ template _C4REQUIRE(std::is_trivially_default_constructible::value) construct(U* ptr) noexcept { memset(ptr, 0, sizeof(U)); } /** default-construct an object, non-trivial version */ template _C4REQUIRE( ! std::is_trivially_default_constructible::value) construct(U* ptr) noexcept { new ((void*)ptr) U(); } /** default-construct n objects, trivial version */ template _C4REQUIRE(std::is_trivially_default_constructible::value) construct_n(U* ptr, I n) noexcept { memset(ptr, 0, n * sizeof(U)); } /** default-construct n objects, non-trivial version */ template _C4REQUIRE( ! std::is_trivially_default_constructible::value) construct_n(U* ptr, I n) noexcept { for(I i = 0; i < n; ++i) { new ((void*)(ptr + i)) U(); } } template inline void construct(U* ptr, Args&&... args) { new ((void*)ptr) U(std::forward(args)...); } template inline void construct_n(U* ptr, I n, Args&&... args) { for(I i = 0; i < n; ++i) { new ((void*)(ptr + i)) U(args...); } } //----------------------------------------------------------------------------- // copy-construct template _C4REQUIRE(std::is_trivially_copy_constructible::value) copy_construct(U* dst, U const* src) noexcept { C4_ASSERT(dst != src); memcpy(dst, src, sizeof(U)); } template _C4REQUIRE( ! std::is_trivially_copy_constructible::value) copy_construct(U* dst, U const* src) { C4_ASSERT(dst != src); new ((void*)dst) U(*src); } template _C4REQUIRE(std::is_trivially_copy_constructible::value) copy_construct_n(U* dst, U const* src, I n) noexcept { C4_ASSERT(dst != src); memcpy(dst, src, n * sizeof(U)); } template _C4REQUIRE( ! std::is_trivially_copy_constructible::value) copy_construct_n(U* dst, U const* src, I n) { C4_ASSERT(dst != src); for(I i = 0; i < n; ++i) { new ((void*)(dst + i)) U(*(src + i)); } } template _C4REQUIRE(std::is_scalar::value) copy_construct(U* dst, U src) noexcept // pass by value for scalar types { *dst = src; } template _C4REQUIRE( ! std::is_scalar::value) copy_construct(U* dst, U const& src) // pass by reference for non-scalar types { C4_ASSERT(dst != &src); new ((void*)dst) U(src); } template _C4REQUIRE(std::is_scalar::value) copy_construct_n(U* dst, U src, I n) noexcept // pass by value for scalar types { for(I i = 0; i < n; ++i) { dst[i] = src; } } template _C4REQUIRE( ! std::is_scalar::value) copy_construct_n(U* dst, U const& src, I n) // pass by reference for non-scalar types { C4_ASSERT(dst != &src); for(I i = 0; i < n; ++i) { new ((void*)(dst + i)) U(src); } } template C4_ALWAYS_INLINE void copy_construct(U (&dst)[N], U const (&src)[N]) noexcept { copy_construct_n(dst, src, N); } //----------------------------------------------------------------------------- // copy-assign template _C4REQUIRE(std::is_trivially_copy_assignable::value) copy_assign(U* dst, U const* src) noexcept { C4_ASSERT(dst != src); memcpy(dst, src, sizeof(U)); } template _C4REQUIRE( ! std::is_trivially_copy_assignable::value) copy_assign(U* dst, U const* src) noexcept { C4_ASSERT(dst != src); *dst = *src; } template _C4REQUIRE(std::is_trivially_copy_assignable::value) copy_assign_n(U* dst, U const* src, I n) noexcept { C4_ASSERT(dst != src); memcpy(dst, src, n * sizeof(U)); } template _C4REQUIRE( ! std::is_trivially_copy_assignable::value) copy_assign_n(U* dst, U const* src, I n) noexcept { C4_ASSERT(dst != src); for(I i = 0; i < n; ++i) { dst[i] = src[i]; } } template _C4REQUIRE(std::is_scalar::value) copy_assign(U* dst, U src) noexcept // pass by value for scalar types { *dst = src; } template _C4REQUIRE( ! std::is_scalar::value) copy_assign(U* dst, U const& src) noexcept // pass by reference for non-scalar types { C4_ASSERT(dst != &src); *dst = src; } template _C4REQUIRE(std::is_scalar::value) copy_assign_n(U* dst, U src, I n) noexcept // pass by value for scalar types { for(I i = 0; i < n; ++i) { dst[i] = src; } } template _C4REQUIRE( ! std::is_scalar::value) copy_assign_n(U* dst, U const& src, I n) noexcept // pass by reference for non-scalar types { C4_ASSERT(dst != &src); for(I i = 0; i < n; ++i) { dst[i] = src; } } template C4_ALWAYS_INLINE void copy_assign(U (&dst)[N], U const (&src)[N]) noexcept { copy_assign_n(dst, src, N); } //----------------------------------------------------------------------------- // move-construct template _C4REQUIRE(std::is_trivially_move_constructible::value) move_construct(U* dst, U* src) noexcept { C4_ASSERT(dst != src); memcpy(dst, src, sizeof(U)); } template _C4REQUIRE( ! std::is_trivially_move_constructible::value) move_construct(U* dst, U* src) noexcept { C4_ASSERT(dst != src); new ((void*)dst) U(std::move(*src)); } template _C4REQUIRE(std::is_trivially_move_constructible::value) move_construct_n(U* dst, U* src, I n) noexcept { C4_ASSERT(dst != src); memcpy(dst, src, n * sizeof(U)); } template _C4REQUIRE( ! std::is_trivially_move_constructible::value) move_construct_n(U* dst, U* src, I n) noexcept { C4_ASSERT(dst != src); for(I i = 0; i < n; ++i) { new ((void*)(dst + i)) U(std::move(src[i])); } } //----------------------------------------------------------------------------- // move-assign template _C4REQUIRE(std::is_trivially_move_assignable::value) move_assign(U* dst, U* src) noexcept { C4_ASSERT(dst != src); memcpy(dst, src, sizeof(U)); } template _C4REQUIRE( ! std::is_trivially_move_assignable::value) move_assign(U* dst, U* src) noexcept { C4_ASSERT(dst != src); *dst = std::move(*src); } template _C4REQUIRE(std::is_trivially_move_assignable::value) move_assign_n(U* dst, U* src, I n) noexcept { C4_ASSERT(dst != src); memcpy(dst, src, n * sizeof(U)); } template _C4REQUIRE( ! std::is_trivially_move_assignable::value) move_assign_n(U* dst, U* src, I n) noexcept { C4_ASSERT(dst != src); for(I i = 0; i < n; ++i) { *(dst + i) = std::move(*(src + i)); } } //----------------------------------------------------------------------------- // destroy template _C4REQUIRE(std::is_trivially_destructible::value) destroy(U* ptr) noexcept { C4_UNUSED(ptr); // nothing to do } template _C4REQUIRE( ! std::is_trivially_destructible::value) destroy(U* ptr) noexcept { ptr->~U(); } template _C4REQUIRE(std::is_trivially_destructible::value) destroy_n(U* ptr, I n) noexcept { C4_UNUSED(ptr); C4_UNUSED(n); // nothing to do } template _C4REQUIRE( ! std::is_trivially_destructible::value) destroy_n(U* ptr, I n) noexcept { for(I i = 0; i _C4REQUIRE(std::is_trivially_move_constructible::value) make_room(U *buf, I bufsz, I room) C4_NOEXCEPT_A { C4_ASSERT(bufsz >= 0 && room >= 0); if(room >= bufsz) { memcpy (buf + room, buf, bufsz * sizeof(U)); } else { memmove(buf + room, buf, bufsz * sizeof(U)); } } /** makes room at the beginning of buf, which has a current size of bufsz */ template _C4REQUIRE( ! std::is_trivially_move_constructible::value) make_room(U *buf, I bufsz, I room) C4_NOEXCEPT_A { C4_ASSERT(bufsz >= 0 && room >= 0); if(room >= bufsz) { for(I i = 0; i < bufsz; ++i) { new ((void*)(buf + (i + room))) U(std::move(buf[i])); } } else { for(I i = 0; i < bufsz; ++i) { I w = bufsz-1 - i; // do a backwards loop new ((void*)(buf + (w + room))) U(std::move(buf[w])); } } } /** make room to the right of pos */ template C4_ALWAYS_INLINE void make_room(U *buf, I bufsz, I currsz, I pos, I room) { C4_ASSERT(pos >= 0 && pos <= currsz); C4_ASSERT(currsz <= bufsz); C4_ASSERT(room + currsz <= bufsz); C4_UNUSED(bufsz); make_room(buf + pos, currsz - pos, room); } /** make room to the right of pos, copying to the beginning of a different buffer */ template _C4REQUIRE(std::is_trivially_move_constructible::value) make_room(U *dst, U const* src, I srcsz, I room, I pos) C4_NOEXCEPT_A { C4_ASSERT(srcsz >= 0 && room >= 0 && pos >= 0); C4_ASSERT(pos < srcsz || (pos == 0 && srcsz == 0)); memcpy(dst , src , pos * sizeof(U)); memcpy(dst + room + pos, src + pos, (srcsz - pos) * sizeof(U)); } /** make room to the right of pos, copying to the beginning of a different buffer */ template _C4REQUIRE( ! std::is_trivially_move_constructible::value) make_room(U *dst, U const* src, I srcsz, I room, I pos) { C4_ASSERT(srcsz >= 0 && room >= 0 && pos >= 0); C4_ASSERT(pos < srcsz || (pos == 0 && srcsz == 0)); for(I i = 0; i < pos; ++i) { new ((void*)(dst + i)) U(std::move(src[i])); } src += pos; dst += room + pos; for(I i = 0, e = srcsz - pos; i < e; ++i) { new ((void*)(dst + i)) U(std::move(src[i])); } } template C4_ALWAYS_INLINE void make_room ( U * dst, I dstsz, U const* src, I srcsz, I room, I pos ) { C4_ASSERT(pos >= 0 && pos < srcsz || (srcsz == 0 && pos == 0)); C4_ASSERT(pos >= 0 && pos < dstsz || (dstsz == 0 && pos == 0)); C4_ASSERT(srcsz+room <= dstsz); C4_UNUSED(dstsz); make_room(dst, src, srcsz, room, pos); } //----------------------------------------------------------------------------- /** destroy room at the beginning of buf, which has a current size of n */ template _C4REQUIRE(std::is_scalar::value || std::is_pod::value) destroy_room(U *buf, I n, I room) C4_NOEXCEPT_A { C4_ASSERT(n >= 0 && room >= 0); C4_ASSERT(room <= n); if(room < n) { memmove(buf, buf + room, (n - room) * sizeof(U)); } else { // nothing to do - no need to destroy scalar types } } /** destroy room at the beginning of buf, which has a current size of n */ template _C4REQUIRE( ! (std::is_scalar::value || std::is_pod::value)) destroy_room(U *buf, I n, I room) { C4_ASSERT(n >= 0 && room >= 0); C4_ASSERT(room <= n); if(room < n) { for(I i = 0, e = n - room; i < e; ++i) { buf[i] = std::move(buf[i + room]); } } else { for(I i = 0; i < n; ++i) { buf[i].~U(); } } } /** destroy room to the right of pos, copying to a different buffer */ template _C4REQUIRE(std::is_trivially_move_constructible::value) destroy_room(U *dst, U const* src, I n, I room, I pos) C4_NOEXCEPT_A { C4_ASSERT(n >= 0 && room >= 0 && pos >= 0); C4_ASSERT(pos _C4REQUIRE( ! std::is_trivially_move_constructible::value) destroy_room(U *dst, U const* src, I n, I room, I pos) { C4_ASSERT(n >= 0 && room >= 0 && pos >= 0); C4_ASSERT(pos < n); C4_ASSERT(pos + room <= n); for(I i = 0; i < pos; ++i) { new ((void*)(dst + i)) U(std::move(src[i])); } src += room + pos; dst += pos; for(I i = 0, e = n - pos - room; i < e; ++i) { new ((void*)(dst + i)) U(std::move(src[i])); } } C4_END_NAMESPACE(c4) #undef _C4REQUIRE #endif /* _C4_CTOR_DTOR_H_ */