Add C++ interface for the libbabeltrace2 `bt_value` API
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 11 Dec 2020 00:40:00 +0000 (19:40 -0500)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 28 Jan 2022 16:22:26 +0000 (11:22 -0500)
This patch adds C++ wrappers for Babeltrace 2 value objects.

The class hierarchy is:

    Value
      NullValue
      BoolValue
      UnsignedIntegerValue
      SignedIntegerValue
      RealValue
      StringValue
      ArrayValue
      MapValue
    ConstValue
      ConstNullValue
      ConstBoolValue
      ConstUnsignedIntegerValue
      ConstSignedIntegerValue
      ConstRealValue
      ConstStringValue
      ConstArrayValue
      ConstMapValue

Implicitly convert from a mutable value to a constant value with
converting constructors and assignment operators.

All classes have the `Shared` type alias which is what the shared()
method returns. You can also implicitly convert from a shared mutable
value to a shared constant value.

Create a shared value with the static create() methods, for example:

    auto myRealVal = bt2::RealValue::create(17.42);

You can also use one of the overloaded bt2::createValue() functions:

    auto myStrVal = bt2::createValue("salut");

Those methods and functions can throw a `LibMemoryError` instance.

`NullValue` has no create() static function as there's nothing to be
created. If you want to wrap the null value singleton, use:

    bt2::NullValue {}

or

    bt2::ConstNullValue {}

If you want a shared null value for any reason, use:

    bt2::NullValue {}.shared()

Downcast a `Value` or `ConstValue` object to a specific value object
with one of its as*() methods, for example:

    auto myBoolVal = myVal.asBool();

Each as*() method checks that the conversion is legal with
BT_ASSERT_DBG().

MapValue::forEach() and ConstMapValue::forEach() accept a function which
receives the key and value of the entry, for example:

    myMapVal.forEach([&](const bpstd::string_view& key,
                         const Value val) {
        // Do something
    });

If you throw anything from such a function, then
bt_value_map_foreach_entry() or bt_value_map_foreach_entry_const()
receives `BT_VALUE_MAP_FOREACH_ENTRY_STATUS_ERROR` or
`BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_ERROR`, which in turn makes the
forEach() method throw a `LibError` instance. As of this patch, there's
no way for the user function to gracefully interrupt the iterating
operation (`BT_VALUE_MAP_FOREACH_ENTRY_STATUS_INTERRUPT` and
`BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_INTERRUPT` status code
equivalents).

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: I7c278aa660e9716a69e7d540763dc31623e45fec
Reviewed-on: https://review.lttng.org/c/babeltrace/+/4537

src/cpp-common/bt2/value.hpp [new file with mode: 0644]

diff --git a/src/cpp-common/bt2/value.hpp b/src/cpp-common/bt2/value.hpp
new file mode 100644 (file)
index 0000000..3141118
--- /dev/null
@@ -0,0 +1,1245 @@
+/*
+ * Copyright (c) 2020 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef BABELTRACE_CPP_COMMON_BT2_VALUE_HPP
+#define BABELTRACE_CPP_COMMON_BT2_VALUE_HPP
+
+#include <type_traits>
+#include <cstdint>
+#include <functional>
+#include <babeltrace2/babeltrace.h>
+
+#include "common/assert.h"
+#include "common/common.h"
+#include "internal/borrowed-obj.hpp"
+#include "internal/shared-obj.hpp"
+#include "internal/utils.hpp"
+#include "cpp-common/optional.hpp"
+#include "cpp-common/string_view.hpp"
+#include "lib-error.hpp"
+
+namespace bt2 {
+
+namespace internal {
+
+struct ValueRefFuncs final
+{
+    static void get(const bt_value * const libObjPtr)
+    {
+        bt_value_get_ref(libObjPtr);
+    }
+
+    static void put(const bt_value * const libObjPtr)
+    {
+        bt_value_put_ref(libObjPtr);
+    }
+};
+
+template <typename ObjT, typename LibObjT>
+using SharedValue = internal::SharedObj<ObjT, LibObjT, internal::ValueRefFuncs>;
+
+} // namespace internal
+
+template <typename LibObjT>
+class CommonNullValue;
+
+template <typename LibObjT>
+class CommonBoolValue;
+
+template <typename LibObjT>
+class CommonUnsignedIntegerValue;
+
+template <typename LibObjT>
+class CommonSignedIntegerValue;
+
+template <typename LibObjT>
+class CommonRealValue;
+
+template <typename LibObjT>
+class CommonStringValue;
+
+template <typename LibObjT>
+class CommonArrayValue;
+
+template <typename LibObjT>
+class CommonMapValue;
+
+enum class ValueType
+{
+    NUL = BT_VALUE_TYPE_NULL,
+    BOOL = BT_VALUE_TYPE_BOOL,
+    UNSIGNED_INTEGER = BT_VALUE_TYPE_UNSIGNED_INTEGER,
+    SIGNED_INTEGER = BT_VALUE_TYPE_SIGNED_INTEGER,
+    REAL = BT_VALUE_TYPE_REAL,
+    STRING = BT_VALUE_TYPE_STRING,
+    ARRAY = BT_VALUE_TYPE_ARRAY,
+    MAP = BT_VALUE_TYPE_MAP,
+};
+
+template <typename LibObjT>
+class CommonValue : public internal::BorrowedObj<LibObjT>
+{
+    // Allow append() to call `val._libObjPtr()`
+    friend class CommonArrayValue<bt_value>;
+
+    // Allow insert() to call `val._libObjPtr()`
+    friend class CommonMapValue<bt_value>;
+
+    // Allow operator==() to call `other._libObjPtr()`
+    friend class CommonValue<bt_value>;
+    friend class CommonValue<const bt_value>;
+
+private:
+    using typename internal::BorrowedObj<LibObjT>::_ThisBorrowedObj;
+
+protected:
+    using typename internal::BorrowedObj<LibObjT>::_LibObjPtr;
+    using _ThisCommonValue = CommonValue<LibObjT>;
+
+public:
+    using Shared = internal::SharedValue<CommonValue<LibObjT>, LibObjT>;
+
+    explicit CommonValue(const _LibObjPtr libObjPtr) noexcept : _ThisBorrowedObj {libObjPtr}
+    {
+    }
+
+    template <typename OtherLibObjT>
+    CommonValue(const CommonValue<OtherLibObjT>& val) noexcept : _ThisBorrowedObj {val}
+    {
+    }
+
+    template <typename OtherLibObjT>
+    _ThisCommonValue& operator=(const CommonValue<OtherLibObjT>& val) noexcept
+    {
+        _ThisBorrowedObj::operator=(val);
+        return *this;
+    }
+
+    ValueType type() const noexcept
+    {
+        return static_cast<ValueType>(bt_value_get_type(this->_libObjPtr()));
+    }
+
+    bool isNull() const noexcept
+    {
+        return this->_libTypeIs(BT_VALUE_TYPE_NULL);
+    }
+
+    bool isBool() const noexcept
+    {
+        return this->_libTypeIs(BT_VALUE_TYPE_BOOL);
+    }
+
+    bool isInteger() const noexcept
+    {
+        return this->_libTypeIs(BT_VALUE_TYPE_INTEGER);
+    }
+
+    bool isUnsignedInteger() const noexcept
+    {
+        return this->_libTypeIs(BT_VALUE_TYPE_UNSIGNED_INTEGER);
+    }
+
+    bool isSignedInteger() const noexcept
+    {
+        return this->_libTypeIs(BT_VALUE_TYPE_SIGNED_INTEGER);
+    }
+
+    bool isReal() const noexcept
+    {
+        return this->_libTypeIs(BT_VALUE_TYPE_REAL);
+    }
+
+    bool isString() const noexcept
+    {
+        return this->_libTypeIs(BT_VALUE_TYPE_STRING);
+    }
+
+    bool isArray() const noexcept
+    {
+        return this->_libTypeIs(BT_VALUE_TYPE_ARRAY);
+    }
+
+    bool isMap() const noexcept
+    {
+        return this->_libTypeIs(BT_VALUE_TYPE_MAP);
+    }
+
+    template <typename OtherLibObjT>
+    bool operator==(const CommonValue<OtherLibObjT>& other) const noexcept
+    {
+        return static_cast<bool>(bt_value_is_equal(this->_libObjPtr(), other._libObjPtr()));
+    }
+
+    template <typename OtherLibObjT>
+    bool operator!=(const CommonValue<OtherLibObjT>& other) const noexcept
+    {
+        return !(*this == other);
+    }
+
+    Shared shared() const noexcept
+    {
+        return Shared {*this};
+    }
+
+    CommonNullValue<LibObjT> asNull() const noexcept;
+    CommonBoolValue<LibObjT> asBool() const noexcept;
+    CommonSignedIntegerValue<LibObjT> asSignedInteger() const noexcept;
+    CommonUnsignedIntegerValue<LibObjT> asUnsignedInteger() const noexcept;
+    CommonRealValue<LibObjT> asReal() const noexcept;
+    CommonStringValue<LibObjT> asString() const noexcept;
+    CommonArrayValue<LibObjT> asArray() const noexcept;
+    CommonMapValue<LibObjT> asMap() const noexcept;
+
+protected:
+    bool _libTypeIs(const bt_value_type type) const noexcept
+    {
+        return bt_value_type_is(bt_value_get_type(this->_libObjPtr()), type);
+    }
+};
+
+using Value = CommonValue<bt_value>;
+using ConstValue = CommonValue<const bt_value>;
+
+template <typename LibObjT>
+class CommonNullValue final : public CommonValue<LibObjT>
+{
+private:
+    using typename CommonValue<LibObjT>::_ThisCommonValue;
+
+public:
+    using Shared = internal::SharedValue<CommonNullValue<LibObjT>, LibObjT>;
+
+    CommonNullValue() noexcept : _ThisCommonValue {bt_value_null}
+    {
+    }
+
+    template <typename OtherLibObjT>
+    CommonNullValue(const CommonNullValue<OtherLibObjT>& val) noexcept : _ThisCommonValue {val}
+    {
+    }
+
+    template <typename OtherLibObjT>
+    CommonNullValue<LibObjT>& operator=(const CommonNullValue<OtherLibObjT>& val) noexcept
+    {
+        _ThisCommonValue::operator=(val);
+        return *this;
+    }
+
+    Shared shared() const noexcept
+    {
+        return Shared {*this};
+    }
+};
+
+using NullValue = CommonNullValue<bt_value>;
+using ConstNullValue = CommonNullValue<const bt_value>;
+
+template <typename LibObjT>
+class CommonBoolValue final : public CommonValue<LibObjT>
+{
+private:
+    using typename CommonValue<LibObjT>::_LibObjPtr;
+    using typename CommonValue<LibObjT>::_ThisCommonValue;
+
+public:
+    using Shared = internal::SharedValue<CommonBoolValue<LibObjT>, LibObjT>;
+    using Value = bool;
+
+    explicit CommonBoolValue(const _LibObjPtr libObjPtr) noexcept : _ThisCommonValue {libObjPtr}
+    {
+        BT_ASSERT_DBG(this->isBool());
+    }
+
+    template <typename OtherLibObjT>
+    CommonBoolValue(const CommonBoolValue<OtherLibObjT>& val) noexcept : _ThisCommonValue {val}
+    {
+    }
+
+    static Shared create(const Value rawVal = false)
+    {
+        const auto libObjPtr = bt_value_bool_create_init(static_cast<bt_bool>(rawVal));
+
+        internal::validateCreatedObjPtr(libObjPtr);
+        return Shared {CommonBoolValue<LibObjT> {libObjPtr}};
+    }
+
+    template <typename OtherLibObjT>
+    CommonBoolValue<LibObjT>& operator=(const CommonBoolValue<OtherLibObjT>& val) noexcept
+    {
+        _ThisCommonValue::operator=(val);
+        return *this;
+    }
+
+    CommonBoolValue<LibObjT>& operator=(const Value rawVal) noexcept
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        bt_value_bool_set(this->_libObjPtr(), static_cast<bt_bool>(rawVal));
+        return *this;
+    }
+
+    Value value() const noexcept
+    {
+        return static_cast<Value>(bt_value_bool_get(this->_libObjPtr()));
+    }
+
+    operator Value() const noexcept
+    {
+        return this->value();
+    }
+
+    Shared shared() const noexcept
+    {
+        return Shared {*this};
+    }
+};
+
+using BoolValue = CommonBoolValue<bt_value>;
+using ConstBoolValue = CommonBoolValue<const bt_value>;
+
+template <typename LibObjT>
+class CommonUnsignedIntegerValue final : public CommonValue<LibObjT>
+{
+private:
+    using typename CommonValue<LibObjT>::_LibObjPtr;
+    using typename CommonValue<LibObjT>::_ThisCommonValue;
+
+public:
+    using Shared = internal::SharedValue<CommonUnsignedIntegerValue<LibObjT>, LibObjT>;
+    using Value = std::uint64_t;
+
+    explicit CommonUnsignedIntegerValue(const _LibObjPtr libObjPtr) noexcept :
+        _ThisCommonValue {libObjPtr}
+    {
+        BT_ASSERT_DBG(this->isUnsignedInteger());
+    }
+
+    static Shared create(const Value rawVal = 0)
+    {
+        const auto libObjPtr = bt_value_integer_unsigned_create_init(rawVal);
+
+        internal::validateCreatedObjPtr(libObjPtr);
+        return Shared {CommonUnsignedIntegerValue<LibObjT> {libObjPtr}};
+    }
+
+    template <typename OtherLibObjT>
+    CommonUnsignedIntegerValue(const CommonUnsignedIntegerValue<OtherLibObjT>& val) noexcept :
+        _ThisCommonValue {val}
+    {
+    }
+
+    template <typename OtherLibObjT>
+    CommonUnsignedIntegerValue<LibObjT>&
+    operator=(const CommonUnsignedIntegerValue<OtherLibObjT>& val) noexcept
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        _ThisCommonValue::operator=(val);
+        return *this;
+    }
+
+    CommonUnsignedIntegerValue<LibObjT>& operator=(const Value rawVal) noexcept
+    {
+        bt_value_integer_unsigned_set(this->_libObjPtr(), rawVal);
+        return *this;
+    }
+
+    Value value() const noexcept
+    {
+        return bt_value_integer_unsigned_get(this->_libObjPtr());
+    }
+
+    operator Value() const noexcept
+    {
+        return this->value();
+    }
+
+    Shared shared() const noexcept
+    {
+        return Shared {*this};
+    }
+};
+
+using UnsignedIntegerValue = CommonUnsignedIntegerValue<bt_value>;
+using ConstUnsignedIntegerValue = CommonUnsignedIntegerValue<const bt_value>;
+
+template <typename LibObjT>
+class CommonSignedIntegerValue final : public CommonValue<LibObjT>
+{
+private:
+    using typename CommonValue<LibObjT>::_LibObjPtr;
+    using typename CommonValue<LibObjT>::_ThisCommonValue;
+
+public:
+    using Shared = internal::SharedValue<CommonSignedIntegerValue<LibObjT>, LibObjT>;
+    using Value = std::int64_t;
+
+    explicit CommonSignedIntegerValue(const _LibObjPtr libObjPtr) noexcept :
+        _ThisCommonValue {libObjPtr}
+    {
+        BT_ASSERT_DBG(this->isSignedInteger());
+    }
+
+    static Shared create(const Value rawVal = 0)
+    {
+        const auto libObjPtr = bt_value_integer_signed_create_init(rawVal);
+
+        internal::validateCreatedObjPtr(libObjPtr);
+        return Shared {CommonSignedIntegerValue<LibObjT> {libObjPtr}};
+    }
+
+    template <typename OtherLibObjT>
+    CommonSignedIntegerValue(const CommonSignedIntegerValue<OtherLibObjT>& val) noexcept :
+        _ThisCommonValue {val}
+    {
+    }
+
+    template <typename OtherLibObjT>
+    CommonSignedIntegerValue<LibObjT>&
+    operator=(const CommonSignedIntegerValue<OtherLibObjT>& val) noexcept
+    {
+        _ThisCommonValue::operator=(val);
+        return *this;
+    }
+
+    CommonSignedIntegerValue<LibObjT>& operator=(const Value rawVal) noexcept
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        bt_value_integer_signed_set(this->_libObjPtr(), rawVal);
+        return *this;
+    }
+
+    Value value() const noexcept
+    {
+        return bt_value_integer_signed_get(this->_libObjPtr());
+    }
+
+    operator Value() const noexcept
+    {
+        return this->value();
+    }
+
+    Shared shared() const noexcept
+    {
+        return Shared {*this};
+    }
+};
+
+using SignedIntegerValue = CommonSignedIntegerValue<bt_value>;
+using ConstSignedIntegerValue = CommonSignedIntegerValue<const bt_value>;
+
+template <typename LibObjT>
+class CommonRealValue final : public CommonValue<LibObjT>
+{
+private:
+    using typename CommonValue<LibObjT>::_LibObjPtr;
+    using typename CommonValue<LibObjT>::_ThisCommonValue;
+
+public:
+    using Shared = internal::SharedValue<CommonRealValue<LibObjT>, LibObjT>;
+    using Value = double;
+
+    explicit CommonRealValue(const _LibObjPtr libObjPtr) noexcept : _ThisCommonValue {libObjPtr}
+    {
+        BT_ASSERT_DBG(this->isReal());
+    }
+
+    static Shared create(const Value rawVal = 0)
+    {
+        const auto libObjPtr = bt_value_real_create_init(rawVal);
+
+        internal::validateCreatedObjPtr(libObjPtr);
+        return Shared {CommonRealValue<LibObjT> {libObjPtr}};
+    }
+
+    template <typename OtherLibObjT>
+    CommonRealValue(const CommonRealValue<OtherLibObjT>& val) noexcept : _ThisCommonValue {val}
+    {
+    }
+
+    template <typename OtherLibObjT>
+    CommonRealValue<LibObjT>& operator=(const CommonRealValue<OtherLibObjT>& val) noexcept
+    {
+        _ThisCommonValue::operator=(val);
+        return *this;
+    }
+
+    CommonRealValue<LibObjT>& operator=(const Value rawVal) noexcept
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        bt_value_real_set(this->_libObjPtr(), rawVal);
+        return *this;
+    }
+
+    Value value() const noexcept
+    {
+        return bt_value_real_get(this->_libObjPtr());
+    }
+
+    operator Value() const noexcept
+    {
+        return this->value();
+    }
+
+    Shared shared() const noexcept
+    {
+        return Shared {*this};
+    }
+};
+
+using RealValue = CommonRealValue<bt_value>;
+using ConstRealValue = CommonRealValue<const bt_value>;
+
+template <typename LibObjT>
+class CommonStringValue final : public CommonValue<LibObjT>
+{
+private:
+    using typename CommonValue<LibObjT>::_LibObjPtr;
+    using typename CommonValue<LibObjT>::_ThisCommonValue;
+
+public:
+    using Shared = internal::SharedValue<CommonStringValue<LibObjT>, LibObjT>;
+
+    explicit CommonStringValue(const _LibObjPtr libObjPtr) noexcept : _ThisCommonValue {libObjPtr}
+    {
+        BT_ASSERT_DBG(this->isString());
+    }
+
+    static Shared create(const char * const rawVal = "")
+    {
+        const auto libObjPtr = bt_value_string_create_init(rawVal);
+
+        internal::validateCreatedObjPtr(libObjPtr);
+        return Shared {CommonStringValue<LibObjT> {libObjPtr}};
+    }
+
+    static Shared create(const std::string& rawVal)
+    {
+        return CommonStringValue<LibObjT>::create(rawVal.data());
+    }
+
+    template <typename OtherLibObjT>
+    CommonStringValue(const CommonStringValue<OtherLibObjT>& val) noexcept : _ThisCommonValue {val}
+    {
+    }
+
+    template <typename OtherLibObjT>
+    CommonStringValue<LibObjT>& operator=(const CommonStringValue<OtherLibObjT>& val) noexcept
+    {
+        _ThisCommonValue::operator=(val);
+        return *this;
+    }
+
+    CommonStringValue<LibObjT>& operator=(const char * const rawVal)
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        const auto status = bt_value_string_set(this->_libObjPtr(), rawVal);
+
+        if (status == BT_VALUE_STRING_SET_STATUS_MEMORY_ERROR) {
+            throw LibMemoryError {};
+        }
+
+        return *this;
+    }
+
+    CommonStringValue<LibObjT>& operator=(const std::string& rawVal) noexcept
+    {
+        return *this = rawVal.data();
+    }
+
+    bpstd::string_view value() const noexcept
+    {
+        return bt_value_string_get(this->_libObjPtr());
+    }
+
+    Shared shared() const noexcept
+    {
+        return Shared {*this};
+    }
+};
+
+using StringValue = CommonStringValue<bt_value>;
+using ConstStringValue = CommonStringValue<const bt_value>;
+
+namespace internal {
+
+template <typename LibObjT>
+struct CommonArrayValueSpec;
+
+// Functions specific to mutable array values
+template <>
+struct CommonArrayValueSpec<bt_value> final
+{
+    static bt_value *elementByIndex(bt_value * const libValPtr, const std::uint64_t index) noexcept
+    {
+        return bt_value_array_borrow_element_by_index(libValPtr, index);
+    }
+};
+
+// Functions specific to constant array values
+template <>
+struct CommonArrayValueSpec<const bt_value> final
+{
+    static const bt_value *elementByIndex(const bt_value * const libValPtr,
+                                          const std::uint64_t index) noexcept
+    {
+        return bt_value_array_borrow_element_by_index_const(libValPtr, index);
+    }
+};
+
+} // namespace internal
+
+template <typename LibObjT>
+class CommonArrayValue final : public CommonValue<LibObjT>
+{
+private:
+    using typename CommonValue<LibObjT>::_LibObjPtr;
+    using typename CommonValue<LibObjT>::_ThisCommonValue;
+
+public:
+    using Shared = internal::SharedValue<CommonArrayValue<LibObjT>, LibObjT>;
+
+    explicit CommonArrayValue(const _LibObjPtr libObjPtr) noexcept : _ThisCommonValue {libObjPtr}
+    {
+        BT_ASSERT_DBG(this->isArray());
+    }
+
+    static Shared create()
+    {
+        const auto libObjPtr = bt_value_array_create();
+
+        internal::validateCreatedObjPtr(libObjPtr);
+        return Shared {CommonArrayValue<LibObjT> {libObjPtr}};
+    }
+
+    template <typename OtherLibObjT>
+    CommonArrayValue(const CommonArrayValue<OtherLibObjT>& val) noexcept : _ThisCommonValue {val}
+    {
+    }
+
+    template <typename OtherLibObjT>
+    CommonArrayValue<LibObjT>& operator=(const CommonArrayValue<OtherLibObjT>& val) noexcept
+    {
+        _ThisCommonValue::operator=(val);
+        return *this;
+    }
+
+    std::uint64_t length() const noexcept
+    {
+        return bt_value_array_get_length(this->_libObjPtr());
+    }
+
+    bool isEmpty() const noexcept
+    {
+        return this->length() == 0;
+    }
+
+    ConstValue operator[](const std::uint64_t index) const noexcept
+    {
+        return ConstValue {internal::CommonArrayValueSpec<const bt_value>::elementByIndex(
+            this->_libObjPtr(), index)};
+    }
+
+    CommonValue<LibObjT> operator[](const std::uint64_t index) noexcept
+    {
+        return CommonValue<LibObjT> {
+            internal::CommonArrayValueSpec<LibObjT>::elementByIndex(this->_libObjPtr(), index)};
+    }
+
+    void append(const Value& val)
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        const auto status = bt_value_array_append_element(this->_libObjPtr(), val._libObjPtr());
+
+        this->_handleAppendLibStatus(status);
+    }
+
+    void append(const bool rawVal)
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        const auto status =
+            bt_value_array_append_bool_element(this->_libObjPtr(), static_cast<bt_bool>(rawVal));
+
+        this->_handleAppendLibStatus(status);
+    }
+
+    void append(const std::uint64_t rawVal)
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        const auto status =
+            bt_value_array_append_unsigned_integer_element(this->_libObjPtr(), rawVal);
+
+        this->_handleAppendLibStatus(status);
+    }
+
+    void append(const std::int64_t rawVal)
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        const auto status =
+            bt_value_array_append_signed_integer_element(this->_libObjPtr(), rawVal);
+
+        this->_handleAppendLibStatus(status);
+    }
+
+    void append(const double rawVal)
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        const auto status = bt_value_array_append_real_element(this->_libObjPtr(), rawVal);
+
+        this->_handleAppendLibStatus(status);
+    }
+
+    void append(const char * const rawVal)
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        const auto status = bt_value_array_append_string_element(this->_libObjPtr(), rawVal);
+
+        this->_handleAppendLibStatus(status);
+    }
+
+    void append(const std::string& rawVal)
+    {
+        this->append(rawVal.data());
+    }
+
+    CommonArrayValue<bt_value> appendEmptyArray();
+    CommonMapValue<bt_value> appendEmptyMap();
+
+    void operator+=(const Value& val)
+    {
+        this->append(val);
+    }
+
+    void operator+=(const bool rawVal)
+    {
+        this->append(rawVal);
+    }
+
+    void operator+=(const std::uint64_t rawVal)
+    {
+        this->append(rawVal);
+    }
+
+    void operator+=(const std::int64_t rawVal)
+    {
+        this->append(rawVal);
+    }
+
+    void operator+=(const double rawVal)
+    {
+        this->append(rawVal);
+    }
+
+    void operator+=(const char * const rawVal)
+    {
+        this->append(rawVal);
+    }
+
+    void operator+=(const std::string& rawVal)
+    {
+        this->append(rawVal);
+    }
+
+    Shared shared() const noexcept
+    {
+        return Shared {*this};
+    }
+
+private:
+    void _handleAppendLibStatus(const bt_value_array_append_element_status status) const
+    {
+        if (status == BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_MEMORY_ERROR) {
+            throw LibMemoryError {};
+        }
+    }
+};
+
+using ArrayValue = CommonArrayValue<bt_value>;
+using ConstArrayValue = CommonArrayValue<const bt_value>;
+
+namespace internal {
+
+/*
+ * Type of a user function passed to `CommonMapValue<ObjT>::forEach()`.
+ *
+ * First argument is the entry's key, second is its value.
+ */
+template <typename ObjT>
+using CommonMapValueForEachUserFunc = std::function<void(const bpstd::string_view&, ObjT)>;
+
+/*
+ * Template of a function to be passed to bt_value_map_foreach_entry()
+ * for bt_value_map_foreach_entry_const() which calls a user function.
+ *
+ * `userData` is casted to a `const` pointer to
+ * `CommonMapValueForEachUserFunc<ObjT>` (the user function to call).
+ *
+ * This function catches any exception which the user function throws
+ * and returns the `ErrorStatus` value. If there's no execption, this
+ * function returns the `OkStatus` value.
+ */
+template <typename ObjT, typename LibObjT, typename LibStatusT, int OkStatus, int ErrorStatus>
+LibStatusT mapValueForEachLibFunc(const char * const key, LibObjT * const libObjPtr,
+                                  void * const userData)
+{
+    const auto& userFunc = *reinterpret_cast<const CommonMapValueForEachUserFunc<ObjT> *>(userData);
+
+    try {
+        userFunc(key, ObjT {libObjPtr});
+    } catch (...) {
+        return static_cast<LibStatusT>(ErrorStatus);
+    }
+
+    return static_cast<LibStatusT>(OkStatus);
+}
+
+template <typename LibObjT>
+struct CommonMapValueSpec;
+
+// Functions specific to mutable map values
+template <>
+struct CommonMapValueSpec<bt_value> final
+{
+    static bt_value *entryByKey(bt_value * const libValPtr, const char * const key) noexcept
+    {
+        return bt_value_map_borrow_entry_value(libValPtr, key);
+    }
+
+    static void forEach(bt_value * const libValPtr,
+                        const CommonMapValueForEachUserFunc<Value>& func)
+    {
+        const auto status = bt_value_map_foreach_entry(
+            libValPtr,
+            mapValueForEachLibFunc<Value, bt_value, bt_value_map_foreach_entry_func_status,
+                                   BT_VALUE_MAP_FOREACH_ENTRY_FUNC_STATUS_OK,
+                                   BT_VALUE_MAP_FOREACH_ENTRY_FUNC_STATUS_ERROR>,
+            const_cast<void *>(reinterpret_cast<const void *>(&func)));
+
+        switch (status) {
+        case BT_VALUE_MAP_FOREACH_ENTRY_STATUS_OK:
+            return;
+        case BT_VALUE_MAP_FOREACH_ENTRY_STATUS_USER_ERROR:
+        case BT_VALUE_MAP_FOREACH_ENTRY_STATUS_ERROR:
+            throw LibError {};
+        default:
+            bt_common_abort();
+        }
+    }
+};
+
+// Functions specific to constant map values
+template <>
+struct CommonMapValueSpec<const bt_value> final
+{
+    static const bt_value *entryByKey(const bt_value * const libValPtr,
+                                      const char * const key) noexcept
+    {
+        return bt_value_map_borrow_entry_value_const(libValPtr, key);
+    }
+
+    static void forEach(const bt_value * const libValPtr,
+                        const CommonMapValueForEachUserFunc<ConstValue>& func)
+    {
+        const auto status = bt_value_map_foreach_entry_const(
+            libValPtr,
+            mapValueForEachLibFunc<ConstValue, const bt_value,
+                                   bt_value_map_foreach_entry_const_func_status,
+                                   BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_OK,
+                                   BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_ERROR>,
+            const_cast<void *>(reinterpret_cast<const void *>(&func)));
+
+        switch (status) {
+        case BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_OK:
+            return;
+        case BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_USER_ERROR:
+        case BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_ERROR:
+            throw LibError {};
+        default:
+            bt_common_abort();
+        }
+    }
+};
+
+} // namespace internal
+
+template <typename LibObjT>
+class CommonMapValue final : public CommonValue<LibObjT>
+{
+private:
+    using typename CommonValue<LibObjT>::_LibObjPtr;
+    using typename CommonValue<LibObjT>::_ThisCommonValue;
+
+public:
+    using Shared = internal::SharedValue<CommonMapValue<LibObjT>, LibObjT>;
+
+    explicit CommonMapValue(const _LibObjPtr libObjPtr) noexcept : _ThisCommonValue {libObjPtr}
+    {
+        BT_ASSERT_DBG(this->isMap());
+    }
+
+    static Shared create()
+    {
+        const auto libObjPtr = bt_value_map_create();
+
+        internal::validateCreatedObjPtr(libObjPtr);
+        return Shared {CommonMapValue<LibObjT> {libObjPtr}};
+    }
+
+    template <typename OtherLibObjT>
+    CommonMapValue(const CommonMapValue<OtherLibObjT>& val) noexcept : _ThisCommonValue {val}
+    {
+    }
+
+    template <typename OtherLibObjT>
+    CommonMapValue<LibObjT>& operator=(const CommonMapValue<OtherLibObjT>& val) noexcept
+    {
+        _ThisCommonValue::operator=(val);
+        return *this;
+    }
+
+    std::uint64_t size() const noexcept
+    {
+        return bt_value_map_get_size(this->_libObjPtr());
+    }
+
+    bool isEmpty() const noexcept
+    {
+        return this->size() == 0;
+    }
+
+    nonstd::optional<ConstValue> operator[](const char * const key) const noexcept
+    {
+        const auto libObjPtr =
+            internal::CommonMapValueSpec<const bt_value>::entryByKey(this->_libObjPtr(), key);
+
+        if (!libObjPtr) {
+            return nonstd::nullopt;
+        }
+
+        return ConstValue {libObjPtr};
+    }
+
+    nonstd::optional<ConstValue> operator[](const std::string& key) const noexcept
+    {
+        return (*this)[key.data()];
+    }
+
+    nonstd::optional<CommonValue<LibObjT>> operator[](const char * const key) noexcept
+    {
+        const auto libObjPtr =
+            internal::CommonMapValueSpec<LibObjT>::entryByKey(this->_libObjPtr(), key);
+
+        if (!libObjPtr) {
+            return nonstd::nullopt;
+        }
+
+        return CommonValue<LibObjT> {libObjPtr};
+    }
+
+    nonstd::optional<CommonValue<LibObjT>> operator[](const std::string& key) noexcept
+    {
+        return (*this)[key.data()];
+    }
+
+    bool hasEntry(const char * const key) const noexcept
+    {
+        return static_cast<bool>(bt_value_map_has_entry(this->_libObjPtr(), key));
+    }
+
+    bool hasEntry(const std::string& key) const noexcept
+    {
+        return this->hasEntry(key.data());
+    }
+
+    void insert(const char * const key, const Value& val)
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        const auto status = bt_value_map_insert_entry(this->_libObjPtr(), key, val._libObjPtr());
+
+        this->_handleInsertLibStatus(status);
+    }
+
+    void insert(const std::string& key, const Value& val)
+    {
+        this->insert(key.data(), val);
+    }
+
+    void insert(const char * const key, const bool rawVal)
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        const auto status =
+            bt_value_map_insert_bool_entry(this->_libObjPtr(), key, static_cast<bt_bool>(rawVal));
+
+        this->_handleInsertLibStatus(status);
+    }
+
+    void insert(const std::string& key, const bool rawVal)
+    {
+        this->insert(key.data(), rawVal);
+    }
+
+    void insert(const char * const key, const std::uint64_t rawVal)
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        const auto status =
+            bt_value_map_insert_unsigned_integer_entry(this->_libObjPtr(), key, rawVal);
+
+        this->_handleInsertLibStatus(status);
+    }
+
+    void insert(const std::string& key, const std::uint64_t rawVal)
+    {
+        this->insert(key.data(), rawVal);
+    }
+
+    void insert(const char * const key, const std::int64_t rawVal)
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        const auto status =
+            bt_value_map_insert_signed_integer_entry(this->_libObjPtr(), key, rawVal);
+
+        this->_handleInsertLibStatus(status);
+    }
+
+    void insert(const std::string& key, const std::int64_t rawVal)
+    {
+        this->insert(key.data(), rawVal);
+    }
+
+    void insert(const char * const key, const double rawVal)
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        const auto status = bt_value_map_insert_real_entry(this->_libObjPtr(), key, rawVal);
+
+        this->_handleInsertLibStatus(status);
+    }
+
+    void insert(const std::string& key, const double rawVal)
+    {
+        this->insert(key.data(), rawVal);
+    }
+
+    void insert(const char * const key, const char * const rawVal)
+    {
+        static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+        const auto status = bt_value_map_insert_string_entry(this->_libObjPtr(), key, rawVal);
+
+        this->_handleInsertLibStatus(status);
+    }
+
+    void insert(const char * const key, const std::string& rawVal)
+    {
+        this->insert(key, rawVal.data());
+    }
+
+    void insert(const std::string& key, const char * const rawVal)
+    {
+        this->insert(key.data(), rawVal);
+    }
+
+    void insert(const std::string& key, const std::string& rawVal)
+    {
+        this->insert(key.data(), rawVal.data());
+    }
+
+    CommonArrayValue<bt_value> insertEmptyArray(const char *key);
+    CommonArrayValue<bt_value> insertEmptyArray(const std::string& key);
+    CommonMapValue<bt_value> insertEmptyMap(const char *key);
+    CommonMapValue<bt_value> insertEmptyMap(const std::string& key);
+
+    void forEach(const internal::CommonMapValueForEachUserFunc<ConstValue>& func) const
+    {
+        internal::CommonMapValueSpec<const bt_value>::forEach(this->_libObjPtr(), func);
+    }
+
+    void forEach(const internal::CommonMapValueForEachUserFunc<CommonValue<LibObjT>>& func)
+    {
+        internal::CommonMapValueSpec<LibObjT>::forEach(this->_libObjPtr(), func);
+    }
+
+    Shared shared() const noexcept
+    {
+        return Shared {*this};
+    }
+
+private:
+    void _handleInsertLibStatus(const bt_value_map_insert_entry_status status) const
+    {
+        if (status == BT_VALUE_MAP_INSERT_ENTRY_STATUS_MEMORY_ERROR) {
+            throw LibMemoryError {};
+        }
+    }
+};
+
+using MapValue = CommonMapValue<bt_value>;
+using ConstMapValue = CommonMapValue<const bt_value>;
+
+template <typename LibObjT>
+CommonNullValue<LibObjT> CommonValue<LibObjT>::asNull() const noexcept
+{
+    BT_ASSERT_DBG(this->isNull());
+    return CommonNullValue<LibObjT> {this->_libObjPtr()};
+}
+
+template <typename LibObjT>
+CommonBoolValue<LibObjT> CommonValue<LibObjT>::asBool() const noexcept
+{
+    BT_ASSERT_DBG(this->isBool());
+    return CommonBoolValue<LibObjT> {this->_libObjPtr()};
+}
+
+template <typename LibObjT>
+CommonSignedIntegerValue<LibObjT> CommonValue<LibObjT>::asSignedInteger() const noexcept
+{
+    BT_ASSERT_DBG(this->isSignedInteger());
+    return CommonSignedIntegerValue<LibObjT> {this->_libObjPtr()};
+}
+
+template <typename LibObjT>
+CommonUnsignedIntegerValue<LibObjT> CommonValue<LibObjT>::asUnsignedInteger() const noexcept
+{
+    BT_ASSERT_DBG(this->isUnsignedInteger());
+    return CommonUnsignedIntegerValue<LibObjT> {this->_libObjPtr()};
+}
+
+template <typename LibObjT>
+CommonRealValue<LibObjT> CommonValue<LibObjT>::asReal() const noexcept
+{
+    BT_ASSERT_DBG(this->isReal());
+    return CommonRealValue<LibObjT> {this->_libObjPtr()};
+}
+
+template <typename LibObjT>
+CommonStringValue<LibObjT> CommonValue<LibObjT>::asString() const noexcept
+{
+    BT_ASSERT_DBG(this->isString());
+    return CommonStringValue<LibObjT> {this->_libObjPtr()};
+}
+
+template <typename LibObjT>
+CommonArrayValue<LibObjT> CommonValue<LibObjT>::asArray() const noexcept
+{
+    BT_ASSERT_DBG(this->isArray());
+    return CommonArrayValue<LibObjT> {this->_libObjPtr()};
+}
+
+template <typename LibObjT>
+CommonMapValue<LibObjT> CommonValue<LibObjT>::asMap() const noexcept
+{
+    BT_ASSERT_DBG(this->isMap());
+    return CommonMapValue<LibObjT> {this->_libObjPtr()};
+}
+
+template <typename LibObjT>
+ArrayValue CommonArrayValue<LibObjT>::appendEmptyArray()
+{
+    static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+    bt_value *libElemPtr;
+    const auto status = bt_value_array_append_empty_array_element(this->_libObjPtr(), &libElemPtr);
+
+    this->_handleAppendLibStatus(status);
+    return ArrayValue {libElemPtr};
+}
+
+template <typename LibObjT>
+MapValue CommonArrayValue<LibObjT>::appendEmptyMap()
+{
+    static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+    bt_value *libElemPtr;
+    const auto status = bt_value_array_append_empty_map_element(this->_libObjPtr(), &libElemPtr);
+
+    this->_handleAppendLibStatus(status);
+    return MapValue {libElemPtr};
+}
+
+template <typename LibObjT>
+ArrayValue CommonMapValue<LibObjT>::insertEmptyArray(const char * const key)
+{
+    static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+    bt_value *libEntryPtr;
+    const auto status =
+        bt_value_map_insert_empty_array_entry(this->_libObjPtr(), key, &libEntryPtr);
+
+    this->_handleInsertLibStatus(status);
+    return ArrayValue {libEntryPtr};
+}
+
+template <typename LibObjT>
+ArrayValue CommonMapValue<LibObjT>::insertEmptyArray(const std::string& key)
+{
+    return this->insertEmptyArray(key.data());
+}
+
+template <typename LibObjT>
+MapValue CommonMapValue<LibObjT>::insertEmptyMap(const char * const key)
+{
+    static_assert(!std::is_const<LibObjT>::value, "`LibObjT` must NOT be `const`.");
+
+    bt_value *libEntryPtr;
+    const auto status = bt_value_map_insert_empty_map_entry(this->_libObjPtr(), key, &libEntryPtr);
+
+    this->_handleInsertLibStatus(status);
+    return MapValue {libEntryPtr};
+}
+
+template <typename LibObjT>
+MapValue CommonMapValue<LibObjT>::insertEmptyMap(const std::string& key)
+{
+    return this->insertEmptyMap(key.data());
+}
+
+inline BoolValue::Shared createValue(const bool rawVal)
+{
+    return BoolValue::create(rawVal);
+}
+
+inline UnsignedIntegerValue::Shared createValue(const std::uint64_t rawVal)
+{
+    return UnsignedIntegerValue::create(rawVal);
+}
+
+inline SignedIntegerValue::Shared createValue(const std::int64_t rawVal)
+{
+    return SignedIntegerValue::create(rawVal);
+}
+
+inline RealValue::Shared createValue(const double rawVal)
+{
+    return RealValue::create(rawVal);
+}
+
+inline StringValue::Shared createValue(const char * const rawVal)
+{
+    return StringValue::create(rawVal);
+}
+
+inline StringValue::Shared createValue(const std::string& rawVal)
+{
+    return StringValue::create(rawVal);
+}
+
+} // namespace bt2
+
+#endif // BABELTRACE_CPP_COMMON_BT2_VALUE_HPP
This page took 0.035564 seconds and 4 git commands to generate.