cpp-common/bt2c: add `bt2c::CStringView`
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Tue, 5 Dec 2023 07:00:28 +0000 (02:00 -0500)
committerSimon Marchi <simon.marchi@efficios.com>
Thu, 14 Dec 2023 15:57:04 +0000 (10:57 -0500)
A `bt2c::CStringView` is like a `bt2s::string_view`, but specialized for
strings that are known to be null-terminated (C strings).

This is useful when wrapping an existing API which has functions
returning `const char *`: return `bt2c::CStringView` from the wrappers
at no cost, but with improved usability:

    if (myObj.name().len() >= 16) {
        // ...
    }

vs.

    if (std::strlen(myObj.name()) >= 16) {
        // ...
    }

A `bt2c::CStringView` only computes the length of the underlying
C string with std::strlen() when needed. It can convert to `std::string`
and `bt2s::string_view`.

`c-string-view.hpp` includes an {fmt} formatter for convenience. It
writes `(null)` when the underlying pointer is null, just like the glibc
printf() does.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: I522ce586e9966736dadeeabf30f02da5dc62c80c
Reviewed-on: https://review.lttng.org/c/babeltrace/+/11485
CI-Build: Simon Marchi <simon.marchi@efficios.com>
Reviewed-by: Simon Marchi <simon.marchi@efficios.com>
Tested-by: jenkins <jenkins@lttng.org>
src/Makefile.am
src/cpp-common/bt2c/c-string-view.hpp [new file with mode: 0644]

index f158fe2724362eb05abdc28b30e419a223f00644..6bb2269bbd97dbfc771684d0f734b157a0c5bb6d 100644 (file)
@@ -44,6 +44,7 @@ noinst_HEADERS = \
        cpp-common/bt2/value.hpp \
        cpp-common/bt2/wrap.hpp \
        cpp-common/bt2c/align.hpp \
+       cpp-common/bt2c/c-string-view.hpp \
        cpp-common/bt2c/call.hpp \
        cpp-common/bt2c/endian.hpp \
        cpp-common/bt2c/exc.hpp \
diff --git a/src/cpp-common/bt2c/c-string-view.hpp b/src/cpp-common/bt2c/c-string-view.hpp
new file mode 100644 (file)
index 0000000..ddcf36c
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2023 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef BABELTRACE_CPP_COMMON_BT2C_C_STRING_VIEW_HPP
+#define BABELTRACE_CPP_COMMON_BT2C_C_STRING_VIEW_HPP
+
+#include <cstddef>
+#include <cstring>
+#include <string>
+
+#include "common/assert.h"
+#include "cpp-common/bt2s/string-view.hpp"
+#include "cpp-common/vendor/fmt/core.h"
+
+namespace bt2c {
+
+/*
+ * A view on a constant null-terminated C string.
+ *
+ * Similar to `bt2s::string_view`, but len() and end() compute the
+ * length on demand.
+ */
+class CStringView final
+{
+public:
+    /*
+     * Builds an empty view (data() returns `nullptr`).
+     *
+     * Intentionally not explicit.
+     */
+    CStringView() noexcept = default;
+
+    /*
+     * Builds a view of the C string `str` (may be `nullptr`).
+     *
+     * Intentionally not explicit.
+     */
+    CStringView(const char * const str) noexcept : _mStr {str}
+    {
+    }
+
+    /*
+     * Makes this view view the C string `str` (may be `nullptr`).
+     *
+     * Intentionally not explicit.
+     */
+    CStringView& operator=(const char * const str) noexcept
+    {
+        _mStr = str;
+        return *this;
+    }
+
+    /*
+     * Viewed null-terminated C string (may be `nullptr`).
+     */
+    const char *data() const noexcept
+    {
+        return _mStr;
+    }
+
+    /*
+     * Alias of data().
+     */
+    operator const char *() const noexcept
+    {
+        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
+    {
+        BT_ASSERT_DBG(_mStr);
+        return this->data();
+    }
+
+    /*
+     * Pointer to the null character of the viewed C string.
+     *
+     * data() must not return `nullptr`.
+     */
+    const char *end() const noexcept
+    {
+        BT_ASSERT_DBG(_mStr);
+        return _mStr + this->len();
+    }
+
+    /*
+     * Length of the viewed C string, excluding the null character.
+     *
+     * data() must not return `nullptr`.
+     */
+    std::size_t len() const noexcept
+    {
+        BT_ASSERT_DBG(_mStr);
+        return std::strlen(_mStr);
+    }
+
+    /*
+     * Returns an `std::string` instance containing a copy of the viewed
+     * C string.
+     *
+     * data() must not return `nullptr`.
+     */
+    std::string str() const
+    {
+        BT_ASSERT_DBG(_mStr);
+        return std::string {_mStr};
+    }
+
+    /*
+     * Alias of str().
+     */
+    operator std::string() const
+    {
+        return this->str();
+    }
+
+    /*
+     * Returns a `bt2s::string_view` instance to view the contents,
+     * excluding the null character, of the viewed C string.
+     */
+    bt2s::string_view strView() const noexcept
+    {
+        if (_mStr) {
+            return bt2s::string_view {this->begin(), this->len()};
+        } else {
+            return {};
+        }
+    }
+
+    /*
+     * Alias of strView().
+     */
+    operator bt2s::string_view() const noexcept
+    {
+        return this->strView();
+    }
+
+    /*
+     * 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
+    {
+        BT_ASSERT_DBG(_mStr);
+        BT_ASSERT_DBG(i < this->len());
+        return _mStr[i];
+    }
+
+private:
+    const char *_mStr = nullptr;
+};
+
+} /* namespace bt2c */
+
+namespace fmt {
+
+template <>
+struct formatter<bt2c::CStringView>
+{
+    constexpr auto parse(format_parse_context& ctx) const -> format_parse_context::iterator
+    {
+        return ctx.end();
+    }
+
+    auto format(const bt2c::CStringView& str, format_context& ctx) const -> format_context::iterator
+    {
+        return str ? fmt::format_to(ctx.out(), "{}", *str) : fmt::format_to(ctx.out(), "(null)");
+    }
+};
+
+} /* namespace fmt */
+
+#endif /* BABELTRACE_CPP_COMMON_BT2C_C_STRING_VIEW_HPP */
This page took 0.02761 seconds and 4 git commands to generate.