mimic++ v9.2.1
Loading...
Searching...
No Matches
StringMatchers.hpp
Go to the documentation of this file.
1// Copyright Dominic (DNKpp) Koepke 2024 - 2025.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at
4// https://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef MIMICPP_MATCHERS_STRING_MATCHERS_HPP
7#define MIMICPP_MATCHERS_STRING_MATCHERS_HPP
8
9#include "mimic++/Fwd.hpp"
10#include "mimic++/String.hpp"
14
15#ifndef MIMICPP_DETAIL_IS_MODULE
16 #include <algorithm>
17 #include <concepts>
18 #include <ranges>
19 #include <tuple>
20 #include <utility>
21#endif
22
24{
30 {
31 } constexpr case_insensitive{};
32}
33
34namespace mimicpp::matches::detail
35{
36 template <string Target, string Pattern>
37 constexpr void check_string_compatibility() noexcept
38 {
39 static_assert(
40 std::same_as<
43 "Pattern and target string must have the same character-type.");
44 }
45
46 struct make_view_fn
47 {
48 template <string T>
49 [[nodiscard]]
50 constexpr auto operator()(T const& str) const
51 {
52 return string_traits<T>::view(str);
53 }
54 };
55
56 template <string String>
57 [[nodiscard]]
58 constexpr auto make_view(String const& str)
59 {
60 return std::invoke(make_view_fn{}, str);
61 }
62
63 template <case_foldable_string String, std::ranges::borrowed_range View>
64 [[nodiscard]]
65 constexpr auto make_case_folded_string(View&& str)
66 {
67 return std::invoke(
68 string_case_fold_converter<string_char_t<String>>{},
69 std::forward<View>(str));
70 }
71
72 struct describe_fn
73 {
74 template <string T>
75 [[nodiscard]]
76 constexpr auto operator()(T const& str) const
77 {
78 return mimicpp::print(make_view(str));
79 }
80 };
81
82 // This specialization is needed for raw char (const)* strings, for which the matcher loses information about
83 // and wrongly treats as general raw-pointer.
84 template <string T>
85 using string_arg_storage = mimicpp::detail::arg_storage<
86 T,
87 make_view_fn,
88 describe_fn>;
89
90 template <string String>
91 [[nodiscard]]
92 constexpr auto forward_store(std::remove_reference_t<String>& str)
93 {
94 return string_arg_storage<std::decay_t<String>>{
95 std::forward<String>(str)};
96 }
97}
98
100{
149
155 template <string Pattern>
156 [[nodiscard]]
157 constexpr auto eq(Pattern&& pattern)
158 {
159 return PredicateMatcher{
160 []<string T>(T&& target, auto const& patternView) {
161 detail::check_string_compatibility<T, Pattern>();
162
163 return std::ranges::equal(
164 detail::make_view(target),
165 patternView);
166 },
167 "is equal to {}",
168 "is not equal to {}",
169 std::make_tuple(detail::forward_store<Pattern>(pattern))};
170 }
171
177 template <case_foldable_string Pattern>
178 [[nodiscard]]
179 constexpr auto eq(Pattern&& pattern, [[maybe_unused]] const case_insensitive_t)
180 {
181 return PredicateMatcher{
182 []<case_foldable_string T>(T&& target, auto const& patternView) {
183 detail::check_string_compatibility<T, Pattern>();
184
185 return std::ranges::equal(
186 detail::make_case_folded_string<T>(detail::make_view(target)),
187 detail::make_case_folded_string<Pattern>(patternView));
188 },
189 "is case-insensitively equal to {}",
190 "is case-insensitively not equal to {}",
191 std::make_tuple(detail::forward_store<Pattern>(pattern))};
192 }
193
199 template <string Pattern>
200 [[nodiscard]]
201 constexpr auto starts_with(Pattern&& pattern)
202 {
203 return PredicateMatcher{
204 []<string T>(T&& target, auto const& patternView) {
205 detail::check_string_compatibility<T, Pattern>();
206
207 auto const [ignore, patternIter] = std::ranges::mismatch(
208 detail::make_view(target),
209 patternView);
210
211 return patternIter == std::ranges::end(patternView);
212 },
213 "starts with {}",
214 "starts not with {}",
215 std::make_tuple(detail::forward_store<Pattern>(pattern))};
216 }
217
223 template <string Pattern>
224 [[nodiscard]]
225 constexpr auto starts_with(Pattern&& pattern, [[maybe_unused]] const case_insensitive_t)
226 {
227 return PredicateMatcher{
228 []<case_foldable_string T>(T&& target, auto const& patternView) {
229 detail::check_string_compatibility<T, Pattern>();
230
231 auto const caseFoldedPattern = detail::make_case_folded_string<Pattern>(patternView);
232 auto const [ignore, patternIter] = std::ranges::mismatch(
233 detail::make_case_folded_string<T>(detail::make_view(target)),
234 caseFoldedPattern);
235
236 return patternIter == std::ranges::end(caseFoldedPattern);
237 },
238 "case-insensitively starts with {}",
239 "case-insensitively starts not with {}",
240 std::make_tuple(detail::forward_store<Pattern>(pattern))};
241 }
242
248 template <string Pattern>
249 [[nodiscard]]
250 constexpr auto ends_with(Pattern&& pattern)
251 {
252 return PredicateMatcher{
253 []<string T>(T&& target, auto const& patternView) {
254 detail::check_string_compatibility<T, Pattern>();
255
256 auto reversedPattern = patternView | std::views::reverse;
257 const auto [ignore, patternIter] = std::ranges::mismatch(
258 detail::make_view(target) | std::views::reverse,
259 reversedPattern);
260
261 return patternIter == std::ranges::end(reversedPattern);
262 },
263 "ends with {}",
264 "ends not with {}",
265 std::make_tuple(detail::forward_store<Pattern>(pattern))};
266 }
267
273 template <string Pattern>
274 [[nodiscard]]
275 constexpr auto ends_with(Pattern&& pattern, [[maybe_unused]] const case_insensitive_t)
276 {
277 return PredicateMatcher{
278 []<case_foldable_string T>(T&& target, auto const& patternView) {
279 detail::check_string_compatibility<T, Pattern>();
280
281 auto caseFoldedPattern = detail::make_case_folded_string<Pattern>(patternView);
282 auto reversedCaseFoldedPattern = caseFoldedPattern | std::views::reverse;
283 auto caseFoldedTargetPattern = detail::make_case_folded_string<T>(detail::make_view(target));
284 const auto [ignore, patternIter] = std::ranges::mismatch(
285 caseFoldedTargetPattern | std::views::reverse,
286 reversedCaseFoldedPattern);
287
288 return patternIter == std::ranges::end(reversedCaseFoldedPattern);
289 },
290 "case-insensitively ends with {}",
291 "case-insensitively ends not with {}",
292 std::make_tuple(detail::forward_store<Pattern>(pattern))};
293 }
294
300 template <string Pattern>
301 [[nodiscard]]
302 constexpr auto contains(Pattern&& pattern)
303 {
304 return PredicateMatcher{
305 []<string T>(T&& target, auto const& patternView) {
306 detail::check_string_compatibility<T, Pattern>();
307
308 return std::ranges::empty(patternView)
309 || !std::ranges::empty(
310 std::ranges::search(
311 detail::make_view(target),
312 patternView));
313 },
314 "contains {}",
315 "contains not {}",
316 std::make_tuple(detail::forward_store<Pattern>(pattern))};
317 }
318
324 template <string Pattern>
325 [[nodiscard]]
326 constexpr auto contains(Pattern&& pattern, [[maybe_unused]] const case_insensitive_t)
327 {
328 return PredicateMatcher{
329 []<case_foldable_string T>(T&& target, auto const& patternView) {
330 detail::check_string_compatibility<T, Pattern>();
331
332 auto caseFoldedPattern = detail::make_case_folded_string<Pattern>(patternView);
333 auto targetView = detail::make_case_folded_string<T>(detail::make_view(target));
334 return std::ranges::empty(caseFoldedPattern)
335 || !std::ranges::empty(std::ranges::search(targetView, caseFoldedPattern));
336 },
337 "case-insensitively contains {}",
338 "case-insensitively contains not {}",
339 std::make_tuple(detail::forward_store<Pattern>(pattern))};
340 }
341
345}
346
347#endif
#define MIMICPP_DETAIL_MODULE_EXPORT
Definition Config.hpp:19
Generic matcher and the basic building block of most of the built-in matchers.
Definition GeneralMatchers.hpp:75
Determines, whether the given type supports string normalization.
Definition String.hpp:379
struct mimicpp::case_insensitive_t case_insensitive
constexpr auto eq(Pattern &&pattern)
Tests, whether the target string compares equal to the expected string.
Definition StringMatchers.hpp:157
constexpr auto ends_with(Pattern &&pattern)
Tests, whether the target string ends with the pattern string.
Definition StringMatchers.hpp:250
constexpr auto contains(Pattern &&pattern)
Tests, whether the pattern string is part of the target string.
Definition StringMatchers.hpp:302
constexpr auto starts_with(Pattern &&pattern)
Tests, whether the target string starts with the pattern string.
Definition StringMatchers.hpp:201
constexpr printing::PrintFn print
Functional object, converting the given object to its textual representation.
Definition Print.hpp:183
typename string_traits< std::remove_cvref_t< T > >::char_t string_char_t
Computes the character type for the given string.
Definition String.hpp:263
Definition StringMatchers.hpp:100
Definition Call.hpp:24
Tag type, used in string matchers.
Definition StringMatchers.hpp:30
static constexpr view_t view(const std::remove_pointer_t< T > *str) noexcept
Definition String.hpp:278