From a6df2497a5c3d9b46b049d6fa0b2fd8a1965cf8a Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Tue, 23 Apr 2024 16:46:47 -0400 Subject: [PATCH] Import CStringView from the Babeltrace tree MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The class is imported as of 1dcaf4b74 in the babeltrace tree. It is renamed and reformated to fit the LTTng-tools conventions. No changes in behaviour are intended. Signed-off-by: Jérémie Galarneau Change-Id: I8acc3833c52c4ac23a91af87157aade0b4bbb7c1 --- src/common/Makefile.am | 2 + src/common/string-utils/c-string-view.hpp | 262 ++++++++++++++++++++++ src/common/type-traits.hpp | 38 ++++ 3 files changed, 302 insertions(+) create mode 100644 src/common/string-utils/c-string-view.hpp create mode 100644 src/common/type-traits.hpp diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 34fd83452..8170e6e5a 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -115,6 +115,7 @@ libcommon_lgpl_la_SOURCES = \ time.cpp \ tracker.cpp tracker.hpp \ trigger.cpp \ + type-traits.hpp \ unix.cpp unix.hpp \ uri.cpp uri.hpp \ userspace-probe.cpp \ @@ -432,6 +433,7 @@ endif # libstring-utils noinst_LTLIBRARIES += libstring-utils.la libstring_utils_la_SOURCES = \ + string-utils/c-string-view.hpp \ string-utils/format.hpp \ string-utils/string-utils.cpp \ string-utils/string-utils.hpp diff --git a/src/common/string-utils/c-string-view.hpp b/src/common/string-utils/c-string-view.hpp new file mode 100644 index 000000000..6b175ea33 --- /dev/null +++ b/src/common/string-utils/c-string-view.hpp @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2023 Philippe Proulx + * + * SPDX-License-Identifier: MIT + */ + +#ifndef LTTNG_C_STRING_VIEW_HPP +#define LTTNG_C_STRING_VIEW_HPP + +#include +#include + +#include +#include +#include +#include + +namespace lttng { + +/* + * A view on a constant null-terminated C string. + */ +class c_string_view final { +public: + /* + * Builds an empty view (data() returns `nullptr`). + * + * Intentionally not explicit. + */ + constexpr c_string_view() noexcept = default; + + /* + * Builds a view of the C string `str` (may be `nullptr`). + * + * Intentionally not explicit. + */ + /* NOLINTBEGIN(google-explicit-constructor) */ + constexpr c_string_view(const char *const str) noexcept : _str{ str } + { + } + /* NOLINTEND(google-explicit-constructor) */ + + /* + * Builds a view of the string `str`. + */ + /* NOLINTBEGIN(google-explicit-constructor) */ + c_string_view(const std::string& str) noexcept : _str{ str.c_str() } + { + } + /* NOLINTEND */ + + /* + * Makes this view view the C string `str` (may be `nullptr`). + */ + c_string_view& operator=(const char *const str) noexcept + { + _str = str; + return *this; + } + + /* + * Viewed null-terminated C string (may be `nullptr`). + */ + const char *data() const noexcept + { + return _str; + } + + /* + * Alias of data(). + */ + operator const char *() const noexcept /* NOLINT(google-explicit-constructor) */ + { + return this->data(); + } + + /* + * Evaluate as boolean (false means an empty string). + */ + operator bool() const noexcept /* NOLINT(google-explicit-constructor) */ + { + return *this->data(); + } + + /* + * Alias of data(). + */ + const char *operator*() const noexcept + { + return this->data(); + } + + /* + * Alias of data(). + * + * data() must not return `nullptr`. + */ + const char *begin() const noexcept + { + return this->data(); + } + + /* + * Pointer to the null character of the viewed C string. + * + * data() must not return `nullptr`. + */ + const char *end() const noexcept + { + return _str + this->len(); + } + + /* + * Length of the viewed C string, excluding the null character. + * + * data() must not return `nullptr`. + */ + std::size_t len() const noexcept + { + return std::strlen(_str); + } + + /* + * Returns an `std::string` instance containing a copy of the viewed + * C string. + * + * data() must not return `nullptr`. + */ + std::string str() const + { + return std::string{ _str }; + } + + /* + * Alias of str(). + */ + operator std::string() const /* NOLINT(google-explicit-constructor) */ + { + return this->str(); + } + + /* + * Returns the character at index `i`. + * + * `i` must be less than what len() returns. + * + * data() must not return `nullptr`. + */ + char operator[](const std::size_t i) const noexcept + { + return _str[i]; + } + + bool startsWith(const lttng::c_string_view prefix) const noexcept + { + return std::strncmp(_str, (const char *) prefix, prefix.len()) == 0; + } + +private: + const char *_str = nullptr; +}; + +inline const char *format_as(const c_string_view& str) +{ + return str ? *str : "(null)"; +} + +namespace internal { + +template +const char *as_const_char_ptr(StrT&& val) noexcept +{ + return val.data(); +} + +inline const char *as_const_char_ptr(const char *const val) noexcept +{ + return val; +} + +template +using comparable_with_c_string_view = lttng::traits:: + is_one_of::type, c_string_view, std::string, const char *>; + +} /* namespace internal */ + +/* + * Returns true if `lhs` is equal to `rhs`. + * + * `LhsT` and `RhsT` may be any of: + * + * • `const char *` + * • `std::string` + * • `c_string_view` + * + * Both `lhs` and `rhs` must not have an underlying `nullptr` raw data. + */ +template < + typename LhsT, + typename RhsT, + typename = + typename std::enable_if::value>::type, + typename = + typename std::enable_if::value>::type> +bool operator==(LhsT&& lhs, RhsT&& rhs) noexcept +{ + const auto raw_lhs = internal::as_const_char_ptr(lhs); + const auto raw_rhs = internal::as_const_char_ptr(rhs); + + return std::strcmp(raw_lhs, raw_rhs) == 0; +} + +/* + * Returns true if `lhs` is not equal to `rhs`. + * + * `LhsT` and `RhsT` may be any of: + * + * • `const char *` + * • `std::string` + * • `c_string_view` + * + * Both `lhs` and `rhs` must not have an underlying `nullptr` raw data. + */ +template < + typename LhsT, + typename RhsT, + typename = + typename std::enable_if::value>::type, + typename = + typename std::enable_if::value>::type> +bool operator!=(LhsT&& lhs, RhsT&& rhs) noexcept +{ + return !(std::forward(lhs) == std::forward(rhs)); +} + +} /* namespace lttng */ + +/* + * Appends `rhs` to `lhs`. + */ +inline void operator+=(std::string& lhs, lttng::c_string_view rhs) +{ + lhs += rhs.data(); +} + +namespace std { +template <> +struct hash { + std::size_t operator()(const lttng::c_string_view& str) const + { + auto hash_value = std::hash{}('\0'); + + for (auto character : str) { + hash_value ^= std::hash{}(character); + } + + return hash_value; + } +}; +} /* namespace std */ + +#endif /* LTTNG_C_STRING_VIEW_HPP */ diff --git a/src/common/type-traits.hpp b/src/common/type-traits.hpp new file mode 100644 index 000000000..3801bf13f --- /dev/null +++ b/src/common/type-traits.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Philippe Proulx + * + * SPDX-License-Identifier: MIT + */ + +#ifndef LTTNG_TYPE_TRAITS_HPP +#define LTTNG_TYPE_TRAITS_HPP + +#include + +namespace lttng { +namespace traits { + +/* + * Provides the member constant `value` equal to: + * + * `T` is in the list of types `Ts`: + * `true` + * + * Otherwise: + * `false` + */ +template +struct is_one_of : std::false_type { +}; + +template +struct is_one_of : std::true_type { +}; + +template +struct is_one_of : is_one_of { +}; +} /* namespace traits */ +} /* namespace lttng */ + +#endif /* LTTNG_TYPE_TRAITS_HPP */ -- 2.34.1