Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,12 @@ if(MSVC)
_iris_cxx_best_practices
INTERFACE
/W4 /analyze /analyze:external-
$<$<CONFIG:Release>:/Zi /Zo>
)
target_link_options(
_iris_cxx_best_practices
INTERFACE
$<$<CONFIG:Release>:/DEBUG:FULL>
)

else()
Expand Down
27 changes: 27 additions & 0 deletions include/iris/format.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef IRIS_ZZ_FORMAT_HPP
#define IRIS_ZZ_FORMAT_HPP

// SPDX-License-Identifier: MIT

#include <iris/format_traits.hpp>

#include <format>

namespace iris {

template<class CharT>
struct no_spec_formatter
{
static constexpr std::basic_format_parse_context<CharT>::const_iterator
parse(std::basic_format_parse_context<CharT>& ctx)
{
auto it = ctx.begin();
if (it == ctx.end()) return it;
if (*it == format_traits<CharT>::brace_close) return it;
throw std::format_error("unknown format specifier");
}
};

} // iris

#endif
8 changes: 7 additions & 1 deletion include/iris/format_traits.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#ifndef IRIS_ZZ_FORMAT_TRAITS_HPP
#ifndef IRIS_ZZ_FORMAT_TRAITS_HPP
#define IRIS_ZZ_FORMAT_TRAITS_HPP

// SPDX-License-Identifier: MIT
Expand All @@ -16,8 +16,11 @@ template<>
struct format_traits<char>
{
using char_type = char;
static constexpr char_type square_brace_open = '[';
static constexpr char_type paren_close = ')';
static constexpr char_type brace_open = '{';
static constexpr char_type brace_close = '}';
static constexpr char_type comma = ',';

template<class T>
static constexpr std::basic_format_string<char_type, std::type_identity_t<T>>
Expand All @@ -28,8 +31,11 @@ template<>
struct format_traits<wchar_t>
{
using char_type = wchar_t;
static constexpr char_type square_brace_open = L'[';
static constexpr char_type paren_close = L')';
static constexpr char_type brace_open = L'{';
static constexpr char_type brace_close = L'}';
static constexpr char_type comma = L',';

template<class T>
static constexpr std::basic_format_string<char_type, std::type_identity_t<T>>
Expand Down
2 changes: 2 additions & 0 deletions include/iris/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

// SPDX-License-Identifier: MIT

#include <iris/config.hpp>

#include <concepts>
#include <string>
#include <string_view>
Expand Down
170 changes: 170 additions & 0 deletions include/iris/string_algo.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#ifndef IRIS_ZZ_STRING_ALGO_HPP
#define IRIS_ZZ_STRING_ALGO_HPP

// SPDX-License-Identifier: MIT

#include <iris/config.hpp>
#include <iris/string.hpp>

#include <string>
#include <string_view>
#include <ranges>
#include <algorithm>

namespace iris {

namespace detail {

template<class CharT>
struct string_algo_traits;

template<>
struct string_algo_traits<char>
{
static constexpr char space = ' ';
static constexpr std::string_view ordinary_spaces{"\u0020\t\r\n"};
static constexpr std::string_view space_like_variant_chars{"\t\r\n"};
};

template<>
struct string_algo_traits<char32_t>
{
static constexpr char32_t space = U' ';
static constexpr std::u32string_view ordinary_spaces{U"\u0020\u3000\t\r\n"}; // includes Japanese space
static constexpr std::u32string_view space_like_variant_chars{U"\u3000\t\r\n"};
};

} // detail

template<class CharT, class Traits>
constexpr void trim_edges(
std::basic_string<CharT, Traits>& input,
std::basic_string_view<CharT, Traits> const spaces = detail::string_algo_traits<CharT>::ordinary_spaces
)
{
auto const first = input.find_first_not_of(spaces);
if (first == std::basic_string<CharT, Traits>::npos) {
input.clear();
return;
}
input.erase(0, first);

auto const last = input.find_last_not_of(spaces);
input.erase(last + 1);
}

template<int = 0>
[[nodiscard]] constexpr std::string trim_edges_copy(
std::string_view input,
std::string_view const spaces = detail::string_algo_traits<char>::ordinary_spaces
)
{
std::string buf(input);
iris::trim_edges(buf, spaces);
return buf;
}

template<int = 0>
[[nodiscard]] constexpr std::u32string trim_edges_copy(
std::u32string_view input,
std::u32string_view const spaces = detail::string_algo_traits<char32_t>::ordinary_spaces
)
{
std::u32string buf(input);
iris::trim_edges(buf, spaces);
return buf;
}


template<class CharT, class Traits>
constexpr void normalize_spaces(
std::basic_string<CharT, Traits>& input,
std::basic_string_view<CharT, Traits> const space_like_variant_chars = detail::string_algo_traits<CharT>::space_like_variant_chars,
CharT const to_space = detail::string_algo_traits<CharT>::space
)
{
std::ranges::replace_if(input, [&](CharT const ch) {
return space_like_variant_chars.contains(ch);
}, to_space);
}

template<int = 0>
[[nodiscard]] constexpr std::string normalize_spaces_copy(
std::string_view input,
std::string_view const space_like_variant_chars = detail::string_algo_traits<char>::space_like_variant_chars,
char const to_space = detail::string_algo_traits<char>::space
)
{
std::string buf(input);
iris::normalize_spaces(buf, space_like_variant_chars, to_space);
return buf;
}

template<int = 0>
[[nodiscard]] constexpr std::u32string normalize_spaces_copy(
std::u32string_view input,
std::u32string_view const space_like_variant_chars = detail::string_algo_traits<char32_t>::space_like_variant_chars,
char32_t const to_space = detail::string_algo_traits<char32_t>::space
)
{
std::u32string buf(input);
iris::normalize_spaces(buf, space_like_variant_chars, to_space);
return buf;
}


template<class CharT, class Traits>
constexpr void compact_spaces(
std::basic_string<CharT, Traits>& input,
std::basic_string_view<CharT, Traits> const spaces = detail::string_algo_traits<CharT>::ordinary_spaces,
CharT const to_space = detail::string_algo_traits<CharT>::space
)
{
iris::trim_edges(input, spaces);
if (input.empty()) return;

std::size_t w = 0;
bool in_space = false;

for (CharT const c : input) {
if (spaces.contains(c)) {
if (!in_space) {
input[w++] = to_space;
}
in_space = true;

} else {
input[w++] = c;
in_space = false;
}
}
input.resize(w);
}

template<int = 0>
[[nodiscard]] constexpr std::string compact_spaces_copy(
std::string_view input,
std::string_view const spaces = detail::string_algo_traits<char>::ordinary_spaces,
char const to_space = detail::string_algo_traits<char>::space
)
{
std::string buf(input);
iris::compact_spaces(buf, spaces, to_space);
return buf;
}

template<int = 0>
[[nodiscard]] constexpr std::u32string compact_spaces_copy(
std::u32string_view input,
std::u32string_view const spaces = detail::string_algo_traits<char32_t>::ordinary_spaces,
char32_t const to_space = detail::string_algo_traits<char32_t>::space
)
{
std::u32string buf(input);
iris::compact_spaces(buf, spaces, to_space);
return buf;
}

} // iris

#endif
4 changes: 2 additions & 2 deletions include/iris/unicode/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

#ifndef IRIS_UNICODE_STRING_HPP
#define IRIS_UNICODE_STRING_HPP
#ifndef IRIS_ZZ_UNICODE_STRING_HPP
#define IRIS_ZZ_UNICODE_STRING_HPP

#include <algorithm>
#include <concepts>
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ if(PROJECT_IS_TOP_LEVEL)
indirect
colorize_format
preprocess
string_algo
)

foreach(test_name IN LISTS IRIS_TEST_IRIS_TESTS)
Expand Down
14 changes: 14 additions & 0 deletions test/iris_test.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,19 @@
#include <iris/config.hpp>

#include <catch2/catch_test_macros.hpp> // IWYU pragma: export
#include <catch2/catch_tostring.hpp>

#include <ranges>
#include <format>

template<std::formattable<char> T>
requires (!std::ranges::range<T>)
struct Catch::StringMaker<T>
{
static std::string convert(T const& value)
{
return std::format("{}", value);
}
};

#endif
Loading
Loading