forked from OctaForge/libostd
various warning fixes with -Weverything
This commit is contained in:
parent
2cbcc85fa8
commit
723c06c612
19 changed files with 255 additions and 224 deletions
2
build.cc
2
build.cc
|
@ -473,7 +473,7 @@ int main(int argc, char **argv) {
|
|||
try_remove("test_runner.o");
|
||||
};
|
||||
|
||||
ostd::thread_pool tp;
|
||||
ostd::thread_pool tp{};
|
||||
tp.start();
|
||||
|
||||
std::queue<std::future<fs::path>> future_obj, future_dynobj;
|
||||
|
|
|
@ -13,10 +13,10 @@ using namespace ostd;
|
|||
* task, which may or may not run in parallel with the other one depending
|
||||
* on the scheduler currently in use - several schedulers are shown
|
||||
*/
|
||||
auto input_array = { 150, 38, 76, 25, 67, 18, -15, 215, 25, -10 };
|
||||
static auto input_array = { 150, 38, 76, 25, 67, 18, -15, 215, 25, -10 };
|
||||
|
||||
auto first_half = iter(input_array).slice(0, input_array.size() / 2);
|
||||
auto second_half = iter(input_array).slice(input_array.size() / 2);
|
||||
static auto first_half = iter(input_array).slice(0, input_array.size() / 2);
|
||||
static auto second_half = iter(input_array).slice(input_array.size() / 2);
|
||||
|
||||
/* this version uses Go-style channels to exchange data; multiple
|
||||
* tasks can put data into channels, the channel itself is a thread
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
using namespace ostd;
|
||||
|
||||
void list_dirs(filesystem::path const &path, int off = 0) {
|
||||
inline void list_dirs(filesystem::path const &path, int off = 0) {
|
||||
filesystem::directory_iterator ds{path};
|
||||
for (auto &v: ds) {
|
||||
auto p = filesystem::path{v};
|
||||
|
|
|
@ -33,7 +33,7 @@ int main() {
|
|||
|
||||
/* prints ABCDEF (ASCII 65, 66, 67, 68, 69, 70) */
|
||||
writeln("string gen test");
|
||||
auto mr = map(range(6), [](int v) -> char { return v + 65; });
|
||||
auto mr = map(range(6), [](int v) { return char(v + 65); });
|
||||
std::string s{mr.iter_begin(), mr.iter_end()};
|
||||
writeln(s);
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ int main() {
|
|||
|
||||
/* prints ABCDEF (ASCII 65, 66, 67, 68, 69, 70) */
|
||||
writeln("string gen test");
|
||||
auto mr = range(6) | map([](int v) -> char { return v + 65; });
|
||||
auto mr = range(6) | map([](int v) { return char(v + 65); });
|
||||
std::string s{mr.iter_begin(), mr.iter_end()};
|
||||
writeln(s);
|
||||
|
||||
|
@ -73,7 +73,7 @@ int main() {
|
|||
/* more complex pipe */
|
||||
writeln("several piped algorithms");
|
||||
|
||||
srand(time(0));
|
||||
srand(static_cast<unsigned int>(time(0)));
|
||||
std::array<int, 100> arr;
|
||||
generate(iter(arr), []() { return rand() % 128; });
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
using namespace ostd;
|
||||
|
||||
void print_result(uint32_t x) {
|
||||
inline void print_result(uint32_t x) {
|
||||
writefln("got x: 0x%X", x);
|
||||
}
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ struct parse_state {
|
|||
((i + 1) < codes.size()) && (codes[i + 1] == (codes[i] + off))
|
||||
);
|
||||
};
|
||||
auto match_range = [&codes, &cases, &match_pair](std::size_t i) {
|
||||
auto match_range = [&cases, &match_pair](std::size_t i) {
|
||||
return match_pair(i, 1) && (
|
||||
cases.empty() || (cases[i + 1] == (cases[i] + 1))
|
||||
);
|
||||
|
|
|
@ -146,7 +146,7 @@ OSTD_UNIT_TEST {
|
|||
|
||||
namespace detail {
|
||||
template<typename R, typename C>
|
||||
static void insort(R range, C &compare) {
|
||||
inline void insort(R range, C &compare) {
|
||||
range_size_t<R> rlen = range.size();
|
||||
for (range_size_t<R> i = 1; i < rlen; ++i) {
|
||||
range_size_t<R> j = i;
|
||||
|
@ -160,7 +160,7 @@ namespace detail {
|
|||
}
|
||||
|
||||
template<typename R, typename C>
|
||||
static void hs_sift_down(
|
||||
inline void hs_sift_down(
|
||||
R range, range_size_t<R> s, range_size_t<R> e, C &compare
|
||||
) {
|
||||
range_size_t<R> r = s;
|
||||
|
@ -184,7 +184,7 @@ namespace detail {
|
|||
}
|
||||
|
||||
template<typename R, typename C>
|
||||
static void heapsort(R range, C &compare) {
|
||||
inline void heapsort(R range, C &compare) {
|
||||
range_size_t<R> len = range.size();
|
||||
range_size_t<R> st = (len - 2) / 2;
|
||||
for (;;) {
|
||||
|
@ -203,7 +203,7 @@ namespace detail {
|
|||
}
|
||||
|
||||
template<typename R, typename C>
|
||||
static void introloop(R range, C &compare, range_size_t<R> depth) {
|
||||
inline void introloop(R range, C &compare, range_size_t<R> depth) {
|
||||
using std::swap;
|
||||
if (range.size() <= 10) {
|
||||
detail::insort(range, compare);
|
||||
|
@ -594,7 +594,7 @@ inline auto none_of(Predicate &&pred) {
|
|||
* Iterates the range and as soon as `range.front()` is equal to `v`,
|
||||
* returns `range`. The `range` is at least ostd::input_range_tag.
|
||||
*
|
||||
* @sse ostd::find_last(), ostd::find_if(), ostd::find_if_not(),
|
||||
* @see ostd::find_last(), ostd::find_if(), ostd::find_if_not(),
|
||||
* ostd::find_one_of()
|
||||
*/
|
||||
template<typename InputRange, typename Value>
|
||||
|
@ -625,7 +625,7 @@ inline auto find(Value &&v) {
|
|||
* the previous result of ostd::find() in case nothing is found next, this
|
||||
* algortihm requires `range` to be at least ostd::forward_range_tag.
|
||||
*
|
||||
* @sse ostd::find(), ostd::find_if(), ostd::find_if_not(),
|
||||
* @see ostd::find(), ostd::find_if(), ostd::find_if_not(),
|
||||
* ostd::find_one_of()
|
||||
*/
|
||||
template<typename ForwardRange, typename Value>
|
||||
|
@ -661,7 +661,7 @@ inline auto find_last(Value &&v) {
|
|||
* Iterates the range and as soon as `pred(range.front())` is true,
|
||||
* returns `range`. The `range` is at least ostd::input_range_tag.
|
||||
*
|
||||
* @sse ostd::find(), ostd::find_last(), ostd::find_if_not(),
|
||||
* @see ostd::find(), ostd::find_last(), ostd::find_if_not(),
|
||||
* ostd::find_one_of()
|
||||
*/
|
||||
template<typename InputRange, typename Predicate>
|
||||
|
@ -690,7 +690,7 @@ inline auto find_if(Predicate &&pred) {
|
|||
* Iterates the range and as soon as `!pred(range.front())` is true,
|
||||
* returns `range`. The `range` is at least ostd::input_range_tag.
|
||||
*
|
||||
* @sse ostd::find(), ostd::find_last(), ostd::find_if(), ostd::find_one_of()
|
||||
* @see ostd::find(), ostd::find_last(), ostd::find_if(), ostd::find_one_of()
|
||||
*/
|
||||
template<typename InputRange, typename Predicate>
|
||||
inline InputRange find_if_not(InputRange range, Predicate pred) {
|
||||
|
@ -729,7 +729,7 @@ inline auto find_if_not(Predicate &&pred) {
|
|||
* Use ostd::find_one_of() if you want to use the `==` operator
|
||||
* instead of calling `compare`.
|
||||
*
|
||||
* @sse ostd::find(), ostd::find_last(), ostd::find_if(), ostd::find_if_not(),
|
||||
* @see ostd::find(), ostd::find_last(), ostd::find_if(), ostd::find_if_not(),
|
||||
* ostd::find_one_of()
|
||||
*/
|
||||
template<typename InputRange, typename ForwardRange, typename Compare>
|
||||
|
@ -779,7 +779,7 @@ inline auto find_one_of_cmp(ForwardRange &&values, Compare &&compare) {
|
|||
* Use ostd::find_one_of_cmp() if you want to use a comparison
|
||||
* function instead of the `==` operator.
|
||||
*
|
||||
* @sse ostd::find(), ostd::find_last(), ostd::find_if(), ostd::find_if_not(),
|
||||
* @see ostd::find(), ostd::find_last(), ostd::find_if(), ostd::find_if_not(),
|
||||
* ostd::find_one_of_cmp()
|
||||
*/
|
||||
template<typename InputRange, typename ForwardRange>
|
||||
|
|
|
@ -492,7 +492,7 @@ private:
|
|||
case arg_value::OPTIONAL:
|
||||
case arg_value::ALL:
|
||||
break;
|
||||
default:
|
||||
case arg_value::REST:
|
||||
throw arg_error{"invalid argument requirement"};
|
||||
}
|
||||
}
|
||||
|
@ -917,7 +917,6 @@ protected:
|
|||
|
||||
private:
|
||||
std::string p_name, p_title;
|
||||
std::vector<std::unique_ptr<arg_description>> p_opts;
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
|
@ -959,9 +958,6 @@ inline bool arg_description_container::for_each(
|
|||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
throw arg_error{"invalid argument type"};
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -1519,8 +1515,8 @@ struct default_help_formatter {
|
|||
/** @brief Formats the options (after usage line).
|
||||
*
|
||||
* Positional arguments not belonging to any group are formatted
|
||||
* first, with `\nPositional arguments:\n` header. Same goes with
|
||||
* optional arguments, except with `\nOptional arguments:\n`.
|
||||
* first, with `\\nPositional arguments:\\n` header. Same goes with
|
||||
* optional arguments, except with `\\nOptional arguments:\\n`.
|
||||
*
|
||||
* If either positional or optional arguments without group don't
|
||||
* exist, the section is skipped.
|
||||
|
@ -1529,7 +1525,7 @@ struct default_help_formatter {
|
|||
* help strings are aligned and offset by 2 spaces from the longest
|
||||
* argument string.
|
||||
*
|
||||
* Group titles are formatted as `\nTITLE:\n`.
|
||||
* Group titles are formatted as `\\nTITLE:\\n`.
|
||||
*
|
||||
* Within groups, positional arguments come first and optional
|
||||
* arguments second. Mutually exclusive groups are expanded.
|
||||
|
@ -1586,8 +1582,6 @@ struct default_help_formatter {
|
|||
}
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}, false, false);
|
||||
|
@ -1636,9 +1630,7 @@ struct default_help_formatter {
|
|||
}
|
||||
auto &garg = static_cast<arg_group const &>(arg);
|
||||
format(out, "\n%s:\n", garg.title());
|
||||
garg.for_each([
|
||||
&write_help, &out, &allopt, &allpos
|
||||
](auto const &marg) {
|
||||
garg.for_each([&allopt, &allpos](auto const &marg) {
|
||||
switch (marg.type()) {
|
||||
case arg_type::OPTIONAL:
|
||||
allopt.push_back(
|
||||
|
@ -1650,7 +1642,8 @@ struct default_help_formatter {
|
|||
static_cast<arg_positional const *>(&marg)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
case arg_type::GROUP:
|
||||
case arg_type::MUTUALLY_EXCLUSIVE_GROUP:
|
||||
/* should never happen */
|
||||
throw arg_error{"invalid argument type"};
|
||||
}
|
||||
|
@ -1700,7 +1693,7 @@ struct default_help_formatter {
|
|||
}
|
||||
format(out, " [%s ...]", mt);
|
||||
break;
|
||||
default:
|
||||
case arg_value::REST:
|
||||
break;
|
||||
}
|
||||
names.pop_front();
|
||||
|
@ -1741,7 +1734,8 @@ struct default_help_formatter {
|
|||
case arg_type::POSITIONAL:
|
||||
format_option(out, static_cast<arg_positional const &>(arg));
|
||||
break;
|
||||
default:
|
||||
case arg_type::GROUP:
|
||||
case arg_type::MUTUALLY_EXCLUSIVE_GROUP:
|
||||
/* should never happen */
|
||||
throw arg_error{"invalid argument type"};
|
||||
}
|
||||
|
@ -1767,7 +1761,7 @@ inline auto arg_print_help(OutputRange o, arg_parser &p) {
|
|||
p.print_help(o);
|
||||
p.stop_parsing();
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/** @brief Like ostd::arg_print_help() with ostd::cout. */
|
||||
inline auto arg_print_help(arg_parser &p) {
|
||||
|
|
|
@ -34,6 +34,35 @@ namespace ostd {
|
|||
* @{
|
||||
*/
|
||||
|
||||
struct coroutine_context;
|
||||
|
||||
namespace detail {
|
||||
/* from boost.fcontext */
|
||||
using fcontext_t = void *;
|
||||
|
||||
struct transfer_t {
|
||||
fcontext_t ctx;
|
||||
void *data;
|
||||
};
|
||||
|
||||
extern "C" OSTD_EXPORT
|
||||
transfer_t OSTD_CDECL ostd_jump_fcontext(
|
||||
fcontext_t const to, void *vp
|
||||
);
|
||||
|
||||
extern "C" OSTD_EXPORT
|
||||
fcontext_t OSTD_CDECL ostd_make_fcontext(
|
||||
void *sp, std::size_t size, void (*fn)(transfer_t)
|
||||
);
|
||||
|
||||
extern "C" OSTD_EXPORT
|
||||
transfer_t OSTD_CDECL ostd_ontop_fcontext(
|
||||
fcontext_t const to, void *vp, transfer_t (*fn)(transfer_t)
|
||||
);
|
||||
|
||||
OSTD_EXPORT extern thread_local coroutine_context *coro_current;
|
||||
} /* namespace detail */
|
||||
|
||||
/** @brief An allocated stack.
|
||||
*
|
||||
* This represents a stack allocated by a stack allocator. It doesn't
|
||||
|
|
|
@ -58,35 +58,6 @@ struct coroutine_error: std::runtime_error {
|
|||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
struct coroutine_context;
|
||||
|
||||
namespace detail {
|
||||
/* from boost.fcontext */
|
||||
using fcontext_t = void *;
|
||||
|
||||
struct transfer_t {
|
||||
fcontext_t ctx;
|
||||
void *data;
|
||||
};
|
||||
|
||||
extern "C" OSTD_EXPORT
|
||||
transfer_t OSTD_CDECL ostd_jump_fcontext(
|
||||
fcontext_t const to, void *vp
|
||||
);
|
||||
|
||||
extern "C" OSTD_EXPORT
|
||||
fcontext_t OSTD_CDECL ostd_make_fcontext(
|
||||
void *sp, std::size_t size, void (*fn)(transfer_t)
|
||||
);
|
||||
|
||||
extern "C" OSTD_EXPORT
|
||||
transfer_t OSTD_CDECL ostd_ontop_fcontext(
|
||||
fcontext_t const to, void *vp, transfer_t (*fn)(transfer_t)
|
||||
);
|
||||
|
||||
OSTD_EXPORT extern thread_local coroutine_context *coro_current;
|
||||
} /* namespace detail */
|
||||
|
||||
/** @brief An encapsulated context any coroutine-type inherits from.
|
||||
*
|
||||
* Internally, this provides some basic infrastructure for creating and
|
||||
|
@ -135,7 +106,7 @@ protected:
|
|||
*/
|
||||
coroutine_context(coroutine_context &&c):
|
||||
p_stack(std::move(c.p_stack)), p_coro(c.p_coro), p_orig(c.p_orig),
|
||||
p_except(std::move(c.p_except)), p_state(c.p_state), p_free(c.p_free)
|
||||
p_free(c.p_free), p_except(std::move(c.p_except)), p_state(c.p_state)
|
||||
{
|
||||
c.p_coro = c.p_orig = nullptr;
|
||||
c.p_stack = { nullptr, 0 };
|
||||
|
@ -249,9 +220,9 @@ protected:
|
|||
swap(p_stack, other.p_stack);
|
||||
swap(p_coro, other.p_coro);
|
||||
swap(p_orig, other.p_orig);
|
||||
swap(p_free, other.p_free);
|
||||
swap(p_except, other.p_except);
|
||||
swap(p_state, other.p_state);
|
||||
swap(p_free, other.p_free);
|
||||
}
|
||||
|
||||
/** @brief Allocates a stack and creates a context.
|
||||
|
@ -276,10 +247,10 @@ protected:
|
|||
p_stack = sa.allocate();
|
||||
|
||||
void *sp = get_stack_ptr<SA>();
|
||||
std::size_t asize = p_stack.size - (
|
||||
auto asize = std::size_t(p_stack.size - std::size_t(
|
||||
static_cast<unsigned char *>(p_stack.ptr) -
|
||||
static_cast<unsigned char *>(sp)
|
||||
);
|
||||
));
|
||||
|
||||
p_coro = detail::ostd_make_fcontext(sp, asize, &context_call<C, SA>);
|
||||
new (sp) SA(std::move(sa));
|
||||
|
@ -374,9 +345,9 @@ release:
|
|||
stack_context p_stack;
|
||||
detail::fcontext_t p_coro = nullptr;
|
||||
detail::fcontext_t p_orig = nullptr;
|
||||
void (*p_free)(void *) = nullptr;
|
||||
std::exception_ptr p_except;
|
||||
state p_state = state::HOLD;
|
||||
void (*p_free)(void *) = nullptr;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
@ -653,7 +624,7 @@ namespace detail {
|
|||
* as they were passed, exactly as if they were passed as regular args.
|
||||
*
|
||||
* @tparam R The return template type.
|
||||
* @tparam A... The argument template types.
|
||||
* @tparam A The argument template types.
|
||||
*/
|
||||
template<typename R, typename ...A>
|
||||
struct coroutine<R(A...)>: coroutine_context {
|
||||
|
|
|
@ -134,7 +134,7 @@ namespace detail {
|
|||
* 7 .. string
|
||||
* 8 .. custom object
|
||||
*/
|
||||
inline constexpr unsigned char const fmt_specs[] = {
|
||||
static inline constexpr unsigned char const fmt_specs[] = {
|
||||
/* uppercase spec set */
|
||||
1, 3, 8, 8, /* A B C D */
|
||||
1, 1, 1, 8, /* E F G H */
|
||||
|
@ -160,12 +160,12 @@ namespace detail {
|
|||
0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
inline constexpr int const fmt_bases[] = {
|
||||
static inline constexpr int const fmt_bases[] = {
|
||||
0, 0, 0, 2, 8, 10, 16, 0
|
||||
};
|
||||
|
||||
/* non-printable escapes up to 0x20 (space) */
|
||||
inline constexpr char const *fmt_escapes[] = {
|
||||
static inline constexpr char const *fmt_escapes[] = {
|
||||
"\\0" , "\\x01", "\\x02", "\\x03", "\\x04", "\\x05",
|
||||
"\\x06", "\\a" , "\\b" , "\\t" , "\\n" , "\\v" ,
|
||||
"\\f" , "\\r" , "\\x0E", "\\x0F", "\\x10", "\\x11",
|
||||
|
@ -215,33 +215,35 @@ namespace detail {
|
|||
* pair, array, possibly other types added later or overridden...
|
||||
*/
|
||||
template<typename T>
|
||||
std::true_type tuple_like_test(typename std::tuple_size<T>::type *);
|
||||
inline std::true_type tuple_like_test(typename std::tuple_size<T>::type *);
|
||||
|
||||
template<typename>
|
||||
std::false_type tuple_like_test(...);
|
||||
inline std::false_type tuple_like_test(...);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_tuple_like = decltype(tuple_like_test<T>(0))::value;
|
||||
static inline constexpr bool is_tuple_like =
|
||||
decltype(tuple_like_test<T>(0))::value;
|
||||
|
||||
/* character type tests */
|
||||
template<typename C>
|
||||
inline constexpr bool is_character = std::is_same_v<C, char> ||
|
||||
std::is_same_v<C, wchar_t> ||
|
||||
std::is_same_v<C, char16_t> ||
|
||||
std::is_same_v<C, char32_t>;
|
||||
static inline constexpr bool is_character = std::is_same_v<C, char> ||
|
||||
std::is_same_v<C, wchar_t> ||
|
||||
std::is_same_v<C, char16_t> ||
|
||||
std::is_same_v<C, char32_t>;
|
||||
|
||||
/* test if format traits are available for the type */
|
||||
template<typename T, typename R>
|
||||
static std::true_type test_tofmt(decltype(format_traits<T>::to_format(
|
||||
inline std::true_type test_tofmt(decltype(format_traits<T>::to_format(
|
||||
std::declval<T const &>(), std::declval<R &>(),
|
||||
std::declval<format_spec const &>()
|
||||
)) *);
|
||||
|
||||
template<typename, typename>
|
||||
static std::false_type test_tofmt(...);
|
||||
inline std::false_type test_tofmt(...);
|
||||
|
||||
template<typename T, typename R>
|
||||
inline constexpr bool fmt_tofmt_test = decltype(test_tofmt<T, R>(0))::value;
|
||||
static inline constexpr bool fmt_tofmt_test =
|
||||
decltype(test_tofmt<T, R>(0))::value;
|
||||
|
||||
template<typename C, typename F>
|
||||
inline int ac_to_mb(C c, F const &f, char *buf) {
|
||||
|
@ -252,7 +254,7 @@ namespace detail {
|
|||
if (ret != std::codecvt_base::ok) {
|
||||
return -1;
|
||||
}
|
||||
return ton - &buf[0];
|
||||
return int(ton - &buf[0]);
|
||||
}
|
||||
|
||||
inline int wc_to_mb_loc(wchar_t c, char *buf, std::locale const &loc) {
|
||||
|
@ -847,14 +849,16 @@ private:
|
|||
if (p.front() == need) {
|
||||
p_is_tuple = tuple;
|
||||
if (tuple) {
|
||||
p_nested = begin_inner.slice(0, &p[0] - &begin_inner[0] - 1);
|
||||
p_nested = begin_inner.slice(
|
||||
0, std::size_t(&p[0] - &begin_inner[0] - 1)
|
||||
);
|
||||
p_nested_sep = nullptr;
|
||||
} else {
|
||||
p_nested = begin_inner.slice(
|
||||
0, &begin_delim[0] - &begin_inner[0]
|
||||
0, std::size_t(&begin_delim[0] - &begin_inner[0])
|
||||
);
|
||||
p_nested_sep = begin_delim.slice(
|
||||
0, &p[0] - &begin_delim[0] - 1
|
||||
0, std::size_t(&p[0] - &begin_delim[0] - 1)
|
||||
);
|
||||
}
|
||||
p.pop_front();
|
||||
|
@ -864,14 +868,16 @@ private:
|
|||
}
|
||||
/* found actual delimiter start... */
|
||||
if ((p.front() == '|') && !tuple) {
|
||||
p_nested = begin_inner.slice(0, &p[0] - &begin_inner[0] - 1);
|
||||
p_nested = begin_inner.slice(
|
||||
0, std::size_t(&p[0] - &begin_inner[0] - 1)
|
||||
);
|
||||
p.pop_front();
|
||||
p_nested_sep = p;
|
||||
for (p = find(p, '%'); !p.empty(); p = find(p, '%')) {
|
||||
p.pop_front();
|
||||
if (p.front() == ')') {
|
||||
p_nested_sep = p_nested_sep.slice(
|
||||
0, &p[0] - &p_nested_sep[0] - 1
|
||||
0, std::size_t(&p[0] - &p_nested_sep[0] - 1)
|
||||
);
|
||||
p.pop_front();
|
||||
p_fmt = p;
|
||||
|
@ -1083,15 +1089,15 @@ private:
|
|||
throw format_error{"cannot format integers with the given spec"};
|
||||
}
|
||||
/* 32 for lowercase variants, 0 for uppercase */
|
||||
int cmask = ((isp >= 'a') << 5);
|
||||
char cmask = char((isp >= 'a') << 5);
|
||||
|
||||
int base = detail::fmt_bases[specn];
|
||||
T base = T(detail::fmt_bases[specn]);
|
||||
if (!val) {
|
||||
ndig = 1;
|
||||
buf[0] = '0';
|
||||
} else {
|
||||
for (; val; val /= base) {
|
||||
T vb = val % base;
|
||||
auto vb = char(val % base);
|
||||
buf[ndig++] = (vb + "70"[vb < 10]) | cmask;
|
||||
}
|
||||
}
|
||||
|
@ -1132,7 +1138,7 @@ private:
|
|||
}
|
||||
++grpp;
|
||||
}
|
||||
total += nseps * ntsep;
|
||||
total += nseps * std::size_t(ntsep);
|
||||
}
|
||||
/* here ends the bullshit */
|
||||
|
||||
|
@ -1244,7 +1250,8 @@ private:
|
|||
fmt_num_put<R> nump;
|
||||
nump.put(
|
||||
fmt_out<R>{&writer, &p_loc}, st,
|
||||
(p_flags & FMT_FLAG_ZERO) ? L'0' : L' ', val
|
||||
(p_flags & FMT_FLAG_ZERO) ? L'0' : L' ',
|
||||
std::conditional_t<std::is_same_v<T, long double>, T, double>(val)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1291,10 +1298,10 @@ private:
|
|||
throw format_error{"tuples need the '%s' spec"};
|
||||
}
|
||||
writer.put('{');
|
||||
write_range_val(writer, [&writer, escape, this](auto const &rval) {
|
||||
format_spec sp{'s', p_loc, escape ? FMT_FLAG_AT : 0};
|
||||
write_range_val(writer, [&writer, this](auto const &rval, bool esc) {
|
||||
format_spec sp{'s', p_loc, esc ? FMT_FLAG_AT : 0};
|
||||
sp.write_arg(writer, 0, rval);
|
||||
}, ", ", val);
|
||||
}, ", ", val, escape);
|
||||
writer.put('}');
|
||||
return;
|
||||
}
|
||||
|
@ -1369,13 +1376,11 @@ private:
|
|||
) const {
|
||||
if constexpr(detail::is_tuple_like<T>) {
|
||||
if (expandval) {
|
||||
std::apply([&writer, escape, &fmt, this](
|
||||
auto const &...args
|
||||
) mutable {
|
||||
std::apply([
|
||||
this, &writer, &fmt, flags = escape ? FMT_FLAG_AT : 0
|
||||
](auto const &...args) mutable {
|
||||
format_spec sp{fmt, p_loc};
|
||||
if (escape) {
|
||||
sp.p_gflags |= FMT_FLAG_AT;
|
||||
}
|
||||
sp.p_gflags |= flags;
|
||||
sp.write_fmt(writer, args...);
|
||||
}, item);
|
||||
return;
|
||||
|
@ -1388,9 +1393,10 @@ private:
|
|||
sp.write_fmt(writer, item);
|
||||
}
|
||||
|
||||
template<typename R, typename F, typename T>
|
||||
template<typename R, typename F, typename T, typename ...A>
|
||||
void write_range_val(
|
||||
R &writer, F &&func, [[maybe_unused]] string_range sep, T const &val
|
||||
R &writer, F &&func, [[maybe_unused]] string_range sep, T const &val,
|
||||
A const &...args
|
||||
) const {
|
||||
if constexpr(detail::iterable_test<T>) {
|
||||
auto range = ostd::iter(val);
|
||||
|
@ -1398,7 +1404,7 @@ private:
|
|||
return;
|
||||
}
|
||||
for (;;) {
|
||||
func(range.front());
|
||||
func(range.front(), args...);
|
||||
range.pop_front();
|
||||
if (range.empty()) {
|
||||
break;
|
||||
|
@ -1424,13 +1430,12 @@ private:
|
|||
}
|
||||
} else {
|
||||
write_range_val(writer, [
|
||||
this, &writer, escape = p_gflags & FMT_FLAG_AT, expandval,
|
||||
fmt = rest()
|
||||
](auto const &rval) {
|
||||
fmt = rest(), this, &writer
|
||||
](auto const &rval, bool expval, bool escape) {
|
||||
this->write_range_item(
|
||||
writer, escape, expandval, fmt, rval
|
||||
writer, escape, expval, fmt, rval
|
||||
);
|
||||
}, sep, val);
|
||||
}, sep, val, expandval, p_gflags & FMT_FLAG_AT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1458,7 +1463,7 @@ private:
|
|||
}
|
||||
} else {
|
||||
if constexpr(detail::is_tuple_like<T>) {
|
||||
std::apply([this, &writer, &val](auto const &...vals) mutable {
|
||||
std::apply([this, &writer](auto const &...vals) mutable {
|
||||
this->write_fmt(writer, vals...);
|
||||
}, val);
|
||||
} else {
|
||||
|
|
|
@ -110,7 +110,37 @@ struct OSTD_EXPORT subprocess {
|
|||
private:
|
||||
struct nat {};
|
||||
|
||||
std::aligned_storage_t<2 * sizeof(void *), alignof(void *)> p_data;
|
||||
void *p_current = nullptr;
|
||||
|
||||
public:
|
||||
/** @brief The standard input stream when redirected.
|
||||
*
|
||||
* If no redirection is done (see ostd::subprocess::use_in) then
|
||||
* this stream will not be opened.
|
||||
*
|
||||
* @see ostd::subprocess::out, ostd::subprocess::err
|
||||
*/
|
||||
file_stream in = file_stream{};
|
||||
|
||||
/** @brief The standard output stream when redirected.
|
||||
*
|
||||
* If no redirection is done (see ostd::subprocess::use_out) then
|
||||
* this stream will not be opened.
|
||||
*
|
||||
* @see ostd::subprocess::in, ostd::subprocess::err
|
||||
*/
|
||||
file_stream out = file_stream{};
|
||||
|
||||
/** @brief The standard error stream when redirected.
|
||||
*
|
||||
* If no redirection is done (see ostd::subprocess::use_err) then
|
||||
* this stream will not be opened.
|
||||
*
|
||||
* @see ostd::subprocess::in, ostd::subprocess::out
|
||||
*/
|
||||
file_stream err = file_stream{};
|
||||
|
||||
/** @brief The standard input redirection mode.
|
||||
*
|
||||
* The value is one of ostd::subprocess_stream. Set this before opening
|
||||
|
@ -154,33 +184,6 @@ public:
|
|||
*/
|
||||
subprocess_stream use_err = subprocess_stream::DEFAULT;
|
||||
|
||||
/** @brief The standard input stream when redirected.
|
||||
*
|
||||
* If no redirection is done (see ostd::subprocess::use_in) then
|
||||
* this stream will not be opened.
|
||||
*
|
||||
* @see ostd::subprocess::out, ostd::subprocess::err
|
||||
*/
|
||||
file_stream in = file_stream{};
|
||||
|
||||
/** @brief The standard output stream when redirected.
|
||||
*
|
||||
* If no redirection is done (see ostd::subprocess::use_out) then
|
||||
* this stream will not be opened.
|
||||
*
|
||||
* @see ostd::subprocess::in, ostd::subprocess::err
|
||||
*/
|
||||
file_stream out = file_stream{};
|
||||
|
||||
/** @brief The standard error stream when redirected.
|
||||
*
|
||||
* If no redirection is done (see ostd::subprocess::use_err) then
|
||||
* this stream will not be opened.
|
||||
*
|
||||
* @see ostd::subprocess::in, ostd::subprocess::out
|
||||
*/
|
||||
file_stream err = file_stream{};
|
||||
|
||||
/** @brief Initializes the structure with the given stream redirections. */
|
||||
subprocess(
|
||||
subprocess_stream in_use = subprocess_stream::DEFAULT,
|
||||
|
@ -232,8 +235,8 @@ public:
|
|||
|
||||
/** @brief Moves the subprocess data. */
|
||||
subprocess(subprocess &&i) noexcept:
|
||||
use_in(i.use_in), use_out(i.use_out), use_err(i.use_err),
|
||||
in(std::move(i.in)), out(std::move(i.out)), err(std::move(i.err))
|
||||
in(std::move(i.in)), out(std::move(i.out)), err(std::move(i.err)),
|
||||
use_in(i.use_in), use_out(i.use_out), use_err(i.use_err)
|
||||
{
|
||||
move_data(i);
|
||||
}
|
||||
|
@ -460,9 +463,6 @@ private:
|
|||
void reset();
|
||||
void move_data(subprocess &i);
|
||||
void swap_data(subprocess &i);
|
||||
|
||||
std::aligned_storage_t<2 * sizeof(void *)> p_data;
|
||||
void *p_current = nullptr;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
|
108
ostd/range.hh
108
ostd/range.hh
|
@ -186,7 +186,8 @@ namespace detail {
|
|||
};
|
||||
|
||||
template<typename R>
|
||||
inline constexpr bool test_range_category = range_category_test<R>::value;
|
||||
static inline constexpr bool const test_range_category =
|
||||
range_category_test<R>::value;
|
||||
|
||||
template<typename R, bool, bool>
|
||||
struct range_traits_base {
|
||||
|
@ -199,7 +200,7 @@ namespace detail {
|
|||
};
|
||||
|
||||
template<typename R>
|
||||
inline constexpr bool test_elem_reference =
|
||||
static inline constexpr bool const test_elem_reference =
|
||||
std::is_convertible_v<typename R::range_category, input_range_tag> &&
|
||||
std::is_lvalue_reference_v<typename R::reference> &&
|
||||
std::is_same_v<
|
||||
|
@ -388,7 +389,7 @@ using range_reference_t = typename range_traits<R>::reference;
|
|||
*
|
||||
*/
|
||||
template<typename R1, typename R2>
|
||||
inline constexpr bool is_range_element_swappable_with =
|
||||
static inline constexpr bool const is_range_element_swappable_with =
|
||||
range_traits<R1>::template is_element_swappable_with<R2>;
|
||||
|
||||
/** @brief Checks whether a range can swap elements within itself.
|
||||
|
@ -401,7 +402,7 @@ inline constexpr bool is_range_element_swappable_with =
|
|||
*
|
||||
*/
|
||||
template<typename R>
|
||||
inline constexpr bool is_range_element_swappable =
|
||||
static inline constexpr bool const is_range_element_swappable =
|
||||
range_traits<R>::is_element_swappable;
|
||||
|
||||
/** @brief Checks whether two ranges can nothrow swap elements with each other.
|
||||
|
@ -414,7 +415,7 @@ inline constexpr bool is_range_element_swappable =
|
|||
*
|
||||
*/
|
||||
template<typename R1, typename R2>
|
||||
inline constexpr bool is_range_element_nothrow_swappable_with =
|
||||
static inline constexpr bool const is_range_element_nothrow_swappable_with =
|
||||
range_traits<R1>::template is_element_nothrow_swappable_with<R2>;
|
||||
|
||||
/** @brief Checks whether a range can nothrow swap elements within itself.
|
||||
|
@ -427,21 +428,21 @@ inline constexpr bool is_range_element_nothrow_swappable_with =
|
|||
*
|
||||
*/
|
||||
template<typename R>
|
||||
inline constexpr bool is_range_element_nothrow_swappable =
|
||||
static inline constexpr bool const is_range_element_nothrow_swappable =
|
||||
range_traits<R>::is_element_nothrow_swappable;
|
||||
|
||||
// is input range
|
||||
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
inline constexpr bool is_input_range_core =
|
||||
static inline constexpr bool const is_input_range_core =
|
||||
std::is_convertible_v<range_category_t<T>, input_range_tag>;
|
||||
|
||||
template<typename T, bool = detail::test_range_category<T>>
|
||||
inline constexpr bool is_input_range_base = false;
|
||||
static inline constexpr bool const is_input_range_base = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_input_range_base<T, true> =
|
||||
static inline constexpr bool const is_input_range_base<T, true> =
|
||||
detail::is_input_range_core<T>;
|
||||
}
|
||||
|
||||
|
@ -453,20 +454,21 @@ namespace detail {
|
|||
* @see ostd::is_forward_range, ostd::is_output_range
|
||||
*/
|
||||
template<typename T>
|
||||
inline constexpr bool is_input_range = detail::is_input_range_base<T>;
|
||||
static inline constexpr bool const is_input_range =
|
||||
detail::is_input_range_base<T>;
|
||||
|
||||
// is forward range
|
||||
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
inline constexpr bool is_forward_range_core =
|
||||
static inline constexpr bool const is_forward_range_core =
|
||||
std::is_convertible_v<range_category_t<T>, forward_range_tag>;
|
||||
|
||||
template<typename T, bool = detail::test_range_category<T>>
|
||||
inline constexpr bool is_forward_range_base = false;
|
||||
static inline constexpr bool const is_forward_range_base = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_forward_range_base<T, true> =
|
||||
static inline constexpr bool const is_forward_range_base<T, true> =
|
||||
detail::is_forward_range_core<T>;
|
||||
}
|
||||
|
||||
|
@ -478,20 +480,21 @@ namespace detail {
|
|||
* @see ostd::is_input_range, ostd::is_bidirectional_range
|
||||
*/
|
||||
template<typename T>
|
||||
inline constexpr bool is_forward_range = detail::is_forward_range_base<T>;
|
||||
static inline constexpr bool const is_forward_range =
|
||||
detail::is_forward_range_base<T>;
|
||||
|
||||
// is bidirectional range
|
||||
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
inline constexpr bool is_bidirectional_range_core =
|
||||
static inline constexpr bool const is_bidirectional_range_core =
|
||||
std::is_convertible_v<range_category_t<T>, bidirectional_range_tag>;
|
||||
|
||||
template<typename T, bool = detail::test_range_category<T>>
|
||||
inline constexpr bool is_bidirectional_range_base = false;
|
||||
static inline constexpr bool const is_bidirectional_range_base = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_bidirectional_range_base<T, true> =
|
||||
static inline constexpr bool const is_bidirectional_range_base<T, true> =
|
||||
detail::is_bidirectional_range_core<T>;
|
||||
}
|
||||
|
||||
|
@ -503,21 +506,21 @@ namespace detail {
|
|||
* @see ostd::is_forward_range, ostd::is_random_access_range
|
||||
*/
|
||||
template<typename T>
|
||||
inline constexpr bool is_bidirectional_range =
|
||||
static inline constexpr bool const is_bidirectional_range =
|
||||
detail::is_bidirectional_range_base<T>;
|
||||
|
||||
// is random access range
|
||||
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
inline constexpr bool is_random_access_range_core =
|
||||
static inline constexpr bool const is_random_access_range_core =
|
||||
std::is_convertible_v<range_category_t<T>, random_access_range_tag>;
|
||||
|
||||
template<typename T, bool = detail::test_range_category<T>>
|
||||
inline constexpr bool is_random_access_range_base = false;
|
||||
static inline constexpr bool const is_random_access_range_base = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_random_access_range_base<T, true> =
|
||||
static inline constexpr bool const is_random_access_range_base<T, true> =
|
||||
detail::is_random_access_range_core<T>;
|
||||
}
|
||||
|
||||
|
@ -530,21 +533,21 @@ namespace detail {
|
|||
* @see ostd::is_bidirectional_range, ostd::is_finite_random_access_range
|
||||
*/
|
||||
template<typename T>
|
||||
inline constexpr bool is_random_access_range =
|
||||
static inline constexpr bool const is_random_access_range =
|
||||
detail::is_random_access_range_base<T>;
|
||||
|
||||
// is finite random access range
|
||||
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
inline constexpr bool is_finite_random_access_range_core =
|
||||
static inline constexpr bool const is_finite_random_access_range_core =
|
||||
std::is_convertible_v<range_category_t<T>, finite_random_access_range_tag>;
|
||||
|
||||
template<typename T, bool = detail::test_range_category<T>>
|
||||
inline constexpr bool is_finite_random_access_range_base = false;
|
||||
static inline constexpr bool const is_finite_random_access_range_base = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_finite_random_access_range_base<T, true> =
|
||||
static inline constexpr bool const is_finite_random_access_range_base<T, true> =
|
||||
detail::is_finite_random_access_range_core<T>;
|
||||
}
|
||||
|
||||
|
@ -557,21 +560,21 @@ namespace detail {
|
|||
* @see ostd::is_random_access_range, ostd::is_contiguous_range
|
||||
*/
|
||||
template<typename T>
|
||||
inline constexpr bool is_finite_random_access_range =
|
||||
static inline constexpr bool const is_finite_random_access_range =
|
||||
detail::is_finite_random_access_range_base<T>;
|
||||
|
||||
// is contiguous range
|
||||
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
inline constexpr bool is_contiguous_range_core =
|
||||
static inline constexpr bool const is_contiguous_range_core =
|
||||
std::is_convertible_v<range_category_t<T>, contiguous_range_tag>;
|
||||
|
||||
template<typename T, bool = detail::test_range_category<T>>
|
||||
inline constexpr bool is_contiguous_range_base = false;
|
||||
static inline constexpr bool const is_contiguous_range_base = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_contiguous_range_base<T, true> =
|
||||
static inline constexpr bool const is_contiguous_range_base<T, true> =
|
||||
detail::is_contiguous_range_core<T>;
|
||||
}
|
||||
|
||||
|
@ -582,25 +585,26 @@ namespace detail {
|
|||
* @see ostd::is_finite_random_access_range
|
||||
*/
|
||||
template<typename T>
|
||||
inline constexpr bool is_contiguous_range = detail::is_contiguous_range_base<T>;
|
||||
static inline constexpr bool const is_contiguous_range =
|
||||
detail::is_contiguous_range_base<T>;
|
||||
|
||||
// is output range
|
||||
|
||||
namespace detail {
|
||||
template<typename R, typename T>
|
||||
static std::true_type test_outrange(typename std::is_same<
|
||||
inline std::true_type test_outrange(typename std::is_same<
|
||||
decltype(std::declval<R &>().put(std::declval<T>())), void
|
||||
>::type *);
|
||||
|
||||
template<typename, typename>
|
||||
static std::false_type test_outrange(...);
|
||||
inline std::false_type test_outrange(...);
|
||||
|
||||
template<typename R, typename T>
|
||||
inline constexpr bool output_range_test =
|
||||
static inline constexpr bool const output_range_test =
|
||||
decltype(test_outrange<R, T>())::value;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_output_range_core =
|
||||
static inline constexpr bool const is_output_range_core =
|
||||
std::is_convertible_v<range_category_t<T>, output_range_tag> || (
|
||||
is_input_range<T> && (
|
||||
output_range_test<T, range_value_t<T> const &> ||
|
||||
|
@ -610,10 +614,10 @@ namespace detail {
|
|||
);
|
||||
|
||||
template<typename T, bool = detail::test_range_category<T>>
|
||||
inline constexpr bool is_output_range_base = false;
|
||||
static inline constexpr bool const is_output_range_base = false;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_output_range_base<T, true> =
|
||||
static inline constexpr bool const is_output_range_base<T, true> =
|
||||
detail::is_output_range_core<T>;
|
||||
}
|
||||
|
||||
|
@ -627,7 +631,8 @@ namespace detail {
|
|||
* @see ostd::is_input_range
|
||||
*/
|
||||
template<typename T>
|
||||
inline constexpr bool is_output_range = detail::is_output_range_base<T>;
|
||||
static inline constexpr bool const is_output_range =
|
||||
detail::is_output_range_base<T>;
|
||||
|
||||
namespace detail {
|
||||
// range iterator
|
||||
|
@ -1203,28 +1208,28 @@ inline auto zip(R1 &&r1, R &&...rr) {
|
|||
|
||||
namespace detail {
|
||||
template<typename C>
|
||||
static std::true_type test_direct_iter(
|
||||
inline std::true_type test_direct_iter(
|
||||
decltype(std::declval<C &>().iter()) *
|
||||
);
|
||||
|
||||
template<typename>
|
||||
static std::false_type test_direct_iter(...);
|
||||
inline std::false_type test_direct_iter(...);
|
||||
|
||||
template<typename C>
|
||||
inline constexpr bool direct_iter_test =
|
||||
static inline constexpr bool const direct_iter_test =
|
||||
decltype(test_direct_iter<C>(0))::value;
|
||||
|
||||
template<typename C>
|
||||
static std::true_type test_std_iter(
|
||||
inline std::true_type test_std_iter(
|
||||
decltype(std::begin(std::declval<C &>())) *,
|
||||
decltype(std::end(std::declval<C &>())) *
|
||||
);
|
||||
|
||||
template<typename>
|
||||
static std::false_type test_std_iter(...);
|
||||
inline std::false_type test_std_iter(...);
|
||||
|
||||
template<typename C>
|
||||
inline constexpr bool std_iter_test =
|
||||
static inline constexpr bool const std_iter_test =
|
||||
decltype(test_std_iter<C>(0, 0))::value;
|
||||
|
||||
/* direct iter and std iter; the case for std iter is
|
||||
|
@ -1298,14 +1303,15 @@ inline auto citer(T const &r) -> decltype(ranged_traits<T const>::iter(r)) {
|
|||
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
static std::true_type test_iterable(
|
||||
inline std::true_type test_iterable(
|
||||
decltype(ostd::iter(std::declval<T>())) *
|
||||
);
|
||||
template<typename>
|
||||
static std::false_type test_iterable(...);
|
||||
inline std::false_type test_iterable(...);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool iterable_test = decltype(test_iterable<T>(0))::value;
|
||||
static inline constexpr bool const iterable_test =
|
||||
decltype(test_iterable<T>(0))::value;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
@ -1387,7 +1393,7 @@ OSTD_UNIT_TEST {
|
|||
fail_if(r.empty() || (r.front() != 9));
|
||||
r.pop_front();
|
||||
fail_if(!r.empty());
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
@ -1894,7 +1900,8 @@ struct iterator_range: input_range<iterator_range<T>> {
|
|||
* If the indexes are not within bounds, the behavior is undefined.
|
||||
*/
|
||||
iterator_range slice(size_type start, size_type end) const {
|
||||
return iterator_range(p_beg + start, p_beg + end);
|
||||
using DT = typename std::iterator_traits<T>::difference_type;
|
||||
return iterator_range(p_beg + DT(start), p_beg + DT(end));
|
||||
}
|
||||
|
||||
/** @brief Slices the range with size() for the second argument.
|
||||
|
@ -1911,7 +1918,10 @@ struct iterator_range: input_range<iterator_range<T>> {
|
|||
* Only valid if the range is at least finite random access.
|
||||
* If the index is not within bounds, the behavior is undefined.
|
||||
*/
|
||||
reference operator[](size_type i) const { return p_beg[i]; }
|
||||
reference operator[](size_type i) const {
|
||||
using DT = typename std::iterator_traits<T>::difference_type;
|
||||
return p_beg[DT(i)];
|
||||
}
|
||||
|
||||
/** @brief Gets the pointer to the first element.
|
||||
*
|
||||
|
|
|
@ -567,6 +567,13 @@ struct stream_range<T, true>: input_range<stream_range<T>> {
|
|||
p_stream(r.p_stream), p_item(r.p_item)
|
||||
{}
|
||||
|
||||
/** @brief Stream ranges can be copied, the cached value is also copied. */
|
||||
stream_range &operator=(stream_range const &r) {
|
||||
p_stream = r.p_stream;
|
||||
p_item = r.p_item;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** @brief Checks if the range (stream) is empty.
|
||||
*
|
||||
* If there is a value cached in this range, this returns false.
|
||||
|
|
|
@ -92,7 +92,7 @@ private:
|
|||
|
||||
public:
|
||||
/** @brief Constructs an empty slice. */
|
||||
basic_char_range() noexcept: p_beg(nullptr), p_end(nullptr) {};
|
||||
basic_char_range() noexcept: p_beg(nullptr), p_end(nullptr) {}
|
||||
|
||||
/** @brief Constructs a slice from two pointers.
|
||||
*
|
||||
|
@ -108,6 +108,11 @@ public:
|
|||
p_beg(nullptr), p_end(nullptr)
|
||||
{}
|
||||
|
||||
/** @brief Slices are arbitrarily copy constructible. */
|
||||
basic_char_range(basic_char_range const &v) noexcept:
|
||||
p_beg(v.p_beg), p_end(v.p_end)
|
||||
{}
|
||||
|
||||
/** @brief Constructs a slice from a pointer or a static array.
|
||||
*
|
||||
* This constructor handles two cases. The input must be convertible
|
||||
|
@ -232,7 +237,7 @@ public:
|
|||
reference back() const noexcept { return *(p_end - 1); }
|
||||
|
||||
/** @brief Gets the number of value_type in the slice. */
|
||||
size_type size() const noexcept { return p_end - p_beg; }
|
||||
size_type size() const noexcept { return size_type(p_end - p_beg); }
|
||||
|
||||
/** @brief Gets the number of code points in the slice.
|
||||
*
|
||||
|
@ -319,7 +324,7 @@ public:
|
|||
int compare(basic_char_range<value_type const> s) const noexcept {
|
||||
size_type s1 = size(), s2 = s.size();
|
||||
for (size_type i = 0, ms = std::min(s1, s2); i < ms; ++i) {
|
||||
int d = p_beg[i] - s[i];
|
||||
int d = int(p_beg[i]) - int(s[i]);
|
||||
if (d) {
|
||||
return d;
|
||||
}
|
||||
|
@ -859,7 +864,7 @@ namespace utf {
|
|||
p_current = -1;
|
||||
throw utf_error{"UTF-8 decoding failed"};
|
||||
} else {
|
||||
p_current = ret;
|
||||
p_current = std::int32_t(ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,9 +46,9 @@ namespace test {
|
|||
#define OSTD_TEST_MODULE_CURRENT OSTD_TEST_MODULE_STR(OSTD_BUILD_TESTS)
|
||||
|
||||
namespace detail {
|
||||
static std::vector<void (*)()> test_cases;
|
||||
static inline std::vector<void (*)()> test_cases;
|
||||
|
||||
static bool add_test(std::string testn, void (*func)()) {
|
||||
inline bool add_test(std::string testn, void (*func)()) {
|
||||
if (testn == OSTD_TEST_MODULE_CURRENT) {
|
||||
test_cases.push_back(func);
|
||||
}
|
||||
|
@ -73,13 +73,13 @@ namespace detail {
|
|||
* after including any headers and undefined at the end of the file.
|
||||
*/
|
||||
#define OSTD_UNIT_TEST \
|
||||
static void OSTD_TEST_FUNC_NAME(test_func, OSTD_TEST_MODULE, __LINE__)(); \
|
||||
static bool OSTD_TEST_FUNC_NAME(test_case, OSTD_TEST_MODULE, __LINE__) = \
|
||||
inline void OSTD_TEST_FUNC_NAME(test_func, OSTD_TEST_MODULE, __LINE__)(); \
|
||||
static inline bool OSTD_TEST_FUNC_NAME(test_case, OSTD_TEST_MODULE, __LINE__) = \
|
||||
ostd::test::detail::add_test( \
|
||||
OSTD_TEST_MODULE_STR(OSTD_TEST_MODULE), \
|
||||
&OSTD_TEST_FUNC_NAME(test_func, OSTD_TEST_MODULE, __LINE__) \
|
||||
); \
|
||||
static void OSTD_TEST_FUNC_NAME(test_func, OSTD_TEST_MODULE, __LINE__)()
|
||||
inline void OSTD_TEST_FUNC_NAME(test_func, OSTD_TEST_MODULE, __LINE__)()
|
||||
|
||||
/** @brief Makes the test fail if the given value is true.
|
||||
*
|
||||
|
@ -90,7 +90,7 @@ static void OSTD_TEST_FUNC_NAME(test_func, OSTD_TEST_MODULE, __LINE__)()
|
|||
*
|
||||
* @see ostd::test::fail(), ostd::test::fail_if_not()
|
||||
*/
|
||||
void fail_if(bool b) {
|
||||
inline void fail_if(bool b) {
|
||||
if (b) {
|
||||
throw detail::test_error{};
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ void fail_if(bool b) {
|
|||
*
|
||||
* The test will fail if the given value is false.
|
||||
*/
|
||||
void fail_if_not(bool b) {
|
||||
inline void fail_if_not(bool b) {
|
||||
if (!b) {
|
||||
throw detail::test_error{};
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ void fail_if_not(bool b) {
|
|||
*
|
||||
* @see ostd::test::fail_if()
|
||||
*/
|
||||
void fail() {
|
||||
[[noreturn]] inline void fail() {
|
||||
throw detail::test_error{};
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ void fail() {
|
|||
* @returns An std::pair containing the number of tests that succeeded
|
||||
* as the first value and failed as the second value.
|
||||
*/
|
||||
std::pair<std::size_t, std::size_t> run() {
|
||||
inline std::pair<std::size_t, std::size_t> run() {
|
||||
std::size_t succ = 0, fail = 0;
|
||||
for (auto &f: detail::test_cases) {
|
||||
try {
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace detail {
|
|||
OSTD_EXPORT void *stack_alloc(std::size_t sz) {
|
||||
if constexpr(CONTEXT_USE_MMAP) {
|
||||
void *p = mmap(
|
||||
0, sz, PROT_READ | PROT_WRITE,
|
||||
nullptr, sz, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | CONTEXT_MAP_ANON, -1, 0
|
||||
);
|
||||
if (p == MAP_FAILED) {
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace detail {
|
|||
ret = (ret << 6) | bch;
|
||||
}
|
||||
/* number of continuation bytes */
|
||||
std::size_t n = sr.data() - r.data() - 1;
|
||||
auto n = sr.data() - r.data() - 1;
|
||||
/* invalid sequence - too many continuation bits */
|
||||
if (n > 3) {
|
||||
return false;
|
||||
|
@ -71,12 +71,12 @@ namespace detail {
|
|||
std::uint8_t (&ret)[4], std::uint32_t ch
|
||||
) noexcept {
|
||||
if (ch <= 0x7F) {
|
||||
ret[0] = ch;
|
||||
ret[0] = std::uint8_t(ch);
|
||||
return 1;
|
||||
}
|
||||
if (ch <= 0x7FF) {
|
||||
ret[0] = 0xC0 | (ch >> 6);
|
||||
ret[1] = 0x80 | (ch & 0x3F);
|
||||
ret[0] = std::uint8_t(0xC0 | (ch >> 6));
|
||||
ret[1] = std::uint8_t(0x80 | (ch & 0x3F));
|
||||
return 2;
|
||||
}
|
||||
if (ch <= 0xFFFF) {
|
||||
|
@ -86,16 +86,16 @@ namespace detail {
|
|||
if ((ch >= 0xD800) && (ch <= 0xDFFF)) {
|
||||
return 0;
|
||||
}
|
||||
ret[0] = 0xE0 | (ch >> 12);
|
||||
ret[1] = 0x80 | ((ch >> 6) & 0x3F);
|
||||
ret[2] = 0x80 | (ch & 0x3F);
|
||||
ret[0] = std::uint8_t(0xE0 | (ch >> 12));
|
||||
ret[1] = std::uint8_t(0x80 | ((ch >> 6) & 0x3F));
|
||||
ret[2] = std::uint8_t(0x80 | (ch & 0x3F));
|
||||
return 3;
|
||||
}
|
||||
if (ch <= MaxCodepoint) {
|
||||
ret[0] = 0xF0 | (ch >> 18);
|
||||
ret[1] = 0x80 | ((ch >> 12) | 0x3F);
|
||||
ret[2] = 0x80 | ((ch >> 6) | 0x3F);
|
||||
ret[3] = 0x80 | (ch | 0x3F);
|
||||
ret[0] = std::uint8_t(0xF0 | (ch >> 18));
|
||||
ret[1] = std::uint8_t(0x80 | ((ch >> 12) | 0x3F));
|
||||
ret[2] = std::uint8_t(0x80 | ((ch >> 6) | 0x3F));
|
||||
ret[3] = std::uint8_t(0x80 | (ch | 0x3F));
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
|
@ -176,7 +176,7 @@ bool isxdigit(char32_t c) noexcept {
|
|||
inline int codepoint_cmp1(void const *a, void const *b) noexcept {
|
||||
char32_t c1 = *static_cast<char32_t const *>(a);
|
||||
char32_t c2 = *static_cast<char32_t const *>(b);
|
||||
return (c1 - c2);
|
||||
return (int(c1) - int(c2));
|
||||
}
|
||||
|
||||
inline int codepoint_cmp2(void const *a, void const *b) noexcept {
|
||||
|
@ -185,7 +185,7 @@ inline int codepoint_cmp2(void const *a, void const *b) noexcept {
|
|||
if ((c >= p[0]) && (c <= p[1])) {
|
||||
return 0;
|
||||
}
|
||||
return (c - p[0]);
|
||||
return (int(c) - int(p[0]));
|
||||
}
|
||||
|
||||
template<
|
||||
|
@ -345,7 +345,12 @@ int case_compare(string_range s1, string_range s2) noexcept {
|
|||
s1 = s1.slice(0, ms);
|
||||
s2 = s2.slice(0, ms);
|
||||
for (;;) {
|
||||
char32_t ldec = s1.front(), rdec = s2.front();
|
||||
/* enforce correct semantics with signed chars; first convert to
|
||||
* 8-bit unsigned and then to char32_t (which is always unsigned)
|
||||
* in order to not get large values from 32-bit unsigned underflow
|
||||
*/
|
||||
auto ldec = char32_t(std::uint8_t(s1.front()));
|
||||
auto rdec = char32_t(std::uint8_t(s2.front()));
|
||||
if ((ldec <= 0x7F) || !utf::decode(s1, ldec)) {
|
||||
s1.pop_front();
|
||||
}
|
||||
|
@ -356,8 +361,13 @@ int case_compare(string_range s1, string_range s2) noexcept {
|
|||
if (d) {
|
||||
return d;
|
||||
}
|
||||
if (s1.empty() || s2.empty()) {
|
||||
s1l = s1.size();
|
||||
s2l = s2.size();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (s1l < s2l) ? -1 : ((s1 > s2) ? 1 : 0);
|
||||
return (s1l < s2l) ? -1 : ((s1l > s2l) ? 1 : 0);
|
||||
}
|
||||
|
||||
int case_compare(u32string_range s1, u32string_range s2) noexcept {
|
||||
|
|
Loading…
Reference in a new issue