diff options
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/kstd/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | libs/kstd/kstd/bits/char_traits.hpp | 119 | ||||
| -rw-r--r-- | libs/kstd/kstd/bits/char_traits.test.cpp | 120 |
3 files changed, 240 insertions, 0 deletions
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 <kstd/string> + +#include <kstd/allocator> + +#include <algorithm> +#include <cstddef> + +namespace kstd +{ + + template<typename CharacterType> + struct char_traits; + + template<> + struct char_traits<char> + { + 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<std::ptrdiff_t>(count), value); + return destination; + } + + constexpr auto static eq(char_type lhs, char_type rhs) noexcept -> bool + { + return static_cast<unsigned char>(lhs) == static_cast<unsigned char>(rhs); + } + + constexpr auto static lt(char_type lhs, char_type rhs) noexcept -> bool + { + return static_cast<unsigned char>(lhs) < static_cast<unsigned char>(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<int_type>(lhs[i]) - static_cast<int_type>(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<char_type>(value); + } + + constexpr auto static to_int_type(char_type value) noexcept -> int_type + { + return static_cast<int_type>(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 <kstd/bits/char_traits.hpp> + +#include <catch2/catch_test_macros.hpp> + +#include <type_traits> + +SCENARIO("Character traits for char", "[string]") +{ + using traits = kstd::char_traits<char>; + + THEN("Type aliases") + { + REQUIRE(std::is_same_v<char, kstd::char_traits<char>::char_type>); + REQUIRE(std::is_same_v<int, kstd::char_traits<char>::int_type>); + REQUIRE(std::is_same_v<long long, kstd::char_traits<char>::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); + } + } +} |
