aboutsummaryrefslogtreecommitdiffstats
path: root/serd/detail
diff options
context:
space:
mode:
Diffstat (limited to 'serd/detail')
-rw-r--r--serd/detail/Copyable.hpp101
-rw-r--r--serd/detail/Flags.hpp73
-rw-r--r--serd/detail/Optional.hpp129
-rw-r--r--serd/detail/StringView.hpp148
-rw-r--r--serd/detail/Wrapper.hpp87
5 files changed, 538 insertions, 0 deletions
diff --git a/serd/detail/Copyable.hpp b/serd/detail/Copyable.hpp
new file mode 100644
index 00000000..225fc18c
--- /dev/null
+++ b/serd/detail/Copyable.hpp
@@ -0,0 +1,101 @@
+/*
+ Copyright 2019 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef SERD_DETAIL_COPYABLE_HPP
+#define SERD_DETAIL_COPYABLE_HPP
+
+#include "serd/detail/Wrapper.hpp"
+#include "serd/serd.h"
+
+#include <cstddef>
+#include <memory>
+#include <type_traits>
+
+namespace serd {
+namespace detail {
+
+/// Copy function for a C object
+template <class T>
+using CopyFunc = T* (*)(const T*);
+
+template <class T, Mutable<T>* Copy(const T*), void Free(Mutable<T>*)>
+typename std::enable_if<std::is_const<T>::value, T>::type*
+copy(const T* ptr)
+{
+ return ptr; // Making a view (const reference), do not copy
+}
+
+template <class T,
+ Mutable<T>* Copy(const T*),
+ void Free(typename std::remove_const<T>::type*)>
+typename std::enable_if<!std::is_const<T>::value, T>::type*
+copy(const T* ptr)
+{
+ return Copy(ptr); // Making a mutable wrapper, copy
+}
+
+/// Generic C++ wrapper for a copyable C object
+template <class T,
+ Mutable<T>* Copy(const T*),
+ bool Equals(const T*, const T*),
+ void Free(Mutable<T>*)>
+class Copyable : public Wrapper<T, Free>
+{
+public:
+ explicit Copyable(T* ptr) : Wrapper<T, Free>(ptr) {}
+
+ Copyable(const Copyable& wrapper)
+ : Wrapper<T, Free>(copy<T, Copy, Free>(wrapper.cobj()))
+ {
+ }
+
+ template <class U, void UFree(Mutable<U>*)>
+ explicit Copyable(const Copyable<U, Copy, Equals, UFree>& wrapper)
+ : Wrapper<T, Free>(copy<T, Copy, Free>(wrapper.cobj()))
+ {
+ }
+
+ Copyable(Copyable&&) noexcept = default;
+ Copyable& operator=(Copyable&&) noexcept = default;
+ ~Copyable() noexcept = default;
+
+ Copyable& operator=(const Copyable& wrapper)
+ {
+ this->_ptr = std::unique_ptr<T, Deleter<T, Free>>(
+ copy<T, Copy, Free>(wrapper.cobj()));
+ return *this;
+ }
+
+ template <class U, void UFree(Mutable<U>*)>
+ bool operator==(const Copyable<U, Copy, Equals, UFree>& wrapper) const
+ {
+ return Equals(this->cobj(), wrapper.cobj());
+ }
+
+ template <class U, void UFree(Mutable<U>*)>
+ bool operator!=(const Copyable<U, Copy, Equals, UFree>& wrapper) const
+ {
+ return !operator==(wrapper);
+ }
+
+protected:
+ explicit Copyable(std::nullptr_t) : Wrapper<T, Free>(nullptr) {}
+};
+
+} // namespace detail
+} // namespace serd
+
+#endif // SERD_DETAIL_COPYABLE_HPP
diff --git a/serd/detail/Flags.hpp b/serd/detail/Flags.hpp
new file mode 100644
index 00000000..bae2da96
--- /dev/null
+++ b/serd/detail/Flags.hpp
@@ -0,0 +1,73 @@
+/*
+ Copyright 2019 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef SERD_DETAIL_FLAGS_HPP
+#define SERD_DETAIL_FLAGS_HPP
+
+#include "serd/serd.h"
+
+#include <type_traits>
+
+namespace serd {
+namespace detail {
+
+/**
+ Type-safe bit flags
+
+ This is a minimal interface for a type-safe bit flags field, which only
+ allows values from the given enum to be set.
+
+ @tparam Flag Enum class of flag values.
+*/
+template <typename Flag>
+class Flags
+{
+public:
+ static_assert(std::is_enum<Flag>::value, "");
+
+ using FlagUnderlyingType = typename std::underlying_type<Flag>::type;
+ using Value = typename std::make_unsigned<FlagUnderlyingType>::type;
+
+ constexpr Flags() noexcept : _value(0) {}
+ constexpr explicit Flags(const Value value) noexcept : _value{value} {}
+
+ // NOLINTNEXTLINE(hicpp-explicit-conversions)
+ constexpr Flags(const Flag f) noexcept
+ : _value(static_cast<Value>(f))
+ {
+ }
+
+ constexpr Flags operator|(const Flag rhs) const noexcept
+ {
+ return Flags{_value | static_cast<Value>(rhs)};
+ }
+
+ constexpr Flags operator|(const Flags rhs) const noexcept
+ {
+ return Flags{_value | rhs._value};
+ }
+
+ // NOLINTNEXTLINE(hicpp-explicit-conversions)
+ constexpr operator Value() const noexcept { return _value; }
+
+private:
+ Value _value{};
+};
+
+} // namespace detail
+} // namespace serd
+
+#endif // SERD_DETAIL_FLAGS_HPP
diff --git a/serd/detail/Optional.hpp b/serd/detail/Optional.hpp
new file mode 100644
index 00000000..5ca7f83f
--- /dev/null
+++ b/serd/detail/Optional.hpp
@@ -0,0 +1,129 @@
+/*
+ Copyright 2019 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef SERD_DETAIL_OPTIONAL_HPP
+#define SERD_DETAIL_OPTIONAL_HPP
+
+#include "serd/serd.h"
+
+#include <cassert>
+#include <cstddef>
+#include <utility>
+
+namespace serd {
+namespace detail {
+
+struct ConstructNullOptional
+{
+};
+
+/**
+ A simple optional wrapper around a wrapped type with a pointer-like API
+
+ This works like a typical optional type, but only works with Wrapper types,
+ and exploits the fact that these are interally just pointers to avoid adding
+ space overhead for an "is_set" flag, like a generic optional class would.
+
+ Types must explicitly opt-in to being optional by providing a constructor
+ that takes a single ContructNullOptional argument. This constructor should
+ only be used by the Optional implementation, which guarantees that such an
+ object will not be used except by calling its cobj() method.
+*/
+template <typename T>
+class Optional
+{
+public:
+ using CType = typename T::CType;
+
+ Optional() : _value(nullptr) {}
+
+ // NOLINTNEXTLINE(hicpp-explicit-conversions, modernize-pass-by-value)
+ Optional(const T& value) : _value(value) {}
+
+ // NOLINTNEXTLINE(hicpp-explicit-conversions)
+ Optional(T&& value) : _value(std::move(value)) {}
+
+ template <typename U,
+ typename = typename std::enable_if<
+ std::is_convertible<U, T>::value>::type>
+ // NOLINTNEXTLINE(hicpp-explicit-conversions)
+ Optional(U&& value) : _value(std::forward<U>(value))
+ {
+ }
+
+ void reset() { _value = T{nullptr}; }
+
+ const T& operator*() const
+ {
+ assert(_value.cobj());
+ return _value;
+ }
+
+ T& operator*()
+ {
+ assert(_value.cobj());
+ return _value;
+ }
+
+ const T* operator->() const
+ {
+ assert(_value.cobj());
+ return &_value;
+ }
+
+ T* operator->()
+ {
+ assert(_value.cobj());
+ return &_value;
+ }
+
+ bool operator==(const Optional& optional)
+ {
+ return (!*this && !optional) ||
+ (*this && optional && _value == optional._value);
+ }
+
+ bool operator!=(const Optional& optional) { return !operator==(optional); }
+
+ explicit operator bool() const { return _value.cobj(); }
+ bool operator!() const { return !_value.cobj(); }
+
+ inline CType* cobj() { return _value.cobj(); }
+ inline const CType* cobj() const { return _value.cobj(); }
+
+private:
+ T _value;
+};
+
+} // namespace detail
+
+template <class T>
+constexpr detail::Optional<T>
+make_optional(T&& value)
+{
+ return detail::Optional<T>{std::forward<T>(value)};
+}
+
+template <class T, class... Args>
+constexpr detail::Optional<T>
+make_optional(Args&&... args)
+{
+ return detail::Optional<T>{std::forward<Args>(args)...};
+}
+
+} // namespace serd
+
+#endif // SERD_DETAIL_OPTIONAL_HPP
diff --git a/serd/detail/StringView.hpp b/serd/detail/StringView.hpp
new file mode 100644
index 00000000..0915daed
--- /dev/null
+++ b/serd/detail/StringView.hpp
@@ -0,0 +1,148 @@
+/*
+ Copyright 2019 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef SERD_DETAIL_STRINGVIEW_HPP
+#define SERD_DETAIL_STRINGVIEW_HPP
+
+#include "serd/serd.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+#include <ostream>
+#include <stdexcept>
+#include <string>
+
+namespace serd {
+namespace detail {
+
+/**
+ Immutable slice of a string.
+
+ This is a minimal implementation that is compatible with std::string_view
+ and std::string for most basic use cases. This could be replaced with
+ std::string_view once C++17 support can be relied on.
+*/
+class StringView
+{
+public:
+ using char_type = char;
+ using size_type = size_t;
+ using traits_type = std::char_traits<char>;
+ using value_type = char;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using iterator = const char*;
+ using const_iterator = const char*;
+
+ static constexpr size_type npos = size_t(-1);
+
+ constexpr StringView() noexcept : _str{nullptr}, _len{0U} {}
+
+ constexpr StringView(const char* const str, const size_t len) noexcept
+ : _str{str}, _len{len}
+ {
+ }
+
+ // NOLINTNEXTLINE(hicpp-explicit-conversions)
+ StringView(const char* const str) noexcept
+ : _str{str}, _len{str ? strlen(str) : 0}
+ {
+ }
+
+ // NOLINTNEXTLINE(hicpp-explicit-conversions)
+ StringView(const std::string& str) noexcept
+ : _str{str.c_str()}, _len{str.length()}
+ {
+ }
+
+ constexpr size_t size() const { return _len; }
+ constexpr size_t length() const { return _len; }
+ constexpr bool empty() const { return _len == 0; }
+ constexpr const char* c_str() const { return _str; }
+ constexpr const char* data() const { return _str; }
+ constexpr const char& front() const { return _str[0]; }
+ constexpr const char& back() const { return _str[_len - 1]; }
+
+ constexpr const_iterator begin() const { return _str; }
+ constexpr const_iterator end() const { return _str + _len; }
+ constexpr const_iterator cbegin() const { return begin(); }
+ constexpr const_iterator cend() const { return end(); }
+
+ constexpr const char& operator[](size_t pos) const { return _str[pos]; }
+
+ const char& at(size_t pos) const
+ {
+ if (pos >= size()) {
+ throw std::out_of_range("serd::StringView::at pos");
+ }
+
+ return _str[pos];
+ }
+
+ StringView substr(size_t pos, size_t n = npos) const
+ {
+ if (pos > size()) {
+ throw std::out_of_range("serd::StringView::substr pos");
+ }
+
+ return StringView{data() + pos, std::min(size() - pos, n)};
+ }
+
+ template <class Alloc = std::allocator<char>>
+ std::basic_string<char, traits_type, Alloc>
+ str(const Alloc& alloc = {}) const
+ {
+ return std::basic_string<char, traits_type, Alloc>(
+ data(), size(), alloc);
+ }
+
+ // NOLINTNEXTLINE(hicpp-explicit-conversions)
+ explicit operator std::string() const { return str(); }
+
+ // NOLINTNEXTLINE(hicpp-explicit-conversions)
+ explicit operator const char*() const { return _str; }
+
+private:
+ const char* const _str{};
+ const size_t _len{};
+};
+
+inline bool
+operator==(const detail::StringView& lhs, const std::string& rhs)
+{
+ return lhs.length() == rhs.length() && rhs == lhs.c_str();
+}
+
+inline bool
+operator==(const detail::StringView& lhs, const char* rhs)
+{
+ return !strncmp(lhs.c_str(), rhs, lhs.length());
+}
+
+inline std::ostream&
+operator<<(std::ostream& os, const StringView& str)
+{
+ os.write(str.data(), std::streamsize(str.size()));
+ return os;
+}
+
+} // namespace detail
+} // namespace serd
+
+#endif // SERD_DETAIL_STRINGVIEW_HPP
diff --git a/serd/detail/Wrapper.hpp b/serd/detail/Wrapper.hpp
new file mode 100644
index 00000000..5048dfd1
--- /dev/null
+++ b/serd/detail/Wrapper.hpp
@@ -0,0 +1,87 @@
+/*
+ Copyright 2019 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef SERD_DETAIL_WRAPPER_HPP
+#define SERD_DETAIL_WRAPPER_HPP
+
+#include "serd/serd.h"
+
+#include <cstddef>
+#include <memory>
+
+namespace serd {
+namespace detail {
+
+template <typename T>
+class Optional;
+
+// Free function for a C object
+template <typename T>
+using FreeFunc = void (*)(T*);
+
+template <class T>
+using Mutable = typename std::remove_const<T>::type;
+
+/// Callable deleter for a C object, noopt for const pointers
+template <typename T, void Free(Mutable<T>*)>
+struct Deleter
+{
+ template <typename = std::enable_if<!std::is_const<T>::value>>
+ void operator()(typename std::remove_const<T>::type* ptr)
+ {
+ Free(ptr);
+ }
+
+ template <typename = std::enable_if<std::is_const<T>::value>>
+ void operator()(const T*)
+ {
+ }
+};
+
+/// Generic C++ wrapper for a C object
+template <typename T, void FreeFunc(Mutable<T>*)>
+class Wrapper
+{
+public:
+ using CType = T;
+
+ explicit Wrapper(T* ptr) : _ptr(ptr) {}
+
+ Wrapper(Wrapper&& wrapper) noexcept = default;
+ Wrapper& operator=(Wrapper&& wrapper) noexcept = default;
+
+ Wrapper(const Wrapper&) = delete;
+ Wrapper& operator=(const Wrapper&) = delete;
+
+ ~Wrapper() = default;
+
+ T* cobj() { return _ptr.get(); }
+ const T* cobj() const { return _ptr.get(); }
+
+protected:
+ friend class detail::Optional<T>;
+
+ explicit Wrapper(std::nullptr_t) : _ptr(nullptr) {}
+
+ void reset() { _ptr.reset(); }
+
+ std::unique_ptr<T, Deleter<T, FreeFunc>> _ptr;
+};
+
+} // namespace detail
+} // namespace serd
+
+#endif // SERD_DETAIL_WRAPPER_HPP