diff options
Diffstat (limited to 'ingen')
-rw-r--r-- | ingen/Atom.hpp | 203 | ||||
-rw-r--r-- | ingen/Forge.hpp | 8 |
2 files changed, 100 insertions, 111 deletions
diff --git a/ingen/Atom.hpp b/ingen/Atom.hpp index a0e30805..18e75c59 100644 --- a/ingen/Atom.hpp +++ b/ingen/Atom.hpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2015 David Robillard <http://drobilla.net/> + Copyright 2007-2017 David Robillard <http://drobilla.net/> Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free @@ -17,14 +17,16 @@ #ifndef INGEN_ATOM_HPP #define INGEN_ATOM_HPP -#include <algorithm> #include <cassert> #include <cstdint> #include <cstdlib> #include <cstring> +#include <memory> + +#include <boost/variant.hpp> #include "ingen/ingen.h" -#include "lv2/atom/atom.h" +#include "lv2/atom/Atom.hpp" #include "lv2/urid/urid.h" namespace ingen { @@ -38,141 +40,136 @@ namespace ingen { Otherwise, if the size is larger than sizeof(void*), the value will be dynamically allocated in a separate chunk of memory. - In either case, the data is stored in a binary compatible format to LV2_Atom - (i.e., if the value is dynamically allocated, the header is repeated there). + In either case, the data is stored in a binary compatible format to LV2_Atom. */ class INGEN_API Atom { public: - Atom() noexcept { _atom.size = 0; _atom.type = 0; _body.ptr = nullptr; } - ~Atom() { dealloc(); } - - /** Construct a raw atom. - * - * Typically this is not used directly, use Forge methods to make atoms. - */ - Atom(uint32_t size, LV2_URID type, const void* body) { - _atom.size = size; - _atom.type = type; - _body.ptr = nullptr; - if (is_reference()) { - _body.ptr = (LV2_Atom*)malloc(sizeof(LV2_Atom) + size); - memcpy(_body.ptr, &_atom, sizeof(LV2_Atom)); - } - if (body) { - memcpy(this->body(), body, size); - } - } + using InlineBody = uint64_t; - Atom(const Atom& copy) - : _atom(copy._atom) + Atom() : _value{InlineAtom{{0, 0}, 0}} {} + + template<typename AtomType> + Atom(const lv2::atom::Primitive<AtomType>& primitive) { - if (is_reference()) { - _body.ptr = (LV2_Atom*)malloc(sizeof(LV2_Atom) + _atom.size); - memcpy(_body.ptr, copy._body.ptr, sizeof(LV2_Atom) + _atom.size); - } else { - _body.val = copy._body.val; - } + InlineAtom atom{{primitive.atom.size, primitive.atom.type}, 0}; + memcpy(&atom.body, &primitive.body, primitive.atom.size); + _value = atom; } - Atom& operator=(const Atom& other) { - if (&other == this) { - return *this; - } - dealloc(); - _atom = other._atom; - if (is_reference()) { - _body.ptr = (LV2_Atom*)malloc(sizeof(LV2_Atom) + _atom.size); - memcpy(_body.ptr, other._body.ptr, sizeof(LV2_Atom) + _atom.size); + Atom(const uint32_t size, const LV2_URID type, const void* const body) + { + if (size <= sizeof(InlineBody)) { + InlineAtom atom{{size, type}, 0}; + memcpy(&atom.body, body, size); + _value = atom; } else { - _body.val = other._body.val; + LV2_Atom* atom = (LV2_Atom*)malloc(sizeof(LV2_Atom) + size); + atom->size = size; + atom->type = type; + memcpy(atom + 1, body, size); + _value = AtomPtr(atom, free); } - return *this; } - inline bool operator==(const Atom& other) const { - if (_atom.type != other._atom.type || - _atom.size != other._atom.size) { - return false; - } - return is_reference() - ? !memcmp(_body.ptr, other._body.ptr, sizeof(LV2_Atom) + _atom.size) - : _body.val == other._body.val; - } - - inline bool operator!=(const Atom& other) const { - return !operator==(other); - } + Atom(Atom&&) = default; + Atom& operator=(Atom&&) = default; - inline bool operator<(const Atom& other) const { - if (_atom.type == other._atom.type) { - const uint32_t min_size = std::min(_atom.size, other._atom.size); - const int cmp = is_reference() - ? memcmp(_body.ptr, other._body.ptr, min_size) - : memcmp(&_body.val, &other._body.val, min_size); - return cmp < 0 || (cmp == 0 && _atom.size < other._atom.size); + Atom(const Atom& other) { + if (other.is_inline()) { + _value = boost::get<InlineAtom>(other._value); + } else { + _value = AtomPtr(copy_new_atom(other.atom()), free); } - return type() < other.type(); } - /** Like assignment, but only works for value atoms (not references). - * Always real-time safe. - * @return true iff set succeeded. - */ - inline bool set_rt(const Atom& other) { - if (is_reference()) { - return false; + const Atom& operator=(const Atom& other) { + if (other.is_inline()) { + _value = boost::get<InlineAtom>(other._value); } else { - _atom = other._atom; - _body.val = other._body.val; - return true; + _value = AtomPtr(copy_new_atom(other.atom()), free); } + return *this; } - inline uint32_t size() const { return _atom.size; } - inline LV2_URID type() const { return _atom.type; } - inline bool is_valid() const { return _atom.type; } - - inline const void* body() const { - return is_reference() ? (void*)(_body.ptr + 1) : &_body.val; + inline bool operator==(const Atom& rhs) const { + return lv2_atom_equals(atom(), rhs.atom()); } - inline void* body() { - return is_reference() ? (void*)(_body.ptr + 1) : &_body.val; + inline bool operator!=(const Atom& rhs) const { + return !lv2_atom_equals(atom(), rhs.atom()); } - template <typename T> const T& get() const { - assert(size() == sizeof(T)); - return *static_cast<const T*>(body()); - } + inline uint32_t size() const { return atom()->size; } + inline LV2_URID type() const { return atom()->type; } + inline const void* body() const { return atom() + 1; } + inline void* body() { return atom() + 1; } + inline bool is_valid() const { return type(); } - template <typename T> const T* ptr() const { - return static_cast<const T*>(body()); - } + template<typename T> const T& get() const; + template<typename T> const T* ptr() const; const LV2_Atom* atom() const { - return is_reference() ? _body.ptr : &_atom; + if (auto* atom = boost::get<InlineAtom>(&_value)) { + return &atom->atom; + } + return boost::get<AtomPtr>(_value).get(); } -private: - /** Free dynamically allocated value, if applicable. */ - inline void dealloc() { - if (is_reference()) { - free(_body.ptr); + LV2_Atom* atom() { + if (auto* atom = boost::get<InlineAtom>(&_value)) { + return &atom->atom; } + return boost::get<AtomPtr>(_value).get(); } - /** Return true iff this value is dynamically allocated. */ - inline bool is_reference() const { - return _atom.size > sizeof(_body.val); +private: + friend class Forge; + + struct InlineAtom { + LV2_Atom atom; + InlineBody body; + }; + + using AtomPtr = std::unique_ptr<LV2_Atom, decltype(&free)>; + + bool is_inline() const { return _value.which() == 0; } + + LV2_Atom* copy_new_atom(const LV2_Atom* atom) { + LV2_Atom* copy = (LV2_Atom*)malloc(sizeof(LV2_Atom) + atom->size); + memcpy(copy, atom, sizeof(LV2_Atom) + atom->size); + return copy; } - LV2_Atom _atom; - union { - intptr_t val; - LV2_Atom* ptr; - } _body; + boost::variant<InlineAtom, AtomPtr> _value; }; +template<> +inline const int32_t& Atom::get<int32_t>() const +{ + assert(size() == sizeof(int32_t)); + return *static_cast<const int32_t*>(body()); +} + +template<> +inline const float& Atom::get<float>() const +{ + assert(size() == sizeof(float)); + return *static_cast<const float*>(body()); +} + +template<> +inline const LV2_URID& Atom::get<LV2_URID>() const +{ + assert(size() == sizeof(LV2_URID)); + return *static_cast<const LV2_URID*>(body()); +} + +template<> +inline const char* Atom::ptr<char>() const +{ + return static_cast<const char*>(body()); +} + } // namespace ingen #endif // INGEN_ATOM_HPP diff --git a/ingen/Forge.hpp b/ingen/Forge.hpp index 81b64998..e70f7b38 100644 --- a/ingen/Forge.hpp +++ b/ingen/Forge.hpp @@ -45,14 +45,6 @@ public: return atom.type() == URI || atom.type() == URID; } - Atom make() { return Atom(); } - Atom make(int32_t v) { return Atom(sizeof(v), Int, &v); } - Atom make(float v) { return Atom(sizeof(v), Float, &v); } - Atom make(bool v) { - const int32_t iv = v ? 1 : 0; - return Atom(sizeof(int32_t), Bool, &iv); - } - Atom make_urid(int32_t v) { return Atom(sizeof(int32_t), URID, &v); } Atom make_urid(const ingen::URI& u); |