Skip to content

Commit d3f5b92

Browse files
authored
Merge pull request #62 from iris-cpp/add-string-algo
Add string algorithm library
2 parents cbb3f57 + 4305a13 commit d3f5b92

9 files changed

Lines changed: 360 additions & 3 deletions

File tree

‎CMakeLists.txt‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,12 @@ if(MSVC)
185185
_iris_cxx_best_practices
186186
INTERFACE
187187
/W4 /analyze /analyze:external-
188+
$<$<CONFIG:Release>:/Zi /Zo>
189+
)
190+
target_link_options(
191+
_iris_cxx_best_practices
192+
INTERFACE
193+
$<$<CONFIG:Release>:/DEBUG:FULL>
188194
)
189195

190196
else()

‎include/iris/format.hpp‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef IRIS_ZZ_FORMAT_HPP
2+
#define IRIS_ZZ_FORMAT_HPP
3+
4+
// SPDX-License-Identifier: MIT
5+
6+
#include <iris/format_traits.hpp>
7+
8+
#include <format>
9+
10+
namespace iris {
11+
12+
template<class CharT>
13+
struct no_spec_formatter
14+
{
15+
static constexpr std::basic_format_parse_context<CharT>::const_iterator
16+
parse(std::basic_format_parse_context<CharT>& ctx)
17+
{
18+
auto it = ctx.begin();
19+
if (it == ctx.end()) return it;
20+
if (*it == format_traits<CharT>::brace_close) return it;
21+
throw std::format_error("unknown format specifier");
22+
}
23+
};
24+
25+
} // iris
26+
27+
#endif

‎include/iris/format_traits.hpp‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#ifndef IRIS_ZZ_FORMAT_TRAITS_HPP
1+
#ifndef IRIS_ZZ_FORMAT_TRAITS_HPP
22
#define IRIS_ZZ_FORMAT_TRAITS_HPP
33

44
// SPDX-License-Identifier: MIT
@@ -16,8 +16,11 @@ template<>
1616
struct format_traits<char>
1717
{
1818
using char_type = char;
19+
static constexpr char_type square_brace_open = '[';
20+
static constexpr char_type paren_close = ')';
1921
static constexpr char_type brace_open = '{';
2022
static constexpr char_type brace_close = '}';
23+
static constexpr char_type comma = ',';
2124

2225
template<class T>
2326
static constexpr std::basic_format_string<char_type, std::type_identity_t<T>>
@@ -28,8 +31,11 @@ template<>
2831
struct format_traits<wchar_t>
2932
{
3033
using char_type = wchar_t;
34+
static constexpr char_type square_brace_open = L'[';
35+
static constexpr char_type paren_close = L')';
3136
static constexpr char_type brace_open = L'{';
3237
static constexpr char_type brace_close = L'}';
38+
static constexpr char_type comma = L',';
3339

3440
template<class T>
3541
static constexpr std::basic_format_string<char_type, std::type_identity_t<T>>

‎include/iris/string.hpp‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
// SPDX-License-Identifier: MIT
55

6+
#include <iris/config.hpp>
7+
68
#include <concepts>
79
#include <string>
810
#include <string_view>

‎include/iris/string_algo.hpp‎

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#ifndef IRIS_ZZ_STRING_ALGO_HPP
2+
#define IRIS_ZZ_STRING_ALGO_HPP
3+
4+
// SPDX-License-Identifier: MIT
5+
6+
#include <iris/config.hpp>
7+
#include <iris/string.hpp>
8+
9+
#include <string>
10+
#include <string_view>
11+
#include <ranges>
12+
#include <algorithm>
13+
14+
namespace iris {
15+
16+
namespace detail {
17+
18+
template<class CharT>
19+
struct string_algo_traits;
20+
21+
template<>
22+
struct string_algo_traits<char>
23+
{
24+
static constexpr char space = ' ';
25+
static constexpr std::string_view ordinary_spaces{"\u0020\t\r\n"};
26+
static constexpr std::string_view space_like_variant_chars{"\t\r\n"};
27+
};
28+
29+
template<>
30+
struct string_algo_traits<char32_t>
31+
{
32+
static constexpr char32_t space = U' ';
33+
static constexpr std::u32string_view ordinary_spaces{U"\u0020\u3000\t\r\n"}; // includes Japanese space
34+
static constexpr std::u32string_view space_like_variant_chars{U"\u3000\t\r\n"};
35+
};
36+
37+
} // detail
38+
39+
template<class CharT, class Traits>
40+
constexpr void trim_edges(
41+
std::basic_string<CharT, Traits>& input,
42+
std::basic_string_view<CharT, Traits> const spaces = detail::string_algo_traits<CharT>::ordinary_spaces
43+
)
44+
{
45+
auto const first = input.find_first_not_of(spaces);
46+
if (first == std::basic_string<CharT, Traits>::npos) {
47+
input.clear();
48+
return;
49+
}
50+
input.erase(0, first);
51+
52+
auto const last = input.find_last_not_of(spaces);
53+
input.erase(last + 1);
54+
}
55+
56+
template<int = 0>
57+
[[nodiscard]] constexpr std::string trim_edges_copy(
58+
std::string_view input,
59+
std::string_view const spaces = detail::string_algo_traits<char>::ordinary_spaces
60+
)
61+
{
62+
std::string buf(input);
63+
iris::trim_edges(buf, spaces);
64+
return buf;
65+
}
66+
67+
template<int = 0>
68+
[[nodiscard]] constexpr std::u32string trim_edges_copy(
69+
std::u32string_view input,
70+
std::u32string_view const spaces = detail::string_algo_traits<char32_t>::ordinary_spaces
71+
)
72+
{
73+
std::u32string buf(input);
74+
iris::trim_edges(buf, spaces);
75+
return buf;
76+
}
77+
78+
79+
template<class CharT, class Traits>
80+
constexpr void normalize_spaces(
81+
std::basic_string<CharT, Traits>& input,
82+
std::basic_string_view<CharT, Traits> const space_like_variant_chars = detail::string_algo_traits<CharT>::space_like_variant_chars,
83+
CharT const to_space = detail::string_algo_traits<CharT>::space
84+
)
85+
{
86+
std::ranges::replace_if(input, [&](CharT const ch) {
87+
return space_like_variant_chars.contains(ch);
88+
}, to_space);
89+
}
90+
91+
template<int = 0>
92+
[[nodiscard]] constexpr std::string normalize_spaces_copy(
93+
std::string_view input,
94+
std::string_view const space_like_variant_chars = detail::string_algo_traits<char>::space_like_variant_chars,
95+
char const to_space = detail::string_algo_traits<char>::space
96+
)
97+
{
98+
std::string buf(input);
99+
iris::normalize_spaces(buf, space_like_variant_chars, to_space);
100+
return buf;
101+
}
102+
103+
template<int = 0>
104+
[[nodiscard]] constexpr std::u32string normalize_spaces_copy(
105+
std::u32string_view input,
106+
std::u32string_view const space_like_variant_chars = detail::string_algo_traits<char32_t>::space_like_variant_chars,
107+
char32_t const to_space = detail::string_algo_traits<char32_t>::space
108+
)
109+
{
110+
std::u32string buf(input);
111+
iris::normalize_spaces(buf, space_like_variant_chars, to_space);
112+
return buf;
113+
}
114+
115+
116+
template<class CharT, class Traits>
117+
constexpr void compact_spaces(
118+
std::basic_string<CharT, Traits>& input,
119+
std::basic_string_view<CharT, Traits> const spaces = detail::string_algo_traits<CharT>::ordinary_spaces,
120+
CharT const to_space = detail::string_algo_traits<CharT>::space
121+
)
122+
{
123+
iris::trim_edges(input, spaces);
124+
if (input.empty()) return;
125+
126+
std::size_t w = 0;
127+
bool in_space = false;
128+
129+
for (CharT const c : input) {
130+
if (spaces.contains(c)) {
131+
if (!in_space) {
132+
input[w++] = to_space;
133+
}
134+
in_space = true;
135+
136+
} else {
137+
input[w++] = c;
138+
in_space = false;
139+
}
140+
}
141+
input.resize(w);
142+
}
143+
144+
template<int = 0>
145+
[[nodiscard]] constexpr std::string compact_spaces_copy(
146+
std::string_view input,
147+
std::string_view const spaces = detail::string_algo_traits<char>::ordinary_spaces,
148+
char const to_space = detail::string_algo_traits<char>::space
149+
)
150+
{
151+
std::string buf(input);
152+
iris::compact_spaces(buf, spaces, to_space);
153+
return buf;
154+
}
155+
156+
template<int = 0>
157+
[[nodiscard]] constexpr std::u32string compact_spaces_copy(
158+
std::u32string_view input,
159+
std::u32string_view const spaces = detail::string_algo_traits<char32_t>::ordinary_spaces,
160+
char32_t const to_space = detail::string_algo_traits<char32_t>::space
161+
)
162+
{
163+
std::u32string buf(input);
164+
iris::compact_spaces(buf, spaces, to_space);
165+
return buf;
166+
}
167+
168+
} // iris
169+
170+
#endif

‎include/iris/unicode/string.hpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2525
DEALINGS IN THE SOFTWARE.
2626
*/
2727

28-
#ifndef IRIS_UNICODE_STRING_HPP
29-
#define IRIS_UNICODE_STRING_HPP
28+
#ifndef IRIS_ZZ_UNICODE_STRING_HPP
29+
#define IRIS_ZZ_UNICODE_STRING_HPP
3030

3131
#include <algorithm>
3232
#include <concepts>

‎test/CMakeLists.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ if(PROJECT_IS_TOP_LEVEL)
183183
indirect
184184
colorize_format
185185
preprocess
186+
string_algo
186187
)
187188

188189
foreach(test_name IN LISTS IRIS_TEST_IRIS_TESTS)

‎test/iris_test.hpp‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,19 @@
66
#include <iris/config.hpp>
77

88
#include <catch2/catch_test_macros.hpp> // IWYU pragma: export
9+
#include <catch2/catch_tostring.hpp>
10+
11+
#include <ranges>
12+
#include <format>
13+
14+
template<std::formattable<char> T>
15+
requires (!std::ranges::range<T>)
16+
struct Catch::StringMaker<T>
17+
{
18+
static std::string convert(T const& value)
19+
{
20+
return std::format("{}", value);
21+
}
22+
};
923

1024
#endif

0 commit comments

Comments
 (0)