aboutsummaryrefslogtreecommitdiff
path: root/libs/kstd
diff options
context:
space:
mode:
Diffstat (limited to 'libs/kstd')
-rw-r--r--libs/kstd/CMakeLists.txt1
-rw-r--r--libs/kstd/kstd/bits/char_traits.hpp119
-rw-r--r--libs/kstd/kstd/bits/char_traits.test.cpp120
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);
+ }
+ }
+}