various warning fixes with -Weverything

master
Daniel Kolesa 2018-01-03 17:09:28 +01:00
parent 2cbcc85fa8
commit 723c06c612
19 changed files with 255 additions and 224 deletions

View File

@ -473,7 +473,7 @@ int main(int argc, char **argv) {
try_remove("test_runner.o"); try_remove("test_runner.o");
}; };
ostd::thread_pool tp; ostd::thread_pool tp{};
tp.start(); tp.start();
std::queue<std::future<fs::path>> future_obj, future_dynobj; std::queue<std::future<fs::path>> future_obj, future_dynobj;

View File

@ -13,10 +13,10 @@ using namespace ostd;
* task, which may or may not run in parallel with the other one depending * task, which may or may not run in parallel with the other one depending
* on the scheduler currently in use - several schedulers are shown * 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); static 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 second_half = iter(input_array).slice(input_array.size() / 2);
/* this version uses Go-style channels to exchange data; multiple /* this version uses Go-style channels to exchange data; multiple
* tasks can put data into channels, the channel itself is a thread * tasks can put data into channels, the channel itself is a thread

View File

@ -9,7 +9,7 @@
using namespace ostd; 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}; filesystem::directory_iterator ds{path};
for (auto &v: ds) { for (auto &v: ds) {
auto p = filesystem::path{v}; auto p = filesystem::path{v};

View File

@ -33,7 +33,7 @@ int main() {
/* prints ABCDEF (ASCII 65, 66, 67, 68, 69, 70) */ /* prints ABCDEF (ASCII 65, 66, 67, 68, 69, 70) */
writeln("string gen test"); 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()}; std::string s{mr.iter_begin(), mr.iter_end()};
writeln(s); writeln(s);

View File

@ -28,7 +28,7 @@ int main() {
/* prints ABCDEF (ASCII 65, 66, 67, 68, 69, 70) */ /* prints ABCDEF (ASCII 65, 66, 67, 68, 69, 70) */
writeln("string gen test"); 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()}; std::string s{mr.iter_begin(), mr.iter_end()};
writeln(s); writeln(s);
@ -73,7 +73,7 @@ int main() {
/* more complex pipe */ /* more complex pipe */
writeln("several piped algorithms"); writeln("several piped algorithms");
srand(time(0)); srand(static_cast<unsigned int>(time(0)));
std::array<int, 100> arr; std::array<int, 100> arr;
generate(iter(arr), []() { return rand() % 128; }); generate(iter(arr), []() { return rand() % 128; });

View File

@ -9,7 +9,7 @@
using namespace ostd; using namespace ostd;
void print_result(uint32_t x) { inline void print_result(uint32_t x) {
writefln("got x: 0x%X", x); writefln("got x: 0x%X", x);
} }

View File

@ -135,7 +135,7 @@ struct parse_state {
((i + 1) < codes.size()) && (codes[i + 1] == (codes[i] + off)) ((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) && ( return match_pair(i, 1) && (
cases.empty() || (cases[i + 1] == (cases[i] + 1)) cases.empty() || (cases[i + 1] == (cases[i] + 1))
); );

View File

@ -146,7 +146,7 @@ OSTD_UNIT_TEST {
namespace detail { namespace detail {
template<typename R, typename C> 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(); range_size_t<R> rlen = range.size();
for (range_size_t<R> i = 1; i < rlen; ++i) { for (range_size_t<R> i = 1; i < rlen; ++i) {
range_size_t<R> j = i; range_size_t<R> j = i;
@ -160,7 +160,7 @@ namespace detail {
} }
template<typename R, typename C> 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 R range, range_size_t<R> s, range_size_t<R> e, C &compare
) { ) {
range_size_t<R> r = s; range_size_t<R> r = s;
@ -184,7 +184,7 @@ namespace detail {
} }
template<typename R, typename C> 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> len = range.size();
range_size_t<R> st = (len - 2) / 2; range_size_t<R> st = (len - 2) / 2;
for (;;) { for (;;) {
@ -203,7 +203,7 @@ namespace detail {
} }
template<typename R, typename C> 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; using std::swap;
if (range.size() <= 10) { if (range.size() <= 10) {
detail::insort(range, compare); 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`, * Iterates the range and as soon as `range.front()` is equal to `v`,
* returns `range`. The `range` is at least ostd::input_range_tag. * 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() * ostd::find_one_of()
*/ */
template<typename InputRange, typename Value> 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 * the previous result of ostd::find() in case nothing is found next, this
* algortihm requires `range` to be at least ostd::forward_range_tag. * 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() * ostd::find_one_of()
*/ */
template<typename ForwardRange, typename Value> 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, * Iterates the range and as soon as `pred(range.front())` is true,
* returns `range`. The `range` is at least ostd::input_range_tag. * 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() * ostd::find_one_of()
*/ */
template<typename InputRange, typename Predicate> 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, * Iterates the range and as soon as `!pred(range.front())` is true,
* returns `range`. The `range` is at least ostd::input_range_tag. * 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> template<typename InputRange, typename Predicate>
inline InputRange find_if_not(InputRange range, Predicate pred) { 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 * Use ostd::find_one_of() if you want to use the `==` operator
* instead of calling `compare`. * 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() * ostd::find_one_of()
*/ */
template<typename InputRange, typename ForwardRange, typename Compare> 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 * Use ostd::find_one_of_cmp() if you want to use a comparison
* function instead of the `==` operator. * 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() * ostd::find_one_of_cmp()
*/ */
template<typename InputRange, typename ForwardRange> template<typename InputRange, typename ForwardRange>

View File

@ -492,7 +492,7 @@ private:
case arg_value::OPTIONAL: case arg_value::OPTIONAL:
case arg_value::ALL: case arg_value::ALL:
break; break;
default: case arg_value::REST:
throw arg_error{"invalid argument requirement"}; throw arg_error{"invalid argument requirement"};
} }
} }
@ -917,7 +917,6 @@ protected:
private: private:
std::string p_name, p_title; std::string p_name, p_title;
std::vector<std::unique_ptr<arg_description>> p_opts;
}; };
template<typename F> template<typename F>
@ -959,9 +958,6 @@ inline bool arg_description_container::for_each(
return false; return false;
} }
break; break;
default:
/* should never happen */
throw arg_error{"invalid argument type"};
} }
} }
return true; return true;
@ -1519,8 +1515,8 @@ struct default_help_formatter {
/** @brief Formats the options (after usage line). /** @brief Formats the options (after usage line).
* *
* Positional arguments not belonging to any group are formatted * Positional arguments not belonging to any group are formatted
* first, with `\nPositional arguments:\n` header. Same goes with * first, with `\\nPositional arguments:\\n` header. Same goes with
* optional arguments, except with `\nOptional arguments:\n`. * optional arguments, except with `\\nOptional arguments:\\n`.
* *
* If either positional or optional arguments without group don't * If either positional or optional arguments without group don't
* exist, the section is skipped. * 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 * help strings are aligned and offset by 2 spaces from the longest
* argument string. * argument string.
* *
* Group titles are formatted as `\nTITLE:\n`. * Group titles are formatted as `\\nTITLE:\\n`.
* *
* Within groups, positional arguments come first and optional * Within groups, positional arguments come first and optional
* arguments second. Mutually exclusive groups are expanded. * arguments second. Mutually exclusive groups are expanded.
@ -1586,8 +1582,6 @@ struct default_help_formatter {
} }
); );
break; break;
default:
break;
} }
return true; return true;
}, false, false); }, false, false);
@ -1636,9 +1630,7 @@ struct default_help_formatter {
} }
auto &garg = static_cast<arg_group const &>(arg); auto &garg = static_cast<arg_group const &>(arg);
format(out, "\n%s:\n", garg.title()); format(out, "\n%s:\n", garg.title());
garg.for_each([ garg.for_each([&allopt, &allpos](auto const &marg) {
&write_help, &out, &allopt, &allpos
](auto const &marg) {
switch (marg.type()) { switch (marg.type()) {
case arg_type::OPTIONAL: case arg_type::OPTIONAL:
allopt.push_back( allopt.push_back(
@ -1650,7 +1642,8 @@ struct default_help_formatter {
static_cast<arg_positional const *>(&marg) static_cast<arg_positional const *>(&marg)
); );
break; break;
default: case arg_type::GROUP:
case arg_type::MUTUALLY_EXCLUSIVE_GROUP:
/* should never happen */ /* should never happen */
throw arg_error{"invalid argument type"}; throw arg_error{"invalid argument type"};
} }
@ -1700,7 +1693,7 @@ struct default_help_formatter {
} }
format(out, " [%s ...]", mt); format(out, " [%s ...]", mt);
break; break;
default: case arg_value::REST:
break; break;
} }
names.pop_front(); names.pop_front();
@ -1741,7 +1734,8 @@ struct default_help_formatter {
case arg_type::POSITIONAL: case arg_type::POSITIONAL:
format_option(out, static_cast<arg_positional const &>(arg)); format_option(out, static_cast<arg_positional const &>(arg));
break; break;
default: case arg_type::GROUP:
case arg_type::MUTUALLY_EXCLUSIVE_GROUP:
/* should never happen */ /* should never happen */
throw arg_error{"invalid argument type"}; 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.print_help(o);
p.stop_parsing(); p.stop_parsing();
}; };
}; }
/** @brief Like ostd::arg_print_help() with ostd::cout. */ /** @brief Like ostd::arg_print_help() with ostd::cout. */
inline auto arg_print_help(arg_parser &p) { inline auto arg_print_help(arg_parser &p) {

View File

@ -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. /** @brief An allocated stack.
* *
* This represents a stack allocated by a stack allocator. It doesn't * This represents a stack allocated by a stack allocator. It doesn't

View File

@ -58,35 +58,6 @@ struct coroutine_error: std::runtime_error {
using std::runtime_error::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. /** @brief An encapsulated context any coroutine-type inherits from.
* *
* Internally, this provides some basic infrastructure for creating and * Internally, this provides some basic infrastructure for creating and
@ -135,7 +106,7 @@ protected:
*/ */
coroutine_context(coroutine_context &&c): coroutine_context(coroutine_context &&c):
p_stack(std::move(c.p_stack)), p_coro(c.p_coro), p_orig(c.p_orig), 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_coro = c.p_orig = nullptr;
c.p_stack = { nullptr, 0 }; c.p_stack = { nullptr, 0 };
@ -249,9 +220,9 @@ protected:
swap(p_stack, other.p_stack); swap(p_stack, other.p_stack);
swap(p_coro, other.p_coro); swap(p_coro, other.p_coro);
swap(p_orig, other.p_orig); swap(p_orig, other.p_orig);
swap(p_free, other.p_free);
swap(p_except, other.p_except); swap(p_except, other.p_except);
swap(p_state, other.p_state); swap(p_state, other.p_state);
swap(p_free, other.p_free);
} }
/** @brief Allocates a stack and creates a context. /** @brief Allocates a stack and creates a context.
@ -276,10 +247,10 @@ protected:
p_stack = sa.allocate(); p_stack = sa.allocate();
void *sp = get_stack_ptr<SA>(); 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 *>(p_stack.ptr) -
static_cast<unsigned char *>(sp) static_cast<unsigned char *>(sp)
); ));
p_coro = detail::ostd_make_fcontext(sp, asize, &context_call<C, SA>); p_coro = detail::ostd_make_fcontext(sp, asize, &context_call<C, SA>);
new (sp) SA(std::move(sa)); new (sp) SA(std::move(sa));
@ -374,9 +345,9 @@ release:
stack_context p_stack; stack_context p_stack;
detail::fcontext_t p_coro = nullptr; detail::fcontext_t p_coro = nullptr;
detail::fcontext_t p_orig = nullptr; detail::fcontext_t p_orig = nullptr;
void (*p_free)(void *) = nullptr;
std::exception_ptr p_except; std::exception_ptr p_except;
state p_state = state::HOLD; state p_state = state::HOLD;
void (*p_free)(void *) = nullptr;
}; };
template<typename T> template<typename T>
@ -653,7 +624,7 @@ namespace detail {
* as they were passed, exactly as if they were passed as regular args. * as they were passed, exactly as if they were passed as regular args.
* *
* @tparam R The return template type. * @tparam R The return template type.
* @tparam A... The argument template types. * @tparam A The argument template types.
*/ */
template<typename R, typename ...A> template<typename R, typename ...A>
struct coroutine<R(A...)>: coroutine_context { struct coroutine<R(A...)>: coroutine_context {

View File

@ -134,7 +134,7 @@ namespace detail {
* 7 .. string * 7 .. string
* 8 .. custom object * 8 .. custom object
*/ */
inline constexpr unsigned char const fmt_specs[] = { static inline constexpr unsigned char const fmt_specs[] = {
/* uppercase spec set */ /* uppercase spec set */
1, 3, 8, 8, /* A B C D */ 1, 3, 8, 8, /* A B C D */
1, 1, 1, 8, /* E F G H */ 1, 1, 1, 8, /* E F G H */
@ -160,12 +160,12 @@ namespace detail {
0, 0, 0, 0, 0 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 0, 0, 0, 2, 8, 10, 16, 0
}; };
/* non-printable escapes up to 0x20 (space) */ /* 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", "\\0" , "\\x01", "\\x02", "\\x03", "\\x04", "\\x05",
"\\x06", "\\a" , "\\b" , "\\t" , "\\n" , "\\v" , "\\x06", "\\a" , "\\b" , "\\t" , "\\n" , "\\v" ,
"\\f" , "\\r" , "\\x0E", "\\x0F", "\\x10", "\\x11", "\\f" , "\\r" , "\\x0E", "\\x0F", "\\x10", "\\x11",
@ -215,33 +215,35 @@ namespace detail {
* pair, array, possibly other types added later or overridden... * pair, array, possibly other types added later or overridden...
*/ */
template<typename T> 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> template<typename>
std::false_type tuple_like_test(...); inline std::false_type tuple_like_test(...);
template<typename T> 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 */ /* character type tests */
template<typename C> template<typename C>
inline constexpr bool is_character = std::is_same_v<C, char> || static inline constexpr bool is_character = std::is_same_v<C, char> ||
std::is_same_v<C, wchar_t> || std::is_same_v<C, wchar_t> ||
std::is_same_v<C, char16_t> || std::is_same_v<C, char16_t> ||
std::is_same_v<C, char32_t>; std::is_same_v<C, char32_t>;
/* test if format traits are available for the type */ /* test if format traits are available for the type */
template<typename T, typename R> 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<T const &>(), std::declval<R &>(),
std::declval<format_spec const &>() std::declval<format_spec const &>()
)) *); )) *);
template<typename, typename> template<typename, typename>
static std::false_type test_tofmt(...); inline std::false_type test_tofmt(...);
template<typename T, typename R> 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> template<typename C, typename F>
inline int ac_to_mb(C c, F const &f, char *buf) { inline int ac_to_mb(C c, F const &f, char *buf) {
@ -252,7 +254,7 @@ namespace detail {
if (ret != std::codecvt_base::ok) { if (ret != std::codecvt_base::ok) {
return -1; 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) { inline int wc_to_mb_loc(wchar_t c, char *buf, std::locale const &loc) {
@ -847,14 +849,16 @@ private:
if (p.front() == need) { if (p.front() == need) {
p_is_tuple = tuple; p_is_tuple = tuple;
if (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; p_nested_sep = nullptr;
} else { } else {
p_nested = begin_inner.slice( 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( 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(); p.pop_front();
@ -864,14 +868,16 @@ private:
} }
/* found actual delimiter start... */ /* found actual delimiter start... */
if ((p.front() == '|') && !tuple) { 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.pop_front();
p_nested_sep = p; p_nested_sep = p;
for (p = find(p, '%'); !p.empty(); p = find(p, '%')) { for (p = find(p, '%'); !p.empty(); p = find(p, '%')) {
p.pop_front(); p.pop_front();
if (p.front() == ')') { if (p.front() == ')') {
p_nested_sep = p_nested_sep.slice( 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.pop_front();
p_fmt = p; p_fmt = p;
@ -1083,15 +1089,15 @@ private:
throw format_error{"cannot format integers with the given spec"}; throw format_error{"cannot format integers with the given spec"};
} }
/* 32 for lowercase variants, 0 for uppercase */ /* 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) { if (!val) {
ndig = 1; ndig = 1;
buf[0] = '0'; buf[0] = '0';
} else { } else {
for (; val; val /= base) { for (; val; val /= base) {
T vb = val % base; auto vb = char(val % base);
buf[ndig++] = (vb + "70"[vb < 10]) | cmask; buf[ndig++] = (vb + "70"[vb < 10]) | cmask;
} }
} }
@ -1132,7 +1138,7 @@ private:
} }
++grpp; ++grpp;
} }
total += nseps * ntsep; total += nseps * std::size_t(ntsep);
} }
/* here ends the bullshit */ /* here ends the bullshit */
@ -1244,7 +1250,8 @@ private:
fmt_num_put<R> nump; fmt_num_put<R> nump;
nump.put( nump.put(
fmt_out<R>{&writer, &p_loc}, st, 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"}; throw format_error{"tuples need the '%s' spec"};
} }
writer.put('{'); writer.put('{');
write_range_val(writer, [&writer, escape, this](auto const &rval) { write_range_val(writer, [&writer, this](auto const &rval, bool esc) {
format_spec sp{'s', p_loc, escape ? FMT_FLAG_AT : 0}; format_spec sp{'s', p_loc, esc ? FMT_FLAG_AT : 0};
sp.write_arg(writer, 0, rval); sp.write_arg(writer, 0, rval);
}, ", ", val); }, ", ", val, escape);
writer.put('}'); writer.put('}');
return; return;
} }
@ -1369,13 +1376,11 @@ private:
) const { ) const {
if constexpr(detail::is_tuple_like<T>) { if constexpr(detail::is_tuple_like<T>) {
if (expandval) { if (expandval) {
std::apply([&writer, escape, &fmt, this]( std::apply([
auto const &...args this, &writer, &fmt, flags = escape ? FMT_FLAG_AT : 0
) mutable { ](auto const &...args) mutable {
format_spec sp{fmt, p_loc}; format_spec sp{fmt, p_loc};
if (escape) { sp.p_gflags |= flags;
sp.p_gflags |= FMT_FLAG_AT;
}
sp.write_fmt(writer, args...); sp.write_fmt(writer, args...);
}, item); }, item);
return; return;
@ -1388,9 +1393,10 @@ private:
sp.write_fmt(writer, item); 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( 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 { ) const {
if constexpr(detail::iterable_test<T>) { if constexpr(detail::iterable_test<T>) {
auto range = ostd::iter(val); auto range = ostd::iter(val);
@ -1398,7 +1404,7 @@ private:
return; return;
} }
for (;;) { for (;;) {
func(range.front()); func(range.front(), args...);
range.pop_front(); range.pop_front();
if (range.empty()) { if (range.empty()) {
break; break;
@ -1424,13 +1430,12 @@ private:
} }
} else { } else {
write_range_val(writer, [ write_range_val(writer, [
this, &writer, escape = p_gflags & FMT_FLAG_AT, expandval, fmt = rest(), this, &writer
fmt = rest() ](auto const &rval, bool expval, bool escape) {
](auto const &rval) {
this->write_range_item( 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 { } else {
if constexpr(detail::is_tuple_like<T>) { 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...); this->write_fmt(writer, vals...);
}, val); }, val);
} else { } else {

View File

@ -110,7 +110,37 @@ struct OSTD_EXPORT subprocess {
private: private:
struct nat {}; struct nat {};
std::aligned_storage_t<2 * sizeof(void *), alignof(void *)> p_data;
void *p_current = nullptr;
public: 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. /** @brief The standard input redirection mode.
* *
* The value is one of ostd::subprocess_stream. Set this before opening * The value is one of ostd::subprocess_stream. Set this before opening
@ -154,33 +184,6 @@ public:
*/ */
subprocess_stream use_err = subprocess_stream::DEFAULT; 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. */ /** @brief Initializes the structure with the given stream redirections. */
subprocess( subprocess(
subprocess_stream in_use = subprocess_stream::DEFAULT, subprocess_stream in_use = subprocess_stream::DEFAULT,
@ -232,8 +235,8 @@ public:
/** @brief Moves the subprocess data. */ /** @brief Moves the subprocess data. */
subprocess(subprocess &&i) noexcept: 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); move_data(i);
} }
@ -460,9 +463,6 @@ private:
void reset(); void reset();
void move_data(subprocess &i); void move_data(subprocess &i);
void swap_data(subprocess &i); void swap_data(subprocess &i);
std::aligned_storage_t<2 * sizeof(void *)> p_data;
void *p_current = nullptr;
}; };
/** @} */ /** @} */

View File

@ -186,7 +186,8 @@ namespace detail {
}; };
template<typename R> 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> template<typename R, bool, bool>
struct range_traits_base { struct range_traits_base {
@ -199,7 +200,7 @@ namespace detail {
}; };
template<typename R> 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_convertible_v<typename R::range_category, input_range_tag> &&
std::is_lvalue_reference_v<typename R::reference> && std::is_lvalue_reference_v<typename R::reference> &&
std::is_same_v< std::is_same_v<
@ -388,7 +389,7 @@ using range_reference_t = typename range_traits<R>::reference;
* *
*/ */
template<typename R1, typename R2> 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>; range_traits<R1>::template is_element_swappable_with<R2>;
/** @brief Checks whether a range can swap elements within itself. /** @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> 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; range_traits<R>::is_element_swappable;
/** @brief Checks whether two ranges can nothrow swap elements with each other. /** @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> 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>; range_traits<R1>::template is_element_nothrow_swappable_with<R2>;
/** @brief Checks whether a range can nothrow swap elements within itself. /** @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> 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; range_traits<R>::is_element_nothrow_swappable;
// is input range // is input range
namespace detail { namespace detail {
template<typename T> 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>; std::is_convertible_v<range_category_t<T>, input_range_tag>;
template<typename T, bool = detail::test_range_category<T>> 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> 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>; detail::is_input_range_core<T>;
} }
@ -453,20 +454,21 @@ namespace detail {
* @see ostd::is_forward_range, ostd::is_output_range * @see ostd::is_forward_range, ostd::is_output_range
*/ */
template<typename T> 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 // is forward range
namespace detail { namespace detail {
template<typename T> 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>; std::is_convertible_v<range_category_t<T>, forward_range_tag>;
template<typename T, bool = detail::test_range_category<T>> 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> 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>; detail::is_forward_range_core<T>;
} }
@ -478,20 +480,21 @@ namespace detail {
* @see ostd::is_input_range, ostd::is_bidirectional_range * @see ostd::is_input_range, ostd::is_bidirectional_range
*/ */
template<typename T> 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 // is bidirectional range
namespace detail { namespace detail {
template<typename T> 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>; std::is_convertible_v<range_category_t<T>, bidirectional_range_tag>;
template<typename T, bool = detail::test_range_category<T>> 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> 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>; detail::is_bidirectional_range_core<T>;
} }
@ -503,21 +506,21 @@ namespace detail {
* @see ostd::is_forward_range, ostd::is_random_access_range * @see ostd::is_forward_range, ostd::is_random_access_range
*/ */
template<typename T> template<typename T>
inline constexpr bool is_bidirectional_range = static inline constexpr bool const is_bidirectional_range =
detail::is_bidirectional_range_base<T>; detail::is_bidirectional_range_base<T>;
// is random access range // is random access range
namespace detail { namespace detail {
template<typename T> 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>; std::is_convertible_v<range_category_t<T>, random_access_range_tag>;
template<typename T, bool = detail::test_range_category<T>> 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> 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>; detail::is_random_access_range_core<T>;
} }
@ -530,21 +533,21 @@ namespace detail {
* @see ostd::is_bidirectional_range, ostd::is_finite_random_access_range * @see ostd::is_bidirectional_range, ostd::is_finite_random_access_range
*/ */
template<typename T> 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>; detail::is_random_access_range_base<T>;
// is finite random access range // is finite random access range
namespace detail { namespace detail {
template<typename T> 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>; std::is_convertible_v<range_category_t<T>, finite_random_access_range_tag>;
template<typename T, bool = detail::test_range_category<T>> 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> 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>; detail::is_finite_random_access_range_core<T>;
} }
@ -557,21 +560,21 @@ namespace detail {
* @see ostd::is_random_access_range, ostd::is_contiguous_range * @see ostd::is_random_access_range, ostd::is_contiguous_range
*/ */
template<typename T> 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>; detail::is_finite_random_access_range_base<T>;
// is contiguous range // is contiguous range
namespace detail { namespace detail {
template<typename T> 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>; std::is_convertible_v<range_category_t<T>, contiguous_range_tag>;
template<typename T, bool = detail::test_range_category<T>> 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> 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>; detail::is_contiguous_range_core<T>;
} }
@ -582,25 +585,26 @@ namespace detail {
* @see ostd::is_finite_random_access_range * @see ostd::is_finite_random_access_range
*/ */
template<typename T> 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 // is output range
namespace detail { namespace detail {
template<typename R, typename T> 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 decltype(std::declval<R &>().put(std::declval<T>())), void
>::type *); >::type *);
template<typename, typename> template<typename, typename>
static std::false_type test_outrange(...); inline std::false_type test_outrange(...);
template<typename R, typename T> 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; decltype(test_outrange<R, T>())::value;
template<typename T> 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> || ( std::is_convertible_v<range_category_t<T>, output_range_tag> || (
is_input_range<T> && ( is_input_range<T> && (
output_range_test<T, range_value_t<T> const &> || output_range_test<T, range_value_t<T> const &> ||
@ -610,10 +614,10 @@ namespace detail {
); );
template<typename T, bool = detail::test_range_category<T>> 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> 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>; detail::is_output_range_core<T>;
} }
@ -627,7 +631,8 @@ namespace detail {
* @see ostd::is_input_range * @see ostd::is_input_range
*/ */
template<typename T> 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 { namespace detail {
// range iterator // range iterator
@ -1203,28 +1208,28 @@ inline auto zip(R1 &&r1, R &&...rr) {
namespace detail { namespace detail {
template<typename C> template<typename C>
static std::true_type test_direct_iter( inline std::true_type test_direct_iter(
decltype(std::declval<C &>().iter()) * decltype(std::declval<C &>().iter()) *
); );
template<typename> template<typename>
static std::false_type test_direct_iter(...); inline std::false_type test_direct_iter(...);
template<typename C> template<typename C>
inline constexpr bool direct_iter_test = static inline constexpr bool const direct_iter_test =
decltype(test_direct_iter<C>(0))::value; decltype(test_direct_iter<C>(0))::value;
template<typename C> 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::begin(std::declval<C &>())) *,
decltype(std::end(std::declval<C &>())) * decltype(std::end(std::declval<C &>())) *
); );
template<typename> template<typename>
static std::false_type test_std_iter(...); inline std::false_type test_std_iter(...);
template<typename C> 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; decltype(test_std_iter<C>(0, 0))::value;
/* direct iter and std iter; the case for std iter is /* 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 { namespace detail {
template<typename T> template<typename T>
static std::true_type test_iterable( inline std::true_type test_iterable(
decltype(ostd::iter(std::declval<T>())) * decltype(ostd::iter(std::declval<T>())) *
); );
template<typename> template<typename>
static std::false_type test_iterable(...); inline std::false_type test_iterable(...);
template<typename T> 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 { namespace detail {
@ -1387,7 +1393,7 @@ OSTD_UNIT_TEST {
fail_if(r.empty() || (r.front() != 9)); fail_if(r.empty() || (r.front() != 9));
r.pop_front(); r.pop_front();
fail_if(!r.empty()); fail_if(!r.empty());
}; }
#endif #endif
namespace detail { 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. * If the indexes are not within bounds, the behavior is undefined.
*/ */
iterator_range slice(size_type start, size_type end) const { 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. /** @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. * Only valid if the range is at least finite random access.
* If the index is not within bounds, the behavior is undefined. * 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. /** @brief Gets the pointer to the first element.
* *

View File

@ -567,6 +567,13 @@ struct stream_range<T, true>: input_range<stream_range<T>> {
p_stream(r.p_stream), p_item(r.p_item) 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. /** @brief Checks if the range (stream) is empty.
* *
* If there is a value cached in this range, this returns false. * If there is a value cached in this range, this returns false.

View File

@ -92,7 +92,7 @@ private:
public: public:
/** @brief Constructs an empty slice. */ /** @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. /** @brief Constructs a slice from two pointers.
* *
@ -108,6 +108,11 @@ public:
p_beg(nullptr), p_end(nullptr) 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. /** @brief Constructs a slice from a pointer or a static array.
* *
* This constructor handles two cases. The input must be convertible * This constructor handles two cases. The input must be convertible
@ -232,7 +237,7 @@ public:
reference back() const noexcept { return *(p_end - 1); } reference back() const noexcept { return *(p_end - 1); }
/** @brief Gets the number of value_type in the slice. */ /** @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. /** @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 { int compare(basic_char_range<value_type const> s) const noexcept {
size_type s1 = size(), s2 = s.size(); size_type s1 = size(), s2 = s.size();
for (size_type i = 0, ms = std::min(s1, s2); i < ms; ++i) { 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) { if (d) {
return d; return d;
} }
@ -859,7 +864,7 @@ namespace utf {
p_current = -1; p_current = -1;
throw utf_error{"UTF-8 decoding failed"}; throw utf_error{"UTF-8 decoding failed"};
} else { } else {
p_current = ret; p_current = std::int32_t(ret);
} }
} }

View File

@ -46,9 +46,9 @@ namespace test {
#define OSTD_TEST_MODULE_CURRENT OSTD_TEST_MODULE_STR(OSTD_BUILD_TESTS) #define OSTD_TEST_MODULE_CURRENT OSTD_TEST_MODULE_STR(OSTD_BUILD_TESTS)
namespace detail { 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) { if (testn == OSTD_TEST_MODULE_CURRENT) {
test_cases.push_back(func); test_cases.push_back(func);
} }
@ -73,13 +73,13 @@ namespace detail {
* after including any headers and undefined at the end of the file. * after including any headers and undefined at the end of the file.
*/ */
#define OSTD_UNIT_TEST \ #define OSTD_UNIT_TEST \
static void OSTD_TEST_FUNC_NAME(test_func, OSTD_TEST_MODULE, __LINE__)(); \ inline void OSTD_TEST_FUNC_NAME(test_func, OSTD_TEST_MODULE, __LINE__)(); \
static bool OSTD_TEST_FUNC_NAME(test_case, OSTD_TEST_MODULE, __LINE__) = \ static inline bool OSTD_TEST_FUNC_NAME(test_case, OSTD_TEST_MODULE, __LINE__) = \
ostd::test::detail::add_test( \ ostd::test::detail::add_test( \
OSTD_TEST_MODULE_STR(OSTD_TEST_MODULE), \ OSTD_TEST_MODULE_STR(OSTD_TEST_MODULE), \
&OSTD_TEST_FUNC_NAME(test_func, OSTD_TEST_MODULE, __LINE__) \ &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. /** @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() * @see ostd::test::fail(), ostd::test::fail_if_not()
*/ */
void fail_if(bool b) { inline void fail_if(bool b) {
if (b) { if (b) {
throw detail::test_error{}; throw detail::test_error{};
} }
@ -100,7 +100,7 @@ void fail_if(bool b) {
* *
* The test will fail if the given value is false. * 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) { if (!b) {
throw detail::test_error{}; throw detail::test_error{};
} }
@ -112,7 +112,7 @@ void fail_if_not(bool b) {
* *
* @see ostd::test::fail_if() * @see ostd::test::fail_if()
*/ */
void fail() { [[noreturn]] inline void fail() {
throw detail::test_error{}; throw detail::test_error{};
} }
@ -121,7 +121,7 @@ void fail() {
* @returns An std::pair containing the number of tests that succeeded * @returns An std::pair containing the number of tests that succeeded
* as the first value and failed as the second value. * 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; std::size_t succ = 0, fail = 0;
for (auto &f: detail::test_cases) { for (auto &f: detail::test_cases) {
try { try {

View File

@ -40,7 +40,7 @@ namespace detail {
OSTD_EXPORT void *stack_alloc(std::size_t sz) { OSTD_EXPORT void *stack_alloc(std::size_t sz) {
if constexpr(CONTEXT_USE_MMAP) { if constexpr(CONTEXT_USE_MMAP) {
void *p = mmap( void *p = mmap(
0, sz, PROT_READ | PROT_WRITE, nullptr, sz, PROT_READ | PROT_WRITE,
MAP_PRIVATE | CONTEXT_MAP_ANON, -1, 0 MAP_PRIVATE | CONTEXT_MAP_ANON, -1, 0
); );
if (p == MAP_FAILED) { if (p == MAP_FAILED) {

View File

@ -47,7 +47,7 @@ namespace detail {
ret = (ret << 6) | bch; ret = (ret << 6) | bch;
} }
/* number of continuation bytes */ /* 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 */ /* invalid sequence - too many continuation bits */
if (n > 3) { if (n > 3) {
return false; return false;
@ -71,12 +71,12 @@ namespace detail {
std::uint8_t (&ret)[4], std::uint32_t ch std::uint8_t (&ret)[4], std::uint32_t ch
) noexcept { ) noexcept {
if (ch <= 0x7F) { if (ch <= 0x7F) {
ret[0] = ch; ret[0] = std::uint8_t(ch);
return 1; return 1;
} }
if (ch <= 0x7FF) { if (ch <= 0x7FF) {
ret[0] = 0xC0 | (ch >> 6); ret[0] = std::uint8_t(0xC0 | (ch >> 6));
ret[1] = 0x80 | (ch & 0x3F); ret[1] = std::uint8_t(0x80 | (ch & 0x3F));
return 2; return 2;
} }
if (ch <= 0xFFFF) { if (ch <= 0xFFFF) {
@ -86,16 +86,16 @@ namespace detail {
if ((ch >= 0xD800) && (ch <= 0xDFFF)) { if ((ch >= 0xD800) && (ch <= 0xDFFF)) {
return 0; return 0;
} }
ret[0] = 0xE0 | (ch >> 12); ret[0] = std::uint8_t(0xE0 | (ch >> 12));
ret[1] = 0x80 | ((ch >> 6) & 0x3F); ret[1] = std::uint8_t(0x80 | ((ch >> 6) & 0x3F));
ret[2] = 0x80 | (ch & 0x3F); ret[2] = std::uint8_t(0x80 | (ch & 0x3F));
return 3; return 3;
} }
if (ch <= MaxCodepoint) { if (ch <= MaxCodepoint) {
ret[0] = 0xF0 | (ch >> 18); ret[0] = std::uint8_t(0xF0 | (ch >> 18));
ret[1] = 0x80 | ((ch >> 12) | 0x3F); ret[1] = std::uint8_t(0x80 | ((ch >> 12) | 0x3F));
ret[2] = 0x80 | ((ch >> 6) | 0x3F); ret[2] = std::uint8_t(0x80 | ((ch >> 6) | 0x3F));
ret[3] = 0x80 | (ch | 0x3F); ret[3] = std::uint8_t(0x80 | (ch | 0x3F));
return 4; return 4;
} }
return 0; return 0;
@ -176,7 +176,7 @@ bool isxdigit(char32_t c) noexcept {
inline int codepoint_cmp1(void const *a, void const *b) noexcept { inline int codepoint_cmp1(void const *a, void const *b) noexcept {
char32_t c1 = *static_cast<char32_t const *>(a); char32_t c1 = *static_cast<char32_t const *>(a);
char32_t c2 = *static_cast<char32_t const *>(b); 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 { 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])) { if ((c >= p[0]) && (c <= p[1])) {
return 0; return 0;
} }
return (c - p[0]); return (int(c) - int(p[0]));
} }
template< template<
@ -345,7 +345,12 @@ int case_compare(string_range s1, string_range s2) noexcept {
s1 = s1.slice(0, ms); s1 = s1.slice(0, ms);
s2 = s2.slice(0, ms); s2 = s2.slice(0, ms);
for (;;) { 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)) { if ((ldec <= 0x7F) || !utf::decode(s1, ldec)) {
s1.pop_front(); s1.pop_front();
} }
@ -356,8 +361,13 @@ int case_compare(string_range s1, string_range s2) noexcept {
if (d) { if (d) {
return 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 { int case_compare(u32string_range s1, u32string_range s2) noexcept {