diff --git a/src/libs/utils/include/utils/LiteralString.hpp b/src/libs/utils/include/utils/LiteralString.hpp new file mode 100644 index 00000000..9bcf16bd --- /dev/null +++ b/src/libs/utils/include/utils/LiteralString.hpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2024 Emeric Poupon + * + * This file is part of LMS. + * + * LMS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LMS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LMS. If not, see . + */ + +#pragma once + +#include +#include +#include + +class LiteralString +{ +public: + constexpr LiteralString() noexcept = default; + template + constexpr LiteralString(const char(&str)[N]) noexcept : _str{ str, N - 1 } { static_assert(N > 0); } + + constexpr const char* c_str() const noexcept { return _str.data(); } + constexpr std::size_t length() const noexcept { return _str.length(); } + constexpr std::string_view str() const noexcept { return _str; } + constexpr auto operator<=>(const LiteralString& other) const = default; + +private: + std::string_view _str; +}; + +namespace std +{ + template<> + struct hash + { + size_t operator()(const LiteralString& str) const + { + return hash{}(str.str()); + } + }; +} + +struct LiteralStringHash +{ + using hash_type = std::hash; + using is_transparent = void; + + [[nodiscard]] size_t operator()(const LiteralString& str) const { + return hash_type{}(str.str()); + } + + [[nodiscard]] size_t operator()(std::string_view str) const { + return hash_type{}(str); + } + + [[nodiscard]] size_t operator()(const std::string& str) const { + return hash_type{}(str); + } +}; + +struct LiteralStringEqual +{ + using is_transparent = void; + + [[nodiscard]] bool operator()(const LiteralString& lhs, const LiteralString& rhs) const { + return lhs == rhs; + } + + [[nodiscard]] bool operator()(const LiteralString& lhs, const std::string& rhs) const { + return lhs.str() == rhs; + } + + [[nodiscard]] bool operator()(const LiteralString& lhs, std::string_view rhs) const { + return lhs.str() == rhs; + } + + [[nodiscard]] bool operator()(const std::string_view& lhs, LiteralString rhs) const { + return lhs == rhs.str(); + } + + [[nodiscard]] bool operator()(const std::string& lhs, const LiteralString& rhs) const { + return lhs == rhs.str(); + } +}; diff --git a/src/libs/utils/test/CMakeLists.txt b/src/libs/utils/test/CMakeLists.txt index fbfb94e7..f6de0dbd 100644 --- a/src/libs/utils/test/CMakeLists.txt +++ b/src/libs/utils/test/CMakeLists.txt @@ -2,6 +2,7 @@ include(GoogleTest) add_executable(test-utils EnumSet.cpp + LiteralString.cpp Path.cpp RecursiveSharedMutex.cpp String.cpp diff --git a/src/libs/utils/test/LiteralString.cpp b/src/libs/utils/test/LiteralString.cpp new file mode 100644 index 00000000..b191f7af --- /dev/null +++ b/src/libs/utils/test/LiteralString.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 Emeric Poupon + * + * This file is part of LMS. + * + * LMS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LMS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LMS. If not, see . + */ + +#include +#include + +#include "utils/LiteralString.hpp" + +TEST(LiteralString, ctr) +{ + { + constexpr LiteralString foo{ "abc" }; + static_assert(foo.length() == 3); + static_assert(foo == "abc"); + static_assert(foo == LiteralString{ "abc" }); + static_assert(foo < LiteralString{ "abcd" }); + static_assert(foo > LiteralString{ "aac" }); + + EXPECT_EQ(::strlen(foo.c_str()), 3); + EXPECT_EQ(foo, LiteralString{ "abc" }); + EXPECT_GT(foo, LiteralString{ "abb" }); + EXPECT_LT(foo, LiteralString{ "abcd" }); + } + + { + constexpr LiteralString foo{ "" }; + static_assert(foo.length() == 0); + static_assert(foo == ""); + static_assert(foo == LiteralString{ "" }); + static_assert(foo < LiteralString{"a"}); + EXPECT_EQ(::strlen(foo.c_str()), 0); + } +} + +TEST(LiteralString, unordered_map) +{ + { + std::unordered_map myMap{ {"abc", 42} }; + + EXPECT_TRUE(myMap.contains("abc")); + EXPECT_TRUE(myMap.contains(LiteralString{ "abc" })); + EXPECT_FALSE(myMap.contains("abcd")); + } + + { + std::unordered_map myMap{ {"abc", 42} }; + EXPECT_TRUE(myMap.contains(std::string{ "abc" })); + EXPECT_TRUE(myMap.contains(std::string_view{ "abc" })); + EXPECT_FALSE(myMap.contains(std::string{ "abcd" })); + EXPECT_FALSE(myMap.contains(std::string_view{ "abcd" })); + } + +}