Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Emplacer—allocate subtypes of an abstract base class directly in a container!
/* This code is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. */
#ifndef EMPLACER_H
#define EMPLACER_H
#include <new>
#include <type_traits>
#include <stdexcept>
template <typename ...Elements>
class type_collection;
template <>
class type_collection<> {
public:
static constexpr size_t max_size() { return 0; }
static constexpr size_t max_alignment() { return 0; }
template <typename Type>
static constexpr bool is_member() { return false; }
template <typename Type>
static constexpr bool are_all_subtypes() { return true; }
};
template <typename First, typename ...Rest>
class type_collection<First, Rest...> {
public:
static constexpr size_t max_size() {
return sizeof(First) > type_collection<Rest...>::max_size() ? sizeof(First) : type_collection<Rest...>::max_size();
}
static constexpr size_t max_alignment() {
return alignof(First) > type_collection<Rest...>::max_alignment() ? alignof(First) : type_collection<Rest...>::max_alignment();
}
template <typename Type>
static constexpr bool is_member() {
return std::is_same<First, Type>::value ? true : type_collection<Rest...>::template is_member<Type>();
}
template <typename Type>
static constexpr bool are_all_subtypes() {
return std::is_base_of<Type, First>::value ? type_collection<Rest...>::template are_all_subtypes<Type>() : false;
}
};
template <typename Type, typename TypeCollection>
class emplacer {
private:
char data[TypeCollection::max_size()] __attribute__((align(TypeCollection::max_alignment())));
bool live = false;
void throw_if_not_live() const {
if(!live)
throw std::logic_error("Attempt to use uninitialized object in emplacer");
}
public:
template <typename Subtype, typename ...Args>
void emplace(Args ...args) {
static_assert(TypeCollection::template are_all_subtypes<Type>(), "TypeCollection contains non-subclasses of Type");
static_assert(TypeCollection::template is_member<Subtype>(), "Subtype not part of TypeCollection");
if(live) {
(*this)->~Type();
live = false;
}
new(data) Subtype(args...);
live = true;
}
~emplacer() {
if(live)
(*this)->~Type();
}
const Type &operator*() const { throw_if_not_live(); return *reinterpret_cast<Type *>(data); }
Type &operator*() { throw_if_not_live(); return *reinterpret_cast<Type *>(data); }
const Type *operator->() const { throw_if_not_live(); return reinterpret_cast<Type *>(data); }
Type *operator->() { throw_if_not_live(); return reinterpret_cast<Type *>(data); }
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment