src/cpp-common: improve C++ UUID utilities
authorSimon Marchi <simon.marchi@efficios.com>
Thu, 30 Mar 2023 16:14:09 +0000 (12:14 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Mon, 11 Sep 2023 15:24:02 +0000 (11:24 -0400)
Philippe Proulx writing below.

This patch improves the C++ common UUID utilities.

Francis wrote the initial version of `bt2_common::Uuid`, and then we
worked together to improve many little things at once, leading to this
patch.

His original message was:

> Add `bt2_common::Uuid`
>
> This patch adds the `bt2_common::Uuid` class which represent UUIDs.
>
> `Uuid` instances can be created from byte array, strings, or
> bt2_common::UuidView objects.
>
> The generate() static method returns a Uuid object with newly
> generated UUID.
>
> The operator UuidView() method returns a bt2_common::UuidView object
> representing the entire content of the UUID.
>
> The data() method returns a const pointer to the underlying
> std::array<>.
>
> The str() method returns a new `std::string` instance containing the
> canonical string representation of the UUID.

The final improvements are:

* Add said `bt2_common::Uuid` class.

  I also added the operator[](), operator=(), isNil(), begin(), and
  end() methods, the `Val` and `ConstIter` aliases, and the fact that
  most of the class relies on creating a `bt2_common::UuidView` to wrap
  itself when needed.

  data() just returns `const Val *`.

* In `bt2_common::UuidView`:

  * Make the class `final`.

  * Add the `Val` and `ConstIter` aliases.

  * Add operator<(): makes it possible to use a `bt2_common::UuidView`
    as an `std::set` value type or as an `std::map` key type, and to use
    it with STL algorithms.

  * Make size() `constexpr`.

  * Rename string() to str() for consistency with internal C++ naming.

  * Add begin() and end().

  * Add operator=() which accepts a UUID pointer.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: Id049953aecc51562e5939db546cb7d82bbaf88eb
Reviewed-on: https://review.lttng.org/c/babeltrace/+/10822
Tested-by: jenkins <jenkins@lttng.org>
src/cpp-common/Makefile.am
src/cpp-common/uuid-view.cpp [new file with mode: 0644]
src/cpp-common/uuid-view.hpp
src/cpp-common/uuid.hpp [new file with mode: 0644]

index 607b85ab8241ad0356cd9b24dddf1b9f1ebfad12..cfe4efd13a138647de91c2b9e55dbdbc28ff180f 100644 (file)
@@ -15,4 +15,5 @@ EXTRA_DIST = bt2 \
        endian.hpp \
        make-unique.hpp \
        safe-ops.hpp \
-       align.hpp
+       align.hpp \
+       uuid.hpp
diff --git a/src/cpp-common/uuid-view.cpp b/src/cpp-common/uuid-view.cpp
new file mode 100644 (file)
index 0000000..7257277
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2016-2022 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "uuid.hpp"
+#include "uuid-view.hpp"
+
+namespace bt2_common {
+
+UuidView::UuidView(const Uuid& uuid) noexcept : _mUuid {uuid.data()}
+{
+}
+
+UuidView::operator Uuid() const noexcept
+{
+    return Uuid {*this};
+}
+
+} /* namespace bt2_common */
index 8829019b8154414362c15c0fe6b4612fbeddd92b..c45c8ac348eb67389beffa0ad873dbd14e9b551b 100644 (file)
 #include <array>
 #include <cstdint>
 #include <string>
+#include <algorithm>
 
 #include "common/assert.h"
 #include "common/uuid.h"
 
 namespace bt2_common {
 
+class Uuid;
+
+/*
+ * A view on existing UUID data.
+ *
+ * A `UuidView` object doesn't contain its UUID data: see `Uuid` for a
+ * UUID data container.
+ */
 class UuidView final
 {
 public:
-    explicit UuidView(const std::uint8_t * const uuid) noexcept : _mUuid {uuid}
+    using Val = std::uint8_t;
+    using ConstIter = const Val *;
+
+public:
+    explicit UuidView(const Val * const uuid) noexcept : _mUuid {uuid}
     {
         BT_ASSERT_DBG(uuid);
     }
 
+    explicit UuidView(const Uuid& uuid) noexcept;
     UuidView(const UuidView&) noexcept = default;
     UuidView& operator=(const UuidView&) noexcept = default;
 
+    UuidView& operator=(const Val * const uuid) noexcept
+    {
+        _mUuid = uuid;
+        return *this;
+    }
+
+    operator Uuid() const noexcept;
+
+    std::string str() const
+    {
+        std::string s;
+
+        s.resize(BT_UUID_STR_LEN);
+        bt_uuid_to_str(_mUuid, &s[0]);
+
+        return s;
+    }
+
     bool operator==(const UuidView& other) const noexcept
     {
         return bt_uuid_compare(_mUuid, other._mUuid) == 0;
@@ -42,28 +74,40 @@ public:
         return bt_uuid_compare(_mUuid, other._mUuid) < 0;
     }
 
-    std::string str() const
+    static constexpr std::size_t size() noexcept
     {
-        std::string s;
-
-        s.resize(BT_UUID_STR_LEN);
-        bt_uuid_to_str(_mUuid, &s[0]);
+        return BT_UUID_LEN;
+    }
 
-        return s;
+    const Val *data() const noexcept
+    {
+        return _mUuid;
     }
 
-    static constexpr std::size_t size() noexcept
+    Val operator[](const std::size_t index) const noexcept
     {
-        return BT_UUID_LEN;
+        return _mUuid[index];
     }
 
-    const std::uint8_t *data() const noexcept
+    ConstIter begin() const noexcept
     {
         return _mUuid;
     }
 
+    ConstIter end() const noexcept
+    {
+        return _mUuid + this->size();
+    }
+
+    bool isNil() const noexcept
+    {
+        return std::all_of(this->begin(), this->end(), [](const std::uint8_t byte) {
+            return byte == 0;
+        });
+    }
+
 private:
-    const std::uint8_t *_mUuid;
+    const Val *_mUuid;
 };
 
 } /* namespace bt2_common */
diff --git a/src/cpp-common/uuid.hpp b/src/cpp-common/uuid.hpp
new file mode 100644 (file)
index 0000000..935091f
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2022 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef BABELTRACE_CPP_COMMON_UUID_HPP
+#define BABELTRACE_CPP_COMMON_UUID_HPP
+
+#include <algorithm>
+#include <array>
+#include <cstdint>
+#include <string>
+
+#include "common/assert.h"
+#include "common/uuid.h"
+#include "uuid-view.hpp"
+
+namespace bt2_common {
+
+/*
+ * A universally unique identifier.
+ *
+ * A `Uuid` object contains its UUID data: see `UuidView` to have a
+ * UUID view on existing UUID data.
+ */
+class Uuid final
+{
+public:
+    using Val = UuidView::Val;
+    using ConstIter = UuidView::ConstIter;
+
+public:
+    /*
+     * Builds a nil UUID.
+     */
+    explicit Uuid() noexcept = default;
+
+    explicit Uuid(const Val * const uuid) noexcept
+    {
+        this->_setFromPtr(uuid);
+    }
+
+    explicit Uuid(const char * const str) noexcept
+    {
+        const auto ret = bt_uuid_from_str(str, _mUuid.data());
+        BT_ASSERT(ret == 0);
+    }
+
+    explicit Uuid(const std::string& str) noexcept : Uuid {str.c_str()}
+    {
+    }
+
+    explicit Uuid(const UuidView& view) noexcept : Uuid {view.data()}
+    {
+    }
+
+    Uuid(const Uuid&) noexcept = default;
+    Uuid& operator=(const Uuid&) noexcept = default;
+
+    Uuid& operator=(const Val * const uuid) noexcept
+    {
+        this->_setFromPtr(uuid);
+        return *this;
+    }
+
+    static Uuid generate() noexcept
+    {
+        bt_uuid_t uuidGen;
+
+        bt_uuid_generate(uuidGen);
+        return Uuid {uuidGen};
+    }
+
+    std::string str() const
+    {
+        return this->_view().str();
+    }
+
+    bool operator==(const Uuid& other) const noexcept
+    {
+        return this->_view() == other._view();
+    }
+
+    bool operator!=(const Uuid& other) const noexcept
+    {
+        return this->_view() != other._view();
+    }
+
+    bool operator<(const Uuid& other) const noexcept
+    {
+        return this->_view() < other._view();
+    }
+
+    /*
+     * The returned UUID view must not outlive the UUID object.
+     */
+    operator UuidView() const noexcept
+    {
+        return this->_view();
+    }
+
+    static constexpr std::size_t size() noexcept
+    {
+        return UuidView::size();
+    }
+
+    const Val *data() const noexcept
+    {
+        return _mUuid.data();
+    }
+
+    Val operator[](const std::size_t index) const noexcept
+    {
+        return this->_view()[index];
+    }
+
+    ConstIter begin() const noexcept
+    {
+        return this->_view().begin();
+    }
+
+    ConstIter end() const noexcept
+    {
+        return this->_view().end();
+    }
+
+    bool isNil() const noexcept
+    {
+        return this->_view().isNil();
+    }
+
+private:
+    /*
+     * std::copy_n() won't throw when simply copying bytes below,
+     * therefore this method won't throw.
+     */
+    void _setFromPtr(const Val * const uuid) noexcept
+    {
+        BT_ASSERT(uuid);
+        std::copy_n(uuid, BT_UUID_LEN, std::begin(_mUuid));
+    }
+
+    UuidView _view() const noexcept
+    {
+        return UuidView {_mUuid.data()};
+    }
+
+    std::array<Val, UuidView::size()> _mUuid = {};
+};
+
+} /* namespace bt2_common */
+
+#endif /* BABELTRACE_CPP_COMMON_UUID_HPP */
This page took 0.029882 seconds and 4 git commands to generate.