aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLexi Winter <lexi@le-fay.org>2025-06-29 17:16:22 +0100
committerLexi Winter <lexi@le-fay.org>2025-06-29 17:16:22 +0100
commit4fa6821e0645ff61a9380cd090abff472205c630 (patch)
treebd95f13b2dc0bd9692681f50c365d2914a520bfe
parente5180acf5f2dfac788e8c12886095ed1ac66fae5 (diff)
downloadnihil-4fa6821e0645ff61a9380cd090abff472205c630.tar.gz
nihil-4fa6821e0645ff61a9380cd090abff472205c630.tar.bz2
add clang-tidy support
-rw-r--r--.gitignore1
-rw-r--r--CMakeLists.txt23
-rw-r--r--clang-tidy.conf8
-rw-r--r--nihil.cli/command.cc1
-rw-r--r--nihil.cli/command_node.cc9
-rw-r--r--nihil.cli/command_path.ccm16
-rw-r--r--nihil.cli/test.cc12
-rw-r--r--nihil.config/option.cc1
-rw-r--r--nihil.core/CMakeLists.txt11
-rw-r--r--nihil.core/errc.cc51
-rw-r--r--nihil.core/errc.ccm44
-rw-r--r--nihil.core/nihil.core.ccm9
-rw-r--r--nihil.error/error.cc2
-rw-r--r--nihil.error/error.ccm2
-rw-r--r--nihil.generator/CMakeLists.txt6
-rw-r--r--nihil.generator/elements_of.ccm69
-rw-r--r--nihil.generator/generator.ccm209
-rw-r--r--nihil.generator/manual_lifetime.ccm117
-rw-r--r--nihil.generator/nihil.generator.ccm32
-rw-r--r--nihil.generator/promise_base_alloc.ccm94
-rw-r--r--nihil.generator/test.cc2
-rw-r--r--nihil.generator/util.ccm37
-rw-r--r--nihil.guard/guard.ccm12
-rw-r--r--nihil.posix/posix.spawn.ccm7
-rw-r--r--nihil.posix/posix.tempfile.cc17
-rw-r--r--nihil.posix/posix.tempfile.ccm8
-rw-r--r--nihil.posix/test.fd.cc6
-rw-r--r--nihil.ucl/integer.ccm2
-rw-r--r--nihil.ucl/map.ccm3
-rw-r--r--nihil.ucl/object.cc21
-rw-r--r--nihil.ucl/object.ccm2
-rw-r--r--nihil.ucl/parser.ccm2
-rw-r--r--nihil.ucl/real.ccm2
-rw-r--r--nihil.ucl/tests/map.cc16
-rw-r--r--nihil.util/capture_stream.ccm5
-rw-r--r--nihil.util/parse_size.ccm10
-rw-r--r--nihil.uuid/test.cc28
-rw-r--r--nihil.uuid/uuid.ccm458
38 files changed, 867 insertions, 488 deletions
diff --git a/.gitignore b/.gitignore
index 4cb47c2..ad0c823 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,3 @@
/build
/dist
*.sw?
-*.core
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8bf5a42..8e8b131 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,11 +7,34 @@ project(nihil)
option(NIHIL_CONFIG "Build the nihil.config library" ON)
option(NIHIL_UCL "Build the nihil.ucl library" ON)
option(NIHIL_TESTS "Build nihil's unit tests" ON)
+option(NIHIL_TIDY "Run clang-tidy during build" ON)
set(CMAKE_CXX_STANDARD 26)
find_package(PkgConfig REQUIRED)
+# clang-tidy support
+find_program(CLANG_TIDY clang-tidy)
+
+if(NOT (CLANG_TIDY STREQUAL ""))
+ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+ file(GLOB_RECURSE NIHIL_SOURCES "*.cc" "*.ccm")
+ list(FILTER NIHIL_SOURCES EXCLUDE REGEX ${CMAKE_CURRENT_BINARY_DIR})
+
+ add_custom_target(tidy COMMAND
+ ${CLANG_TIDY} -config-file=${CMAKE_CURRENT_SOURCE_DIR}/clang-tidy.conf
+ -p=${CMAKE_CURRENT_BINARY_DIR}
+ ${NIHIL_SOURCES})
+
+ if(NIHIL_TIDY)
+ set(CMAKE_CXX_CLANG_TIDY
+ ${CLANG_TIDY};
+ -config-file=${CMAKE_CURRENT_SOURCE_DIR}/clang-tidy.conf;
+ )
+ endif()
+endif()
+
add_compile_options(-W)
add_compile_options(-Wall)
add_compile_options(-Wextra)
diff --git a/clang-tidy.conf b/clang-tidy.conf
new file mode 100644
index 0000000..92a59bc
--- /dev/null
+++ b/clang-tidy.conf
@@ -0,0 +1,8 @@
+---
+WarningsAsErrors: '*'
+Checks: >
+ -*,
+ bugprone-*,
+ -bugprone-reserved-identifier,
+ -bugprone-easily-swappable-parameters,
+ modernize-*,
diff --git a/nihil.cli/command.cc b/nihil.cli/command.cc
index 475cad0..725b4eb 100644
--- a/nihil.cli/command.cc
+++ b/nihil.cli/command.cc
@@ -22,6 +22,7 @@ import :registry;
namespace nihil {
+//NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
command::command(std::string_view path, std::string_view usage,
command_function_t handler)
: command_node(path)
diff --git a/nihil.cli/command_node.cc b/nihil.cli/command_node.cc
index 98aeac1..dd18716 100644
--- a/nihil.cli/command_node.cc
+++ b/nihil.cli/command_node.cc
@@ -9,6 +9,8 @@ module;
#include <print>
#include <string>
+#include <unistd.h>
+
module nihil.cli;
import nihil.core;
@@ -16,9 +18,14 @@ import nihil.error;
namespace nihil {
+//NOLINTNEXTLINE(bugprone-exception-escape)
command_node::command_node(std::string_view path) noexcept
- : m_path(path)
+try : m_path(path)
{
+} catch (std::exception const &exc) {
+ std::fprintf(stderr, "%s\n", exc.what());
+ _exit(1);
+ /*NOTREACHED*/
}
command_node::~command_node()
diff --git a/nihil.cli/command_path.ccm b/nihil.cli/command_path.ccm
deleted file mode 100644
index a5bd5e3..0000000
--- a/nihil.cli/command_path.ccm
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * This source code is released into the public domain.
- */
-
-module;
-
-/*
- * command_path represents a command split into its component parts.
- */
-
-export module nihil.cli:command_path;
-
-namespace nihil {
-
-
-} // namespace nihil
diff --git a/nihil.cli/test.cc b/nihil.cli/test.cc
index c265700..c82281e 100644
--- a/nihil.cli/test.cc
+++ b/nihil.cli/test.cc
@@ -36,7 +36,8 @@ TEST_CASE("nihil.cli: dispatch_command: basic", "[nihil.cli]")
};
auto argv = const_cast<char **>(args.data());
- int ret = nihil::dispatch_command(args.size() - 1, argv);
+ int ret = nihil::dispatch_command(
+ static_cast<int>(args.size()) - 1, argv);
REQUIRE(ret == 0);
REQUIRE(cmd_sub1_called == true);
REQUIRE(cmd_sub2_called == false);
@@ -48,7 +49,8 @@ TEST_CASE("nihil.cli: dispatch_command: basic", "[nihil.cli]")
};
auto argv = const_cast<char **>(args.data());
- int ret = nihil::dispatch_command(args.size() - 1, argv);
+ int ret = nihil::dispatch_command(
+ static_cast<int>(args.size()) - 1, argv);
REQUIRE(ret == 0);
REQUIRE(cmd_sub2_called == true);
}
@@ -65,7 +67,8 @@ TEST_CASE("nihil.cli: dispatch_command: unknown command", "[nihil.cli]")
auto ret = int{};
{
auto capture = nihil::capture_stream(std::cerr);
- ret = nihil::dispatch_command(args.size() - 1, argv);
+ ret = nihil::dispatch_command(
+ static_cast<int>(args.size()) - 1, argv);
std::cerr.flush();
output = capture.str();
}
@@ -87,7 +90,8 @@ TEST_CASE("nihil.cli: dispatch_command: incomplete command", "[nihil.cli]")
auto ret = int{};
{
auto capture = nihil::capture_stream(std::cerr);
- ret = nihil::dispatch_command(args.size() - 1, argv);
+ ret = nihil::dispatch_command(
+ static_cast<int>(args.size()) - 1, argv);
std::cerr.flush();
output = capture.str();
}
diff --git a/nihil.config/option.cc b/nihil.config/option.cc
index bcaf167..886f4b6 100644
--- a/nihil.config/option.cc
+++ b/nihil.config/option.cc
@@ -17,6 +17,7 @@ import nihil.ucl;
namespace nihil::config {
+//NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
option::option(std::string_view name, std::string_view description)
: m_name(name)
, m_description(description)
diff --git a/nihil.core/CMakeLists.txt b/nihil.core/CMakeLists.txt
new file mode 100644
index 0000000..4564640
--- /dev/null
+++ b/nihil.core/CMakeLists.txt
@@ -0,0 +1,11 @@
+# This source code is released into the public domain.
+
+add_library(nihil.core STATIC)
+target_sources(nihil.core
+ PUBLIC FILE_SET modules TYPE CXX_MODULES FILES
+ nihil.core.ccm
+ errc.ccm
+
+ PRIVATE
+ errc.cc
+)
diff --git a/nihil.core/errc.cc b/nihil.core/errc.cc
new file mode 100644
index 0000000..35c9d8f
--- /dev/null
+++ b/nihil.core/errc.cc
@@ -0,0 +1,51 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <string>
+#include <system_error>
+
+module nihil.core;
+
+namespace nihil {
+
+struct nihil_error_category final : std::error_category {
+ [[nodiscard]] auto name() const noexcept -> char const * override;
+ [[nodiscard]] auto message(int err) const -> std::string override;
+};
+
+[[nodiscard]] auto nihil_category() noexcept -> std::error_category &
+{
+ static auto category = nihil_error_category();
+ return category;
+}
+
+auto make_error_condition(errc ec) -> std::error_condition
+{
+ return {static_cast<int>(ec), nihil_category()};
+}
+
+auto nihil_error_category::name() const noexcept -> char const *
+{
+ return "nihil";
+}
+
+auto nihil_error_category::message(int err) const -> std::string
+{
+ switch (static_cast<errc>(err)) {
+ case errc::no_error:
+ return "No error";
+ case errc::incomplete_command:
+ return "Incomplete command";
+ case errc::empty_string:
+ return "Empty string is not permitted";
+ case errc::invalid_unit:
+ return "Invalid unit specifier";
+ default:
+ return "Undefined error";
+ }
+}
+
+} // namespace nihil
diff --git a/nihil.core/errc.ccm b/nihil.core/errc.ccm
new file mode 100644
index 0000000..c597faf
--- /dev/null
+++ b/nihil.core/errc.ccm
@@ -0,0 +1,44 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <string>
+#include <system_error>
+
+export module nihil.core:errc;
+
+namespace nihil {
+
+export enum struct errc {
+ no_error = 0,
+
+ /*
+ * nihil.command
+ */
+
+ incomplete_command,
+
+ /*
+ * nihil.util
+ */
+
+ // Empty string is not allowed.
+ empty_string,
+
+ // Invalid unit, e.g. in parse_size()
+ invalid_unit,
+};
+
+export [[nodiscard]] auto nihil_category() noexcept -> std::error_category &;
+export [[nodiscard]] auto make_error_condition(errc ec) -> std::error_condition;
+
+} // namespace nihil
+
+namespace std {
+
+export template<>
+struct is_error_condition_enum<nihil::errc> : true_type {};
+
+} // namespace std
diff --git a/nihil.core/nihil.core.ccm b/nihil.core/nihil.core.ccm
new file mode 100644
index 0000000..a7a4100
--- /dev/null
+++ b/nihil.core/nihil.core.ccm
@@ -0,0 +1,9 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+export module nihil.core;
+
+export import :errc;
diff --git a/nihil.error/error.cc b/nihil.error/error.cc
index 15805a3..e4023f9 100644
--- a/nihil.error/error.cc
+++ b/nihil.error/error.cc
@@ -85,7 +85,7 @@ auto error::root_cause(this error const &self) -> error const &
if (self.m_cause)
return self.m_cause->root_cause();
- return self;
+ return self; //NOLINT(bugprone-return-const-ref-from-parameter)
}
auto error::str(this error const &self) -> std::string
diff --git a/nihil.error/error.ccm b/nihil.error/error.ccm
index b624184..12d47cc 100644
--- a/nihil.error/error.ccm
+++ b/nihil.error/error.ccm
@@ -53,7 +53,7 @@ export struct error : std::exception {
error();
// Destroy an error.
- virtual ~error();
+ ~error() override;
// Create an error from a freeform string.
error(std::string_view what, error cause);
diff --git a/nihil.generator/CMakeLists.txt b/nihil.generator/CMakeLists.txt
index 7d278a8..56afdac 100644
--- a/nihil.generator/CMakeLists.txt
+++ b/nihil.generator/CMakeLists.txt
@@ -3,7 +3,13 @@
add_library(nihil.generator STATIC)
target_sources(nihil.generator
PUBLIC FILE_SET modules TYPE CXX_MODULES FILES
+ nihil.generator.ccm
+
generator.ccm
+ elements_of.ccm
+ manual_lifetime.ccm
+ promise_base_alloc.ccm
+ util.ccm
)
if(NIHIL_TESTS)
diff --git a/nihil.generator/elements_of.ccm b/nihil.generator/elements_of.ccm
new file mode 100644
index 0000000..0e34eb9
--- /dev/null
+++ b/nihil.generator/elements_of.ccm
@@ -0,0 +1,69 @@
+///////////////////////////////////////////////////////////////////////////////
+// Reference implementation of std::generator proposal P2168.
+//
+// See https://wg21.link/P2168 for details.
+//
+///////////////////////////////////////////////////////////////////////////////
+// Copyright Lewis Baker, Corentin Jabot
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0.
+// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt)
+///////////////////////////////////////////////////////////////////////////////
+
+module;
+
+#include <concepts>
+
+export module nihil.generator:elements_of;
+
+import :util;
+
+namespace nihil {
+
+export template <typename Range, typename Allocator = use_allocator_arg>
+struct elements_of {
+ explicit constexpr elements_of(Range &&range) noexcept
+ requires std::is_default_constructible_v<Allocator>
+ : m_range(static_cast<Range &&>(range))
+ {
+ }
+
+ constexpr elements_of(Range &&range, Allocator &&alloc) noexcept
+ : m_range(static_cast<Range &&>(range))
+ , m_alloc(static_cast<Allocator &&>(alloc))
+ {}
+
+ constexpr elements_of(elements_of &&) noexcept = default;
+
+ constexpr elements_of(const elements_of &) = delete;
+
+ constexpr auto operator=(this elements_of &, const elements_of &)
+ -> elements_of & = delete;
+ constexpr auto operator=(this elements_of &, elements_of &&) noexcept
+ -> elements_of & = delete;
+
+ [[nodiscard]] constexpr auto
+ get(this elements_of const &self) noexcept -> Range &&
+ {
+ return static_cast<Range &&>(self.m_range);
+ }
+
+ [[nodiscard]] constexpr auto
+ get_allocator(this elements_of const &self) noexcept -> Allocator
+ {
+ return self.m_alloc;
+ }
+
+private:
+ [[no_unique_address]] Allocator m_alloc;
+ Range &&m_range;
+};
+
+export template <typename Range>
+elements_of(Range &&) -> elements_of<Range>;
+
+export template <typename Range, typename Allocator>
+elements_of(Range &&, Allocator &&) -> elements_of<Range, Allocator>;
+
+} // namespace nihil
diff --git a/nihil.generator/generator.ccm b/nihil.generator/generator.ccm
index f022287..27e8103 100644
--- a/nihil.generator/generator.ccm
+++ b/nihil.generator/generator.ccm
@@ -21,197 +21,20 @@ module;
#include <type_traits>
#include <utility>
-export module nihil.generator;
+export module nihil.generator:generator;
-namespace nihil {
-
-template <typename _T>
-class __manual_lifetime {
- public:
- __manual_lifetime() noexcept {}
- ~__manual_lifetime() {}
-
- template <typename... _Args>
- _T& construct(_Args&&... __args) noexcept(std::is_nothrow_constructible_v<_T, _Args...>) {
- return *::new (static_cast<void*>(std::addressof(__value_))) _T((_Args&&)__args...);
- }
-
- void destruct() noexcept(std::is_nothrow_destructible_v<_T>) {
- __value_.~_T();
- }
-
- _T& get() & noexcept {
- return __value_;
- }
- _T&& get() && noexcept {
- return static_cast<_T&&>(__value_);
- }
- const _T& get() const & noexcept {
- return __value_;
- }
- const _T&& get() const && noexcept {
- return static_cast<const _T&&>(__value_);
- }
-
- private:
- union {
- std::remove_const_t<_T> __value_;
- };
-};
-
-template <typename _T>
-class __manual_lifetime<_T&> {
- public:
- __manual_lifetime() noexcept : __value_(nullptr) {}
- ~__manual_lifetime() {}
-
- _T& construct(_T& __value) noexcept {
- __value_ = std::addressof(__value);
- return __value;
- }
-
- void destruct() noexcept {}
-
- _T& get() const noexcept {
- return *__value_;
- }
-
- private:
- _T* __value_;
-};
-
-template <typename _T>
-class __manual_lifetime<_T&&> {
- public:
- __manual_lifetime() noexcept : __value_(nullptr) {}
- ~__manual_lifetime() {}
-
- _T&& construct(_T&& __value) noexcept {
- __value_ = std::addressof(__value);
- return static_cast<_T&&>(__value);
- }
-
- void destruct() noexcept {}
-
- _T&& get() const noexcept {
- return static_cast<_T&&>(*__value_);
- }
-
- private:
- _T* __value_;
-};
-
-struct use_allocator_arg {};
-
-namespace ranges {
-
-export template <typename _Rng, typename _Allocator = use_allocator_arg>
-struct elements_of {
- explicit constexpr elements_of(_Rng&& __rng) noexcept
- requires std::is_default_constructible_v<_Allocator>
- : __range(static_cast<_Rng&&>(__rng))
- {}
-
- constexpr elements_of(_Rng&& __rng, _Allocator&& __alloc) noexcept
- : __range((_Rng&&)__rng), __alloc((_Allocator&&)__alloc) {}
-
- constexpr elements_of(elements_of&&) noexcept = default;
-
- constexpr elements_of(const elements_of &) = delete;
- constexpr elements_of &operator=(const elements_of &) = delete;
- constexpr elements_of &operator=(elements_of &&) = delete;
-
- constexpr _Rng&& get() noexcept {
- return static_cast<_Rng&&>(__range);
- }
-
- constexpr _Allocator get_allocator() const noexcept {
- return __alloc;
- }
-
-private:
- [[no_unique_address]] _Allocator __alloc; // \expos
- _Rng && __range; // \expos
-};
-
-export template <typename _Rng>
-elements_of(_Rng &&) -> elements_of<_Rng>;
-
-export template <typename _Rng, typename Allocator>
-elements_of(_Rng &&, Allocator&&) -> elements_of<_Rng, Allocator>;
-
-} // namespace ranges
-
-template <typename _Alloc>
-static constexpr bool __allocator_needs_to_be_stored =
- !std::allocator_traits<_Alloc>::is_always_equal::value ||
- !std::is_default_constructible_v<_Alloc>;
-
-// Round s up to next multiple of a.
-constexpr size_t __aligned_allocation_size(size_t s, size_t a) {
- return (s + a - 1) & ~(a - 1);
-}
+import :elements_of;
+import :manual_lifetime;
+import :promise_base_alloc;
+import :util;
+namespace nihil {
export template <typename _Ref,
typename _Value = std::remove_cvref_t<_Ref>,
typename _Allocator = use_allocator_arg>
class generator;
-template<typename _Alloc>
-class __promise_base_alloc {
- static constexpr std::size_t __offset_of_allocator(std::size_t __frameSize) noexcept {
- return __aligned_allocation_size(__frameSize, alignof(_Alloc));
- }
-
- static constexpr std::size_t __padded_frame_size(std::size_t __frameSize) noexcept {
- return __offset_of_allocator(__frameSize) + sizeof(_Alloc);
- }
-
- static _Alloc& __get_allocator(void* __frame, std::size_t __frameSize) noexcept {
- return *reinterpret_cast<_Alloc*>(
- static_cast<char*>(__frame) + __offset_of_allocator(__frameSize));
- }
-
-public:
- template<typename... _Args>
- static void* operator new(std::size_t __frameSize, std::allocator_arg_t, _Alloc __alloc, _Args&...) {
- void* __frame = __alloc.allocate(__padded_frame_size(__frameSize));
-
- // Store allocator at end of the coroutine frame.
- // Assuming the allocator's move constructor is non-throwing (a requirement for allocators)
- ::new (static_cast<void*>(std::addressof(__get_allocator(__frame, __frameSize)))) _Alloc(std::move(__alloc));
-
- return __frame;
- }
-
- template<typename _This, typename... _Args>
- static void* operator new(std::size_t __frameSize, _This&, std::allocator_arg_t, _Alloc __alloc, _Args&...) {
- return __promise_base_alloc::operator new(__frameSize, std::allocator_arg, std::move(__alloc));
- }
-
- static void operator delete(void* __ptr, std::size_t __frameSize) noexcept {
- _Alloc& __alloc = __get_allocator(__ptr, __frameSize);
- _Alloc __localAlloc(std::move(__alloc));
- __alloc.~Alloc();
- __localAlloc.deallocate(static_cast<std::byte*>(__ptr), __padded_frame_size(__frameSize));
- }
-};
-
-template<typename _Alloc>
- requires (!__allocator_needs_to_be_stored<_Alloc>)
-class __promise_base_alloc<_Alloc> {
-public:
- static void* operator new(std::size_t __size) {
- _Alloc __alloc;
- return __alloc.allocate(__size);
- }
-
- static void operator delete(void* __ptr, std::size_t __size) noexcept {
- _Alloc __alloc;
- __alloc.deallocate(static_cast<std::byte*>(__ptr), __size);
- }
-};
template<typename _Ref>
struct __generator_promise_base
@@ -226,8 +49,8 @@ struct __generator_promise_base
// generator coroutine is not used as a nested coroutine).
// This member is lazily constructed by the __yield_sequence_awaiter::await_suspend()
// method if this generator is used as a nested generator.
- __manual_lifetime<std::exception_ptr> __exception_;
- __manual_lifetime<_Ref> __value_;
+ manual_lifetime<std::exception_ptr> __exception_;
+ manual_lifetime<_Ref> __value_;
explicit __generator_promise_base(std::coroutine_handle<> thisCoro) noexcept
: __root_(this)
@@ -345,13 +168,13 @@ struct __generator_promise_base
template <typename _OValue, typename _OAlloc>
__yield_sequence_awaiter<generator<_Ref, _OValue, _OAlloc>>
- yield_value(nihil::ranges::elements_of<generator<_Ref, _OValue, _OAlloc>> __g) noexcept {
+ yield_value(nihil::elements_of<generator<_Ref, _OValue, _OAlloc>> __g) noexcept {
return std::move(__g).get();
}
template <std::ranges::range _Rng, typename _Allocator>
__yield_sequence_awaiter<generator<_Ref, std::remove_cvref_t<_Ref>, _Allocator>>
- yield_value(nihil::ranges::elements_of<_Rng, _Allocator> && __x) {
+ yield_value(nihil::elements_of<_Rng, _Allocator> && __x) {
return [](std::allocator_arg_t, _Allocator, auto && __rng) -> generator<_Ref, std::remove_cvref_t<_Ref>, _Allocator> {
for(auto && e: __rng)
co_yield static_cast<decltype(e)>(e);
@@ -372,7 +195,7 @@ struct __generator_promise;
template<typename _Ref, typename _Value, typename _Alloc, typename _ByteAllocator, bool _ExplicitAllocator>
struct __generator_promise<generator<_Ref, _Value, _Alloc>, _ByteAllocator, _ExplicitAllocator> final
: public __generator_promise_base<_Ref>
- , public __promise_base_alloc<_ByteAllocator> {
+ , public promise_base_alloc<_ByteAllocator> {
__generator_promise() noexcept
: __generator_promise_base<_Ref>(std::coroutine_handle<__generator_promise>::from_promise(*this))
{}
@@ -387,7 +210,7 @@ struct __generator_promise<generator<_Ref, _Value, _Alloc>, _ByteAllocator, _Exp
template <std::ranges::range _Rng>
typename __generator_promise_base<_Ref>::template __yield_sequence_awaiter<generator<_Ref, _Value, _Alloc>>
- yield_value(nihil::ranges::elements_of<_Rng> && __x) {
+ yield_value(nihil::elements_of<_Rng> && __x) {
static_assert (!_ExplicitAllocator,
"This coroutine has an explicit allocator specified with std::allocator_arg so an allocator needs to be passed "
"explicitely to std::elements_of");
@@ -682,11 +505,3 @@ private:
};
} // namespace nihil
-
-export namespace std::ranges {
-
-template <typename _T, typename _U, typename _Alloc>
-constexpr inline bool enable_view<nihil::generator<_T, _U, _Alloc>> = true;
-
-} // namespace std::ranges
-
diff --git a/nihil.generator/manual_lifetime.ccm b/nihil.generator/manual_lifetime.ccm
new file mode 100644
index 0000000..d249e99
--- /dev/null
+++ b/nihil.generator/manual_lifetime.ccm
@@ -0,0 +1,117 @@
+///////////////////////////////////////////////////////////////////////////////
+// Reference implementation of std::generator proposal P2168.
+//
+// See https://wg21.link/P2168 for details.
+//
+///////////////////////////////////////////////////////////////////////////////
+// Copyright Lewis Baker, Corentin Jabot
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0.
+// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt)
+///////////////////////////////////////////////////////////////////////////////
+
+module;
+
+#include <concepts>
+#include <memory>
+
+export module nihil.generator:manual_lifetime;
+
+namespace nihil {
+
+template <typename T>
+struct manual_lifetime {
+ manual_lifetime() noexcept {}
+ ~manual_lifetime() {}
+
+ template <typename ...Args>
+ auto construct(this manual_lifetime &self, Args && ...args)
+ noexcept(std::is_nothrow_constructible_v<T, Args...>)
+ -> T &
+ {
+ return *::new (static_cast<void*>(std::addressof(self.m_value)))
+ T(static_cast<Args &&>(args)...);
+ }
+
+ void destruct(this manual_lifetime &self)
+ noexcept(std::is_nothrow_destructible_v<T>)
+ {
+ self.m_value.~T();
+ }
+
+ auto get(this manual_lifetime &self) noexcept -> T &
+ {
+ return self.m_value;
+ }
+
+ auto get(this manual_lifetime &&self) noexcept -> T &&
+ {
+ return static_cast<T&&>(self.m_value);
+ }
+
+ auto get(this manual_lifetime const &self) noexcept -> T const &
+ {
+ return self.m_value;
+ }
+
+ auto get(this manual_lifetime const &&self) noexcept -> T const &&
+ {
+ return static_cast<T const &&>(self.m_value);
+ }
+
+private:
+ union {
+ std::remove_const_t<T> m_value;
+ };
+};
+
+template <typename T>
+class manual_lifetime<T &> {
+ manual_lifetime() noexcept {}
+ ~manual_lifetime() {}
+
+ auto construct(this manual_lifetime &self, T &value) noexcept -> T &
+ {
+ self.m_value = std::addressof(value);
+ return self.m_value;
+ }
+
+ auto destruct(this manual_lifetime &) noexcept -> void
+ {
+ }
+
+ auto get(this manual_lifetime const &self) noexcept -> T &
+ {
+ return *self.m_value;
+ }
+
+private:
+ T *m_value = nullptr;
+};
+
+template <typename T>
+class manual_lifetime<T &&> {
+ manual_lifetime() noexcept {}
+ ~manual_lifetime() {}
+
+ auto construct(this manual_lifetime &self, T &&value) noexcept -> T &&
+ {
+ self.m_value = std::addressof(value);
+ return static_cast<T &&>(value);
+ }
+
+ void destruct(this manual_lifetime &) noexcept
+ {
+ }
+
+ auto get(this manual_lifetime const &self) noexcept -> T &&
+ {
+ return static_cast<T &&>(*self.m_value);
+ }
+
+private:
+ T* m_value = nullptr;
+};
+
+}
diff --git a/nihil.generator/nihil.generator.ccm b/nihil.generator/nihil.generator.ccm
new file mode 100644
index 0000000..9eec5b4
--- /dev/null
+++ b/nihil.generator/nihil.generator.ccm
@@ -0,0 +1,32 @@
+///////////////////////////////////////////////////////////////////////////////
+// Reference implementation of std::generator proposal P2168.
+//
+// See https://wg21.link/P2168 for details.
+//
+///////////////////////////////////////////////////////////////////////////////
+// Copyright Lewis Baker, Corentin Jabot
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0.
+// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt)
+///////////////////////////////////////////////////////////////////////////////
+
+module;
+
+#include <ranges>
+
+export module nihil.generator;
+
+export import :elements_of;
+export import :generator;
+export import :manual_lifetime;
+export import :promise_base_alloc;
+export import :util;
+
+export namespace std::ranges {
+
+template <typename T, typename U, typename Alloc>
+constexpr inline bool enable_view<nihil::generator<T, U, Alloc>> = true;
+
+} // namespace std::ranges
+
diff --git a/nihil.generator/promise_base_alloc.ccm b/nihil.generator/promise_base_alloc.ccm
new file mode 100644
index 0000000..e59fc57
--- /dev/null
+++ b/nihil.generator/promise_base_alloc.ccm
@@ -0,0 +1,94 @@
+///////////////////////////////////////////////////////////////////////////////
+// Reference implementation of std::generator proposal P2168.
+//
+// See https://wg21.link/P2168 for details.
+//
+///////////////////////////////////////////////////////////////////////////////
+// Copyright Lewis Baker, Corentin Jabot
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0.
+// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt)
+///////////////////////////////////////////////////////////////////////////////
+
+module;
+
+#include <cstdlib>
+#include <memory>
+
+export module nihil.generator:promise_base_alloc;
+
+import :util;
+
+namespace nihil {
+
+template<typename Alloc>
+struct promise_base_alloc
+{
+ template<typename... Args>
+ static void* operator new(std::size_t frame_size, std::allocator_arg_t, Alloc alloc, Args &...)
+ {
+ void* frame = alloc.allocate(padded_frame_size(frame_size));
+
+ // Store allocator at end of the coroutine frame. Assuming the
+ // allocator's move constructor is non-throwing (a requirement
+ // for allocators)
+ auto *alloc_address = static_cast<void*>(std::addressof(get_allocator(frame, frame_size)));
+ ::new (alloc_address) Alloc(std::move(alloc));
+
+ return frame;
+ }
+
+ template<typename This, typename... Args>
+ static void* operator new(std::size_t frame_size, This &, std::allocator_arg_t, Alloc alloc, Args &...)
+ {
+ return promise_base_alloc::operator new(frame_size, std::allocator_arg, std::move(alloc));
+ }
+
+ static void operator delete(void* ptr, std::size_t frame_size) noexcept
+ {
+ auto &alloc = get_allocator(ptr, frame_size);
+ auto local_alloc = Alloc(std::move(alloc));
+
+ alloc.~Alloc();
+
+ local_alloc.deallocate(static_cast<std::byte*>(ptr), padded_frame_size(frame_size));
+ }
+
+private:
+ [[nodiscard]] static constexpr auto offset_of_allocator(std::size_t frame_size) noexcept -> std::size_t
+ {
+ return aligned_allocation_size(frame_size, alignof(Alloc));
+ }
+
+ [[nodiscard]] static constexpr auto padded_frame_size(std::size_t frame_size) noexcept -> std::size_t
+ {
+ return offset_of_allocator(frame_size) + sizeof(Alloc);
+ }
+
+ [[nodiscard]] static auto get_allocator(void* frame, std::size_t frame_size) noexcept -> Alloc &
+ {
+ return *reinterpret_cast<Alloc*>(
+ static_cast<char*>(frame) + offset_of_allocator(frame_size));
+ }
+
+};
+
+template<typename Alloc>
+requires (!allocator_needs_to_be_stored<Alloc>)
+struct promise_base_alloc<Alloc>
+{
+ static void* operator new(std::size_t size)
+ {
+ auto alloc = Alloc();
+ return alloc.allocate(size);
+ }
+
+ static void operator delete(void *ptr, std::size_t size) noexcept
+ {
+ auto alloc = Alloc();
+ alloc.deallocate(static_cast<std::byte *>(ptr), size);
+ }
+};
+
+} // namespace nihil
diff --git a/nihil.generator/test.cc b/nihil.generator/test.cc
index d167f30..49272b4 100644
--- a/nihil.generator/test.cc
+++ b/nihil.generator/test.cc
@@ -46,7 +46,7 @@ TEST_CASE("generator: elements_of", "[generator]")
};
auto fn2 = [&fn1] -> nihil::generator<int> {
- co_yield nihil::ranges::elements_of(fn1());
+ co_yield nihil::elements_of(fn1());
};
auto values = std::vector<int>();
diff --git a/nihil.generator/util.ccm b/nihil.generator/util.ccm
new file mode 100644
index 0000000..4d732b9
--- /dev/null
+++ b/nihil.generator/util.ccm
@@ -0,0 +1,37 @@
+///////////////////////////////////////////////////////////////////////////////
+// Reference implementation of std::generator proposal P2168.
+//
+// See https://wg21.link/P2168 for details.
+//
+///////////////////////////////////////////////////////////////////////////////
+// Copyright Lewis Baker, Corentin Jabot
+//
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0.
+// (See accompanying file LICENSE or http://www.boost.org/LICENSE_1_0.txt)
+///////////////////////////////////////////////////////////////////////////////
+
+module;
+
+#include <concepts>
+#include <memory>
+
+export module nihil.generator:util;
+
+namespace nihil {
+
+export struct use_allocator_arg {};
+
+template <typename Alloc>
+constexpr bool allocator_needs_to_be_stored =
+ !std::allocator_traits<Alloc>::is_always_equal::value ||
+ !std::is_default_constructible_v<Alloc>;
+
+// Round s up to next multiple of a.
+[[nodiscard]] constexpr auto
+aligned_allocation_size(std::size_t s, std::size_t a) -> std::size_t
+{
+ return (s + a - 1) & ~(a - 1);
+}
+
+} // namespace nihil
diff --git a/nihil.guard/guard.ccm b/nihil.guard/guard.ccm
index c586a20..7b6cf66 100644
--- a/nihil.guard/guard.ccm
+++ b/nihil.guard/guard.ccm
@@ -26,22 +26,24 @@ struct guard final {
* We are being destroyed, so call the callable.
* If the callable throws, std::terminate() will be called.
*/
- ~guard() {
+ ~guard()
+ {
if (m_func)
std::invoke(*m_func);
}
// Release the guard. This turns the destructor into a no-op.
- void release() noexcept {
- m_func.reset();
+ auto release(this guard &self) noexcept -> void
+ {
+ self.m_func.reset();
}
// Not default-constructible, movable or copyable.
guard() = delete;
guard(guard const &) = delete;
guard(guard &&) noexcept = delete;
- guard &operator=(guard const &) = delete;
- guard &operator=(guard &&) noexcept = delete;
+ auto operator=(this guard &, guard const &) -> guard & = delete;
+ auto operator=(this guard &, guard &&) noexcept -> guard & = delete;
private:
// The callable to be invoked when we are destroyed.
diff --git a/nihil.posix/posix.spawn.ccm b/nihil.posix/posix.spawn.ccm
index 5812716..4cce334 100644
--- a/nihil.posix/posix.spawn.ccm
+++ b/nihil.posix/posix.spawn.ccm
@@ -229,12 +229,9 @@ spawn(executor auto &&executor, auto &&...actions)
auto proc = process(pid);
if (pid == 0) {
- // We are in the child. Release the process so we don't
- // try to wait for ourselves, then run child handlers and
- // exec the process.
-
- std::ignore = std::move(proc).release();
+ // We are in the child.
(actions.run_in_child(proc), ...);
+ std::ignore = std::move(proc).release();
auto err = executor.exec();
std::print("{}\n", err.error());
diff --git a/nihil.posix/posix.tempfile.cc b/nihil.posix/posix.tempfile.cc
index 801aa5e..b1d3dee 100644
--- a/nihil.posix/posix.tempfile.cc
+++ b/nihil.posix/posix.tempfile.cc
@@ -40,22 +40,7 @@ temporary_file::temporary_file(temporary_file &&other) noexcept
{
}
-auto temporary_file::operator=(this temporary_file &self,
- temporary_file &&other)
- noexcept -> temporary_file &
-{
- if (&self != &other) {
- if (self.m_fd)
- self.release();
-
- self.m_fd = std::move(other.m_fd);
- self.m_path = std::move(other.m_path);
- }
-
- return self;
-}
-
-temporary_file::~temporary_file()
+temporary_file::~temporary_file() //NOLINT(bugprone-exception-escape)
{
if (m_fd)
release();
diff --git a/nihil.posix/posix.tempfile.ccm b/nihil.posix/posix.tempfile.ccm
index 20378b5..82f3be4 100644
--- a/nihil.posix/posix.tempfile.ccm
+++ b/nihil.posix/posix.tempfile.ccm
@@ -56,13 +56,15 @@ export struct temporary_file final {
// Not copyable.
temporary_file(temporary_file const &) = delete;
- auto operator=(this temporary_file &, temporary_file const &)
- -> temporary_file & = delete;
// Movable.
temporary_file(temporary_file &&other) noexcept;
+
+ // Not assignable.
+ auto operator=(this temporary_file &, temporary_file const &)
+ -> temporary_file & = delete;
auto operator=(this temporary_file &, temporary_file &&) noexcept
- -> temporary_file &;
+ -> temporary_file & = delete;
private:
// The file descriptor for the file.
diff --git a/nihil.posix/test.fd.cc b/nihil.posix/test.fd.cc
index 8dff323..6b6394b 100644
--- a/nihil.posix/test.fd.cc
+++ b/nihil.posix/test.fd.cc
@@ -64,7 +64,7 @@ TEST_CASE("fd: move construct", "[fd]") {
REQUIRE(fd_is_open(fd1.get()));
auto fd2(std::move(fd1));
- REQUIRE(!fd1);
+ REQUIRE(!fd1); //NOLINT
REQUIRE(fd2);
REQUIRE(fd2.get() == file);
REQUIRE(fd_is_open(file));
@@ -82,7 +82,7 @@ TEST_CASE("fd: move assign", "[fd]") {
fd2 = std::move(fd1);
- REQUIRE(!fd1);
+ REQUIRE(!fd1); //NOLINT
REQUIRE(fd2);
REQUIRE(fd2.get() == file);
REQUIRE(fd_is_open(file));
@@ -94,7 +94,7 @@ TEST_CASE("fd: release", "[fd]") {
auto fd = nihil::fd(file);
auto fdesc = std::move(fd).release();
- REQUIRE(!fd);
+ REQUIRE(!fd); //NOLINT
REQUIRE(fdesc == file);
}
diff --git a/nihil.ucl/integer.ccm b/nihil.ucl/integer.ccm
index 0ea490c..e35a471 100644
--- a/nihil.ucl/integer.ccm
+++ b/nihil.ucl/integer.ccm
@@ -81,7 +81,7 @@ export constexpr auto operator""_ucl (unsigned long long i) -> integer
if (std::cmp_greater(i, std::numeric_limits<std::int64_t>::max()))
throw std::out_of_range("literal out of range");
- return integer(i);
+ return integer(static_cast<std::int64_t>(i));
}
} // namespace nihil::ucl::literals
diff --git a/nihil.ucl/map.ccm b/nihil.ucl/map.ccm
index 1c5dd19..fa77601 100644
--- a/nihil.ucl/map.ccm
+++ b/nihil.ucl/map.ccm
@@ -88,7 +88,8 @@ private:
struct state {
state(::ucl_object_t const *obj)
{
- if ((iter = ::ucl_object_iterate_new(obj)) == nullptr)
+ iter = ::ucl_object_iterate_new(obj);
+ if (iter == nullptr)
throw std::system_error(make_error_code(
std::errc(errno)));
}
diff --git a/nihil.ucl/object.cc b/nihil.ucl/object.cc
index 9a150fb..53fc4c7 100644
--- a/nihil.ucl/object.cc
+++ b/nihil.ucl/object.cc
@@ -33,10 +33,12 @@ object::object(object &&other) noexcept
: m_object(std::exchange(other.m_object, nullptr))
{}
-object::object(object const &other) noexcept
+object::object(object const &other)
: m_object(nullptr)
{
- *this = other;
+ m_object = ::ucl_object_copy(other.get_ucl_object());
+ if (m_object == nullptr)
+ throw std::runtime_error("failed to copy UCL object");
}
auto object::operator=(this object &self, object &&other) noexcept
@@ -47,20 +49,9 @@ auto object::operator=(this object &self, object &&other) noexcept
return self;
}
-auto object::operator=(this object &self, object const &other)
- -> object &
+auto object::operator=(this object &self, object const &other) -> object &
{
- if (&self != &other) {
- auto *new_uobj = ::ucl_object_copy(other.get_ucl_object());
- if (new_uobj == nullptr)
- throw std::runtime_error("failed to copy UCL object");
-
- if (self.m_object != nullptr)
- ::ucl_object_unref(self.m_object);
- self.m_object = new_uobj;
- }
-
- return self;
+ return self = object(other);
}
auto object::ref(this object const &self) -> object
diff --git a/nihil.ucl/object.ccm b/nihil.ucl/object.ccm
index dffb54e..9a7eaf7 100644
--- a/nihil.ucl/object.ccm
+++ b/nihil.ucl/object.ccm
@@ -49,7 +49,7 @@ export struct object {
// Copyable.
// Note that this copies the entire UCL object.
- object(object const &other) noexcept;
+ object(object const &other);
auto operator=(this object &self, object const &other) -> object &;
// Increase the refcount of this object.
diff --git a/nihil.ucl/parser.ccm b/nihil.ucl/parser.ccm
index 20e5c66..5fa3495 100644
--- a/nihil.ucl/parser.ccm
+++ b/nihil.ucl/parser.ccm
@@ -72,7 +72,7 @@ struct parser {
requires (std::same_as<bool, std::invoke_result<F>>)
{
auto handler = std::make_unique<macro_handler>(
- std::move(func));
+ std::forward<F>(func));
auto cname = std::string(name);
::ucl_parser_register_macro(
diff --git a/nihil.ucl/real.ccm b/nihil.ucl/real.ccm
index c491553..f425a9a 100644
--- a/nihil.ucl/real.ccm
+++ b/nihil.ucl/real.ccm
@@ -78,7 +78,7 @@ export constexpr auto operator""_ucl (long double d) -> real
d < static_cast<long double>(std::numeric_limits<double>::min()))
throw std::out_of_range("literal out of range");
- return real(d);
+ return real(static_cast<double>(d));
}
} // namespace nihil::ucl::literals
diff --git a/nihil.ucl/tests/map.cc b/nihil.ucl/tests/map.cc
index 5d2fbe1..7240cb3 100644
--- a/nihil.ucl/tests/map.cc
+++ b/nihil.ucl/tests/map.cc
@@ -9,6 +9,8 @@
import nihil.ucl;
+//NOLINTBEGIN(bugprone-unchecked-optional-access)
+
TEST_CASE("ucl: map: invariants", "[ucl]")
{
using namespace nihil::ucl;
@@ -110,11 +112,10 @@ TEST_CASE("ucl: map: find", "[ucl]")
};
auto obj = map.find("42");
- REQUIRE(obj != std::nullopt);
- REQUIRE(*obj == 42);
+ REQUIRE(obj.value() == 42);
obj = map.find("43");
- REQUIRE(obj == std::nullopt);
+ REQUIRE(!obj.has_value());
}
TEST_CASE("ucl: map: iterate", "[ucl]")
@@ -179,12 +180,13 @@ TEST_CASE("ucl: map: pop", "[uc]")
REQUIRE(map.find("42") != std::nullopt);
auto obj = map.pop("42");
- REQUIRE(obj != std::nullopt);
- REQUIRE(*obj == 42);
+ REQUIRE(obj.value() == 42);
- REQUIRE(map.find("42") == std::nullopt);
+ REQUIRE(!map.find("42"));
REQUIRE(map["1"] == 1);
obj = map.pop("42");
- REQUIRE(obj == std::nullopt);
+ REQUIRE(!obj);
}
+
+//NOLINTEND(bugprone-unchecked-optional-access)
diff --git a/nihil.util/capture_stream.ccm b/nihil.util/capture_stream.ccm
index 3333505..7ec39a9 100644
--- a/nihil.util/capture_stream.ccm
+++ b/nihil.util/capture_stream.ccm
@@ -24,10 +24,11 @@ struct capture_stream {
m_stream->rdbuf(m_buffer.rdbuf());
}
- ~capture_stream() {
+ ~capture_stream()
+ {
if (m_old_streambuf == nullptr)
return;
- release();
+ m_stream->rdbuf(m_old_streambuf);
}
/*
diff --git a/nihil.util/parse_size.ccm b/nihil.util/parse_size.ccm
index c692578..c95ac50 100644
--- a/nihil.util/parse_size.ccm
+++ b/nihil.util/parse_size.ccm
@@ -29,11 +29,11 @@ auto get_multiplier(Char c) -> std::expected<std::uint64_t, error>
auto ret = std::uint64_t{1};
switch (c) {
- case 'p': case 'P': ret *= 1024;
- case 't': case 'T': ret *= 1024;
- case 'g': case 'G': ret *= 1024;
- case 'm': case 'M': ret *= 1024;
- case 'k': case 'K': ret *= 1024;
+ case 'p': case 'P': ret *= 1024; //NOLINT
+ case 't': case 'T': ret *= 1024; //NOLINT
+ case 'g': case 'G': ret *= 1024; //NOLINT
+ case 'm': case 'M': ret *= 1024; //NOLINT
+ case 'k': case 'K': ret *= 1024; //NOLINT
return ret;
default:
diff --git a/nihil.uuid/test.cc b/nihil.uuid/test.cc
index 04a6ab5..0f21298 100644
--- a/nihil.uuid/test.cc
+++ b/nihil.uuid/test.cc
@@ -29,6 +29,8 @@
#include <catch2/catch_test_macros.hpp>
+//NOLINTBEGIN(bugprone-unchecked-optional-access)
+
namespace
{
@@ -69,7 +71,7 @@ TEST_CASE("uuid: Test multiple default generators", "[uuid]")
{
std::random_device rd;
auto seed_data = std::array<int, std::mt19937::state_size> {};
- std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
+ std::ranges::generate(seed_data, std::ref(rd));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
std::mt19937 generator(seq);
@@ -82,7 +84,7 @@ TEST_CASE("uuid: Test multiple default generators", "[uuid]")
{
std::random_device rd;
auto seed_data = std::array<int, std::mt19937::state_size> {};
- std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
+ std::ranges::generate(seed_data, std::ref(rd));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
std::mt19937 generator(seq);
@@ -99,7 +101,7 @@ TEST_CASE("uuid: Test default generator", "[uuid]")
{
std::random_device rd;
auto seed_data = std::array<int, std::mt19937::state_size> {};
- std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
+ std::ranges::generate(seed_data, std::ref(rd));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
std::mt19937 generator(seq);
@@ -114,7 +116,7 @@ TEST_CASE("uuid: Test random generator (conversion ctor w/ smart ptr)",
{
std::random_device rd;
auto seed_data = std::array<int, std::mt19937::state_size> {};
- std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
+ std::ranges::generate(seed_data, std::ref(rd));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
std::mt19937 generator(seq);
@@ -136,7 +138,7 @@ TEST_CASE("uuid: Test random generator (conversion ctor w/ ptr)", "[uuid]")
{
std::random_device rd;
auto seed_data = std::array<int, std::mt19937::state_size> {};
- std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
+ std::ranges::generate(seed_data, std::ref(rd));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
auto generator = std::make_unique<std::mt19937>(seq);
@@ -158,7 +160,7 @@ TEST_CASE("uuid: Test random generator (conversion ctor w/ ref)", "[uuid]")
{
std::random_device rd;
auto seed_data = std::array<int, std::mt19937::state_size> {};
- std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
+ std::ranges::generate(seed_data, std::ref(rd));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
std::mt19937 generator(seq);
@@ -181,7 +183,7 @@ TEST_CASE("uuid: Test basic random generator (conversion ctor w/ ptr) "
{
std::random_device rd;
auto seed_data = std::array<int, 6> {};
- std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
+ std::ranges::generate(seed_data, std::ref(rd));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
std::ranlux48_base generator(seq);
@@ -204,7 +206,7 @@ TEST_CASE("uuid: Test basic random generator (conversion ctor w/ smart ptr) "
{
std::random_device rd;
auto seed_data = std::array<int, 6> {};
- std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
+ std::ranges::generate(seed_data, std::ref(rd));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
auto generator = std::make_unique<std::ranlux48_base>(seq);
@@ -227,7 +229,7 @@ TEST_CASE("uuid: Test basic random generator (conversion ctor w/ ref) "
{
std::random_device rd;
auto seed_data = std::array<int, 6> {};
- std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
+ std::ranges::generate(seed_data, std::ref(rd));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
std::ranlux48_base generator(seq);
@@ -347,7 +349,8 @@ TEST_CASE("uuid: Test name generator equality (char const*, std::string, "
{
using namespace std::literals;
- uuid_name_generator dgen(uuid::from_string("47183823-2574-4bfd-b411-99ed177d3e43").value());
+ auto dgen = uuid_name_generator(uuid::from_string(
+ "47183823-2574-4bfd-b411-99ed177d3e43").value());
auto id1 = dgen("john");
auto id2 = dgen("john"s);
auto id3 = dgen("john"sv);
@@ -791,7 +794,7 @@ TEST_CASE("uuid: Test iterators constructor", "[uuid]")
}
{
- uuid::value_type arr[16] = {
+ uuid::value_type arr[16] = { // NOLINT
0x47, 0x18, 0x38, 0x23,
0x25, 0x74,
0x4b, 0xfd,
@@ -837,7 +840,7 @@ TEST_CASE("uuid: Test array constructors", "[uuid]")
}
{
- uuid::value_type arr[16] {
+ uuid::value_type arr[16] { //NOLINT
0x47, 0x18, 0x38, 0x23,
0x25, 0x74,
0x4b, 0xfd,
@@ -995,3 +998,4 @@ TEST_CASE("uuid: Test as_bytes", "[uuid]")
}
}
+//NOLINTEND(bugprone-unchecked-optional-access)
diff --git a/nihil.uuid/uuid.ccm b/nihil.uuid/uuid.ccm
index 0c46b60..4aa424e 100644
--- a/nihil.uuid/uuid.ccm
+++ b/nihil.uuid/uuid.ccm
@@ -48,28 +48,37 @@ export module nihil.uuid;
namespace nihil {
template <typename TChar>
-[[nodiscard]] constexpr unsigned char hex2char(TChar const ch) noexcept
+[[nodiscard]] constexpr auto hex2char(TChar const ch) noexcept -> unsigned char
{
if (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9'))
- return static_cast<unsigned char>(ch - static_cast<TChar>('0'));
+ return static_cast<unsigned char>(
+ ch - static_cast<TChar>('0'));
+
if (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f'))
- return static_cast<unsigned char>(10 + ch - static_cast<TChar>('a'));
+ return static_cast<unsigned char>(
+ 10 + ch - static_cast<TChar>('a'));
+
if (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F'))
- return static_cast<unsigned char>(10 + ch - static_cast<TChar>('A'));
+ return static_cast<unsigned char>(
+ 10 + ch - static_cast<TChar>('A'));
+
return 0;
}
template <typename TChar>
-[[nodiscard]] constexpr bool is_hex(TChar const ch) noexcept
+[[nodiscard]] constexpr auto is_hex(TChar const ch) noexcept -> bool
{
- return
- (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9')) ||
- (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f')) ||
- (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F'));
+ return (ch >= static_cast<TChar>('0') &&
+ ch <= static_cast<TChar>('9')) ||
+ (ch >= static_cast<TChar>('a') &&
+ ch <= static_cast<TChar>('f')) ||
+ (ch >= static_cast<TChar>('A') &&
+ ch <= static_cast<TChar>('F'));
}
template <typename TChar>
-[[nodiscard]] constexpr std::basic_string_view<TChar> to_string_view(TChar const * str) noexcept
+[[nodiscard]] constexpr auto to_string_view(TChar const *str) noexcept
+ -> std::basic_string_view<TChar>
{
if (str)
return str;
@@ -77,101 +86,117 @@ template <typename TChar>
}
template <typename StringType>
-[[nodiscard]]
-constexpr std::basic_string_view<
- typename StringType::value_type,
- typename StringType::traits_type>
-to_string_view(StringType const & str) noexcept
+[[nodiscard]] constexpr auto to_string_view(StringType const &str) noexcept
+ -> std::basic_string_view<
+ typename StringType::value_type,
+ typename StringType::traits_type>
{
return str;
}
struct sha1
{
- using digest32_t = uint32_t[5];
- using digest8_t = uint8_t[20];
+ using digest32_t = std::array<std::uint32_t, 5>;
+ using digest8_t = std::array<std::uint8_t, 20>;
static constexpr unsigned int block_bytes = 64;
- [[nodiscard]] inline static uint32_t left_rotate(uint32_t value, size_t const count) noexcept
+ sha1()
{
- return (value << count) ^ (value >> (32 - count));
+ reset();
}
- sha1()
+ [[nodiscard]] inline static auto
+ left_rotate(std::uint32_t value, std::size_t const count) noexcept
+ -> std::uint32_t
{
- reset();
+ return (value << count) ^ (value >> (32 - count));
}
- void reset() noexcept
+ auto reset(this sha1 &self) noexcept -> void
{
- m_digest[0] = 0x67452301;
- m_digest[1] = 0xEFCDAB89;
- m_digest[2] = 0x98BADCFE;
- m_digest[3] = 0x10325476;
- m_digest[4] = 0xC3D2E1F0;
- m_blockByteIndex = 0;
- m_byteCount = 0;
+ self.m_digest[0] = 0x67452301;
+ self.m_digest[1] = 0xEFCDAB89;
+ self.m_digest[2] = 0x98BADCFE;
+ self.m_digest[3] = 0x10325476;
+ self.m_digest[4] = 0xC3D2E1F0;
+ self.m_blockByteIndex = 0;
+ self.m_byteCount = 0;
}
- void process_byte(uint8_t octet)
+ auto process_byte(this sha1 &self, std::uint8_t octet) -> void
{
- this->m_block[this->m_blockByteIndex++] = octet;
- ++this->m_byteCount;
- if (m_blockByteIndex == block_bytes) {
- this->m_blockByteIndex = 0;
- process_block();
+ self.m_block[self.m_blockByteIndex++] = octet;
+ ++self.m_byteCount;
+
+ if (self.m_blockByteIndex == block_bytes) {
+ self.m_blockByteIndex = 0;
+ self.process_block();
}
}
- void process_block(void const * const start, void const * const end)
+ auto process_block(this sha1 &self,
+ void const *const start,
+ void const *const end)
+ -> void
{
- auto *begin = static_cast<const uint8_t*>(start);
- auto *finish = static_cast<const uint8_t*>(end);
- while (begin != finish) {
- process_byte(*begin);
- begin++;
+ auto *first = static_cast<uint8_t const *>(start);
+ auto *last = static_cast<uint8_t const *>(end);
+
+ while (first != last) {
+ self.process_byte(*first);
+ first++;
}
}
- void process_bytes(void const * const data, size_t const len)
+ auto process_bytes(this sha1 &self,
+ void const *const data,
+ size_t const len)
+ -> void
{
- auto *block = static_cast<const uint8_t*>(data);
- process_block(block, block + len);
+ auto *block = static_cast<uint8_t const *>(data);
+ self.process_block(block, block + len);
}
- uint32_t const * get_digest(digest32_t digest)
+ auto get_digest(this sha1 &self) -> digest32_t
{
- size_t const bitCount = this->m_byteCount * 8;
- process_byte(0x80);
- if (this->m_blockByteIndex > 56) {
- while (m_blockByteIndex != 0)
- process_byte(0);
- while (m_blockByteIndex < 56)
- process_byte(0);
+ auto const bit_count = self.m_byteCount * 8;
+
+ self.process_byte(0x80);
+ if (self.m_blockByteIndex > 56) {
+ while (self.m_blockByteIndex != 0)
+ self.process_byte(0);
+
+ while (self.m_blockByteIndex < 56)
+ self.process_byte(0);
} else {
- while (m_blockByteIndex < 56)
- process_byte(0);
+ while (self.m_blockByteIndex < 56)
+ self.process_byte(0);
}
- process_byte(0);
- process_byte(0);
- process_byte(0);
- process_byte(0);
- process_byte(static_cast<unsigned char>((bitCount >> 24) & 0xFF));
- process_byte(static_cast<unsigned char>((bitCount >> 16) & 0xFF));
- process_byte(static_cast<unsigned char>((bitCount >> 8) & 0xFF));
- process_byte(static_cast<unsigned char>((bitCount) & 0xFF));
-
- std::memcpy(digest, m_digest, 5 * sizeof(uint32_t));
- return digest;
+ self.process_byte(0);
+ self.process_byte(0);
+ self.process_byte(0);
+ self.process_byte(0);
+ self.process_byte(static_cast<unsigned char>(
+ (bit_count >> 24) & 0xFF));
+ self.process_byte(static_cast<unsigned char>(
+ (bit_count >> 16) & 0xFF));
+ self.process_byte(static_cast<unsigned char>(
+ (bit_count >> 8) & 0xFF));
+ self.process_byte(static_cast<unsigned char>(
+ (bit_count) & 0xFF));
+
+ return self.m_digest;
}
- uint8_t const * get_digest_bytes(digest8_t digest)
+ auto get_digest_bytes(this sha1 &self) -> digest8_t
{
- digest32_t d32;
- get_digest(d32);
- size_t di = 0;
+ auto d32 = self.get_digest();
+ auto digest = digest8_t{};
+
+ auto di = std::size_t{0};
+
digest[di++] = static_cast<uint8_t>(d32[0] >> 24);
digest[di++] = static_cast<uint8_t>(d32[0] >> 16);
digest[di++] = static_cast<uint8_t>(d32[0] >> 8);
@@ -201,28 +226,35 @@ struct sha1
}
private:
- void process_block()
+ auto process_block(this sha1 &self) -> void
{
- uint32_t w[80];
- for (size_t i = 0; i < 16; i++) {
- w[i] = static_cast<uint32_t>(m_block[i * 4 + 0] << 24);
- w[i] |= static_cast<uint32_t>(m_block[i * 4 + 1] << 16);
- w[i] |= static_cast<uint32_t>(m_block[i * 4 + 2] << 8);
- w[i] |= static_cast<uint32_t>(m_block[i * 4 + 3]);
+ auto w = std::array<std::uint32_t, 80>();
+
+ for (std::size_t i = 0; i < 16; i++) {
+ w[i] = static_cast<std::uint32_t>(
+ self.m_block[i * 4 + 0]) << 24;
+ w[i] |= static_cast<std::uint32_t>(
+ self.m_block[i * 4 + 1]) << 16;
+ w[i] |= static_cast<std::uint32_t>(
+ self.m_block[i * 4 + 2]) << 8;
+ w[i] |= static_cast<std::uint32_t>(
+ self.m_block[i * 4 + 3]);
}
- for (size_t i = 16; i < 80; i++) {
- w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
+
+ for (std::size_t i = 16; i < 80; i++) {
+ w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^
+ w[i - 14] ^ w[i - 16]), 1);
}
- uint32_t a = m_digest[0];
- uint32_t b = m_digest[1];
- uint32_t c = m_digest[2];
- uint32_t d = m_digest[3];
- uint32_t e = m_digest[4];
+ auto a = self.m_digest[0];
+ auto b = self.m_digest[1];
+ auto c = self.m_digest[2];
+ auto d = self.m_digest[3];
+ auto e = self.m_digest[4];
for (std::size_t i = 0; i < 80; ++i) {
- uint32_t f = 0;
- uint32_t k = 0;
+ auto f = std::uint32_t{0};
+ auto k = std::uint32_t{0};
if (i < 20) {
f = (b & c) | (~b & d);
@@ -238,7 +270,8 @@ private:
k = 0xCA62C1D6;
}
- uint32_t temp = left_rotate(a, 5) + f + e + k + w[i];
+ auto temp = std::uint32_t{left_rotate(a, 5)
+ + f + e + k + w[i]};
e = d;
d = c;
c = left_rotate(b, 30);
@@ -246,45 +279,54 @@ private:
a = temp;
}
- m_digest[0] += a;
- m_digest[1] += b;
- m_digest[2] += c;
- m_digest[3] += d;
- m_digest[4] += e;
+ self.m_digest[0] += a;
+ self.m_digest[1] += b;
+ self.m_digest[2] += c;
+ self.m_digest[3] += d;
+ self.m_digest[4] += e;
}
- digest32_t m_digest;
- uint8_t m_block[64];
- size_t m_blockByteIndex;
- size_t m_byteCount;
+ digest32_t m_digest;
+ std::array<std::uint8_t, 64> m_block;
+ std::size_t m_blockByteIndex;
+ std::size_t m_byteCount;
};
template <typename CharT>
-inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000";
+inline constexpr std::string_view empty_guid =
+ "00000000-0000-0000-0000-000000000000";
template <>
-inline constexpr wchar_t empty_guid<wchar_t>[37] = L"00000000-0000-0000-0000-000000000000";
+inline constexpr std::wstring_view empty_guid<wchar_t>
+ = L"00000000-0000-0000-0000-000000000000";
template <typename CharT>
-inline constexpr CharT guid_encoder[17] = "0123456789abcdef";
+inline constexpr std::string_view guid_encoder = "0123456789abcdef";
template <>
-inline constexpr wchar_t guid_encoder<wchar_t>[17] = L"0123456789abcdef";
+inline constexpr std::wstring_view guid_encoder<wchar_t> = L"0123456789abcdef";
-// --------------------------------------------------------------------------------------------------------------------------
+// ---------------------------------------------------------------------
// UUID format https://tools.ietf.org/html/rfc4122
-// --------------------------------------------------------------------------------------------------------------------------
+// ---------------------------------------------------------------------
-// --------------------------------------------------------------------------------------------------------------------------
+// ---------------------------------------------------------------------
// Field NDR Data Type Octet # Note
-// --------------------------------------------------------------------------------------------------------------------------
-// time_low unsigned long 0 - 3 The low field of the timestamp.
-// time_mid unsigned short 4 - 5 The middle field of the timestamp.
-// time_hi_and_version unsigned short 6 - 7 The high field of the timestamp multiplexed with the version number.
-// clock_seq_hi_and_reserved unsigned small 8 The high field of the clock sequence multiplexed with the variant.
-// clock_seq_low unsigned small 9 The low field of the clock sequence.
-// node character 10 - 15 The spatially unique node identifier.
-// --------------------------------------------------------------------------------------------------------------------------
+// Note
+// ---------------------------------------------------------------------
+// time_low unsigned long 0 - 3
+// The low field of the timestamp.
+// time_mid unsigned short 4 - 5
+// The middle field of the timestamp.
+// time_hi_and_version unsigned short 6 - 7
+// The high field of the timestamp multiplexed with the version number.
+// clock_seq_hi_and_reserved unsigned small 8
+// The high field of the clock sequence multiplexed with the variant.
+// clock_seq_low unsigned small 9
+// The low field of the clock sequence.
+// node character 10 - 15
+// The spatially unique node identifier.
+// ---------------------------------------------------------------------
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -297,18 +339,22 @@ inline constexpr wchar_t guid_encoder<wchar_t>[17] = L"0123456789abcdef";
// | node (2-5) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// --------------------------------------------------------------------------------------------------------------------------
+// ---------------------------------------------------------------------
// enumerations
-// --------------------------------------------------------------------------------------------------------------------------
+// ---------------------------------------------------------------------
-// indicated by a bit pattern in octet 8, marked with N in xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx
+// indicated by a bit pattern in octet 8, marked with N in
+// xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx
export enum struct uuid_variant {
- // NCS backward compatibility (with the obsolete Apollo Network Computing System 1.5 UUID format)
+ // NCS backward compatibility (with the obsolete Apollo Network
+ // Computing System 1.5 UUID format).
// N bit pattern: 0xxx
- // > the first 6 octets of the UUID are a 48-bit timestamp (the number of 4 microsecond units of time since 1 Jan 1980 UTC);
+ // > the first 6 octets of the UUID are a 48-bit timestamp (the number
+ // of 4 microsecond units of time since 1 Jan 1980 UTC);
// > the next 2 octets are reserved;
// > the next octet is the "address family";
- // > the final 7 octets are a 56-bit host ID in the form specified by the address family
+ // > the final 7 octets are a 56-bit host ID in the form specified by
+ // the address family
ncs,
// RFC 4122/DCE 1.1
@@ -327,37 +373,45 @@ export enum struct uuid_variant {
reserved
};
-// indicated by a bit pattern in octet 6, marked with M in xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx
+// indicated by a bit pattern in octet 6, marked with M in
+// xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx
export enum struct uuid_version {
- none = 0, // only possible for nil or invalid uuids
- time_based = 1, // The time-based version specified in RFC 4122
- dce_security = 2, // DCE Security version, with embedded POSIX UIDs.
- name_based_md5 = 3, // The name-based version specified in RFS 4122 with MD5 hashing
- random_number_based = 4, // The randomly or pseudo-randomly generated version specified in RFS 4122
- name_based_sha1 = 5 // The name-based version specified in RFS 4122 with SHA1 hashing
+ // only possible for nil or invalid uuids
+ none = 0,
+ // The time-based version specified in RFC 4122
+ time_based = 1,
+ // DCE Security version, with embedded POSIX UIDs.
+ dce_security = 2,
+ // The name-based version specified in RFS 4122 with MD5 hashing
+ name_based_md5 = 3,
+ // The randomly or pseudo-randomly generated version specified in RFS 4122
+ random_number_based = 4,
+ // The name-based version specified in RFS 4122 with SHA1 hashing
+ name_based_sha1 = 5
};
-// Forward declare uuid & to_string so that we can declare to_string as a friend later.
+// Forward declare uuid and to_string so that we can declare to_string as a
+// friend later.
export struct uuid;
export template <typename CharT = char,
typename Traits = std::char_traits<CharT>,
typename Allocator = std::allocator<CharT>>
-std::basic_string<CharT, Traits, Allocator> to_string(uuid const &id);
+auto to_string(uuid const &id) -> std::basic_string<CharT, Traits, Allocator>;
// --------------------------------------------------------------------------------------------------------------------------
// uuid class
// --------------------------------------------------------------------------------------------------------------------------
export struct uuid {
- using value_type = uint8_t;
+ using value_type = std::uint8_t;
constexpr uuid() noexcept = default;
- uuid(value_type(&arr)[16]) noexcept
+ uuid(value_type(&arr)[16]) noexcept // NOLINT
{
std::ranges::copy(arr, std::ranges::begin(data));
}
- constexpr uuid(std::array<value_type, 16> const & arr) noexcept
+ constexpr uuid(std::array<value_type, 16> const &arr) noexcept
: data{arr}
{
}
@@ -367,14 +421,23 @@ export struct uuid {
std::ranges::copy(bytes, std::ranges::begin(data));
}
+ explicit uuid(std::span<value_type> bytes)
+ {
+ if (bytes.size() != 16)
+ throw std::logic_error("wrong size for uuid");
+ std::ranges::copy(bytes, std::ranges::begin(data));
+ }
+
template<typename ForwardIterator>
explicit uuid(ForwardIterator first, ForwardIterator last)
{
- if (std::distance(first, last) == 16)
- std::copy(first, last, std::begin(data));
+ if (std::distance(first, last) != 16)
+ throw std::logic_error("wrong size for uuid");
+
+ std::copy(first, last, std::begin(data));
}
- [[nodiscard]] constexpr uuid_variant variant() const noexcept
+ [[nodiscard]] constexpr auto variant() const noexcept -> uuid_variant
{
if ((data[8] & 0x80) == 0x00)
return uuid_variant::ncs;
@@ -386,7 +449,7 @@ export struct uuid {
return uuid_variant::reserved;
}
- [[nodiscard]] constexpr uuid_version version() const noexcept
+ [[nodiscard]] constexpr auto version() const noexcept -> uuid_version
{
if ((data[6] & 0xF0) == 0x10)
return uuid_version::time_based;
@@ -402,37 +465,43 @@ export struct uuid {
return uuid_version::none;
}
- [[nodiscard]] constexpr bool is_nil() const noexcept
+ [[nodiscard]] constexpr auto is_nil() const noexcept -> bool
{
- for (size_t i = 0; i < data.size(); ++i)
- if (data[i] != 0)
+ for (auto i : data)
+ if (i != 0)
return false;
return true;
}
- void swap(uuid &other) noexcept
+ auto swap(uuid &other) noexcept -> void
{
data.swap(other.data);
}
- [[nodiscard]] inline std::span<std::byte const, 16> as_bytes() const
+ [[nodiscard]] inline auto as_bytes() const
+ -> std::span<std::byte const, 16>
{
- return std::span<std::byte const, 16>(reinterpret_cast<std::byte const*>(data.data()), 16);
+ return std::span<std::byte const, 16>(
+ reinterpret_cast<std::byte const*>(data.data()),
+ 16);
}
template <typename StringType>
- [[nodiscard]] constexpr static bool is_valid_uuid(StringType const & in_str) noexcept
+ [[nodiscard]] constexpr static auto
+ is_valid_uuid(StringType const &in_str) noexcept
+ -> bool
{
auto str = to_string_view(in_str);
- bool firstDigit = true;
- size_t hasBraces = 0;
- size_t index = 0;
+ auto firstDigit = true;
+ auto hasBraces = std::size_t{0};
+ auto index = std::size_t{0};
if (str.empty())
return false;
if (str.front() == '{')
hasBraces = 1;
+
if (hasBraces && str.back() != '}')
return false;
@@ -458,7 +527,9 @@ export struct uuid {
}
template <typename StringType>
- [[nodiscard]] constexpr static std::optional<uuid> from_string(StringType const & in_str) noexcept
+ [[nodiscard]] constexpr static auto
+ from_string(StringType const & in_str) noexcept
+ -> std::optional<uuid>
{
auto str = to_string_view(in_str);
bool firstDigit = true;
@@ -503,14 +574,17 @@ export struct uuid {
private:
std::array<value_type, 16> data{ { 0 } };
- friend bool operator==(uuid const & lhs, uuid const & rhs) noexcept;
- friend bool operator<(uuid const & lhs, uuid const & rhs) noexcept;
+ friend auto operator==(uuid const &, uuid const &) noexcept -> bool;
+ friend auto operator<(uuid const &, uuid const &) noexcept -> bool;
template <class Elem, class Traits>
- friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
+ friend auto operator<<(std::basic_ostream<Elem, Traits> &s,
+ uuid const &id)
+ -> std::basic_ostream<Elem, Traits> &;
template<class CharT, class Traits, class Allocator>
- friend std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id);
+ friend auto to_string(uuid const &id)
+ -> std::basic_string<CharT, Traits, Allocator>;
friend std::hash<uuid>;
};
@@ -520,19 +594,19 @@ private:
// --------------------------------------------------------------------------------------------------------------------------
export [[nodiscard]]
-auto operator== (uuid const& lhs, uuid const& rhs) noexcept -> bool
+auto operator== (uuid const &lhs, uuid const &rhs) noexcept -> bool
{
return lhs.data == rhs.data;
}
export [[nodiscard]]
-auto operator!= (uuid const& lhs, uuid const& rhs) noexcept -> bool
+auto operator!= (uuid const &lhs, uuid const &rhs) noexcept -> bool
{
return !(lhs == rhs);
}
export [[nodiscard]]
-auto operator< (uuid const& lhs, uuid const& rhs) noexcept -> bool
+auto operator< (uuid const &lhs, uuid const &rhs) noexcept -> bool
{
return lhs.data < rhs.data;
}
@@ -541,9 +615,10 @@ export template <typename CharT, typename Traits, typename Allocator>
[[nodiscard]] auto to_string(uuid const &id)
-> std::basic_string<CharT, Traits, Allocator>
{
- std::basic_string<CharT, Traits, Allocator> uustr{empty_guid<CharT>};
+ auto uustr = std::basic_string<CharT, Traits, Allocator>(
+ std::from_range, empty_guid<CharT>);
- for (size_t i = 0, index = 0; i < 36; ++i) {
+ for (std::size_t i = 0, index = 0; i < 36; ++i) {
if (i == 8 || i == 13 || i == 18 || i == 23)
continue;
@@ -556,14 +631,14 @@ export template <typename CharT, typename Traits, typename Allocator>
}
export template <class Elem, class Traits>
-auto operator<<(std::basic_ostream<Elem, Traits>& s, uuid const &id)
- -> std::basic_ostream<Elem, Traits>&
+auto operator<<(std::basic_ostream<Elem, Traits> &s, uuid const &id)
+ -> std::basic_ostream<Elem, Traits> &
{
s << to_string(id);
return s;
}
-export void swap(uuid & lhs, uuid & rhs) noexcept
+export auto swap(uuid &lhs, uuid &rhs) noexcept -> void
{
lhs.swap(rhs);
}
@@ -608,21 +683,24 @@ struct basic_uuid_random_generator
{
using engine_type = UniformRandomNumberGenerator;
- explicit basic_uuid_random_generator(engine_type& gen)
+ explicit basic_uuid_random_generator(engine_type &gen)
: generator(&gen, [](auto) {})
{
}
- explicit basic_uuid_random_generator(engine_type* gen)
+ explicit basic_uuid_random_generator(engine_type *gen)
: generator(gen, [](auto) {})
{
}
- [[nodiscard]] uuid operator()()
+ [[nodiscard]] auto operator()() -> uuid
{
- alignas(uint32_t) uint8_t bytes[16];
+ alignas(std::uint32_t)
+ auto bytes = std::array<std::uint8_t, 16>{};
+
for (int i = 0; i < 16; i += 4)
- *reinterpret_cast<uint32_t*>(bytes + i) = distribution(*generator);
+ *reinterpret_cast<std::uint32_t *>(bytes.data() + i) =
+ distribution(*generator);
// variant must be 10xxxxxx
bytes[8] &= 0xBF;
@@ -636,7 +714,7 @@ struct basic_uuid_random_generator
}
private:
- std::uniform_int_distribution<uint32_t> distribution;
+ std::uniform_int_distribution<std::uint32_t> distribution;
std::shared_ptr<UniformRandomNumberGenerator> generator;
};
@@ -644,13 +722,13 @@ export using uuid_random_generator = basic_uuid_random_generator<std::mt19937>;
export struct uuid_name_generator
{
- explicit uuid_name_generator(uuid const& namespace_uuid) noexcept
+ explicit uuid_name_generator(uuid const &namespace_uuid) noexcept
: nsuuid(namespace_uuid)
{
}
template <typename StringType>
- [[nodiscard]] uuid operator()(StringType const & name)
+ [[nodiscard]] auto operator()(StringType const &name) -> uuid
{
reset();
process_characters(to_string_view(name));
@@ -658,32 +736,38 @@ export struct uuid_name_generator
}
private:
- void reset()
+ auto reset() -> void
{
hasher.reset();
- std::byte bytes[16];
+
auto nsbytes = nsuuid.as_bytes();
- std::ranges::copy(nsbytes, bytes);
- hasher.process_bytes(bytes, 16);
+
+ auto bytes = std::array<std::byte, 16>();
+ std::ranges::copy(nsbytes, std::ranges::begin(bytes));
+
+ hasher.process_bytes(bytes.data(), bytes.size());
}
template <typename CharT, typename Traits>
- void process_characters(std::basic_string_view<CharT, Traits> const str)
+ auto process_characters(
+ std::basic_string_view<CharT, Traits> const str) -> void
{
- for (uint32_t c : str) {
- hasher.process_byte(static_cast<uint8_t>(c & 0xFF));
+ for (std::uint32_t c : str) {
+ hasher.process_byte(static_cast<std::uint8_t>(c & 0xFF));
if constexpr (!std::is_same_v<CharT, char>) {
- hasher.process_byte(static_cast<uint8_t>((c >> 8) & 0xFF));
- hasher.process_byte(static_cast<uint8_t>((c >> 16) & 0xFF));
- hasher.process_byte(static_cast<uint8_t>((c >> 24) & 0xFF));
+ hasher.process_byte(
+ static_cast<uint8_t>((c >> 8) & 0xFF));
+ hasher.process_byte(
+ static_cast<uint8_t>((c >> 16) & 0xFF));
+ hasher.process_byte(
+ static_cast<uint8_t>((c >> 24) & 0xFF));
}
}
}
- [[nodiscard]] uuid make_uuid()
+ [[nodiscard]] auto make_uuid() -> uuid
{
- sha1::digest8_t digest;
- hasher.get_digest_bytes(digest);
+ auto digest = hasher.get_digest_bytes();
// variant must be 0b10xxxxxx
digest[8] &= 0xBF;
@@ -693,7 +777,7 @@ private:
digest[6] &= 0x5F;
digest[6] |= 0x50;
- return uuid{ digest, digest + 16 };
+ return uuid(std::span(digest).subspan(0, 16));
}
private:
@@ -708,9 +792,10 @@ export auto random_uuid() -> uuid
{
auto rd = std::random_device();
auto seed_data = std::array<int, std::mt19937::state_size> {};
-
std::ranges::generate(seed_data, std::ref(rd));
- auto seq = std::seed_seq(std::begin(seed_data), std::end(seed_data));
+
+ auto seq = std::seed_seq(std::ranges::begin(seed_data),
+ std::ranges::end(seed_data));
auto generator = std::mt19937(seq);
auto gen = uuid_random_generator{generator};
@@ -727,9 +812,10 @@ struct hash<nihil::uuid>
using argument_type = nihil::uuid;
using result_type = std::size_t;
- [[nodiscard]] result_type operator()(argument_type const &uuid) const
+ [[nodiscard]] auto operator()(argument_type const &uuid) const
+ -> result_type
{
- uint64_t l =
+ std::uint64_t l =
static_cast<uint64_t>(uuid.data[0]) << 56 |
static_cast<uint64_t>(uuid.data[1]) << 48 |
static_cast<uint64_t>(uuid.data[2]) << 40 |
@@ -738,7 +824,8 @@ struct hash<nihil::uuid>
static_cast<uint64_t>(uuid.data[5]) << 16 |
static_cast<uint64_t>(uuid.data[6]) << 8 |
static_cast<uint64_t>(uuid.data[7]);
- uint64_t h =
+
+ std::uint64_t h =
static_cast<uint64_t>(uuid.data[8]) << 56 |
static_cast<uint64_t>(uuid.data[9]) << 48 |
static_cast<uint64_t>(uuid.data[10]) << 40 |
@@ -748,12 +835,7 @@ struct hash<nihil::uuid>
static_cast<uint64_t>(uuid.data[14]) << 8 |
static_cast<uint64_t>(uuid.data[15]);
- if constexpr (sizeof(result_type) > 4) {
- return result_type(l ^ h);
- } else {
- uint64_t hash64 = l ^ h;
- return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64));
- }
+ return std::hash<std::uint64_t>{}(l ^ h);
}
};