From 125e82863d66cf2a25fdcba967ce5a6fd9a55d12 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 10 Jun 2026 17:23:07 +0200 Subject: kstd: add basic char_traits implementation --- libs/kstd/CMakeLists.txt | 1 + libs/kstd/kstd/bits/char_traits.hpp | 119 ++++++++++++++++++++++++++++++ libs/kstd/kstd/bits/char_traits.test.cpp | 120 +++++++++++++++++++++++++++++++ 3 files changed, 240 insertions(+) create mode 100644 libs/kstd/kstd/bits/char_traits.hpp create mode 100644 libs/kstd/kstd/bits/char_traits.test.cpp (limited to 'libs/kstd') diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index 0f64761..36bacfc 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -77,6 +77,7 @@ if(BUILD_TESTING) "kstd/flat_map.test.cpp" "kstd/format.test.cpp" "kstd/vector.test.cpp" + "kstd/bits/char_traits.test.cpp" "kstd/bits/observer_ptr.test.cpp" "kstd/test_support/os_panic.test.cpp" "kstd/string.test.cpp" diff --git a/libs/kstd/kstd/bits/char_traits.hpp b/libs/kstd/kstd/bits/char_traits.hpp new file mode 100644 index 0000000..b9a4a03 --- /dev/null +++ b/libs/kstd/kstd/bits/char_traits.hpp @@ -0,0 +1,119 @@ +#ifndef KSTD_BITS_CHAR_TRAITS_HPP +#define KSTD_BITS_CHAR_TRAITS_HPP + +// IWYU pragma: private, include + +#include + +#include +#include + +namespace kstd +{ + + template + struct char_traits; + + template<> + struct char_traits + { + using char_type = char; + using int_type = int; + using off_type = long long; + + constexpr auto static assign(char_type & lhs, char_type const & rhs) noexcept -> void + { + lhs = rhs; + } + + constexpr auto static assign(char_type * destination, std::size_t count, char_type value) noexcept -> char_type * + { + std::ranges::fill_n(destination, static_cast(count), value); + return destination; + } + + constexpr auto static eq(char_type lhs, char_type rhs) noexcept -> bool + { + return static_cast(lhs) == static_cast(rhs); + } + + constexpr auto static lt(char_type lhs, char_type rhs) noexcept -> bool + { + return static_cast(lhs) < static_cast(rhs); + } + + constexpr auto static move(char_type * destination, char_type const * source, std::size_t count) noexcept + -> char_type * + { + std::ranges::move_backward(source, source + count, destination); + return destination; + } + + constexpr auto static copy(char_type * destination, char_type const * source, std::size_t count) noexcept + -> char_type * + { + std::ranges::copy(source, source + count, destination); + return destination; + } + + constexpr auto static compare(char_type const * lhs, char_type const * rhs, std::size_t count) noexcept -> int + { + for (auto i = 0uz; i < count; ++i) + { + auto comparison_result = static_cast(lhs[i]) - static_cast(rhs[i]); + if (comparison_result) + { + return comparison_result; + } + } + return 0; + } + + constexpr auto static length(char_type const * string) noexcept -> std::size_t + { + auto string_length = 0uz; + for (; string[string_length] != char_type{}; ++string_length) + ; + return string_length; + } + + constexpr auto static find(char_type const * string, std::size_t count, char_type const & needle) noexcept + -> char_type const * + { + auto found = std::ranges::find(string, string + count, needle); + if (found == string + count) + { + return nullptr; + } + return found; + } + + constexpr auto static to_char_type(int_type value) noexcept -> char_type + { + return static_cast(value); + } + + constexpr auto static to_int_type(char_type value) noexcept -> int_type + { + return static_cast(value); + } + + constexpr auto static eq_int_type(int_type lhs, int_type rhs) noexcept -> bool + { + return lhs == rhs; + } + + constexpr auto static eof() noexcept -> int_type + { + return -1; + } + + constexpr auto static not_eof(int_type value) noexcept -> int_type + { + return value == eof() ? 0 : value; + } + }; + +} // namespace kstd + +#endif diff --git a/libs/kstd/kstd/bits/char_traits.test.cpp b/libs/kstd/kstd/bits/char_traits.test.cpp new file mode 100644 index 0000000..4864c37 --- /dev/null +++ b/libs/kstd/kstd/bits/char_traits.test.cpp @@ -0,0 +1,120 @@ +#include + +#include + +#include + +SCENARIO("Character traits for char", "[string]") +{ + using traits = kstd::char_traits; + + THEN("Type aliases") + { + REQUIRE(std::is_same_v::char_type>); + REQUIRE(std::is_same_v::int_type>); + REQUIRE(std::is_same_v::off_type>); + } + + GIVEN("two unequal characters 'a' and 'B'") + { + auto const a = 'a'; + auto const B = 'B'; + + WHEN("comparing the two") + { + THEN("eq(a, a) returns true") + { + REQUIRE(traits::eq(a, a)); + } + + THEN("eq(a, B) returns false") + { + REQUIRE_FALSE(traits::eq(a, B)); + } + + THEN("eq(B, a) returns false") + { + REQUIRE_FALSE(traits::eq(B, a)); + } + + THEN("lt(a,a) returns false") + { + REQUIRE_FALSE(traits::lt(a, a)); + } + + THEN("lt(a,B) returns false") + { + REQUIRE_FALSE(traits::lt(a, B)); + } + + THEN("lt(B,a) returns true") + { + REQUIRE(traits::lt(B, a)); + } + + THEN("eq_int_type(a, a) returns true") + { + REQUIRE(traits::eq_int_type(a, a)); + } + + THEN("eq_int_type(a, B) returns false") + { + REQUIRE_FALSE(traits::eq_int_type(a, B)); + } + + THEN("eq_int_type(B, a) returns false") + { + REQUIRE_FALSE(traits::eq_int_type(B, a)); + } + } + } + + GIVEN("two unequal strings 'abc', 'DEFG'") + { + auto const abc = "abc"; + auto const abDe = "abDe"; + + WHEN("comparing the two") + { + THEN("compare(abc, abc, 3) returns 0") + { + REQUIRE(traits::compare(abc, abc, 3) == 0); + } + + THEN("compare(abc, abDe, 2) returns 0") + { + REQUIRE(traits::compare(abc, abDe, 2) == 0); + } + + THEN("compare(abc, abDe, 3) returns >0") + { + REQUIRE(traits::compare(abc, abDe, 3) > 0); + } + + THEN("compare(abDe, abc, 3) returns <0") + { + REQUIRE(traits::compare(abDe, abc, 3) < 0); + } + } + } + + GIVEN("The string 'abcd'") + { + auto const abcd = "abcd"; + + THEN("length(abcd) returns 4") + { + REQUIRE(traits::length(abcd) == 4); + } + + THEN("find(abcd, 4, b) returns a pointer to b") + { + REQUIRE(*traits::find(abcd, 4, 'b') == 'b'); + } + + THEN("find(abcd, 4, q) returns a null pointer") + { + REQUIRE(traits::find(abcd, 4, 'q') == nullptr); + } + } +} -- cgit v1.2.3