From: Philippe Proulx Date: Fri, 11 Dec 2020 00:40:00 +0000 (-0500) Subject: Add C++ interface for the libbabeltrace2 `bt_value` API X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=33a17831def0537394f436c42d02ba53da8133c3 Add C++ interface for the libbabeltrace2 `bt_value` API 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 Change-Id: I7c278aa660e9716a69e7d540763dc31623e45fec Reviewed-on: https://review.lttng.org/c/babeltrace/+/4537 --- diff --git a/src/cpp-common/bt2/value.hpp b/src/cpp-common/bt2/value.hpp new file mode 100644 index 00000000..31411183 --- /dev/null +++ b/src/cpp-common/bt2/value.hpp @@ -0,0 +1,1245 @@ +/* + * Copyright (c) 2020 Philippe Proulx + * + * SPDX-License-Identifier: MIT + */ + +#ifndef BABELTRACE_CPP_COMMON_BT2_VALUE_HPP +#define BABELTRACE_CPP_COMMON_BT2_VALUE_HPP + +#include +#include +#include +#include + +#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 +using SharedValue = internal::SharedObj; + +} // namespace internal + +template +class CommonNullValue; + +template +class CommonBoolValue; + +template +class CommonUnsignedIntegerValue; + +template +class CommonSignedIntegerValue; + +template +class CommonRealValue; + +template +class CommonStringValue; + +template +class CommonArrayValue; + +template +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 +class CommonValue : public internal::BorrowedObj +{ + // Allow append() to call `val._libObjPtr()` + friend class CommonArrayValue; + + // Allow insert() to call `val._libObjPtr()` + friend class CommonMapValue; + + // Allow operator==() to call `other._libObjPtr()` + friend class CommonValue; + friend class CommonValue; + +private: + using typename internal::BorrowedObj::_ThisBorrowedObj; + +protected: + using typename internal::BorrowedObj::_LibObjPtr; + using _ThisCommonValue = CommonValue; + +public: + using Shared = internal::SharedValue, LibObjT>; + + explicit CommonValue(const _LibObjPtr libObjPtr) noexcept : _ThisBorrowedObj {libObjPtr} + { + } + + template + CommonValue(const CommonValue& val) noexcept : _ThisBorrowedObj {val} + { + } + + template + _ThisCommonValue& operator=(const CommonValue& val) noexcept + { + _ThisBorrowedObj::operator=(val); + return *this; + } + + ValueType type() const noexcept + { + return static_cast(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 + bool operator==(const CommonValue& other) const noexcept + { + return static_cast(bt_value_is_equal(this->_libObjPtr(), other._libObjPtr())); + } + + template + bool operator!=(const CommonValue& other) const noexcept + { + return !(*this == other); + } + + Shared shared() const noexcept + { + return Shared {*this}; + } + + CommonNullValue asNull() const noexcept; + CommonBoolValue asBool() const noexcept; + CommonSignedIntegerValue asSignedInteger() const noexcept; + CommonUnsignedIntegerValue asUnsignedInteger() const noexcept; + CommonRealValue asReal() const noexcept; + CommonStringValue asString() const noexcept; + CommonArrayValue asArray() const noexcept; + CommonMapValue 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; +using ConstValue = CommonValue; + +template +class CommonNullValue final : public CommonValue +{ +private: + using typename CommonValue::_ThisCommonValue; + +public: + using Shared = internal::SharedValue, LibObjT>; + + CommonNullValue() noexcept : _ThisCommonValue {bt_value_null} + { + } + + template + CommonNullValue(const CommonNullValue& val) noexcept : _ThisCommonValue {val} + { + } + + template + CommonNullValue& operator=(const CommonNullValue& val) noexcept + { + _ThisCommonValue::operator=(val); + return *this; + } + + Shared shared() const noexcept + { + return Shared {*this}; + } +}; + +using NullValue = CommonNullValue; +using ConstNullValue = CommonNullValue; + +template +class CommonBoolValue final : public CommonValue +{ +private: + using typename CommonValue::_LibObjPtr; + using typename CommonValue::_ThisCommonValue; + +public: + using Shared = internal::SharedValue, LibObjT>; + using Value = bool; + + explicit CommonBoolValue(const _LibObjPtr libObjPtr) noexcept : _ThisCommonValue {libObjPtr} + { + BT_ASSERT_DBG(this->isBool()); + } + + template + CommonBoolValue(const CommonBoolValue& val) noexcept : _ThisCommonValue {val} + { + } + + static Shared create(const Value rawVal = false) + { + const auto libObjPtr = bt_value_bool_create_init(static_cast(rawVal)); + + internal::validateCreatedObjPtr(libObjPtr); + return Shared {CommonBoolValue {libObjPtr}}; + } + + template + CommonBoolValue& operator=(const CommonBoolValue& val) noexcept + { + _ThisCommonValue::operator=(val); + return *this; + } + + CommonBoolValue& operator=(const Value rawVal) noexcept + { + static_assert(!std::is_const::value, "`LibObjT` must NOT be `const`."); + + bt_value_bool_set(this->_libObjPtr(), static_cast(rawVal)); + return *this; + } + + Value value() const noexcept + { + return static_cast(bt_value_bool_get(this->_libObjPtr())); + } + + operator Value() const noexcept + { + return this->value(); + } + + Shared shared() const noexcept + { + return Shared {*this}; + } +}; + +using BoolValue = CommonBoolValue; +using ConstBoolValue = CommonBoolValue; + +template +class CommonUnsignedIntegerValue final : public CommonValue +{ +private: + using typename CommonValue::_LibObjPtr; + using typename CommonValue::_ThisCommonValue; + +public: + using Shared = internal::SharedValue, 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 {libObjPtr}}; + } + + template + CommonUnsignedIntegerValue(const CommonUnsignedIntegerValue& val) noexcept : + _ThisCommonValue {val} + { + } + + template + CommonUnsignedIntegerValue& + operator=(const CommonUnsignedIntegerValue& val) noexcept + { + static_assert(!std::is_const::value, "`LibObjT` must NOT be `const`."); + + _ThisCommonValue::operator=(val); + return *this; + } + + CommonUnsignedIntegerValue& 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; +using ConstUnsignedIntegerValue = CommonUnsignedIntegerValue; + +template +class CommonSignedIntegerValue final : public CommonValue +{ +private: + using typename CommonValue::_LibObjPtr; + using typename CommonValue::_ThisCommonValue; + +public: + using Shared = internal::SharedValue, 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 {libObjPtr}}; + } + + template + CommonSignedIntegerValue(const CommonSignedIntegerValue& val) noexcept : + _ThisCommonValue {val} + { + } + + template + CommonSignedIntegerValue& + operator=(const CommonSignedIntegerValue& val) noexcept + { + _ThisCommonValue::operator=(val); + return *this; + } + + CommonSignedIntegerValue& operator=(const Value rawVal) noexcept + { + static_assert(!std::is_const::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; +using ConstSignedIntegerValue = CommonSignedIntegerValue; + +template +class CommonRealValue final : public CommonValue +{ +private: + using typename CommonValue::_LibObjPtr; + using typename CommonValue::_ThisCommonValue; + +public: + using Shared = internal::SharedValue, 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 {libObjPtr}}; + } + + template + CommonRealValue(const CommonRealValue& val) noexcept : _ThisCommonValue {val} + { + } + + template + CommonRealValue& operator=(const CommonRealValue& val) noexcept + { + _ThisCommonValue::operator=(val); + return *this; + } + + CommonRealValue& operator=(const Value rawVal) noexcept + { + static_assert(!std::is_const::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; +using ConstRealValue = CommonRealValue; + +template +class CommonStringValue final : public CommonValue +{ +private: + using typename CommonValue::_LibObjPtr; + using typename CommonValue::_ThisCommonValue; + +public: + using Shared = internal::SharedValue, 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 {libObjPtr}}; + } + + static Shared create(const std::string& rawVal) + { + return CommonStringValue::create(rawVal.data()); + } + + template + CommonStringValue(const CommonStringValue& val) noexcept : _ThisCommonValue {val} + { + } + + template + CommonStringValue& operator=(const CommonStringValue& val) noexcept + { + _ThisCommonValue::operator=(val); + return *this; + } + + CommonStringValue& operator=(const char * const rawVal) + { + static_assert(!std::is_const::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& 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; +using ConstStringValue = CommonStringValue; + +namespace internal { + +template +struct CommonArrayValueSpec; + +// Functions specific to mutable array values +template <> +struct CommonArrayValueSpec 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 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 +class CommonArrayValue final : public CommonValue +{ +private: + using typename CommonValue::_LibObjPtr; + using typename CommonValue::_ThisCommonValue; + +public: + using Shared = internal::SharedValue, 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 {libObjPtr}}; + } + + template + CommonArrayValue(const CommonArrayValue& val) noexcept : _ThisCommonValue {val} + { + } + + template + CommonArrayValue& operator=(const CommonArrayValue& 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::elementByIndex( + this->_libObjPtr(), index)}; + } + + CommonValue operator[](const std::uint64_t index) noexcept + { + return CommonValue { + internal::CommonArrayValueSpec::elementByIndex(this->_libObjPtr(), index)}; + } + + void append(const Value& val) + { + static_assert(!std::is_const::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::value, "`LibObjT` must NOT be `const`."); + + const auto status = + bt_value_array_append_bool_element(this->_libObjPtr(), static_cast(rawVal)); + + this->_handleAppendLibStatus(status); + } + + void append(const std::uint64_t rawVal) + { + static_assert(!std::is_const::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::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::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::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 appendEmptyArray(); + CommonMapValue 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; +using ConstArrayValue = CommonArrayValue; + +namespace internal { + +/* + * Type of a user function passed to `CommonMapValue::forEach()`. + * + * First argument is the entry's key, second is its value. + */ +template +using CommonMapValueForEachUserFunc = std::function; + +/* + * 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` (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 +LibStatusT mapValueForEachLibFunc(const char * const key, LibObjT * const libObjPtr, + void * const userData) +{ + const auto& userFunc = *reinterpret_cast *>(userData); + + try { + userFunc(key, ObjT {libObjPtr}); + } catch (...) { + return static_cast(ErrorStatus); + } + + return static_cast(OkStatus); +} + +template +struct CommonMapValueSpec; + +// Functions specific to mutable map values +template <> +struct CommonMapValueSpec 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& func) + { + const auto status = bt_value_map_foreach_entry( + libValPtr, + mapValueForEachLibFunc, + const_cast(reinterpret_cast(&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 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& func) + { + const auto status = bt_value_map_foreach_entry_const( + libValPtr, + mapValueForEachLibFunc, + const_cast(reinterpret_cast(&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 +class CommonMapValue final : public CommonValue +{ +private: + using typename CommonValue::_LibObjPtr; + using typename CommonValue::_ThisCommonValue; + +public: + using Shared = internal::SharedValue, 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 {libObjPtr}}; + } + + template + CommonMapValue(const CommonMapValue& val) noexcept : _ThisCommonValue {val} + { + } + + template + CommonMapValue& operator=(const CommonMapValue& 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 operator[](const char * const key) const noexcept + { + const auto libObjPtr = + internal::CommonMapValueSpec::entryByKey(this->_libObjPtr(), key); + + if (!libObjPtr) { + return nonstd::nullopt; + } + + return ConstValue {libObjPtr}; + } + + nonstd::optional operator[](const std::string& key) const noexcept + { + return (*this)[key.data()]; + } + + nonstd::optional> operator[](const char * const key) noexcept + { + const auto libObjPtr = + internal::CommonMapValueSpec::entryByKey(this->_libObjPtr(), key); + + if (!libObjPtr) { + return nonstd::nullopt; + } + + return CommonValue {libObjPtr}; + } + + nonstd::optional> operator[](const std::string& key) noexcept + { + return (*this)[key.data()]; + } + + bool hasEntry(const char * const key) const noexcept + { + return static_cast(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::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::value, "`LibObjT` must NOT be `const`."); + + const auto status = + bt_value_map_insert_bool_entry(this->_libObjPtr(), key, static_cast(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::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::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::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::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 insertEmptyArray(const char *key); + CommonArrayValue insertEmptyArray(const std::string& key); + CommonMapValue insertEmptyMap(const char *key); + CommonMapValue insertEmptyMap(const std::string& key); + + void forEach(const internal::CommonMapValueForEachUserFunc& func) const + { + internal::CommonMapValueSpec::forEach(this->_libObjPtr(), func); + } + + void forEach(const internal::CommonMapValueForEachUserFunc>& func) + { + internal::CommonMapValueSpec::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; +using ConstMapValue = CommonMapValue; + +template +CommonNullValue CommonValue::asNull() const noexcept +{ + BT_ASSERT_DBG(this->isNull()); + return CommonNullValue {this->_libObjPtr()}; +} + +template +CommonBoolValue CommonValue::asBool() const noexcept +{ + BT_ASSERT_DBG(this->isBool()); + return CommonBoolValue {this->_libObjPtr()}; +} + +template +CommonSignedIntegerValue CommonValue::asSignedInteger() const noexcept +{ + BT_ASSERT_DBG(this->isSignedInteger()); + return CommonSignedIntegerValue {this->_libObjPtr()}; +} + +template +CommonUnsignedIntegerValue CommonValue::asUnsignedInteger() const noexcept +{ + BT_ASSERT_DBG(this->isUnsignedInteger()); + return CommonUnsignedIntegerValue {this->_libObjPtr()}; +} + +template +CommonRealValue CommonValue::asReal() const noexcept +{ + BT_ASSERT_DBG(this->isReal()); + return CommonRealValue {this->_libObjPtr()}; +} + +template +CommonStringValue CommonValue::asString() const noexcept +{ + BT_ASSERT_DBG(this->isString()); + return CommonStringValue {this->_libObjPtr()}; +} + +template +CommonArrayValue CommonValue::asArray() const noexcept +{ + BT_ASSERT_DBG(this->isArray()); + return CommonArrayValue {this->_libObjPtr()}; +} + +template +CommonMapValue CommonValue::asMap() const noexcept +{ + BT_ASSERT_DBG(this->isMap()); + return CommonMapValue {this->_libObjPtr()}; +} + +template +ArrayValue CommonArrayValue::appendEmptyArray() +{ + static_assert(!std::is_const::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 +MapValue CommonArrayValue::appendEmptyMap() +{ + static_assert(!std::is_const::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 +ArrayValue CommonMapValue::insertEmptyArray(const char * const key) +{ + static_assert(!std::is_const::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 +ArrayValue CommonMapValue::insertEmptyArray(const std::string& key) +{ + return this->insertEmptyArray(key.data()); +} + +template +MapValue CommonMapValue::insertEmptyMap(const char * const key) +{ + static_assert(!std::is_const::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 +MapValue CommonMapValue::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