diff --git a/CMakeLists.txt b/CMakeLists.txt index 64fa6f0..70c5a80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ mark_as_advanced(ENABLE_PROFILING) set(SOURCE_LIST "src/filerd.cpp" "src/string.cpp" "src/binary.cpp" "src/static_string.cpp" "src/threadpool.cpp") add_library(ensure OBJECT "src/ensure.cpp") -target_compile_options(ensure PRIVATE -Wall -Wextra -pedantic -std=c++17) +target_compile_options(ensure PRIVATE -Wall -Wextra -pedantic -std=c++20) if(ENABLE_SHARED) add_library(rexy SHARED ${SOURCE_LIST}) set_target_properties(rexy PROPERTIES SOVERSION "${librexy_VERSION_MAJOR}.${librexy_VERSION_MINOR}") @@ -39,8 +39,8 @@ if(BUILD_TESTS) add_subdirectory(tests) endif() -set(LIBREXY_PUBLIC_HEADERS "include/rexy/rexy.hpp" "include/rexy/algorithm.hpp" "include/rexy/utility.hpp" "include/rexy/basic_string_hash.hpp" "include/rexy/hash.hpp" "include/rexy/static_string_hash.hpp" "include/rexy/string_hash.hpp" "include/rexy/mpmc_queue.hpp" "include/rexy/mpmc_queue.tpp" "include/rexy/traits.hpp" "include/rexy/steal.hpp" "include/rexy/binary.hpp" "include/rexy/expression.hpp" "include/rexy/binary_base.hpp" "include/rexy/binary_base.tpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/filerd.hpp" "include/rexy/string_base.tpp" "include/rexy/allocator.hpp" "include/rexy/meta.hpp" "include/rexy/buffer.hpp" "include/rexy/buffer.tpp") -target_compile_options(rexy PRIVATE -Wall -Wextra -pedantic -std=c++17) +set(LIBREXY_PUBLIC_HEADERS "include/rexy/rexy.hpp" "include/rexy/algorithm.hpp" "include/rexy/utility.hpp" "include/rexy/basic_string_hash.hpp" "include/rexy/hash.hpp" "include/rexy/static_string_hash.hpp" "include/rexy/string_hash.hpp" "include/rexy/mpmc_queue.hpp" "include/rexy/mpmc_queue.tpp" "include/rexy/traits.hpp" "include/rexy/steal.hpp" "include/rexy/binary.hpp" "include/rexy/expression.hpp" "include/rexy/binary_base.hpp" "include/rexy/binary_base.tpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/filerd.hpp" "include/rexy/string_base.tpp" "include/rexy/allocator.hpp" "include/rexy/meta.hpp" "include/rexy/buffer.hpp" "include/rexy/buffer.tpp" "include/rexy/debug_print.hpp" "include/rexy/deferred.hpp" "include/rexy/demangle.hpp" "include/rexy/enum_traits.hpp" "include/rexy/source_location.hpp") +target_compile_options(rexy PRIVATE -Wall -Wextra -pedantic -std=c++20) install(TARGETS rexy ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/include/rexy/debug_print.hpp b/include/rexy/debug_print.hpp new file mode 100644 index 0000000..55f5c77 --- /dev/null +++ b/include/rexy/debug_print.hpp @@ -0,0 +1,155 @@ +/** + This file is a part of rexy's general purpose library + Copyright (C) 2022 rexy712 + + This program 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. + + This program 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 this program. If not, see . +*/ + +#ifndef REXY_DEBUG_PRINT_HPP +#define REXY_DEBUG_PRINT_HPP + +#ifndef REXY_ENABLE_DEBUG_LEVEL + #define REXY_ENABLE_DEBUG_LEVEL 0 +#endif + +#ifndef REXY_ENABLE_COLOR_DEBUG + #define REXY_ENABLE_COLOR_DEBUG 1 +#endif + +//Debug output section +#if REXY_ENABLE_DEBUG_LEVEL > 0 + #define REXY_ENABLE_DEBUG_OUTPUT +#endif +#if REXY_ENABLE_DEBUG_LEVEL > 2 + #define REXY_ENABLE_DEBUG_VERBOSE_OUTPUT +#endif + + +#ifdef REXY_ENABLE_DEBUG_OUTPUT + #include //fprintf, vfprintf + #include //forward + + #include "source_location.hpp" + + + namespace rexy::debug{ + namespace detail{ + static constexpr const char color_red[] = "\033[38;5;9m"; + static constexpr const char color_yellow[] = "\033[38;5;11m"; + static constexpr const char color_green[] = "\033[38;5;2m"; + static constexpr const char color_blue[] = "\033[38;5;12m"; + static constexpr const char color_clear[] = "\033[0m"; + } + template + struct print{ + explicit print(Args&&... args, const rexy::source_location& loc = rexy::source_location::current()){ + std::fprintf(stderr, "%s:%s:%d: ", loc.file_name(), loc.function_name(), loc.line()); + std::fprintf(stderr, std::forward(args)...); + } + print(const print&) = delete; + print(print&&) = delete; + print& operator=(const print&) = delete; + print& operator=(print&&) = delete; + }; + template + print(Args&&...) -> print; + #ifdef REXY_ENABLE_COLOR_DEBUG + template + struct print_info{ + explicit print_info(Args&&... args, const rexy::source_location& loc = rexy::source_location::current()){ + std::fprintf(stderr, "%s", detail::color_blue); + std::fprintf(stderr, "%s:%s:%d: ", loc.file_name(), loc.function_name(), loc.line()); + std::fprintf(stderr, std::forward(args)...); + std::fprintf(stderr, "%s", detail::color_clear); + } + print_info(const print_info&) = delete; + print_info(print_info&&) = delete; + print_info& operator=(const print_info&) = delete; + print_info& operator=(print_info&&) = delete; + }; + template + print_info(Args&&...) -> print_info; + template + struct print_warn{ + explicit print_warn(Args&&... args, const rexy::source_location& loc = rexy::source_location::current()){ + std::fprintf(stderr, "%s", detail::color_yellow); + std::fprintf(stderr, "%s:%s:%d: ", loc.file_name(), loc.function_name(), loc.line()); + std::fprintf(stderr, std::forward(args)...); + std::fprintf(stderr, "%s", detail::color_clear); + } + print_warn(const print_warn&) = delete; + print_warn(print_warn&&) = delete; + print_warn& operator=(const print_warn&) = delete; + print_warn& operator=(print_warn&&) = delete; + }; + template + print_warn(Args&&...) -> print_warn; + template + struct print_error{ + explicit print_error(Args&&... args, const rexy::source_location& loc = rexy::source_location::current()){ + std::fprintf(stderr, "%s", detail::color_red); + std::fprintf(stderr, "%s:%s:%d: ", loc.file_name(), loc.function_name(), loc.line()); + std::fprintf(stderr, std::forward(args)...); + std::fprintf(stderr, "%s", detail::color_clear); + } + print_error(const print_error&) = delete; + print_error(print_error&&) = delete; + print_error& operator=(const print_error&) = delete; + print_error& operator=(print_error&&) = delete; + }; + template + print_error(Args&&...) -> print_error; + #else + template + using print_info = print; + template + using print_warn = print; + template + using print_error = print; + #endif //REXY_ENABLE_COLOR_DEBUG + + #ifdef REXY_ENABLE_DEBUG_VERBOSE_OUTPUT + namespace verbose{ + template + using print = rexy::debug::print; + template + using print_info = rexy::debug::print_info; + template + using print_warn = rexy::debug::print_warn; + template + using print_error = rexy::debug::print_error; + } + #else + namespace verbose{ + static constexpr inline void print(...){} + static constexpr inline void print_warn(...){} + static constexpr inline void print_error(...){} + static constexpr inline void print_info(...){} + } + #endif //REXY_ENABLE_DEBUG_VERBOSE_OUTPUT + } +#else + static constexpr inline void print(...){} + static constexpr inline void print_warn(...){} + static constexpr inline void print_error(...){} + static constexpr inline void print_info(...){} + namespace verbose{ + static constexpr inline void print(...){} + static constexpr inline void print_warn(...){} + static constexpr inline void print_error(...){} + static constexpr inline void print_info(...){} + } +#endif //REXY_ENABLE_DEBUG_OUTPUT + +#endif diff --git a/include/rexy/deferred.hpp b/include/rexy/deferred.hpp new file mode 100644 index 0000000..d246b09 --- /dev/null +++ b/include/rexy/deferred.hpp @@ -0,0 +1,131 @@ +/** + This file is a part of rexy's general purpose library + Copyright (C) 2022 rexy712 + + This program 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. + + This program 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 this program. If not, see . +*/ + +#ifndef REXY_UTIL_DEFERRED_HPP +#define REXY_UTIL_DEFERRED_HPP + +#include +#include //forward, index_sequence + +namespace rexy{ + template + class deferred + { + public: + using value_type = T; + + private: + std::tuple m_args; + + public: + template + constexpr deferred(FArgs&&... args); + + deferred(const deferred&) = default; + deferred(deferred&&) = default; + ~deferred(void) = default; + deferred& operator=(const deferred&) = default; + deferred& operator=(deferred&&) = default; + + constexpr value_type value(void); + constexpr operator value_type(void); + + private: + template + constexpr value_type get_value_(std::index_sequence); + }; + + template + class deferred_function + { + public: + using ret_t = decltype(std::declval()(std::declval()...)); + + private: + Fn m_fn; + std::tuple m_args; + + public: + template + constexpr deferred_function(F&& f, FArgs&&... args); + + constexpr decltype(auto) operator()(void); + + constexpr decltype(auto) value(void); + constexpr operator ret_t(void); + + private: + template + constexpr decltype(auto) get_value_(std::index_sequence); + }; + + template + template + constexpr deferred::deferred(FArgs&&... args): + m_args{std::forward(args)...}{} + template + constexpr auto deferred::value(void) -> value_type{ + return get_value_(std::make_index_sequence()); + } + template + constexpr deferred::operator value_type(void){ + return get_value_(std::make_index_sequence()); + } + template + template + constexpr auto deferred::get_value_(std::index_sequence) -> value_type{ + return T{std::forward>(std::get(m_args))...}; + } + + template + template + constexpr deferred_function::deferred_function(F&& f, FArgs&&... args): + m_fn(std::forward(f)), + m_args{std::forward(args)...}{} + + template + constexpr decltype(auto) deferred_function::operator()(void){ + return get_value_(std::make_index_sequence()); + } + + template + constexpr decltype(auto) deferred_function::value(void){ + return get_value_(std::make_index_sequence()); + } + template + constexpr deferred_function::operator ret_t(void){ + return get_value_(std::make_index_sequence()); + } + template + template + constexpr decltype(auto) deferred_function::get_value_(std::index_sequence){ + return std::forward(m_fn)(std::forward>(std::get(m_args))...); + } + + template + deferred_function(Fn&&, Args&&...) -> deferred_function; + + + template + deferred make_deferred(Args&&... args){ + return deferred(std::forward(args)...); + } + +} + +#endif diff --git a/include/rexy/demangle.hpp b/include/rexy/demangle.hpp new file mode 100644 index 0000000..7209662 --- /dev/null +++ b/include/rexy/demangle.hpp @@ -0,0 +1,29 @@ +/** + This file is a part of rexy's general purpose library + Copyright (C) 2022 rexy712 + + This program 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. + + This program 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 this program. If not, see . +*/ + +#ifndef REXY_UTIL_DEMANGLE_HPP +#define REXY_UTIL_DEMANGLE_HPP + +#include + +namespace rexy{ + std::string demangle(const char* name); +} + +#endif + diff --git a/include/rexy/enum_traits.hpp b/include/rexy/enum_traits.hpp new file mode 100644 index 0000000..6642388 --- /dev/null +++ b/include/rexy/enum_traits.hpp @@ -0,0 +1,204 @@ +/** + This file is a part of rexy's general purpose library + Copyright (C) 2022 rexy712 + + This program 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. + + This program 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 this program. If not, see . +*/ + +//requires c++20 + +#ifndef REXY_ENUM_CLASS_HPP +#define REXY_ENUM_CLASS_HPP + +#include + +template +concept Scoped_Enum = requires{ + typename std::underlying_type_t; + requires std::is_enum_v; + requires !std::is_convertible_v>; +}; + + +//since std::to_underlying is only available since c++23 +namespace rexy::enum_traits{ + template + constexpr std::underlying_type_t to_underlying(E t)noexcept{ + return static_cast>(t); + } +} + +template +constexpr E operator|(E t, E t2)noexcept{ + return static_cast(rexy::enum_traits::to_underlying(t) | rexy::enum_traits::to_underlying(t2)); +} +template +constexpr E& operator|=(E& t, E t2)noexcept{ + t = static_cast(rexy::enum_traits::to_underlying(t) | rexy::enum_traits::to_underlying(t2)); + return t; +} +template +constexpr E operator&(E t, E t2)noexcept{ + return static_cast(rexy::enum_traits::to_underlying(t) & rexy::enum_traits::to_underlying(t2)); +} +template +constexpr E& operator&=(E& t, E t2)noexcept{ + t = static_cast(rexy::enum_traits::to_underlying(t) & rexy::enum_traits::to_underlying(t2)); + return t; +} +template +constexpr E operator^(E t, E t2)noexcept{ + return static_cast(rexy::enum_traits::to_underlying(t) ^ rexy::enum_traits::to_underlying(t2)); +} +template +constexpr E& operator^=(E& t, E t2)noexcept{ + t = static_cast(rexy::enum_traits::to_underlying(t) ^ rexy::enum_traits::to_underlying(t2)); + return t; +} +template +constexpr E operator!(E t)noexcept{ + return static_cast(!(rexy::enum_traits::to_underlying(t))); +} +template +constexpr E operator~(E t)noexcept{ + return static_cast(~rexy::enum_traits::to_underlying(t)); +} +template +constexpr E operator<<(E t, int shift)noexcept{ + return static_cast(rexy::enum_traits::to_underlying(t) << shift); +} +template +constexpr E& operator<<=(E& t, int shift)noexcept{ + t = static_cast(rexy::enum_traits::to_underlying(t) << shift); + return t; +} +template +constexpr E operator>>(E t, int shift)noexcept{ + return static_cast(rexy::enum_traits::to_underlying(t) >> shift); +} +template +constexpr E& operator>>=(E& t, int shift)noexcept{ + t = static_cast(rexy::enum_traits::to_underlying(t) >> shift); + return t; +} + +template +constexpr bool operator>(E t1, E t2)noexcept{ + return rexy::enum_traits::to_underlying(t1) > rexy::enum_traits::to_underlying(t2); +} +template +constexpr bool operator>(E t, std::underlying_type_t u){ + return rexy::enum_traits::to_underlying(t) > u; +} +template +constexpr bool operator<(E t1, E t2)noexcept{ + return rexy::enum_traits::to_underlying(t1) < rexy::enum_traits::to_underlying(t2); +} +template +constexpr bool operator<(E t, std::underlying_type_t u)noexcept{ + return rexy::enum_traits::to_underlying(t) < u; +} +template +constexpr bool operator>=(E t1, E t2)noexcept{ + return rexy::enum_traits::to_underlying(t1) >= rexy::enum_traits::to_underlying(t2); +} +template +constexpr bool operator>=(E t, std::underlying_type_t u)noexcept{ + return rexy::enum_traits::to_underlying(t) >= u; +} +template +constexpr bool operator<=(E t1, E t2)noexcept{ + return rexy::enum_traits::to_underlying(t1) <= rexy::enum_traits::to_underlying(t2); +} +template +constexpr bool operator<=(E t, std::underlying_type_t u)noexcept{ + return rexy::enum_traits::to_underlying(t) <= u; +} +template +constexpr bool operator==(E t1, E t2)noexcept{ + return rexy::enum_traits::to_underlying(t1) == rexy::enum_traits::to_underlying(t2); +} +template +constexpr bool operator==(E t, std::underlying_type_t u)noexcept{ + return rexy::enum_traits::to_underlying(t) == u; +} +template +constexpr bool operator!=(E t1, E t2)noexcept{ + return rexy::enum_traits::to_underlying(t1) != rexy::enum_traits::to_underlying(t2); +} +template +constexpr bool operator!=(E t, std::underlying_type_t u)noexcept{ + return rexy::enum_traits::to_underlying(t) != u; +} + +namespace rexy::enum_traits{ + template + constexpr bool not_zero(E t)noexcept{ + return rexy::enum_traits::to_underlying(t) != 0; + } + template + constexpr bool is_zero(E t)noexcept{ + return rexy::enum_traits::to_underlying(t) == 0; + } + template + constexpr bool is_greater_than(E t1, E t2)noexcept{ + return rexy::enum_traits::to_underlying(t1) > rexy::enum_traits::to_underlying(t2); + } + template + constexpr bool is_greater_than(E t, std::underlying_type_t u){ + return rexy::enum_traits::to_underlying(t) > u; + } + template + constexpr bool is_less_than(E t1, E t2)noexcept{ + return rexy::enum_traits::to_underlying(t1) < rexy::enum_traits::to_underlying(t2); + } + template + constexpr bool is_less_than(E t, std::underlying_type_t u)noexcept{ + return rexy::enum_traits::to_underlying(t) < u; + } + template + constexpr bool is_greater_than_equal(E t1, E t2)noexcept{ + return rexy::enum_traits::to_underlying(t1) >= rexy::enum_traits::to_underlying(t2); + } + template + constexpr bool is_greater_than_equal(E t, std::underlying_type_t u)noexcept{ + return rexy::enum_traits::to_underlying(t) >= u; + } + template + constexpr bool is_less_than_equal(E t1, E t2)noexcept{ + return rexy::enum_traits::to_underlying(t1) <= rexy::enum_traits::to_underlying(t2); + } + template + constexpr bool is_less_than_equal(E t, std::underlying_type_t u)noexcept{ + return rexy::enum_traits::to_underlying(t) <= u; + } + template + constexpr bool is_equal(E t1, E t2)noexcept{ + return rexy::enum_traits::to_underlying(t1) == rexy::enum_traits::to_underlying(t2); + } + template + constexpr bool is_equal(E t, std::underlying_type_t u)noexcept{ + return rexy::enum_traits::to_underlying(t) == u; + } + template + constexpr bool is_not_equal(E t1, E t2)noexcept{ + return rexy::enum_traits::to_underlying(t1) != rexy::enum_traits::to_underlying(t2); + } + template + constexpr bool is_not_equal(E t, std::underlying_type_t u)noexcept{ + return rexy::enum_traits::to_underlying(t) != u; + } +} + +#endif diff --git a/include/rexy/source_location.hpp b/include/rexy/source_location.hpp new file mode 100644 index 0000000..7567ea6 --- /dev/null +++ b/include/rexy/source_location.hpp @@ -0,0 +1,122 @@ +/** + This file is a part of rexy's general purpose library + Copyright (C) 2022 rexy712 + + This program 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. + + This program 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 this program. If not, see . +*/ + +#ifndef REXY_UTIL_SOURCE_LOCATION_HPP +#define REXY_UTIL_SOURCE_LOCATION_HPP + +#include //feature test macro + +#ifndef __cpp_lib_source_location + +#include //uint_least32_t + +#if __cplusplus >= 202002L + #define CONSTEVAL consteval +#else + #define CONSTEVAL constexpr +#endif + +namespace rexy{ + + class source_location + { + private: + const char* m_file; + const char* m_func; + uint_least32_t m_line; + uint_least32_t m_column; + + public: + constexpr source_location(void)noexcept; + constexpr source_location(const source_location&); + constexpr source_location(source_location&&)noexcept; + + constexpr uint_least32_t line(void)const noexcept; + constexpr uint_least32_t column(void)const noexcept; + constexpr const char* file_name(void)const noexcept; + constexpr const char* function_name(void)const noexcept; + + public: + #if (defined(__clang__) && (__clang_major__ >= 9)) || (defined(_MSC_VER) && (_MSC_VER >= 1926)) + static CONSTEVAL source_location current(uint_least32_t line = __builtin_LINE(), + uint_least32_t col = __builtin_COLUMN(), + const char* file = __builtin_FILE(), + const char* func = __builtin_FUNCTION())noexcept; + #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + static CONSTEVAL source_location current(uint_least32_t line = __builtin_LINE(), + uint_least32_t col = 0, + const char* file = __builtin_FILE(), + const char* func = __builtin_FUNCTION())noexcept; + #else + static CONSTEVAL source_location current(uint_least32_t line = 0, + uint_least32_t col = 0, + const char* file = "unknown", + const char* func = "unknown")noexcept; + #endif + + private: + constexpr source_location(uint_least32_t line, uint_least32_t col, const char* file, const char* func)noexcept; + }; + + constexpr source_location::source_location(void)noexcept: + source_location(0, 0, "unknown", "unknown"){} + constexpr source_location::source_location(const source_location& s): + source_location(s.m_line, s.m_column, s.m_file, s.m_func){} + constexpr source_location::source_location(source_location&& s)noexcept: + source_location(s.m_line, s.m_column, s.m_file, s.m_func){} + constexpr source_location::source_location(uint_least32_t line, uint_least32_t col, const char* file, const char* func)noexcept: + m_file(file), + m_func(func), + m_line(line), + m_column(col){} + + constexpr uint_least32_t source_location::line(void)const noexcept{ + return m_line; + } + constexpr uint_least32_t source_location::column(void)const noexcept{ + return m_column; + } + constexpr const char* source_location::file_name(void)const noexcept{ + return m_file; + } + constexpr const char* source_location::function_name(void)const noexcept{ + return m_func; + } + + CONSTEVAL source_location source_location::current(uint_least32_t line, uint_least32_t col, const char* file, const char* func)noexcept{ + return source_location(line, col, file, func); + } + +} + +#undef CONSTEVAL + +#else //__cpp_lib_source_location + +#include + +namespace rexy{ + + using source_location = std::source_location; + +} + +#endif //__cpp_lib_source_location + +#endif + diff --git a/src/ensure.cpp b/src/ensure.cpp index 1d1d19f..5ff17c5 100644 --- a/src/ensure.cpp +++ b/src/ensure.cpp @@ -19,6 +19,11 @@ #include "rexy/traits.hpp" #include "rexy/utility.hpp" #include "rexy/meta.hpp" +#include "rexy/enum_traits.hpp" +#include "rexy/deferred.hpp" +#include "rexy/source_location.hpp" +#include "rexy/demangle.hpp" +#include "rexy/debug_print.hpp" #include "rexy/detail/binary_string_conv.hpp" #include "rexy/detail/string_appender.hpp"