summaryrefslogtreecommitdiffstats
path: root/ingen/Atom.hpp
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2017-12-18 00:59:12 +0100
committerDavid Robillard <d@drobilla.net>2019-01-12 18:20:04 +0100
commitaa00a7ab3a11ea87cb7087eb4bc539df0d30db46 (patch)
tree6c709e4c27dd532f45056297ee71f326c3cfbe38 /ingen/Atom.hpp
parent8c19e157e148efb59d6ea2f815783755b6075c7e (diff)
downloadingen-atom-cpp.tar.gz
ingen-atom-cpp.tar.bz2
ingen-atom-cpp.zip
Rewrite Atomatom-cpp
Diffstat (limited to 'ingen/Atom.hpp')
-rw-r--r--ingen/Atom.hpp203
1 files changed, 100 insertions, 103 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