refactoring, style updates, various fixes

master
Daniel Kolesa 2016-07-31 20:40:25 +01:00
parent 63e5d321f1
commit 8afffc1fb7
34 changed files with 3066 additions and 1788 deletions

View File

@ -1,5 +1,6 @@
#include <ostd/io.hh>
#include <ostd/filesystem.hh>
#include <ostd/range.hh>
using namespace ostd;
@ -7,16 +8,19 @@ void list_dirs(ConstCharRange path, int off = 0) {
DirectoryStream ds{path};
/* iterate all items in directory */
for (auto v: ds.iter()) {
if (v.type() != FileType::directory)
if (v.type() != FileType::directory) {
continue;
for (int i = 0; i < off; ++i) write(' ');
}
for_each(range(off), [](int) { write(' '); });
writeln(v.filename());
list_dirs(v.path(), off + 1);
}
}
int main(int argc, char **argv) {
if (argc < 1) return 1;
if (argc < 1) {
return 1;
}
list_dirs(argv[1]);
return 0;
}

View File

@ -7,19 +7,22 @@ using namespace ostd;
int main() {
/* range iter - prints 0 to 9 each on new line */
writeln("range iter test");
for (int i: range(10))
for (int i: range(10)) {
writeln(i);
}
/* algorithm: map - prints 0.5 to 9.5 each on new line */
writeln("range map test");
for (float f: map(range(10), [](int v) { return v + 0.5f; }))
for (float f: map(range(10), [](int v) { return v + 0.5f; })) {
writeln(f);
}
/* algorithm: filter - prints 10, 15, 8 each on new line */
writeln("range filter test");
auto il = { 5, 5, 5, 5, 5, 10, 15, 4, 8, 2 };
for (int i: filter(iter(il), [](int v) { return v > 5; }))
for (int i: filter(iter(il), [](int v) { return v > 5; })) {
writeln(i);
}
/* prints ABCDEF (ASCII 65, 66, 67, 68, 69, 70) */
writeln("string gen test");
@ -31,8 +34,9 @@ int main() {
auto x = { 11, 22, 33 };
auto y = { 44, 55, 66 };
auto z = { 77, 88, 99 };
for (auto i: iter(x).join(iter(y), iter(z)))
for (auto i: iter(x).join(iter(y), iter(z))) {
writeln(i);
}
/* chunk a range into subranges - prints
* {11, 22, 33}
@ -41,21 +45,25 @@ int main() {
*/
writeln("range chunk test");
auto cr = { 11, 22, 33, 44, 55, 66, 77, 88, 99 };
for (auto r: iter(cr).chunks(3))
for (auto r: iter(cr).chunks(3)) {
writeln(r);
}
/* take test, prints only first 4 */
writeln("range take test");
for (auto r: iter(cr).take(4))
for (auto r: iter(cr).take(4)) {
writeln(r);
}
/* {11, 44, 77}, {22, 55, 88}, {33, 66, 99} */
writeln("range zip test");
for (auto v: iter(x).zip(iter(y), iter(z)))
for (auto v: iter(x).zip(iter(y), iter(z))) {
writeln(v);
}
/* 2-tuple zip uses Pair */
writeln("2-tuple range zip");
for (auto v: iter({ 5, 10, 15, 20 }).zip(iter({ 6, 11, 16, 21 })))
for (auto v: iter({ 5, 10, 15, 20 }).zip(iter({ 6, 11, 16, 21 }))) {
writeln(v.first, ", ", v.second);
}
}

View File

@ -10,14 +10,16 @@ using namespace ostd;
int main() {
/* algorithm: map - prints 0.5 to 9.5 each on new line */
writeln("range map test");
for (float f: range(10) | map([](int v) { return v + 0.5f; }))
for (float f: range(10) | map([](int v) { return v + 0.5f; })) {
writeln(f);
}
/* algorithm: filter - prints 10, 15, 8 each on new line */
writeln("range filter test");
auto il = { 5, 5, 5, 5, 5, 10, 15, 4, 8, 2 };
for (int i: iter(il) | filter([](int v) { return v > 5; }))
for (int i: iter(il) | filter([](int v) { return v > 5; })) {
writeln(i);
}
/* prints ABCDEF (ASCII 65, 66, 67, 68, 69, 70) */
writeln("string gen test");
@ -29,8 +31,9 @@ int main() {
auto x = { 11, 22, 33 };
auto y = { 44, 55, 66 };
auto z = { 77, 88, 99 };
for (auto i: iter(x) | join(iter(y), iter(z)))
for (auto i: iter(x) | join(iter(y), iter(z))) {
writeln(i);
}
/* chunk a range into subranges - prints
* {11, 22, 33}
@ -39,23 +42,27 @@ int main() {
*/
writeln("range chunk test");
auto cr = { 11, 22, 33, 44, 55, 66, 77, 88, 99 };
for (auto r: iter(cr) | chunks(3))
for (auto r: iter(cr) | chunks(3)) {
writeln(r);
}
/* take test, prints only first 4 */
writeln("range take test");
for (auto r: iter(cr) | take(4))
for (auto r: iter(cr) | take(4)) {
writeln(r);
}
/* {11, 44, 77}, {22, 55, 88}, {33, 66, 99} */
writeln("range zip test");
for (auto v: iter(x) | zip(iter(y), iter(z)))
for (auto v: iter(x) | zip(iter(y), iter(z))) {
writeln(v);
}
/* 2-tuple zip uses Pair */
writeln("2-tuple range zip");
for (auto v: iter({ 5, 10, 15, 20 }) | zip(iter({ 6, 11, 16, 21 })))
for (auto v: iter({ 5, 10, 15, 20 }) | zip(iter({ 6, 11, 16, 21 }))) {
writeln(v.first, ", ", v.second);
}
/* more complex pipe */
writeln("several piped algorithms");
@ -65,16 +72,19 @@ int main() {
generate(arr.iter(), []() { return rand() % 128; });
auto r = arr.iter()
| sort()
| sort ()
| filter([](auto v) { return v >= 65 && v <= 90; })
| map([](auto v) { return char(v); });
| map ([](auto v) { return char(v); });
writeln(String(r));
/* "list comprehensions" */
writeln("list initialization");
Vector<int> test(range(20) | filter([](int v) { return v % 2 == 0; })
| map([](int v) { return v * 2; }));
Vector<int> test(
range(20)
| filter([](int v) { return v % 2 == 0; })
| map ([](int v) { return v * 2; })
);
writeln(test);
}

View File

@ -48,8 +48,9 @@ int main() {
/* we can connect lambdas, including closures
* this callback can access "test" easily and it will still work
*/
auto idx = st.on_simple.connect([&](SignalTest const &, int v,
ConstCharRange str) {
auto idx = st.on_simple.connect([&](
SignalTest const &, int v, ConstCharRange str
) {
writefln("and lambda test: %d, %s (%d)", v, str, test);
});
@ -69,13 +70,16 @@ int main() {
/* the reference to SignalTest here is mutable */
st.on_param.connect([](SignalTest &self, float oldval) {
writeln("value changed...");
writefln(" old value: %f, new value: %f", oldval,
self.get_param());
writefln(
" old value: %f, new value: %f", oldval, self.get_param()
);
/* when we have a mutable reference we can change the original
* object, for example re-emit its own signal once again
*/
if (self.get_param() > 140.0f) return;
if (self.get_param() > 140.0f) {
return;
}
self.set_param(self.get_param() + 1.0f);
});

View File

@ -9,14 +9,18 @@ void print_result(Uint32 x) {
int main() {
FileStream wtest{"test.bin", StreamMode::write};
copy(iter({ 0xABCD1214, 0xBADC3264, 0xDEADBEEF, 0xBEEFDEAD }), wtest.iter<Uint32>());
copy(
iter({ 0xABCD1214, 0xBADC3264, 0xDEADBEEF, 0xBEEFDEAD }),
wtest.iter<Uint32>()
);
wtest.close();
FileStream rtest{"test.bin"};
writefln("stream size: %d", rtest.size());
for (Uint32 x: map(rtest.iter<Uint32>(), FromBigEndian<Uint32>()))
for (Uint32 x: map(rtest.iter<Uint32>(), FromBigEndian<Uint32>())) {
print_result(x);
}
return 0;
}

View File

@ -9,12 +9,13 @@ int main() {
FileStream wtest{"test.txt", StreamMode::write};
String smpl = "This is a test file for later read.\n"
"It contains some sample text in order to see whether "
"things actually read correctly.\n\n\n"
""
"This is after a few newlines. The file continues here.\n"
"The file ends here.\n";
String smpl =
"This is a test file for later read.\n"
"It contains some sample text in order to see whether "
"things actually read correctly.\n\n\n"
""
"This is after a few newlines. The file continues here.\n"
"The file ends here.\n";
copy(smpl.iter(), wtest.iter());
wtest.close();

View File

@ -39,8 +39,11 @@ inline auto partition(F &&func) {
template<typename R, typename P>
inline bool is_partitioned(R range, P pred) {
for (; !range.empty() && pred(range.front()); range.pop_front());
for (; !range.empty(); range.pop_front())
if (pred(range.front())) return false;
for (; !range.empty(); range.pop_front()) {
if (pred(range.front())) {
return false;
}
}
return true;
}
@ -69,20 +72,25 @@ namespace detail {
}
template<typename R, typename C>
static void hs_sift_down(R range, RangeSize<R> s,
RangeSize<R> e, C &compare) {
static void hs_sift_down(
R range, RangeSize<R> s, RangeSize<R> e, C &compare
) {
RangeSize<R> r = s;
while ((r * 2 + 1) <= e) {
RangeSize<R> ch = r * 2 + 1;
RangeSize<R> sw = r;
if (compare(range[sw], range[ch]))
if (compare(range[sw], range[ch])) {
sw = ch;
if (((ch + 1) <= e) && compare(range[sw], range[ch + 1]))
}
if (((ch + 1) <= e) && compare(range[sw], range[ch + 1])) {
sw = ch + 1;
}
if (sw != r) {
detail::swap_adl(range[r], range[sw]);
r = sw;
} else return;
} else {
return;
}
}
}
@ -92,7 +100,9 @@ namespace detail {
RangeSize<R> st = (len - 2) / 2;
for (;;) {
detail::hs_sift_down(range, st, len - 1, compare);
if (st-- == 0) break;
if (st-- == 0) {
break;
}
}
RangeSize<R> e = len - 1;
while (e > 0) {
@ -117,19 +127,23 @@ namespace detail {
R pr = range;
pr.pop_back();
for (; !pr.empty(); pr.pop_front()) {
if (compare(pr.front(), range.back()))
if (compare(pr.front(), range.back())) {
detail::swap_adl(pr.front(), range[pi++]);
}
}
detail::swap_adl(range[pi], range.back());
detail::introloop(range.slice(0, pi), compare, depth - 1);
detail::introloop(range.slice(pi + 1, range.size()), compare,
depth - 1);
detail::introloop(
range.slice(pi + 1, range.size()), compare, depth - 1
);
}
template<typename R, typename C>
inline void introsort(R range, C &compare) {
detail::introloop(range, compare, RangeSize<R>(2
* (log(range.size()) / log(2))));
detail::introloop(
range, compare,
static_cast<RangeSize<R>>(2 * (log(range.size()) / log(2)))
);
}
} /* namespace detail */
@ -176,17 +190,21 @@ inline T const &max_cmp(T const &a, T const &b, C compare) {
template<typename R>
inline R min_element(R range) {
R r = range;
for (; !range.empty(); range.pop_front())
if (ostd::min(r.front(), range.front()) == range.front())
for (; !range.empty(); range.pop_front()) {
if (ostd::min(r.front(), range.front()) == range.front()) {
r = range;
}
}
return r;
}
template<typename R, typename C>
inline R min_element_cmp(R range, C compare) {
R r = range;
for (; !range.empty(); range.pop_front())
if (ostd::min_cmp(r.front(), range.front(), compare) == range.front())
for (; !range.empty(); range.pop_front()) {
if (ostd::min_cmp(r.front(), range.front(), compare) == range.front()) {
r = range;
}
}
return r;
}
inline auto min_element() {
@ -202,17 +220,21 @@ inline auto min_element_cmp(C &&compare) {
template<typename R>
inline R max_element(R range) {
R r = range;
for (; !range.empty(); range.pop_front())
if (ostd::max(r.front(), range.front()) == range.front())
for (; !range.empty(); range.pop_front()) {
if (ostd::max(r.front(), range.front()) == range.front()) {
r = range;
}
}
return r;
}
template<typename R, typename C>
inline R max_element_cmp(R range, C compare) {
R r = range;
for (; !range.empty(); range.pop_front())
if (ostd::max_cmp(r.front(), range.front(), compare) == range.front())
for (; !range.empty(); range.pop_front()) {
if (ostd::max_cmp(r.front(), range.front(), compare) == range.front()) {
r = range;
}
}
return r;
}
inline auto max_element() {
@ -261,8 +283,12 @@ inline T clamp(T const &v, U const &lo, U const &hi, C compare) {
template<typename R1, typename R2>
inline bool lexicographical_compare(R1 range1, R2 range2) {
while (!range1.empty() && !range2.empty()) {
if (range1.front() < range2.front()) return true;
if (range2.front() < range1.front()) return false;
if (range1.front() < range2.front()) {
return true;
}
if (range2.front() < range1.front()) {
return false;
}
range1.pop_front();
range2.pop_front();
}
@ -271,15 +297,21 @@ inline bool lexicographical_compare(R1 range1, R2 range2) {
template<typename R>
inline auto lexicographical_compare(R &&range) {
return [range = forward<R>(range)](auto &&obj) mutable {
return lexicographical_compare(forward<decltype(obj)>(obj), forward<R>(range));
return lexicographical_compare(
forward<decltype(obj)>(obj), forward<R>(range)
);
};
}
template<typename R1, typename R2, typename C>
inline bool lexicographical_compare_cmp(R1 range1, R2 range2, C compare) {
while (!range1.empty() && !range2.empty()) {
if (compare(range1.front(), range2.front())) return true;
if (compare(range2.front(), range1.front())) return false;
if (compare(range1.front(), range2.front())) {
return true;
}
if (compare(range2.front(), range1.front())) {
return false;
}
range1.pop_front();
range2.pop_front();
}
@ -287,9 +319,12 @@ inline bool lexicographical_compare_cmp(R1 range1, R2 range2, C compare) {
}
template<typename R, typename C>
inline auto lexicographical_compare_cmp(R &&range, C &&compare) {
return [range = forward<R>(range), compare = forward<C>(compare)](auto &&obj) mutable {
return lexicographical_compare_cmp(forward<decltype(obj)>(obj),
forward<R>(range), forward<C>(compare));
return [
range = forward<R>(range), compare = forward<C>(compare)
](auto &&obj) mutable {
return lexicographical_compare_cmp(
forward<decltype(obj)>(obj), forward<R>(range), forward<C>(compare)
);
};
}
@ -297,8 +332,9 @@ inline auto lexicographical_compare_cmp(R &&range, C &&compare) {
template<typename R, typename F>
inline F for_each(R range, F func) {
for (; !range.empty(); range.pop_front())
for (; !range.empty(); range.pop_front()) {
func(range.front());
}
return move(func);
}
@ -311,8 +347,11 @@ inline auto for_each(F &&func) {
template<typename R, typename P>
inline bool all_of(R range, P pred) {
for (; !range.empty(); range.pop_front())
if (!pred(range.front())) return false;
for (; !range.empty(); range.pop_front()) {
if (!pred(range.front())) {
return false;
}
}
return true;
}
@ -353,9 +392,11 @@ inline auto none_of(F &&func) {
template<typename R, typename T>
inline R find(R range, T const &v) {
for (; !range.empty(); range.pop_front())
if (range.front() == v)
for (; !range.empty(); range.pop_front()) {
if (range.front() == v) {
break;
}
}
return range;
}
@ -369,13 +410,16 @@ inline auto find(T &&v) {
template<typename R, typename T>
inline R find_last(R range, T const &v) {
range = find(range, v);
if (!range.empty()) for (;;) {
R prev = range;
prev.pop_front();
R r = find(prev, v);
if (r.empty())
break;
range = r;
if (!range.empty()) {
for (;;) {
R prev = range;
prev.pop_front();
R r = find(prev, v);
if (r.empty()) {
break;
}
range = r;
}
}
return range;
}
@ -389,9 +433,11 @@ inline auto find_last(T &&v) {
template<typename R, typename P>
inline R find_if(R range, P pred) {
for (; !range.empty(); range.pop_front())
if (pred(range.front()))
for (; !range.empty(); range.pop_front()) {
if (pred(range.front())) {
break;
}
}
return range;
}
@ -404,9 +450,11 @@ inline auto find_if(F &&func) {
template<typename R, typename P>
inline R find_if_not(R range, P pred) {
for (; !range.empty(); range.pop_front())
if (!pred(range.front()))
for (; !range.empty(); range.pop_front()) {
if (!pred(range.front())) {
break;
}
}
return range;
}
@ -419,26 +467,35 @@ inline auto find_if_not(F &&func) {
template<typename R1, typename R2, typename C>
inline R1 find_one_of_cmp(R1 range, R2 values, C compare) {
for (; !range.empty(); range.pop_front())
for (R2 rv = values; !rv.empty(); rv.pop_front())
if (compare(range.front(), rv.front()))
for (; !range.empty(); range.pop_front()) {
for (R2 rv = values; !rv.empty(); rv.pop_front()) {
if (compare(range.front(), rv.front())) {
return range;
}
}
}
return range;
}
template<typename R, typename C>
inline auto find_one_of_cmp(R &&values, C &&compare) {
return [values = forward<R>(values), compare = forward<C>(compare)](auto &&obj) mutable {
return find_one_of_cmp(forward<decltype(obj)>(obj),
forward<R>(values), forward<C>(compare));
return [
values = forward<R>(values), compare = forward<C>(compare)
](auto &&obj) mutable {
return find_one_of_cmp(
forward<decltype(obj)>(obj), forward<R>(values), forward<C>(compare)
);
};
}
template<typename R1, typename R2>
inline R1 find_one_of(R1 range, R2 values) {
for (; !range.empty(); range.pop_front())
for (R2 rv = values; !rv.empty(); rv.pop_front())
if (range.front() == rv.front())
for (; !range.empty(); range.pop_front()) {
for (R2 rv = values; !rv.empty(); rv.pop_front()) {
if (range.front() == rv.front()) {
return range;
}
}
}
return range;
}
template<typename R>
@ -451,9 +508,11 @@ inline auto find_one_of(R &&values) {
template<typename R, typename T>
inline RangeSize<R> count(R range, T const &v) {
RangeSize<R> ret = 0;
for (; !range.empty(); range.pop_front())
if (range.front() == v)
for (; !range.empty(); range.pop_front()) {
if (range.front() == v) {
++ret;
}
}
return ret;
}
@ -467,9 +526,11 @@ inline auto count(T &&v) {
template<typename R, typename P>
inline RangeSize<R> count_if(R range, P pred) {
RangeSize<R> ret = 0;
for (; !range.empty(); range.pop_front())
if (pred(range.front()))
for (; !range.empty(); range.pop_front()) {
if (pred(range.front())) {
++ret;
}
}
return ret;
}
@ -483,9 +544,11 @@ inline auto count_if(F &&func) {
template<typename R, typename P>
inline RangeSize<R> count_if_not(R range, P pred) {
RangeSize<R> ret = 0;
for (; !range.empty(); range.pop_front())
if (!pred(range.front()))
for (; !range.empty(); range.pop_front()) {
if (!pred(range.front())) {
++ret;
}
}
return ret;
}
@ -499,8 +562,9 @@ inline auto count_if_not(F &&func) {
template<typename R>
inline bool equal(R range1, R range2) {
for (; !range1.empty(); range1.pop_front()) {
if (range2.empty() || (range1.front() != range2.front()))
if (range2.empty() || (range1.front() != range2.front())) {
return false;
}
range2.pop_front();
}
return range2.empty();
@ -529,31 +593,37 @@ inline auto slice_until(R &&range) {
template<typename R1, typename R2>
inline R2 copy(R1 irange, R2 orange) {
for (; !irange.empty(); irange.pop_front())
for (; !irange.empty(); irange.pop_front()) {
orange.put(irange.front());
}
return orange;
}
template<typename R1, typename R2, typename P>
inline R2 copy_if(R1 irange, R2 orange, P pred) {
for (; !irange.empty(); irange.pop_front())
if (pred(irange.front()))
for (; !irange.empty(); irange.pop_front()) {
if (pred(irange.front())) {
orange.put(irange.front());
}
}
return orange;
}
template<typename R1, typename R2, typename P>
inline R2 copy_if_not(R1 irange, R2 orange, P pred) {
for (; !irange.empty(); irange.pop_front())
if (!pred(irange.front()))
for (; !irange.empty(); irange.pop_front()) {
if (!pred(irange.front())) {
orange.put(irange.front());
}
}
return orange;
}
template<typename R1, typename R2>
inline R2 move(R1 irange, R2 orange) {
for (; !irange.empty(); irange.pop_front())
for (; !irange.empty(); irange.pop_front()) {
orange.put(move(irange.front()));
}
return orange;
}
@ -568,21 +638,24 @@ inline void reverse(R range) {
template<typename R1, typename R2>
inline R2 reverse_copy(R1 irange, R2 orange) {
for (; !irange.empty(); irange.pop_back())
for (; !irange.empty(); irange.pop_back()) {
orange.put(irange.back());
}
return orange;
}
template<typename R, typename T>
inline void fill(R range, T const &v) {
for (; !range.empty(); range.pop_front())
for (; !range.empty(); range.pop_front()) {
range.front() = v;
}
}
template<typename R, typename F>
inline void generate(R range, F gen) {
for (; !range.empty(); range.pop_front())
for (; !range.empty(); range.pop_front()) {
range.front() = gen();
}
}
template<typename R1, typename R2>
@ -597,21 +670,24 @@ inline Pair<R1, R2> swap_ranges(R1 range1, R2 range2) {
template<typename R, typename T>
inline void iota(R range, T value) {
for (; !range.empty(); range.pop_front())
for (; !range.empty(); range.pop_front()) {
range.front() = value++;
}
}
template<typename R, typename T>
inline T foldl(R range, T init) {
for (; !range.empty(); range.pop_front())
for (; !range.empty(); range.pop_front()) {
init = init + range.front();
}
return init;
}
template<typename R, typename T, typename F>
inline T foldl_f(R range, T init, F func) {
for (; !range.empty(); range.pop_front())
for (; !range.empty(); range.pop_front()) {
init = func(init, range.front());
}
return init;
}
@ -623,22 +699,28 @@ inline auto foldl(T &&init) {
}
template<typename T, typename F>
inline auto foldl_f(T &&init, F &&func) {
return [init = forward<T>(init), func = forward<F>(func)](auto &&obj) mutable {
return foldl_f(forward<decltype(obj)>(obj), forward<T>(init), forward<F>(func));
return [
init = forward<T>(init), func = forward<F>(func)
](auto &&obj) mutable {
return foldl_f(
forward<decltype(obj)>(obj), forward<T>(init), forward<F>(func)
);
};
}
template<typename R, typename T>
inline T foldr(R range, T init) {
for (; !range.empty(); range.pop_back())
for (; !range.empty(); range.pop_back()) {
init = init + range.back();
}
return init;
}
template<typename R, typename T, typename F>
inline T foldr_f(R range, T init, F func) {
for (; !range.empty(); range.pop_back())
for (; !range.empty(); range.pop_back()) {
init = func(init, range.back());
}
return init;
}
@ -650,8 +732,12 @@ inline auto foldr(T &&init) {
}
template<typename T, typename F>
inline auto foldr_f(T &&init, F &&func) {
return [init = forward<T>(init), func = forward<F>(func)](auto &&obj) mutable {
return foldr_f(forward<decltype(obj)>(obj), forward<T>(init), forward<F>(func));
return [
init = forward<T>(init), func = forward<F>(func)
](auto &&obj) mutable {
return foldr_f(
forward<decltype(obj)>(obj), forward<T>(init), forward<F>(func)
);
};
}
@ -734,8 +820,8 @@ public:
};
namespace detail {
template<typename R, typename F> using MapReturnType
= decltype(declval<F>()(declval<RangeReference<R>>()));
template<typename R, typename F>
using MapReturnType = decltype(declval<F>()(declval<RangeReference<R>>()));
}
template<typename R, typename F>
@ -760,22 +846,27 @@ private:
Decay<F> p_pred;
void advance_valid() {
while (!p_range.empty() && !p_pred(front())) p_range.pop_front();
while (!p_range.empty() && !p_pred(front())) {
p_range.pop_front();
}
}
public:
FilterRange() = delete;
template<typename P>
FilterRange(T const &range, P &&pred): p_range(range),
p_pred(forward<P>(pred)) {
FilterRange(T const &range, P &&pred):
p_range(range), p_pred(forward<P>(pred))
{
advance_valid();
}
FilterRange(FilterRange const &it): p_range(it.p_range),
p_pred(it.p_pred) {
FilterRange(FilterRange const &it):
p_range(it.p_range), p_pred(it.p_pred)
{
advance_valid();
}
FilterRange(FilterRange &&it): p_range(move(it.p_range)),
p_pred(move(it.p_pred)) {
FilterRange(FilterRange &&it):
p_range(move(it.p_range)), p_pred(move(it.p_pred))
{
advance_valid();
}
@ -808,10 +899,10 @@ public:
};
namespace detail {
template<typename R, typename P> using FilterPred
= EnableIf<IsSame<
decltype(declval<P>()(declval<RangeReference<R>>())), bool
>, P>;
template<typename R, typename P>
using FilterPred = EnableIf<
IsSame<decltype(declval<P>()(declval<RangeReference<R>>())), bool>, P
>;
}
template<typename R, typename P>

View File

@ -31,11 +31,15 @@ struct Array {
T const &operator[](Size i) const { return p_buf[i]; }
T *at(Size i) {
if (!in_range(i)) return nullptr;
if (!in_range(i)) {
return nullptr;
}
return &p_buf[i];
}
T const *at(Size i) const {
if (!in_range(i)) return nullptr;
if (!in_range(i)) {
return nullptr;
}
return &p_buf[i];
}

View File

@ -31,7 +31,8 @@ namespace detail {
T p_value;
};
template<typename T> T atomic_create();
template<typename T>
T atomic_create();
template<typename T, typename U>
EnableIf<sizeof(T()->value = atomic_create<U>()), char>
@ -41,8 +42,8 @@ namespace detail {
int test_atomic_assignable(...);
template<typename T, typename U>
constexpr bool CanAtomicAssign
= (sizeof(test_atomic_assignable<T, U>(1)) == sizeof(char));
constexpr bool CanAtomicAssign =
(sizeof(test_atomic_assignable<T, U>(1)) == sizeof(char));
template<typename T>
static inline EnableIf<
@ -59,7 +60,9 @@ namespace detail {
char volatile *to = reinterpret_cast<char volatile *>(&a->p_value);
char volatile *end = to + sizeof(T);
char *from = reinterpret_cast<char *>(&v);
while (to != end) *to++ =*from++;
while (to != end) {
*to++ =*from++;
}
}
template<typename T>
@ -88,21 +91,25 @@ static constexpr Size AtomicPointerLockFree = __GCC_ATOMIC_POINTER_LOCK_FREE;
namespace detail {
static inline constexpr int to_gcc_order(MemoryOrder ord) {
return ((ord == MemoryOrder::relaxed) ? __ATOMIC_RELAXED :
((ord == MemoryOrder::acquire) ? __ATOMIC_ACQUIRE :
((ord == MemoryOrder::release) ? __ATOMIC_RELEASE :
((ord == MemoryOrder::seq_cst) ? __ATOMIC_SEQ_CST :
((ord == MemoryOrder::acq_rel) ? __ATOMIC_ACQ_REL :
__ATOMIC_CONSUME)))));
return (
((ord == MemoryOrder::relaxed) ? __ATOMIC_RELAXED :
((ord == MemoryOrder::acquire) ? __ATOMIC_ACQUIRE :
((ord == MemoryOrder::release) ? __ATOMIC_RELEASE :
((ord == MemoryOrder::seq_cst) ? __ATOMIC_SEQ_CST :
((ord == MemoryOrder::acq_rel) ? __ATOMIC_ACQ_REL :
__ATOMIC_CONSUME)))))
);
}
static inline constexpr int to_gcc_failure_order(MemoryOrder ord) {
return ((ord == MemoryOrder::relaxed) ? __ATOMIC_RELAXED :
((ord == MemoryOrder::acquire) ? __ATOMIC_ACQUIRE :
((ord == MemoryOrder::release) ? __ATOMIC_RELAXED :
((ord == MemoryOrder::seq_cst) ? __ATOMIC_SEQ_CST :
((ord == MemoryOrder::acq_rel) ? __ATOMIC_ACQUIRE :
__ATOMIC_CONSUME)))));
return (
((ord == MemoryOrder::relaxed) ? __ATOMIC_RELAXED :
((ord == MemoryOrder::acquire) ? __ATOMIC_ACQUIRE :
((ord == MemoryOrder::release) ? __ATOMIC_RELAXED :
((ord == MemoryOrder::seq_cst) ? __ATOMIC_SEQ_CST :
((ord == MemoryOrder::acq_rel) ? __ATOMIC_ACQUIRE :
__ATOMIC_CONSUME)))))
);
}
static inline void atomic_thread_fence(MemoryOrder ord) {
@ -119,8 +126,9 @@ namespace detail {
}
template<typename T>
static inline void atomic_store(AtomicBase<T> volatile *a,
T v, MemoryOrder ord) {
static inline void atomic_store(
AtomicBase<T> volatile *a, T v, MemoryOrder ord
) {
__atomic_store(&a->p_value, &v, to_gcc_order(ord));
}
@ -163,8 +171,10 @@ namespace detail {
AtomicBase<T> volatile *a, T *expected, T v,
MemoryOrder success, MemoryOrder failure
) {
return __atomic_compare_exchange(&a->p_value, expected, &v, false,
to_gcc_order(success), to_gcc_failure_order(failure));
return __atomic_compare_exchange(
&a->p_value, expected, &v, false,
to_gcc_order(success), to_gcc_failure_order(failure)
);
}
template<typename T>
@ -172,8 +182,10 @@ namespace detail {
AtomicBase<T> *a, T *expected, T v,
MemoryOrder success, MemoryOrder failure
) {
return __atomic_compare_exchange(&a->p_value, expected, &v, false,
to_gcc_order(success), to_gcc_failure_order(failure));
return __atomic_compare_exchange(
&a->p_value, expected, &v, false,
to_gcc_order(success), to_gcc_failure_order(failure)
);
}
template<typename T>
@ -181,8 +193,10 @@ namespace detail {
AtomicBase<T> volatile *a, T *expected, T v,
MemoryOrder success, MemoryOrder failure
) {
return __atomic_compare_exchange(&a->p_value, expected, &v, true,
to_gcc_order(success), to_gcc_failure_order(failure));
return __atomic_compare_exchange(
&a->p_value, expected, &v, true,
to_gcc_order(success), to_gcc_failure_order(failure)
);
}
template<typename T>
@ -190,8 +204,10 @@ namespace detail {
AtomicBase<T> *a, T *expected, T v,
MemoryOrder success, MemoryOrder failure
) {
return __atomic_compare_exchange(&a->p_value, expected, &v, true,
to_gcc_order(success), to_gcc_failure_order(failure));
return __atomic_compare_exchange(
&a->p_value, expected, &v, true,
to_gcc_order(success), to_gcc_failure_order(failure)
);
}
template<typename T>
@ -200,84 +216,96 @@ namespace detail {
template<typename T>
struct SkipAmt<T *> { static constexpr Size value = sizeof(T); };
template<typename T> struct SkipAmt<T[]> {};
template<typename T, Size N> struct SkipAmt<T[N]> {};
template<typename T>
struct SkipAmt<T[]> {};
template<typename T, Size N>
struct SkipAmt<T[N]> {};
template<typename T, typename U>
static inline T atomic_fetch_add(AtomicBase<T> volatile *a,
U d, MemoryOrder ord) {
return __atomic_fetch_add(&a->p_value, d * SkipAmt<T>::value,
to_gcc_order(ord));
static inline T atomic_fetch_add(
AtomicBase<T> volatile *a, U d, MemoryOrder ord
) {
return __atomic_fetch_add(
&a->p_value, d * SkipAmt<T>::value, to_gcc_order(ord)
);
}
template<typename T, typename U>
static inline T atomic_fetch_add(AtomicBase<T> *a,
U d, MemoryOrder ord) {
return __atomic_fetch_add(&a->p_value, d * SkipAmt<T>::value,
to_gcc_order(ord));
static inline T atomic_fetch_add(
AtomicBase<T> *a, U d, MemoryOrder ord
) {
return __atomic_fetch_add(
&a->p_value, d * SkipAmt<T>::value, to_gcc_order(ord)
);
}
template<typename T, typename U>
static inline T atomic_fetch_sub(AtomicBase<T> volatile *a,
U d, MemoryOrder ord) {
return __atomic_fetch_sub(&a->p_value, d * SkipAmt<T>::value,
to_gcc_order(ord));
static inline T atomic_fetch_sub(
AtomicBase<T> volatile *a, U d, MemoryOrder ord
) {
return __atomic_fetch_sub(
&a->p_value, d * SkipAmt<T>::value, to_gcc_order(ord)
);
}
template<typename T, typename U>
static inline T atomic_fetch_sub(AtomicBase<T> *a,
U d, MemoryOrder ord) {
return __atomic_fetch_sub(&a->p_value, d * SkipAmt<T>::value,
to_gcc_order(ord));
static inline T atomic_fetch_sub(
AtomicBase<T> *a, U d, MemoryOrder ord
) {
return __atomic_fetch_sub(
&a->p_value, d * SkipAmt<T>::value, to_gcc_order(ord)
);
}
template<typename T>
static inline T atomic_fetch_and(AtomicBase<T> volatile *a,
T pattern, MemoryOrder ord) {
return __atomic_fetch_and(&a->p_value, pattern,
to_gcc_order(ord));
static inline T atomic_fetch_and(
AtomicBase<T> volatile *a, T pattern, MemoryOrder ord
) {
return __atomic_fetch_and(&a->p_value, pattern, to_gcc_order(ord));
}
template<typename T>
static inline T atomic_fetch_and(AtomicBase<T> *a,
T pattern, MemoryOrder ord) {
return __atomic_fetch_and(&a->p_value, pattern,
to_gcc_order(ord));
static inline T atomic_fetch_and(
AtomicBase<T> *a, T pattern, MemoryOrder ord
) {
return __atomic_fetch_and(&a->p_value, pattern, to_gcc_order(ord));
}
template<typename T>
static inline T atomic_fetch_or(AtomicBase<T> volatile *a,
T pattern, MemoryOrder ord) {
return __atomic_fetch_or(&a->p_value, pattern,
to_gcc_order(ord));
static inline T atomic_fetch_or(
AtomicBase<T> volatile *a, T pattern, MemoryOrder ord
) {
return __atomic_fetch_or(&a->p_value, pattern, to_gcc_order(ord));
}
template<typename T>
static inline T atomic_fetch_or(AtomicBase<T> *a,
T pattern, MemoryOrder ord) {
return __atomic_fetch_or(&a->p_value, pattern,
to_gcc_order(ord));
static inline T atomic_fetch_or(
AtomicBase<T> *a, T pattern, MemoryOrder ord
) {
return __atomic_fetch_or(&a->p_value, pattern, to_gcc_order(ord));
}
template<typename T>
static inline T atomic_fetch_xor(AtomicBase<T> volatile *a,
T pattern, MemoryOrder ord) {
return __atomic_fetch_xor(&a->p_value, pattern,
to_gcc_order(ord));
static inline T atomic_fetch_xor(
AtomicBase<T> volatile *a, T pattern, MemoryOrder ord
) {
return __atomic_fetch_xor(&a->p_value, pattern, to_gcc_order(ord));
}
template<typename T>
static inline T atomic_fetch_xor(AtomicBase<T> *a,
T pattern, MemoryOrder ord) {
return __atomic_fetch_xor(&a->p_value, pattern,
to_gcc_order(ord));
static inline T atomic_fetch_xor(
AtomicBase<T> *a, T pattern, MemoryOrder ord
) {
return __atomic_fetch_xor(&a->p_value, pattern, to_gcc_order(ord));
}
} /* namespace detail */
#else
# error Unsupported compiler
#endif
template <typename T> inline T kill_dependency(T v) {
template <typename T>
inline T kill_dependency(T v) {
return v;
}
@ -330,45 +358,47 @@ namespace detail {
return atomic_exchange(&p_a, v, ord);
}
bool compare_exchange_weak(T &e, T v, MemoryOrder s,
MemoryOrder f) volatile {
bool compare_exchange_weak(
T &e, T v, MemoryOrder s, MemoryOrder f
) volatile {
return atomic_compare_exchange_weak(&p_a, &e, v, s, f);
}
bool compare_exchange_weak(T &e, T v, MemoryOrder s,
MemoryOrder f) {
bool compare_exchange_weak(T &e, T v, MemoryOrder s, MemoryOrder f) {
return atomic_compare_exchange_weak(&p_a, &e, v, s, f);
}
bool compare_exchange_strong(T &e, T v, MemoryOrder s,
MemoryOrder f) volatile {
bool compare_exchange_strong(
T &e, T v, MemoryOrder s, MemoryOrder f
) volatile {
return atomic_compare_exchange_strong(&p_a, &e, v, s, f);
}
bool compare_exchange_strong(T &e, T v, MemoryOrder s,
MemoryOrder f) {
bool compare_exchange_strong(T &e, T v, MemoryOrder s, MemoryOrder f) {
return atomic_compare_exchange_strong(&p_a, &e, v, s, f);
}
bool compare_exchange_weak(T &e, T v, MemoryOrder ord
= MemoryOrder::seq_cst)
volatile {
bool compare_exchange_weak(
T &e, T v, MemoryOrder ord = MemoryOrder::seq_cst
) volatile {
return atomic_compare_exchange_weak(&p_a, &e, v, ord, ord);
}
bool compare_exchange_weak(T &e, T v, MemoryOrder ord
= MemoryOrder::seq_cst) {
bool compare_exchange_weak(
T &e, T v, MemoryOrder ord = MemoryOrder::seq_cst
) {
return atomic_compare_exchange_weak(&p_a, &e, v, ord, ord);
}
bool compare_exchange_strong(T &e, T v, MemoryOrder ord
= MemoryOrder::seq_cst)
volatile {
bool compare_exchange_strong(
T &e, T v, MemoryOrder ord = MemoryOrder::seq_cst
) volatile {
return atomic_compare_exchange_strong(&p_a, &e, v, ord, ord);
}
bool compare_exchange_strong(T &e, T v, MemoryOrder ord
= MemoryOrder::seq_cst) {
bool compare_exchange_strong(
T &e, T v, MemoryOrder ord = MemoryOrder::seq_cst
) {
return atomic_compare_exchange_strong(&p_a, &e, v, ord, ord);
}
};
@ -421,10 +451,10 @@ namespace detail {
return atomic_fetch_xor(&this->p_a, op, ord);
}
T operator++(int) volatile { return fetch_add(T(1)); }
T operator++(int) { return fetch_add(T(1)); }
T operator--(int) volatile { return fetch_sub(T(1)); }
T operator--(int) { return fetch_sub(T(1)); }
T operator++(int) volatile { return fetch_add(T(1)); }
T operator++(int) { return fetch_add(T(1)); }
T operator--(int) volatile { return fetch_sub(T(1)); }
T operator--(int) { return fetch_sub(T(1)); }
T operator++( ) volatile { return fetch_add(T(1)) + T(1); }
T operator++( ) { return fetch_add(T(1)) + T(1); }
T operator--( ) volatile { return fetch_sub(T(1)) - T(1); }
@ -581,20 +611,17 @@ inline T atomic_exchange(Atomic<T> *a, T v) {
}
template <typename T>
inline T atomic_exchange_explicit(Atomic<T> volatile *a, T v,
MemoryOrder ord) {
inline T atomic_exchange_explicit(Atomic<T> volatile *a, T v, MemoryOrder ord) {
return a->exchange(v, ord);
}
template <typename T>
inline T atomic_exchange_explicit(Atomic<T> *a, T v,
MemoryOrder ord) {
inline T atomic_exchange_explicit(Atomic<T> *a, T v, MemoryOrder ord) {
return a->exchange(v, ord);
}
template <typename T>
inline bool atomic_compare_exchange_weak(Atomic<T> volatile *a,
T *e, T v) {
inline bool atomic_compare_exchange_weak(Atomic<T> volatile *a, T *e, T v) {
return a->compare_exchange_weak(*e, v);
}
@ -604,8 +631,7 @@ inline bool atomic_compare_exchange_weak(Atomic<T> *a, T *e, T v) {
}
template <typename T>
inline bool atomic_compare_exchange_strong(Atomic<T> volatile *a,
T *e, T v) {
inline bool atomic_compare_exchange_strong(Atomic<T> volatile *a, T *e, T v) {
return a->compare_exchange_strong(*e, v);
}
@ -615,46 +641,44 @@ inline bool atomic_compare_exchange_strong(Atomic<T> *a, T *e, T v) {
}
template <typename T>
inline bool atomic_compare_exchange_weak_explicit(Atomic<T> volatile *a,
T *e, T v,
MemoryOrder s,
MemoryOrder f) {
inline bool atomic_compare_exchange_weak_explicit(
Atomic<T> volatile *a, T *e, T v, MemoryOrder s, MemoryOrder f
) {
return a->compare_exchange_weak(*e, v, s, f);
}
template <typename T>
inline bool atomic_compare_exchange_weak_explicit(Atomic<T> *a, T *e,
T v,
MemoryOrder s,
MemoryOrder f) {
inline bool atomic_compare_exchange_weak_explicit(
Atomic<T> *a, T *e, T v, MemoryOrder s, MemoryOrder f
) {
return a->compare_exchange_weak(*e, v, s, f);
}
template <typename T>
inline bool atomic_compare_exchange_strong_explicit(Atomic<T> volatile *a,
T *e, T v,
MemoryOrder s,
MemoryOrder f) {
inline bool atomic_compare_exchange_strong_explicit(
Atomic<T> volatile *a, T *e, T v, MemoryOrder s, MemoryOrder f
) {
return a->compare_exchange_strong(*e, v, s, f);
}
template <typename T>
inline bool atomic_compare_exchange_strong_explicit(Atomic<T> *a, T *e,
T v,
MemoryOrder s,
MemoryOrder f) {
inline bool atomic_compare_exchange_strong_explicit(
Atomic<T> *a, T *e, T v, MemoryOrder s, MemoryOrder f
) {
return a->compare_exchange_strong(*e, v, s, f);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_add(Atomic<T> volatile *a, T op) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_add(
Atomic<T> volatile *a, T op
) {
return a->fetch_add(op);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_add(Atomic<T> *a, T op) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_add(
Atomic<T> *a, T op
) {
return a->fetch_add(op);
}
@ -669,39 +693,44 @@ inline T *atomic_fetch_add(Atomic<T *> *a, Ptrdiff op) {
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_add_explicit(Atomic<T> volatile *a, T op,
MemoryOrder ord) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_add_explicit(
Atomic<T> volatile *a, T op, MemoryOrder ord
) {
return a->fetch_add(op, ord);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_add_explicit(Atomic<T> *a, T op, MemoryOrder ord) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_add_explicit(
Atomic<T> *a, T op, MemoryOrder ord
) {
return a->fetch_add(op, ord);
}
template <typename T>
inline T *atomic_fetch_add_explicit(Atomic<T *> volatile *a,
Ptrdiff op, MemoryOrder ord) {
inline T *atomic_fetch_add_explicit(
Atomic<T *> volatile *a, Ptrdiff op, MemoryOrder ord
) {
return a->fetch_add(op, ord);
}
template <typename T>
inline T *atomic_fetch_add_explicit(Atomic<T *> *a, Ptrdiff op,
MemoryOrder ord) {
inline T *atomic_fetch_add_explicit(
Atomic<T *> *a, Ptrdiff op, MemoryOrder ord
) {
return a->fetch_add(op, ord);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_sub(Atomic<T> volatile *a, T op) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_sub(
Atomic<T> volatile *a, T op
) {
return a->fetch_sub(op);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_sub(Atomic<T> *a, T op) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_sub(
Atomic<T> *a, T op
) {
return a->fetch_sub(op);
}
@ -716,102 +745,114 @@ inline T *atomic_fetch_sub(Atomic<T *> *a, Ptrdiff op) {
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_sub_explicit(Atomic<T> volatile *a, T op,
MemoryOrder ord) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_sub_explicit(
Atomic<T> volatile *a, T op, MemoryOrder ord
) {
return a->fetch_sub(op, ord);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_sub_explicit(Atomic<T> *a, T op, MemoryOrder ord) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_sub_explicit(
Atomic<T> *a, T op, MemoryOrder ord
) {
return a->fetch_sub(op, ord);
}
template <typename T>
inline T *atomic_fetch_sub_explicit(Atomic<T *> volatile *a,
Ptrdiff op, MemoryOrder ord) {
inline T *atomic_fetch_sub_explicit(
Atomic<T *> volatile *a, Ptrdiff op, MemoryOrder ord
) {
return a->fetch_sub(op, ord);
}
template <typename T>
inline T *atomic_fetch_sub_explicit(Atomic<T *> *a, Ptrdiff op,
MemoryOrder ord) {
inline T *atomic_fetch_sub_explicit(
Atomic<T *> *a, Ptrdiff op, MemoryOrder ord
) {
return a->fetch_sub(op, ord);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_and(Atomic<T> volatile *a, T op) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_and(
Atomic<T> volatile *a, T op
) {
return a->fetch_and(op);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_and(Atomic<T> *a, T op) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_and(
Atomic<T> *a, T op
) {
return a->fetch_and(op);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_and_explicit(Atomic<T> volatile *a, T op,
MemoryOrder ord) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_and_explicit(
Atomic<T> volatile *a, T op, MemoryOrder ord
) {
return a->fetch_and(op, ord);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_and_explicit(Atomic<T> *a, T op, MemoryOrder ord) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_and_explicit(
Atomic<T> *a, T op, MemoryOrder ord
) {
return a->fetch_and(op, ord);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_or(Atomic<T> volatile *a, T op) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_or(
Atomic<T> volatile *a, T op
) {
return a->fetch_or(op);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_or(Atomic<T> *a, T op) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_or(
Atomic<T> *a, T op
) {
return a->fetch_or(op);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_or_explicit(Atomic<T> volatile *a, T op,
MemoryOrder ord) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_or_explicit(
Atomic<T> volatile *a, T op, MemoryOrder ord
) {
return a->fetch_or(op, ord);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_or_explicit(Atomic<T> *a, T op, MemoryOrder ord) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_or_explicit(
Atomic<T> *a, T op, MemoryOrder ord
) {
return a->fetch_or(op, ord);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_xor(Atomic<T> volatile *a, T op) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_xor(
Atomic<T> volatile *a, T op
) {
return a->fetch_xor(op);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_xor(Atomic<T> *a, T op) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_xor(
Atomic<T> *a, T op
) {
return a->fetch_xor(op);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_xor_explicit(Atomic<T> volatile *a, T op,
MemoryOrder ord) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_xor_explicit(
Atomic<T> volatile *a, T op, MemoryOrder ord
) {
return a->fetch_xor(op, ord);
}
template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T>
atomic_fetch_xor_explicit(Atomic<T> *a, T op, MemoryOrder ord) {
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_xor_explicit(
Atomic<T> *a, T op, MemoryOrder ord
) {
return a->fetch_xor(op, ord);
}
@ -852,13 +893,13 @@ inline bool atomic_flag_test_and_set(AtomicFlag *a) {
return a->test_and_set();
}
inline bool atomic_flag_test_and_set_explicit(AtomicFlag volatile *a,
MemoryOrder ord) {
inline bool atomic_flag_test_and_set_explicit(
AtomicFlag volatile *a, MemoryOrder ord
) {
return a->test_and_set(ord);
}
inline bool atomic_flag_test_and_set_explicit(AtomicFlag *a,
MemoryOrder ord) {
inline bool atomic_flag_test_and_set_explicit(AtomicFlag *a, MemoryOrder ord) {
return a->test_and_set(ord);
}
@ -870,8 +911,7 @@ inline void atomic_flag_clear(AtomicFlag *a) {
a->clear();
}
inline void atomic_flag_clear_explicit(AtomicFlag volatile *a,
MemoryOrder ord) {
inline void atomic_flag_clear_explicit(AtomicFlag volatile *a, MemoryOrder ord) {
a->clear(ord);
}

View File

@ -24,14 +24,19 @@ inline Maybe<String> env_get(ConstCharRange name) {
auto tbuf = to_temp_cstr(name, buf, sizeof(buf));
#ifndef OSTD_PLATFORM_WIN32
char const *ret = getenv(tbuf.get());
if (!ret) return ostd::nothing;
if (!ret) {
return ostd::nothing;
}
return ostd::move(String(ret));
#else
String rbuf;
for (;;) {
auto ret = GetEnvironmentVariable(tbuf.get(), rbuf.data(),
rbuf.capacity() + 1);
if (!ret) return ostd::nothing;
auto ret = GetEnvironmentVariable(
tbuf.get(), rbuf.data(), rbuf.capacity() + 1
);
if (!ret) {
return ostd::nothing;
}
if (ret <= rbuf.capacity()) {
rbuf.advance(ret);
break;
@ -42,13 +47,15 @@ inline Maybe<String> env_get(ConstCharRange name) {
#endif
}
inline bool env_set(ConstCharRange name, ConstCharRange value,
bool update = true) {
inline bool env_set(
ConstCharRange name, ConstCharRange value, bool update = true
) {
char sbuf[2048];
char *buf = sbuf;
bool alloc = (name.size() + value.size() + 2) > sizeof(sbuf);
if (alloc)
if (alloc) {
buf = new char[name.size() + value.size() + 2];
}
memcpy(buf, name.data(), name.size());
buf[name.size()] = '\0';
memcpy(&buf[name.size() + 1], value.data(), value.size());
@ -56,12 +63,14 @@ inline bool env_set(ConstCharRange name, ConstCharRange value,
#ifndef OSTD_PLATFORM_WIN32
bool ret = !setenv(buf, &buf[name.size() + 1], update);
#else
if (!update && GetEnvironmentVariable(buf, nullptr, 0))
if (!update && GetEnvironmentVariable(buf, nullptr, 0)) {
return true;
}
bool ret = !!SetEnvironmentVariable(buf, &buf[name.size() + 1]);
#endif
if (alloc)
if (alloc) {
delete[] buf;
}
return ret;
}
@ -79,7 +88,7 @@ inline bool env_unset(ConstCharRange name) {
#ifndef OSTD_PLATFORM_WIN32
return !unsetenv(String(name).data());
#else
return !!SetEnvironmentVariable(String(name).data(), nullptr);
return !!SetEnvironmentVariable(String(name).data(), nullptr);
#endif
}

View File

@ -16,8 +16,9 @@ namespace detail {
struct SignalBase {
SignalBase(C *cl): p_class(cl), p_funcs(nullptr), p_nfuncs(0) {}
SignalBase(SignalBase const &ev): p_class(ev.p_class),
p_nfuncs(ev.p_nfuncs) {
SignalBase(SignalBase const &ev):
p_class(ev.p_class), p_nfuncs(ev.p_nfuncs)
{
using Func = Function<void(C &, A...)>;
byte *bufp = new byte[sizeof(Func) * p_nfuncs];
Func *nbuf = reinterpret_cast<Func *>(bufp);
@ -26,8 +27,9 @@ namespace detail {
p_funcs = nbuf;
}
SignalBase(SignalBase &&ev): p_class(nullptr), p_funcs(nullptr),
p_nfuncs(0) {
SignalBase(SignalBase &&ev):
p_class(nullptr), p_funcs(nullptr), p_nfuncs(0)
{
swap(ev);
}
@ -37,8 +39,9 @@ namespace detail {
p_nfuncs = ev.p_nfuncs;
byte *bufp = new byte[sizeof(Func) * p_nfuncs];
Func *nbuf = reinterpret_cast<Func *>(bufp);
for (Size i = 0; i < p_nfuncs; ++i)
for (Size i = 0; i < p_nfuncs; ++i) {
new (&nbuf[i]) Func(ev.p_funcs[i]);
}
p_funcs = nbuf;
return *this;
}
@ -51,8 +54,9 @@ namespace detail {
~SignalBase() { clear(); }
void clear() {
for (Size i = 0; i < p_nfuncs; ++i)
for (Size i = 0; i < p_nfuncs; ++i) {
p_funcs[i].~Function<void(C &, A...)>();
}
delete[] reinterpret_cast<byte *>(p_funcs);
p_funcs = nullptr;
p_nfuncs = 0;
@ -80,16 +84,23 @@ namespace detail {
}
bool disconnect(Size idx) {
if ((idx >= p_nfuncs) || !p_funcs[idx]) return false;
if ((idx >= p_nfuncs) || !p_funcs[idx]) {
return false;
}
p_funcs[idx] = nullptr;
return true;
}
template<typename ...Args>
void emit(Args &&...args) const {
if (!p_class) return;
for (Size i = 0; i < p_nfuncs; ++i)
if (p_funcs[i]) p_funcs[i](*p_class, args...);
if (!p_class) {
return;
}
for (Size i = 0; i < p_nfuncs; ++i) {
if (p_funcs[i]) {
p_funcs[i](*p_class, args...);
}
}
}
C *get_class() const {

View File

@ -29,28 +29,41 @@ inline SDL_RWops *stream_to_rwops(Stream &s) {
if (!rwr) {
return nullptr;
}
rwr->hidden.unknown.data1 = &s;
rwr->size = [](SDL_RWops *rw) -> SDLRWopsOffset {
Stream *is = static_cast<Stream *>(rw->hidden.unknown.data1);
return static_cast<SDLRWopsOffset>(is->size());
};
rwr->seek = [](SDL_RWops *rw, SDLRWopsOffset pos, int whence) -> SDLRWopsOffset {
rwr->seek = [](SDL_RWops *rw, SDLRWopsOffset pos, int whence) ->
SDLRWopsOffset
{
Stream *is = static_cast<Stream *>(rw->hidden.unknown.data1);
if (!pos && whence == SEEK_CUR)
if (!pos && whence == SEEK_CUR) {
return static_cast<SDLRWopsOffset>(is->tell());
if (is->seek(((StreamOffset)pos, (StreamSeek)whence))
}
if (is->seek(((StreamOffset)pos, (StreamSeek)whence)) {
return static_cast<SDLRWopsOffset>(is->tell());
}
return -1;
};
rwr->read = [](SDL_RWops *rw, void *buf, Size size, Size nb) -> Size {
Stream *is = static_cast<Stream *>(rw->hidden.unknown.data1);
return is->read_bytes(buf, size * nb) / size;
};
rwr->write = [](SDL_RWops *rw, const void *buf, Size size, Size nb) -> Size {
Stream *is = static_cast<Stream *>(rw->hidden.unknown.data1);
return is->write_bytes(buf, size * nb) / size;
};
rwr->close = [](SDL_RWops *) -> int { return 0; };
rwr->close = [](SDL_RWops *) -> int {
return 0;
};
return rwr;
}

View File

@ -59,12 +59,14 @@ struct FileInfo {
FileInfo(FileInfo const &i):
p_slash(i.p_slash), p_dot(i.p_dot), p_type(i.p_type),
p_path(i.p_path), p_atime(i.p_atime), p_mtime(i.p_mtime),
p_ctime(i.p_ctime) {}
p_ctime(i.p_ctime)
{}
FileInfo(FileInfo &&i):
p_slash(i.p_slash), p_dot(i.p_dot), p_type(i.p_type),
p_path(move(i.p_path)), p_atime(i.p_atime), p_mtime(i.p_mtime),
p_ctime(i.p_ctime) {
p_ctime(i.p_ctime)
{
i.p_slash = i.p_dot = npos;
i.p_type = FileType::unknown;
i.p_atime = i.p_ctime = i.p_mtime = 0;
@ -93,18 +95,22 @@ struct FileInfo {
ConstCharRange path() const { return p_path.iter(); }
ConstCharRange filename() const {
return path().slice((p_slash == npos) ? 0 : (p_slash + 1),
p_path.size());
return path().slice(
(p_slash == npos) ? 0 : (p_slash + 1), p_path.size()
);
}
ConstCharRange stem() const {
return path().slice((p_slash == npos) ? 0 : (p_slash + 1),
(p_dot == npos) ? p_path.size() : p_dot);
return path().slice(
(p_slash == npos) ? 0 : (p_slash + 1),
(p_dot == npos) ? p_path.size() : p_dot
);
}
ConstCharRange extension() const {
return (p_dot == npos) ? ConstCharRange()
: path().slice(p_dot, p_path.size());
return (p_dot == npos)
? ConstCharRange()
: path().slice(p_dot, p_path.size());
}
FileType type() const { return p_type; }
@ -150,53 +156,55 @@ private:
ConstCharRange r = p_path.iter();
ConstCharRange found = find_last(r, PathSeparator);
if (found.empty())
if (found.empty()) {
p_slash = npos;
else
} else {
p_slash = r.distance_front(found);
}
found = find(filename(), '.');
if (found.empty())
if (found.empty()) {
p_dot = npos;
else
} else {
p_dot = r.distance_front(found);
}
#ifdef OSTD_PLATFORM_WIN32
if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
p_type = FileType::directory;
else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
} else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
p_type = FileType::symlink;
else if (attr.dwFileAttributes & (FILE_ATTRIBUTE_ARCHIVE |
FILE_ATTRIBUTE_COMPRESSED |
FILE_ATTRIBUTE_COMPRESSED |
FILE_ATTRIBUTE_HIDDEN |
FILE_ATTRIBUTE_NORMAL |
FILE_ATTRIBUTE_SPARSE_FILE |
FILE_ATTRIBUTE_TEMPORARY))
} else if (attr.dwFileAttributes & (
FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_COMPRESSED |
FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NORMAL |
FILE_ATTRIBUTE_SPARSE_FILE | FILE_ATTRIBUTE_TEMPORARY
)) {
p_type = FileType::regular;
else
} else {
p_type = FileType::unknown;
}
p_atime = detail::filetime_to_time_t(attr.ftLastAccessTime);
p_mtime = detail::filetime_to_time_t(attr.ftLastWriteTime);
p_ctime = detail::filetime_to_time_t(attr.ftCreationTime);
#else
if (S_ISREG(st.st_mode))
if (S_ISREG(st.st_mode)) {
p_type = FileType::regular;
else if (S_ISDIR(st.st_mode))
} else if (S_ISDIR(st.st_mode)) {
p_type = FileType::directory;
else if (S_ISCHR(st.st_mode))
} else if (S_ISCHR(st.st_mode)) {
p_type = FileType::character;
else if (S_ISBLK(st.st_mode))
} else if (S_ISBLK(st.st_mode)) {
p_type = FileType::block;
else if (S_ISFIFO(st.st_mode))
} else if (S_ISFIFO(st.st_mode)) {
p_type = FileType::fifo;
else if (S_ISLNK(st.st_mode))
} else if (S_ISLNK(st.st_mode)) {
p_type = FileType::symlink;
else if (S_ISSOCK(st.st_mode))
} else if (S_ISSOCK(st.st_mode)) {
p_type = FileType::socket;
else
} else {
p_type = FileType::unknown;
}
p_atime = st.st_atime;
p_mtime = st.st_mtime;
@ -219,9 +227,9 @@ struct DirectoryStream {
DirectoryStream(): p_d(), p_de(), p_dev(), p_path() {}
DirectoryStream(DirectoryStream const &) = delete;
DirectoryStream(DirectoryStream &&s): p_d(s.p_d), p_de(s.p_de),
p_dev(s.p_dev),
p_path(move(s.p_path)) {
DirectoryStream(DirectoryStream &&s):
p_d(s.p_d), p_de(s.p_de), p_dev(s.p_dev), p_path(move(s.p_path))
{
s.p_d = nullptr;
s.p_de = nullptr;
memset(&s.p_dev, 0, sizeof(s.p_dev));
@ -241,7 +249,9 @@ struct DirectoryStream {
}
bool open(ConstCharRange path) {
if (p_d || (path.size() > FILENAME_MAX)) return false;
if (p_d || (path.size() > FILENAME_MAX)) {
return false;
}
char buf[FILENAME_MAX + 1];
memcpy(buf, &path[0], path.size());
buf[path.size()] = '\0';
@ -263,20 +273,27 @@ struct DirectoryStream {
}
long size() const {
if (!p_d) return -1;
if (!p_d) {
return -1;
}
DIR *td = opendir(p_path.data());
if (!td) return -1;
if (!td) {
return -1;
}
long ret = 0;
struct dirent rdv;
struct dirent *rd;
while (pop_front(td, &rdv, &rd))
while (pop_front(td, &rdv, &rd)) {
ret += strcmp(rd->d_name, ".") && strcmp(rd->d_name, "..");
}
closedir(td);
return ret;
}
bool rewind() {
if (!p_d) return false;
if (!p_d) {
return false;
}
rewinddir(p_d);
if (!pop_front()) {
close();
@ -290,8 +307,9 @@ struct DirectoryStream {
}
FileInfo read() {
if (!pop_front())
if (!pop_front()) {
return FileInfo();
}
return front();
}
@ -311,10 +329,12 @@ private:
/* order of . and .. in the stream is not guaranteed, apparently...
* gotta check every time because of that
*/
while (*de && (!strcmp((*de)->d_name, ".") ||
!strcmp((*de)->d_name, ".."))) {
if (readdir_r(d, dev, de))
while (*de && (
!strcmp((*de)->d_name, ".") || !strcmp((*de)->d_name, "..")
)) {
if (readdir_r(d, dev, de)) {
return false;
}
}
return !!*de;
}
@ -324,8 +344,9 @@ private:
}
FileInfo front() const {
if (!p_de)
if (!p_de) {
return FileInfo();
}
String ap = p_path;
ap += PathSeparator;
ap += static_cast<char const *>(p_de->d_name);
@ -345,9 +366,9 @@ struct DirectoryStream {
DirectoryStream(): p_handle(INVALID_HANDLE_VALUE), p_data(), p_path() {}
DirectoryStream(DirectoryStream const &) = delete;
DirectoryStream(DirectoryStream &&s): p_handle(s.p_handle),
p_data(s.p_data),
p_path(move(s.p_path)) {
DirectoryStream(DirectoryStream &&s):
p_handle(s.p_handle), p_data(s.p_data), p_path(move(s.p_path))
{
s.p_handle = INVALID_HANDLE_VALUE;
memset(&s.p_data, 0, sizeof(s.p_data));
}
@ -366,10 +387,12 @@ struct DirectoryStream {
}
bool open(ConstCharRange path) {
if (p_handle != INVALID_HANDLE_VALUE)
if (p_handle != INVALID_HANDLE_VALUE) {
return false;
if ((path.size() >= 1024) || !path.size())
}
if ((path.size() >= 1024) || !path.size()) {
return false;
}
char buf[1026];
memcpy(buf, &path[0], path.size());
char *bptr = &buf[path.size()];
@ -378,10 +401,12 @@ struct DirectoryStream {
/* include trailing zero */
memcpy(bptr, "\\*", 3);
p_handle = FindFirstFile(buf, &p_data);
if (p_handle == INVALID_HANDLE_VALUE)
if (p_handle == INVALID_HANDLE_VALUE) {
return false;
while (!strcmp(p_data.cFileName, ".") ||
!strcmp(p_data.cFileName, "..")) {
}
while (
!strcmp(p_data.cFileName, ".") || !strcmp(p_data.cFileName, "..")
) {
if (!FindNextFile(p_handle, &p_data)) {
FindClose(p_handle);
p_handle = INVALID_HANDLE_VALUE;
@ -396,47 +421,55 @@ struct DirectoryStream {
bool is_open() const { return p_handle != INVALID_HANDLE_VALUE; }
void close() {
if (p_handle != INVALID_HANDLE_VALUE)
if (p_handle != INVALID_HANDLE_VALUE) {
FindClose(p_handle);
}
p_handle = INVALID_HANDLE_VALUE;
p_data.cFileName[0] = '\0';
}
long size() const {
if (p_handle == INVALID_HANDLE_VALUE)
if (p_handle == INVALID_HANDLE_VALUE) {
return -1;
}
WIN32_FIND_DATA wfd;
HANDLE td = FindFirstFile(p_path.data(), &wfd);
if (td == INVALID_HANDLE_VALUE)
if (td == INVALID_HANDLE_VALUE) {
return -1;
while (!strcmp(wfd.cFileName, ".") && !strcmp(wfd.cFileName, ".."))
}
while (!strcmp(wfd.cFileName, ".") && !strcmp(wfd.cFileName, "..")) {
if (!FindNextFile(td, &wfd)) {
FindClose(td);
return 0;
}
}
long ret = 1;
while (FindNextFile(td, &wfd))
while (FindNextFile(td, &wfd)) {
++ret;
}
FindClose(td);
return ret;
}
bool rewind() {
if (p_handle != INVALID_HANDLE_VALUE)
if (p_handle != INVALID_HANDLE_VALUE) {
FindClose(p_handle);
}
p_handle = FindFirstFile(p_path.data(), &p_data);
if (p_handle == INVALID_HANDLE_VALUE) {
p_data.cFileName[0] = '\0';
return false;
}
while (!strcmp(p_data.cFileName, ".") ||
!strcmp(p_data.cFileName, ".."))
while (
!strcmp(p_data.cFileName, ".") || !strcmp(p_data.cFileName, "..")
) {
if (!FindNextFile(p_handle, &p_data)) {
FindClose(p_handle);
p_handle = INVALID_HANDLE_VALUE;
p_data.cFileName[0] = '\0';
return false;
}
}
return true;
}
@ -445,8 +478,9 @@ struct DirectoryStream {
}
FileInfo read() {
if (!pop_front())
if (!pop_front()) {
return FileInfo();
}
return front();
}
@ -460,8 +494,9 @@ struct DirectoryStream {
private:
bool pop_front() {
if (!is_open())
if (!is_open()) {
return false;
}
if (!FindNextFile(p_handle, &p_data)) {
p_data.cFileName[0] = '\0';
return false;
@ -470,8 +505,9 @@ private:
}
FileInfo front() const {
if (empty())
if (empty()) {
return FileInfo();
}
String ap = p_path;
ap += PathSeparator;
ap += static_cast<char const *>(p_data.cFileName);
@ -521,7 +557,8 @@ inline DirectoryRange DirectoryStream::iter() {
}
namespace detail {
template<Size I> struct PathJoin {
template<Size I>
struct PathJoin {
template<typename T, typename ...A>
static void join(String &s, T const &a, A const &...b) {
s += a;
@ -530,7 +567,8 @@ namespace detail {
}
};
template<> struct PathJoin<1> {
template<>
struct PathJoin<1> {
template<typename T>
static void join(String &s, T const &a) {
s += a;
@ -548,8 +586,9 @@ inline FileInfo path_join(A const &...args) {
inline bool directory_change(ConstCharRange path) {
char buf[1024];
if (path.size() >= 1024)
if (path.size() >= 1024) {
return false;
}
memcpy(buf, path.data(), path.size());
buf[path.size()] = '\0';
#ifndef OSTD_PLATFORM_WIN32

View File

@ -110,17 +110,17 @@ namespace detail {
/* retrieve width/precision */
template<typename T>
bool convert_arg_param(T const &val, int &param, EnableIf<
IsIntegral<T>, bool
> = true) {
bool convert_arg_param(
T const &val, int &param, EnableIf<IsIntegral<T>, bool> = true
) {
param = int(val);
return true;
}
template<typename T>
bool convert_arg_param(T const &, int &, EnableIf<
!IsIntegral<T>, bool
> = true) {
bool convert_arg_param(
T const &, int &, EnableIf<!IsIntegral<T>, bool> = true
) {
assert(false && "invalid argument for width/precision");
return false;
}
@ -135,7 +135,9 @@ namespace detail {
}
template<typename T, typename ...A>
bool get_arg_param(Size idx, int &param, T const &val, A const &...args) {
if (idx) return get_arg_param(idx - 1, param, args...);
if (idx) {
return get_arg_param(idx - 1, param, args...);
}
return convert_arg_param(val, param);
}
}
@ -143,19 +145,28 @@ namespace detail {
struct FormatSpec {
FormatSpec(): p_nested_escape(false), p_fmt() {}
FormatSpec(ConstCharRange fmt, bool escape = false):
p_nested_escape(escape), p_fmt(fmt) {}
p_nested_escape(escape), p_fmt(fmt)
{}
template<typename R>
bool read_until_spec(R &writer, Size *wret) {
Size written = 0;
if (wret) *wret = 0;
if (p_fmt.empty()) return false;
if (wret) {
*wret = 0;
}
if (p_fmt.empty()) {
return false;
}
while (!p_fmt.empty()) {
if (p_fmt.front() == '%') {
p_fmt.pop_front();
if (p_fmt.front() == '%') goto plain;
if (p_fmt.front() == '%') {
goto plain;
}
bool r = read_spec();
if (wret) *wret = written;
if (wret) {
*wret = written;
}
return r;
}
plain:
@ -163,16 +174,22 @@ struct FormatSpec {
writer.put(p_fmt.front());
p_fmt.pop_front();
}
if (wret) *wret = written;
if (wret) {
*wret = written;
}
return false;
}
template<typename R>
Size write_spaces(R &writer, Size n, bool left, char c = ' ') const {
if (left == bool(p_flags & FMT_FLAG_DASH)) return 0;
if (left == bool(p_flags & FMT_FLAG_DASH)) {
return 0;
}
int r = p_width - int(n);
for (int w = p_width - int(n); --w >= 0; writer.put(c));
if (r < 0) return 0;
if (r < 0) {
return 0;
}
return r;
}
@ -183,11 +200,21 @@ struct FormatSpec {
template<typename R>
Size build_spec(R &&out, ConstCharRange spec) {
Size ret = out.put('%');
if (p_flags & FMT_FLAG_DASH ) ret += out.put('-');
if (p_flags & FMT_FLAG_ZERO ) ret += out.put('0');
if (p_flags & FMT_FLAG_SPACE) ret += out.put(' ');
if (p_flags & FMT_FLAG_PLUS ) ret += out.put('+');
if (p_flags & FMT_FLAG_HASH ) ret += out.put('#');
if (p_flags & FMT_FLAG_DASH ) {
ret += out.put('-');
}
if (p_flags & FMT_FLAG_ZERO ) {
ret += out.put('0');
}
if (p_flags & FMT_FLAG_SPACE) {
ret += out.put(' ');
}
if (p_flags & FMT_FLAG_PLUS ) {
ret += out.put('+');
}
if (p_flags & FMT_FLAG_HASH ) {
ret += out.put('#');
}
ret += out.put_n("*.*", 3);
ret += out.put_n(&spec[0], spec.size());
return ret;
@ -250,7 +277,9 @@ protected:
while (!p_fmt.empty()) {
if (p_fmt.front() == '%') {
p_fmt.pop_front();
if (p_fmt.front() == '%') goto plain;
if (p_fmt.front() == '%') {
goto plain;
}
return read_spec();
}
plain:
@ -339,12 +368,17 @@ protected:
p_flags = detail::parse_fmt_flags(p_fmt, 0);
} else {
for (Size i = 0; i < ndig; ++i) {
if (p_buf[i] != '0') break;
if (p_buf[i] != '0') {
break;
}
++skipd;
}
if (skipd) p_flags = FMT_FLAG_ZERO;
if (skipd == ndig)
if (skipd) {
p_flags = FMT_FLAG_ZERO;
}
if (skipd == ndig) {
p_flags = detail::parse_fmt_flags(p_fmt, p_flags);
}
}
/* range/array formatting */
@ -371,7 +405,9 @@ protected:
p_precision = 0;
p_has_precision = false;
p_arg_precision = false;
if (p_fmt.front() != '.') goto fmtchar;
if (p_fmt.front() != '.') {
goto fmtchar;
}
p_fmt.pop_front();
if (detail::read_digits(p_fmt, p_buf)) {
@ -380,7 +416,9 @@ protected:
} else if (p_fmt.front() == '*') {
p_arg_precision = p_has_precision = true;
p_fmt.pop_front();
} else return false;
} else {
return false;
}
fmtchar:
p_spec = p_fmt.front();
@ -397,11 +435,14 @@ protected:
/* for custom container formatting */
template<typename T, typename R, typename = EnableIf<
IsSame<decltype(declval<T const &>()
.to_format(declval<R &>(), declval<FormatSpec const &>())), bool
template<
typename T, typename R, typename = EnableIf<
IsSame<decltype(declval<T const &>()
.to_format(declval<R &>(), declval<FormatSpec const &>())), bool
>
>
>> inline bool to_format(T const &v, R &writer, FormatSpec const &fs) {
>
inline bool to_format(T const &v, R &writer, FormatSpec const &fs) {
return v.to_format(writer, fs);
}
@ -421,9 +462,12 @@ namespace detail {
}
int base = detail::fmt_bases[specn];
if (!val) buf[n++] = '0';
for (; val; val /= base)
if (!val) {
buf[n++] = '0';
}
for (; val; val /= base) {
buf[n++] = detail::fmt_digits[spec >= 'a'][val % base];
}
r = n;
int flags = fl->flags();
@ -441,12 +485,16 @@ namespace detail {
r += pfxlen;
}
if (!zero)
if (!zero) {
r += fl->write_spaces(writer, n + pfxlen + sign, true, ' ');
if (sign) writer.put(neg ? '-' : *((" \0+") + lsgn * 2));
}
if (sign) {
writer.put(neg ? '-' : *((" \0+") + lsgn * 2));
}
writer.put_n(pfx, pfxlen);
if (zero)
if (zero) {
r += fl->write_spaces(writer, n + pfxlen + sign, true, '0');
}
for (int i = int(n - 1); i >= 0; --i) {
writer.put(buf[i]);
@ -456,8 +504,10 @@ namespace detail {
}
template<typename R, typename ...A>
static Ptrdiff format_impl(R &writer, Size &fmtn, bool escape,
ConstCharRange fmt, A const &...args);
static Ptrdiff format_impl(
R &writer, Size &fmtn, bool escape,
ConstCharRange fmt, A const &...args
);
template<typename T, typename = RangeOf<T>>
static True test_fmt_range(int);
@ -470,88 +520,99 @@ namespace detail {
template<Size I>
struct FmtTupleUnpacker {
template<typename R, typename T, typename ...A>
static inline Ptrdiff unpack(R &writer, Size &fmtn, bool esc,
ConstCharRange fmt, T const &item,
A const &...args) {
return FmtTupleUnpacker<I - 1>::unpack(writer, fmtn, esc, fmt,
item, get<I - 1>(item), args...);
static inline Ptrdiff unpack(
R &writer, Size &fmtn, bool esc, ConstCharRange fmt,
T const &item, A const &...args
) {
return FmtTupleUnpacker<I - 1>::unpack(
writer, fmtn, esc, fmt, item, get<I - 1>(item), args...
);
}
};
template<>
struct FmtTupleUnpacker<0> {
template<typename R, typename T, typename ...A>
static inline Ptrdiff unpack(R &writer, Size &fmtn, bool esc,
ConstCharRange fmt, T const &,
A const &...args) {
static inline Ptrdiff unpack(
R &writer, Size &fmtn, bool esc, ConstCharRange fmt,
T const &, A const &...args
) {
return format_impl(writer, fmtn, esc, fmt, args...);
}
};
template<typename R, typename T>
inline Ptrdiff format_ritem(R &writer, Size &fmtn, bool esc, bool,
ConstCharRange fmt, T const &item,
EnableIf<!IsTupleLike<T>, bool>
= true) {
inline Ptrdiff format_ritem(
R &writer, Size &fmtn, bool esc, bool, ConstCharRange fmt,
T const &item, EnableIf<!IsTupleLike<T>, bool> = true
) {
return format_impl(writer, fmtn, esc, fmt, item);
}
template<typename R, typename T>
inline Ptrdiff format_ritem(R &writer, Size &fmtn, bool esc,
bool expandval, ConstCharRange fmt,
T const &item,
EnableIf<IsTupleLike<T>, bool>
= true) {
inline Ptrdiff format_ritem(
R &writer, Size &fmtn, bool esc, bool expandval, ConstCharRange fmt,
T const &item, EnableIf<IsTupleLike<T>, bool> = true
) {
if (expandval) {
return FmtTupleUnpacker<TupleSize<T>>::unpack(writer,
fmtn, esc, fmt, item);
return FmtTupleUnpacker<TupleSize<T>>::unpack(
writer, fmtn, esc, fmt, item
);
}
return format_impl(writer, fmtn, esc, fmt, item);
}
template<typename R, typename T>
inline Ptrdiff write_range(R &writer, FormatSpec const *fl,
bool escape, bool expandval,
ConstCharRange sep,
T const &val,
EnableIf<FmtRangeTest<T>, bool>
= true) {
inline Ptrdiff write_range(
R &writer, FormatSpec const *fl, bool escape, bool expandval,
ConstCharRange sep, T const &val, EnableIf<FmtRangeTest<T>, bool> = true
) {
auto range = ostd::iter(val);
if (range.empty()) return 0;
if (range.empty()) {
return 0;
}
Ptrdiff ret = 0;
Size fmtn = 0;
/* test first item */
Ptrdiff fret = format_ritem(writer, fmtn, escape, expandval,
fl->rest(), range.front());
if (fret < 0) return fret;
Ptrdiff fret = format_ritem(
writer, fmtn, escape, expandval, fl->rest(), range.front()
);
if (fret < 0) {
return fret;
}
ret += fret;
range.pop_front();
/* write the rest (if any) */
for (; !range.empty(); range.pop_front()) {
auto v = writer.put_n(&sep[0], sep.size());
if (v != sep.size())
if (v != sep.size()) {
return -1;
}
ret += sep.size();
fret = format_ritem(writer, fmtn, escape, expandval,
fl->rest(), range.front());
if (fret < 0) return fret;
fret = format_ritem(
writer, fmtn, escape, expandval, fl->rest(), range.front()
);
if (fret < 0) {
return fret;
}
ret += fret;
}
return ret;
}
template<typename R, typename T>
inline Ptrdiff write_range(R &, FormatSpec const *, bool, bool,
ConstCharRange, T const &,
EnableIf<!FmtRangeTest<T>, bool>
= true) {
inline Ptrdiff write_range(
R &, FormatSpec const *, bool, bool, ConstCharRange,
T const &, EnableIf<!FmtRangeTest<T>, bool> = true
) {
assert(false && "invalid value for ranged format");
return -1;
}
template<typename T>
static True test_fmt_tostr(decltype(ostd::to_string(declval<T>())) *);
template<typename> static False test_fmt_tostr(...);
template<typename>
static False test_fmt_tostr(...);
template<typename T>
constexpr bool FmtTostrTest = decltype(test_fmt_tostr<T>(0))::value;
@ -583,10 +644,11 @@ namespace detail {
ret.push('"');
while (!val.empty()) {
char const *esc = escape_fmt_char(val.front(), '"');
if (esc)
if (esc) {
ret.append(esc);
else
} else {
ret.push(val.front());
}
val.pop_front();
}
ret.push('"');
@ -594,9 +656,9 @@ namespace detail {
}
template<typename T, typename R>
static True test_tofmt(decltype(to_format(declval<T const &>(),
declval<R &>(),
declval<FormatSpec const &>())) *);
static True test_tofmt(decltype(to_format(
declval<T const &>(), declval<R &>(), declval<FormatSpec const &>()
)) *);
template<typename, typename>
static False test_tofmt(...);
@ -615,7 +677,9 @@ namespace detail {
return write_str(writer, false, escape_fmt_str(val));
}
Size n = val.size();
if (this->precision()) n = this->precision();
if (this->precision()) {
n = this->precision();
}
Ptrdiff r = n;
r += this->write_spaces(writer, n, true);
writer.put_n(&val[0], n);
@ -625,9 +689,11 @@ namespace detail {
/* any string value */
template<typename R, typename T>
Ptrdiff write(R &writer, bool escape, T const &val, EnableIf<
IsConstructible<ConstCharRange, T const &>, bool
> = true) {
Ptrdiff write(
R &writer, bool escape, T const &val, EnableIf<
IsConstructible<ConstCharRange, T const &>, bool
> = true
) {
if (this->spec() != 's') {
assert(false && "cannot print strings with the given spec");
return -1;
@ -661,7 +727,9 @@ namespace detail {
writer.put('\'');
writer.put(val);
writer.put('\'');
} else writer.put(val);
} else {
writer.put(val);
}
r += this->write_spaces(writer, 1 + escape * 2, false);
return r;
}
@ -669,33 +737,41 @@ namespace detail {
/* bool */
template<typename R>
Ptrdiff write(R &writer, bool, bool val) {
if (this->spec() == 's')
if (this->spec() == 's') {
return write(writer, ("false\0true") + (6 * val));
else
} else {
return write(writer, int(val));
}
}
/* signed integers */
template<typename R, typename T>
Ptrdiff write(R &writer, bool, T val, EnableIf<
IsIntegral<T> && IsSigned<T>, bool
> = true) {
Ptrdiff write(
R &writer, bool, T val, EnableIf<
IsIntegral<T> && IsSigned<T>, bool
> = true
) {
using UT = MakeUnsigned<T>;
return detail::write_u(writer, this, val < 0,
(val < 0) ? static_cast<UT>(-val) : static_cast<UT>(val));
return detail::write_u(
writer, this, val < 0,
(val < 0) ? static_cast<UT>(-val) : static_cast<UT>(val)
);
}
/* unsigned integers */
template<typename R, typename T>
Ptrdiff write(R &writer, bool, T val, EnableIf<
IsIntegral<T> && IsUnsigned<T>, bool
> = true) {
Ptrdiff write(
R &writer, bool, T val, EnableIf<
IsIntegral<T> && IsUnsigned<T>, bool
> = true
) {
return detail::write_u(writer, this, false, val);
}
template<typename R, typename T, bool Long = IsSame<T, ldouble>>
Ptrdiff write(R &writer, bool, T val, EnableIf<IsFloatingPoint<T>, bool>
= true) {
Ptrdiff write(
R &writer, bool, T val, EnableIf<IsFloatingPoint<T>, bool> = true
) {
char buf[16], rbuf[128];
char fmtspec[Long + 1];
@ -705,31 +781,42 @@ namespace detail {
assert(false && "cannot format floats with the given spec");
return -1;
}
if (specn == 7) fmtspec[Long] = 'g';
if (Long) fmtspec[0] = 'L';
if (specn == 7) {
fmtspec[Long] = 'g';
}
if (Long) {
fmtspec[0] = 'L';
}
buf[this->build_spec(iter(buf), fmtspec)] = '\0';
Ptrdiff ret = snprintf(rbuf, sizeof(rbuf), buf,
this->width(),
this->has_precision() ? this->precision() : 6, val);
Ptrdiff ret = snprintf(
rbuf, sizeof(rbuf), buf, this->width(),
this->has_precision() ? this->precision() : 6, val
);
char *dbuf = nullptr;
if (Size(ret) >= sizeof(rbuf)) {
/* this should typically never happen */
dbuf = new char[ret + 1];
ret = snprintf(dbuf, ret + 1, buf, this->width(),
this->has_precision() ? this->precision() : 6, val);
ret = snprintf(
dbuf, ret + 1, buf, this->width(),
this->has_precision() ? this->precision() : 6, val
);
writer.put_n(dbuf, ret);
delete[] dbuf;
} else writer.put_n(rbuf, ret);
} else {
writer.put_n(rbuf, ret);
}
return ret;
}
/* pointer value */
template<typename R, typename T>
Ptrdiff write(R &writer, bool, T *val, EnableIf<
!IsConstructible<ConstCharRange, T *>, bool
> = true) {
Ptrdiff write(
R &writer, bool, T *val, EnableIf<
!IsConstructible<ConstCharRange, T *>, bool
> = true
) {
if (this->p_spec == 's') {
this->p_spec = 'x';
this->p_flags |= FMT_FLAG_HASH;
@ -739,11 +826,13 @@ namespace detail {
/* generic value */
template<typename R, typename T>
Ptrdiff write(R &writer, bool, T const &val, EnableIf<
!IsArithmetic<T> &&
!IsConstructible<ConstCharRange, T const &> &&
FmtTostrTest<T> && !FmtTofmtTest<T, TostrRange<R>>, bool
> = true) {
Ptrdiff write(
R &writer, bool, T const &val, EnableIf<
!IsArithmetic<T> &&
!IsConstructible<ConstCharRange, T const &> &&
FmtTostrTest<T> && !FmtTofmtTest<T, TostrRange<R>>, bool
> = true
) {
if (this->spec() != 's') {
assert(false && "custom objects need '%s' format");
return -1;
@ -753,21 +842,26 @@ namespace detail {
/* custom format case */
template<typename R, typename T>
Ptrdiff write(R &writer, bool, T const &val,
EnableIf<FmtTofmtTest<T, TostrRange<R>>, bool
> = true) {
Ptrdiff write(
R &writer, bool, T const &val,
EnableIf<FmtTofmtTest<T, TostrRange<R>>, bool> = true
) {
TostrRange<R> sink(writer);
if (!to_format(val, sink, *this)) return -1;
if (!to_format(val, sink, *this)) {
return -1;
}
return sink.get_written();
}
/* generic failure case */
template<typename R, typename T>
Ptrdiff write(R &, bool, T const &, EnableIf<
!IsArithmetic<T> &&
!IsConstructible<ConstCharRange, T const &> &&
!FmtTostrTest<T> && !FmtTofmtTest<T, TostrRange<R>>, bool
> = true) {
Ptrdiff write(
R &, bool, T const &, EnableIf<
!IsArithmetic<T> &&
!IsConstructible<ConstCharRange, T const &> &&
!FmtTostrTest<T> && !FmtTofmtTest<T, TostrRange<R>>, bool
> = true
) {
assert(false && "value cannot be formatted");
return -1;
}
@ -783,39 +877,48 @@ namespace detail {
}
template<typename R, typename T, typename ...A>
Ptrdiff write_arg(R &writer, Size idx, T const &val,
A const &...args) {
if (idx) return write_arg(writer, idx - 1, args...);
Ptrdiff write_arg(
R &writer, Size idx, T const &val, A const &...args
) {
if (idx) {
return write_arg(writer, idx - 1, args...);
}
return write(writer, this->p_nested_escape, val);
}
/* range writer */
template<typename R, typename T>
Ptrdiff write_range(R &writer, Size idx, bool expandval,
ConstCharRange sep, T const &val) {
Ptrdiff write_range(
R &writer, Size idx, bool expandval,
ConstCharRange sep, T const &val
) {
if (idx) {
assert(false && "not enough format args");
return -1;
}
return detail::write_range(writer, this, this->p_nested_escape,
expandval, sep, val);
return detail::write_range(
writer, this, this->p_nested_escape, expandval, sep, val
);
}
template<typename R, typename T, typename ...A>
Ptrdiff write_range(R &writer, Size idx, bool expandval,
ConstCharRange sep, T const &val,
A const &...args) {
Ptrdiff write_range(
R &writer, Size idx, bool expandval, ConstCharRange sep,
T const &val, A const &...args
) {
if (idx) {
return write_range(writer, idx - 1, expandval, sep, args...);
}
return detail::write_range(writer, this,
this->p_nested_escape, expandval, sep, val);
return detail::write_range(
writer, this, this->p_nested_escape, expandval, sep, val
);
}
};
template<typename R, typename ...A>
inline Ptrdiff format_impl(R &writer, Size &fmtn, bool escape,
ConstCharRange fmt, A const &...args) {
inline Ptrdiff format_impl(
R &writer, Size &fmtn, bool escape, ConstCharRange fmt, A const &...args
) {
Size argidx = 1, retn = 0, twr = 0;
Ptrdiff written = 0;
detail::WriteSpec spec(fmt, escape);
@ -823,26 +926,33 @@ namespace detail {
written += twr;
Size argpos = spec.index();
if (spec.is_nested()) {
if (!argpos) argpos = argidx++;
if (!argpos) {
argpos = argidx++;
}
/* FIXME: figure out a better way */
detail::WriteSpec nspec(spec.nested(), spec.nested_escape());
Ptrdiff sw = nspec.write_range(writer, argpos - 1,
(spec.flags() & FMT_FLAG_HASH),
spec.nested_sep(), args...);
if (sw < 0) return sw;
Ptrdiff sw = nspec.write_range(
writer, argpos - 1, (spec.flags() & FMT_FLAG_HASH),
spec.nested_sep(), args...
);
if (sw < 0) {
return sw;
}
written += sw;
continue;
}
if (!argpos) {
argpos = argidx++;
if (spec.arg_width()) {
if (!spec.set_width(argpos - 1, args...))
if (!spec.set_width(argpos - 1, args...)) {
return -1;
}
argpos = argidx++;
}
if (spec.arg_precision()) {
if (!spec.set_precision(argpos - 1, args...))
if (!spec.set_precision(argpos - 1, args...)) {
return -1;
}
argpos = argidx++;
}
} else {
@ -852,20 +962,24 @@ namespace detail {
assert(false && "argument precision not given");
return -1;
}
if (!spec.set_precision(argpos - 2, args...))
if (!spec.set_precision(argpos - 2, args...)) {
return -1;
}
}
if (spec.arg_width()) {
if (argpos <= (Size(argprec) + 1)) {
assert(false && "argument width not given");
return -1;
}
if (!spec.set_width(argpos - 2 - argprec, args...))
if (!spec.set_width(argpos - 2 - argprec, args...)) {
return -1;
}
}
}
Ptrdiff sw = spec.write_arg(writer, argpos - 1, args...);
if (sw < 0) return sw;
if (sw < 0) {
return sw;
}
written += sw;
}
written += twr;
@ -874,19 +988,23 @@ namespace detail {
}
template<typename R, typename ...A>
inline Ptrdiff format_impl(R &writer, Size &fmtn, bool,
ConstCharRange fmt) {
inline Ptrdiff format_impl(
R &writer, Size &fmtn, bool, ConstCharRange fmt
) {
Size written = 0;
detail::WriteSpec spec(fmt, false);
if (spec.read_until_spec(writer, &written)) return -1;
if (spec.read_until_spec(writer, &written)) {
return -1;
}
fmtn = 0;
return written;
}
} /* namespace detail */
template<typename R, typename ...A>
inline Ptrdiff format(R &&writer, Size &fmtn, ConstCharRange fmt,
A const &...args) {
inline Ptrdiff format(
R &&writer, Size &fmtn, ConstCharRange fmt, A const &...args
) {
return detail::format_impl(writer, fmtn, false, fmt, args...);
}

View File

@ -19,7 +19,8 @@ namespace ostd {
/* basic function objects */
#define OSTD_DEFINE_BINARY_OP(name, op, RT) \
template<typename T> struct name { \
template<typename T> \
struct name { \
RT operator()(T const &x, T const &y) const { \
return x op y; \
} \
@ -58,7 +59,8 @@ namespace detail {
}
};
template<typename T> struct CharEqual<T, false> {
template<typename T>
struct CharEqual<T, false> {
using FirstArgument = T *;
using SecondArgument = T *;
using Result = bool;
@ -68,7 +70,8 @@ namespace detail {
};
}
template<typename T> struct EqualWithCstr {
template<typename T>
struct EqualWithCstr {
using FirstArgument = T;
using SecondArgument = T;
bool operator()(T const &x, T const &y) const {
@ -76,36 +79,40 @@ template<typename T> struct EqualWithCstr {
}
};
template<typename T> struct EqualWithCstr<T *>: detail::CharEqual<T> {};
template<typename T>
struct EqualWithCstr<T *>: detail::CharEqual<T> {};
template<typename T> struct LogicalNot {
template<typename T>
struct LogicalNot {
bool operator()(T const &x) const { return !x; }
using Argument = T;
using Result = bool;
};
template<typename T> struct Negate {
template<typename T>
struct Negate {
bool operator()(T const &x) const { return -x; }
using Argument = T;
using Result = T;
};
template<typename T> struct BinaryNegate {
template<typename T>
struct BinaryNegate {
using FirstArgument = typename T::FirstArgument;
using SecondArgument = typename T::SecondArgument;
using Result = bool;
explicit BinaryNegate(T const &f): p_fn(f) {}
bool operator()(FirstArgument const &x,
SecondArgument const &y) {
bool operator()(FirstArgument const &x, SecondArgument const &y) {
return !p_fn(x, y);
}
private:
T p_fn;
};
template<typename T> struct UnaryNegate {
template<typename T>
struct UnaryNegate {
using Argument = typename T::Argument;
using Result = bool;
@ -117,11 +124,13 @@ private:
T p_fn;
};
template<typename T> UnaryNegate<T> not1(T const &fn) {
template<typename T>
UnaryNegate<T> not1(T const &fn) {
return UnaryNegate<T>(fn);
}
template<typename T> BinaryNegate<T> not2(T const &fn) {
template<typename T>
BinaryNegate<T> not2(T const &fn) {
return BinaryNegate<T>(fn);
}
@ -194,19 +203,26 @@ namespace detail {
}
#if OSTD_BYTE_ORDER == OSTD_ENDIAN_LIL
template<typename T> struct FromLilEndian: detail::EndianSame<T> {};
template<typename T> struct FromBigEndian: EndianSwap<T> {};
template<typename T>
struct FromLilEndian: detail::EndianSame<T> {};
template<typename T>
struct FromBigEndian: EndianSwap<T> {};
#else
template<typename T> struct FromLilEndian: EndianSwap<T> {};
template<typename T> struct FromBigEndian: detail::EndianSame<T> {};
template<typename T>
struct FromLilEndian: EndianSwap<T> {};
template<typename T>
struct FromBigEndian: detail::EndianSame<T> {};
#endif
template<typename T> T from_lil_endian(T x) { return FromLilEndian<T>()(x); }
template<typename T> T from_big_endian(T x) { return FromBigEndian<T>()(x); }
template<typename T>
T from_lil_endian(T x) { return FromLilEndian<T>()(x); }
template<typename T>
T from_big_endian(T x) { return FromBigEndian<T>()(x); }
/* hash */
template<typename T> struct ToHash {
template<typename T>
struct ToHash {
using Argument = T;
using Result = Size;
@ -216,7 +232,8 @@ template<typename T> struct ToHash {
};
namespace detail {
template<typename T> struct ToHashBase {
template<typename T>
struct ToHashBase {
using Argument = T;
using Result = Size;
@ -226,7 +243,9 @@ namespace detail {
};
}
#define OSTD_HASH_BASIC(T) template<> struct ToHash<T>: detail::ToHashBase<T> {};
#define OSTD_HASH_BASIC(T) \
template<> \
struct ToHash<T>: detail::ToHashBase<T> {};
OSTD_HASH_BASIC(bool)
OSTD_HASH_BASIC(char)
@ -249,13 +268,15 @@ OSTD_HASH_BASIC(Wchar)
#undef OSTD_HASH_BASIC
namespace detail {
template<Size E> struct FnvConstants {
template<Size E>
struct FnvConstants {
static constexpr Size prime = 16777619u;
static constexpr Size offset = 2166136261u;
};
template<> struct FnvConstants<8> {
template<>
struct FnvConstants<8> {
/* conversion is necessary here because when compiling on
* 32bit, compilers will complain, despite this template
* not being instantiated...
@ -278,7 +299,8 @@ namespace detail {
template<typename T, Size = sizeof(T) / sizeof(Size)>
struct ScalarHash;
template<typename T> struct ScalarHash<T, 0> {
template<typename T>
struct ScalarHash<T, 0> {
using Argument = T;
using Result = Size;
@ -290,7 +312,8 @@ namespace detail {
}
};
template<typename T> struct ScalarHash<T, 1> {
template<typename T>
struct ScalarHash<T, 1> {
using Argument = T;
using Result = Size;
@ -301,7 +324,8 @@ namespace detail {
}
};
template<typename T> struct ScalarHash<T, 2> {
template<typename T>
struct ScalarHash<T, 2> {
using Argument = T;
using Result = Size;
@ -312,7 +336,8 @@ namespace detail {
}
};
template<typename T> struct ScalarHash<T, 3> {
template<typename T>
struct ScalarHash<T, 3> {
using Argument = T;
using Result = Size;
@ -323,7 +348,8 @@ namespace detail {
}
};
template<typename T> struct ScalarHash<T, 4> {
template<typename T>
struct ScalarHash<T, 4> {
using Argument = T;
using Result = Size;
@ -335,26 +361,33 @@ namespace detail {
};
} /* namespace detail */
template<> struct ToHash<llong>: detail::ScalarHash<llong> {};
template<> struct ToHash<ullong>: detail::ScalarHash<ullong> {};
template<>
struct ToHash<llong>: detail::ScalarHash<llong> {};
template<>
struct ToHash<ullong>: detail::ScalarHash<ullong> {};
template<> struct ToHash<float>: detail::ScalarHash<float> {
template<>
struct ToHash<float>: detail::ScalarHash<float> {
Size operator()(float v) const {
if (v == 0) return 0;
return detail::ScalarHash<float>::operator()(v);
}
};
template<> struct ToHash<double>: detail::ScalarHash<double> {
template<>
struct ToHash<double>: detail::ScalarHash<double> {
Size operator()(double v) const {
if (v == 0) return 0;
return detail::ScalarHash<double>::operator()(v);
}
};
template<> struct ToHash<ldouble>: detail::ScalarHash<ldouble> {
template<>
struct ToHash<ldouble>: detail::ScalarHash<ldouble> {
Size operator()(ldouble v) const {
if (v == 0) return 0;
if (v == 0) {
return 0;
}
#ifdef __i386__
union { ldouble v; struct { Size h1, h2, h3, h4; }; } u;
u.h1 = u.h2 = u.h3 = u.h4 = 0;
@ -385,7 +418,8 @@ namespace detail {
}
};
template<typename T> struct ToHashPtr<T, true> {
template<typename T>
struct ToHashPtr<T, true> {
using Argument = T *;
using Result = Size;
Size operator()(T *v) const {
@ -394,7 +428,8 @@ namespace detail {
};
}
template<typename T> struct ToHash<T *>: detail::ToHashPtr<T> {};
template<typename T>
struct ToHash<T *>: detail::ToHashPtr<T> {};
template<typename T>
typename ToHash<T>::Result to_hash(T const &v) {
@ -428,7 +463,8 @@ template<typename T>
ReferenceWrapper<T> ref(ReferenceWrapper<T> v) {
return ReferenceWrapper<T>(v);
}
template<typename T> void ref(T const &&) = delete;
template<typename T>
void ref(T const &&) = delete;
template<typename T>
ReferenceWrapper<T const> cref(T const &v) {
@ -438,12 +474,14 @@ template<typename T>
ReferenceWrapper<T const> cref(ReferenceWrapper<T> v) {
return ReferenceWrapper<T>(v);
}
template<typename T> void cref(T const &&) = delete;
template<typename T>
void cref(T const &&) = delete;
/* mem_fn */
namespace detail {
template<typename, typename> struct MemTypes;
template<typename, typename>
struct MemTypes;
template<typename T, typename R, typename ...A>
struct MemTypes<T, R(A...)> {
using Result = R;
@ -474,22 +512,26 @@ namespace detail {
MemFn(R T::*ptr): p_ptr(ptr) {}
template<typename... A>
auto operator()(T &obj, A &&...args) ->
decltype(((obj).*(p_ptr))(forward<A>(args)...)) {
decltype(((obj).*(p_ptr))(forward<A>(args)...))
{
return ((obj).*(p_ptr))(forward<A>(args)...);
}
template<typename... A>
auto operator()(T const &obj, A &&...args) ->
decltype(((obj).*(p_ptr))(forward<A>(args)...)) const {
decltype(((obj).*(p_ptr))(forward<A>(args)...))
const {
return ((obj).*(p_ptr))(forward<A>(args)...);
}
template<typename... A>
auto operator()(T *obj, A &&...args) ->
decltype(((obj)->*(p_ptr))(forward<A>(args)...)) {
decltype(((obj)->*(p_ptr))(forward<A>(args)...))
{
return ((obj)->*(p_ptr))(forward<A>(args)...);
}
template<typename... A>
auto operator()(T const *obj, A &&...args) ->
decltype(((obj)->*(p_ptr))(forward<A>(args)...)) const {
decltype(((obj)->*(p_ptr))(forward<A>(args)...))
const {
return ((obj)->*(p_ptr))(forward<A>(args)...);
}
};
@ -504,7 +546,8 @@ detail::MemFn<R, T> mem_fn(R T:: *ptr) {
* reference: http://probablydance.com/2013/01/13/a-faster-implementation-of-stdfunction
*/
template<typename> struct Function;
template<typename>
struct Function;
namespace detail {
struct FunctorData {
@ -512,9 +555,9 @@ namespace detail {
};
template<typename T>
constexpr bool FunctorInPlace = sizeof(T) <= sizeof(FunctorData) &&
(alignof(FunctorData) % alignof(T)) == 0 &&
IsMoveConstructible<T>;
constexpr bool FunctorInPlace =
sizeof(T) <= sizeof(FunctorData) &&
(alignof(FunctorData) % alignof(T)) == 0 && IsMoveConstructible<T>;
struct FunctionManager;
@ -547,7 +590,8 @@ namespace detail {
template<typename R, typename ...Args>
static R call(FunctorData const &s, Args ...args) {
return (*reinterpret_cast<T *>(&const_cast<FunctorData &>(s)))(
forward<Args>(args)...);
forward<Args>(args)...
);
}
static void store_f(FmStorage &s, T v) {
@ -577,7 +621,8 @@ namespace detail {
template<typename R, typename ...Args>
static R call(FunctorData const &s, Args ...args) {
return (*reinterpret_cast<AllocatorPointer<A> &>(
const_cast<FunctorData &>(s)))(forward<Args>(args)...);
const_cast<FunctorData &>(s))
)(forward<Args>(args)...);
}
static void store_f(FmStorage &s, T v) {
@ -594,7 +639,9 @@ namespace detail {
static void destroy_f(A &a, FmStorage &s) {
AllocatorPointer<A> &ptr = get_ptr_ref(s);
if (!ptr) return;
if (!ptr) {
return;
}
allocator_destroy(a, ptr);
allocator_deallocate(a, ptr, 1);
ptr = nullptr;
@ -610,7 +657,8 @@ namespace detail {
static AllocatorPointer<A> &get_ptr_ref(FmStorage const &s) {
return reinterpret_cast<AllocatorPointer<A> &>(
const_cast<FunctorData &>(s.data));
const_cast<FunctorData &>(s.data)
);
}
};
@ -634,17 +682,19 @@ namespace detail {
};
}
void (* const call_move_and_destroyf)(FmStorage &lhs,
FmStorage &&rhs);
void (* const call_copyf)(FmStorage &lhs,
FmStorage const &rhs);
void (* const call_copyf_fo)(FmStorage &lhs,
FmStorage const &rhs);
void (* const call_move_and_destroyf)(
FmStorage &lhs, FmStorage &&rhs
);
void (* const call_copyf)(
FmStorage &lhs, FmStorage const &rhs
);
void (* const call_copyf_fo)(
FmStorage &lhs, FmStorage const &rhs
);
void (* const call_destroyf)(FmStorage &s);
template<typename T, typename A>
static void call_move_and_destroy(FmStorage &lhs,
FmStorage &&rhs) {
static void call_move_and_destroy(FmStorage &lhs, FmStorage &&rhs) {
using Spec = FunctorDataManager<T, A>;
Spec::move_f(lhs, move(rhs));
Spec::destroy_f(rhs.get_alloc<A>(), rhs);
@ -653,16 +703,14 @@ namespace detail {
}
template<typename T, typename A>
static void call_copy(FmStorage &lhs,
FmStorage const &rhs) {
static void call_copy(FmStorage &lhs, FmStorage const &rhs) {
using Spec = FunctorDataManager<T, A>;
create_fm<T, A>(lhs, A(rhs.get_alloc<A>()));
Spec::store_f(lhs, Spec::get_ref(rhs));
}
template<typename T, typename A>
static void call_copy_fo(FmStorage &lhs,
FmStorage const &rhs) {
static void call_copy_fo(FmStorage &lhs, FmStorage const &rhs) {
using Spec = FunctorDataManager<T, A>;
Spec::store_f(lhs, Spec::get_ref(rhs));
}
@ -677,8 +725,8 @@ namespace detail {
template<typename T, typename A>
inline static FunctionManager const &get_default_fm() {
static FunctionManager const def_manager
= FunctionManager::create_default_manager<T, A>();
static FunctionManager const def_manager =
FunctionManager::create_default_manager<T, A>();
return def_manager;
}
@ -726,14 +774,15 @@ namespace detail {
struct ValidFunctorNat {};
template<typename U, typename ...A>
static decltype(func_to_functor(declval<U>()) (declval<A>()...))
valid_functor_test(U *);
static decltype(
func_to_functor(declval<U>()) (declval<A>()...)
) valid_functor_test(U *);
template<typename, typename ...>
static ValidFunctorNat valid_functor_test(...);
template<typename T, typename R, typename ...A>
constexpr bool IsValidFunctor<T, R(A...)>
= IsConvertible<decltype(valid_functor_test<T, A...>(nullptr)), R>;
constexpr bool IsValidFunctor<T, R(A...)> =
IsConvertible<decltype(valid_functor_test<T, A...>(nullptr)), R>;
template<typename T>
using FunctorType = decltype(func_to_functor(declval<T>()));
@ -755,13 +804,15 @@ struct Function<R(Args...)>: detail::FunctionBase<R, Args...> {
template<typename T, typename = EnableIf<
detail::IsValidFunctor<T, R(Args...)>
>> Function(T f) {
>>
Function(T f) {
if (func_is_null(f)) {
init_empty();
return;
}
initialize(detail::func_to_functor(forward<T>(f)),
Allocator<detail::FunctorType<T>>());
initialize(detail::func_to_functor(
forward<T>(f)), Allocator<detail::FunctorType<T>>()
);
}
template<typename A>
@ -778,9 +829,10 @@ struct Function<R(Args...)>: detail::FunctionBase<R, Args...> {
template<typename A>
Function(AllocatorArg, A const &a, Function const &f):
p_call(f.p_call) {
detail::FunctionManager const *mfa
= &detail::get_default_fm<AllocatorValue<A>, A>();
p_call(f.p_call)
{
detail::FunctionManager const *mfa =
&detail::get_default_fm<AllocatorValue<A>, A>();
if (f.p_stor.manager == mfa) {
detail::create_fm<AllocatorValue<A>, A>(p_stor, A(a));
mfa->call_copyf_fo(p_stor, f.p_stor);
@ -788,8 +840,8 @@ struct Function<R(Args...)>: detail::FunctionBase<R, Args...> {
}
using AA = AllocatorRebind<A, Function>;
detail::FunctionManager const *mff
= &detail::get_default_fm<Function, AA>();
detail::FunctionManager const *mff =
&detail::get_default_fm<Function, AA>();
if (f.p_stor.manager == mff) {
detail::create_fm<Function, AA>(p_stor, AA(a));
mff->call_copyf_fo(p_stor, f.P_stor);
@ -801,7 +853,8 @@ struct Function<R(Args...)>: detail::FunctionBase<R, Args...> {
template<typename A, typename T, typename = EnableIf<
detail::IsValidFunctor<T, R(Args...)>
>> Function(AllocatorArg, A const &a, T f) {
>>
Function(AllocatorArg, A const &a, T f) {
if (func_is_null(f)) {
init_empty();
return;
@ -860,8 +913,7 @@ private:
using emptya = Allocator<emptyf>;
p_call = nullptr;
detail::create_fm<emptyf, emptya>(p_stor, emptya());
detail::FunctorDataManager<emptyf, emptya>::store_f(p_stor,
nullptr);
detail::FunctorDataManager<emptyf, emptya>::store_f(p_stor, nullptr);
}
template<typename T>
@ -922,9 +974,10 @@ namespace detail {
using Type = typename DcLambdaTypes<F>::Ptr;
};
template<typename F, bool = IsDefaultConstructible<F> &&
IsMoveConstructible<F>
> struct DcFuncTypeObj {
template<typename F, bool =
IsDefaultConstructible<F> && IsMoveConstructible<F>
>
struct DcFuncTypeObj {
using Type = typename DcFuncTypeObjBase<F>::Type;
};
@ -944,8 +997,8 @@ namespace detail {
};
}
template<typename F> using FunctionMakeDefaultConstructible
= typename detail::DcFuncType<F>::Type;
template<typename F>
using FunctionMakeDefaultConstructible = typename detail::DcFuncType<F>::Type;
} /* namespace ostd */

View File

@ -36,7 +36,8 @@ public:
namespace ostd {
template<typename T> using InitializerList = std::initializer_list<T>;
template<typename T>
using InitializerList = std::initializer_list<T>;
template<typename T>
PointerRange<T const> iter(std::initializer_list<T> init) {

View File

@ -26,15 +26,15 @@ namespace detail {
};
template<typename R>
static inline Size estimate_hrsize(const R &range,
EnableIf<IsFiniteRandomAccessRange<R>, bool> = true
static inline Size estimate_hrsize(
const R &range, EnableIf<IsFiniteRandomAccessRange<R>, bool> = true
) {
return range.size();
}
template<typename R>
static inline Size estimate_hrsize(const R &,
EnableIf<!IsFiniteRandomAccessRange<R>, bool> = true
static inline Size estimate_hrsize(
const R &, EnableIf<!IsFiniteRandomAccessRange<R>, bool> = true
) {
/* we have no idea how big the range actually is */
return 16;
@ -55,9 +55,13 @@ public:
HashRange(Chain *node): p_node(node) {}
template<typename U>
HashRange(const HashRange<U> &v, EnableIf<
IsSame<RemoveCv<T>, RemoveCv<U>> && IsConvertible<U *, T *>, bool
> = true): p_node(const_cast<Chain *>(v.p_node)) {}
HashRange(
const HashRange<U> &v, EnableIf<
IsSame<RemoveCv<T>, RemoveCv<U>> && IsConvertible<U *, T *>, bool
> = true
):
p_node(const_cast<Chain *>(v.p_node))
{}
HashRange &operator=(const HashRange &v) {
p_node = v.p_node;
@ -67,7 +71,9 @@ public:
bool empty() const { return !p_node; }
bool pop_front() {
if (!p_node) return false;
if (!p_node) {
return false;
}
p_node = p_node->next;
return true;
}
@ -93,10 +99,14 @@ public:
BucketRange(const BucketRange &v): p_node(v.p_node), p_end(v.p_end) {}
template<typename U>
BucketRange(const BucketRange<U> &v, EnableIf<
IsSame<RemoveCv<T>, RemoveCv<U>> && IsConvertible<U *, T *>, bool
> = true): p_node(const_cast<Chain *>(v.p_node)),
p_end(const_cast<Chain *>(v.p_end)) {}
BucketRange(
const BucketRange<U> &v, EnableIf<
IsSame<RemoveCv<T>, RemoveCv<U>> && IsConvertible<U *, T *>, bool
> = true
):
p_node(const_cast<Chain *>(v.p_node)),
p_end(const_cast<Chain *>(v.p_end))
{}
BucketRange &operator=(const BucketRange &v) {
p_node = v.p_node;
@ -107,7 +117,9 @@ public:
bool empty() const { return p_node == p_end; }
bool pop_front() {
if (p_node == p_end) return false;
if (p_node == p_end) {
return false;
}
p_node = p_node->next;
return true;
}
@ -131,8 +143,8 @@ namespace detail {
static constexpr Size ChunkLowerBound = 32;
static constexpr Size ChunkUpperBound = 128;
template<typename E, Size N> constexpr Size HashChainAlign
= (((sizeof(HashChain<E>[N]) + sizeof(void *)) % CacheLineSize) == 0)
template<typename E, Size N> constexpr Size HashChainAlign =
(((sizeof(HashChain<E>[N]) + sizeof(void *)) % CacheLineSize) == 0)
? N : HashChainAlign<E, N + 1>;
template<typename E>
@ -152,9 +164,11 @@ namespace detail {
template<Size N>
struct HashPad: HashChainPad<N, N % CacheLineSize == 0> {};
template<typename E, Size V = HashChainAlign<E, ChunkLowerBound>,
bool P = (V == ChunkUpperBound)
> struct HashChunk;
template<
typename E, Size V = HashChainAlign<E, ChunkLowerBound>,
bool P = (V == ChunkUpperBound)
>
struct HashChunk;
template<typename E, Size V>
struct HashChunk<E, V, false> {
@ -181,7 +195,8 @@ namespace detail {
typename C, /* equality check */
typename A, /* allocator */
bool Multihash
> struct Hashtable {
>
struct Hashtable {
private:
using Chain = HashChain<E>;
using Chunk = HashChunk<E>;
@ -220,12 +235,16 @@ private:
}
Chain *find(const K &key, Size &h) const {
if (!p_size) return nullptr;
if (!p_size) {
return nullptr;
}
h = bucket(key);
Chain **cp = p_data.first();
for (Chain *c = cp[h], *e = cp[h + 1]; c != e; c = c->next)
if (get_eq()(key, B::get_key(c->value)))
for (Chain *c = cp[h], *e = cp[h + 1]; c != e; c = c->next) {
if (get_eq()(key, B::get_key(c->value))) {
return c;
}
}
return nullptr;
}
@ -236,18 +255,28 @@ private:
if (it) {
c->prev = it->prev;
it->prev = c;
if (c->prev) c->prev->next = c;
if (c->prev) {
c->prev->next = c;
}
} else {
size_t nb = h;
while (nb && !cp[nb]) --nb;
while (nb && !cp[nb]) {
--nb;
}
Chain *prev = cp[nb];
while (prev && prev->next) prev = prev->next;
while (prev && prev->next) {
prev = prev->next;
}
c->prev = prev;
if (prev) prev->next = c;
if (prev) {
prev->next = c;
}
}
for (; it == cp[h]; --h) {
cp[h] = c;
if (!h) break;
if (!h) {
break;
}
}
return c;
}
@ -258,8 +287,9 @@ private:
allocator_construct(get_challoc(), chunk);
chunk->next = p_chunks;
p_chunks = chunk;
for (Size i = 0; i < (Chunk::num - 1); ++i)
for (Size i = 0; i < (Chunk::num - 1); ++i) {
chunk->chains[i].next = &chunk->chains[i + 1];
}
chunk->chains[Chunk::num - 1].next = p_unused;
p_unused = chunk->chains;
}
@ -282,10 +312,11 @@ private:
}
void rehash_ahead(Size n) {
if (!bucket_count())
if (!bucket_count()) {
reserve(n);
else if ((float(size() + n) / bucket_count()) > max_load_factor())
} else if ((float(size() + n) / bucket_count()) > max_load_factor()) {
rehash(Size((size() + 1) / max_load_factor()) * 2);
}
}
protected:
@ -299,7 +330,9 @@ protected:
T &access_or_insert(const K &key) {
Size h = 0;
Chain *c = find(key, h);
if (c) return B::get_data(c->value);
if (c) {
return B::get_data(c->value);
}
rehash_ahead(1);
return insert(bucket(key), key);
}
@ -307,7 +340,9 @@ protected:
T &access_or_insert(K &&key) {
Size h = 0;
Chain *c = find(key, h);
if (c) return B::get_data(c->value);
if (c) {
return B::get_data(c->value);
}
rehash_ahead(1);
return insert(bucket(key), move(key));
}
@ -315,7 +350,9 @@ protected:
T *access(const K &key) const {
Size h;
Chain *c = find(key, h);
if (c) return &B::get_data(c->value);
if (c) {
return &B::get_data(c->value);
}
return nullptr;
}
@ -323,8 +360,9 @@ protected:
void assign_range(R range) {
clear();
reserve_at_least(detail::estimate_hrsize(range));
for (; !range.empty(); range.pop_front())
for (; !range.empty(); range.pop_front()) {
emplace(range.front());
}
rehash_up();
}
@ -332,8 +370,9 @@ protected:
const E *beg = il.begin(), *end = il.end();
clear();
reserve_at_least(end - beg);
while (beg != end)
while (beg != end) {
emplace(*beg++);
}
}
const H &get_hash() const { return p_data.second().second().first(); }
@ -357,7 +396,9 @@ protected:
p_data(nullptr, FAPair(AllocPair(alloc, CoreAllocPair(alloc, alloc)),
FuncPair(hf, eqf))),
p_maxlf(1.0f) {
if (!size) return;
if (!size) {
return;
}
init_buckets();
}
@ -366,7 +407,9 @@ protected:
p_data(nullptr, FAPair(AllocPair(alloc, CoreAllocPair(alloc, alloc)),
FuncPair(ht.get_hash(), ht.get_eq()))),
p_maxlf(ht.p_maxlf) {
if (!p_size) return;
if (!p_size) {
return;
}
init_buckets();
Chain **och = ht.p_data.first();
for (Chain *oc = *och; oc; oc = oc->next) {
@ -418,16 +461,18 @@ protected:
clear();
if (AllocatorPropagateOnContainerCopyAssignment<A>) {
if ((get_cpalloc() != ht.get_cpalloc()) && p_size) {
allocator_deallocate(get_cpalloc(),
p_data.first(), p_size + 1);
allocator_deallocate(
get_cpalloc(), p_data.first(), p_size + 1
);
init_buckets();
}
get_alloc() = ht.get_alloc();
get_cpalloc() = ht.get_cpalloc();
get_challoc() = ht.get_challoc();
}
for (ConstRange range = ht.iter(); !range.empty(); range.pop_front())
for (ConstRange range = ht.iter(); !range.empty(); range.pop_front()) {
emplace(range.front());
}
return *this;
}
@ -439,19 +484,24 @@ protected:
swap_adl(p_unused, ht.p_unused);
swap_adl(p_data.first(), ht.p_data.first());
swap_adl(p_data.second().second(), ht.p_data.second().second());
if (AllocatorPropagateOnContainerMoveAssignment<A>)
if (AllocatorPropagateOnContainerMoveAssignment<A>) {
swap_adl(p_data.second().first(), ht.p_data.second().first());
}
return *this;
}
void rehash_up() {
if (load_factor() <= max_load_factor()) return;
if (load_factor() <= max_load_factor()) {
return;
}
rehash(Size(size() / max_load_factor()) * 2);
}
void reserve_at_least(Size count) {
Size nc = Size(ceil(count / max_load_factor()));
if (p_size > nc) return;
if (p_size > nc) {
return;
}
rehash(nc);
}
@ -462,14 +512,16 @@ protected:
swap_adl(p_unused, ht.p_unused);
swap_adl(p_data.first(), ht.p_data.first());
swap_adl(p_data.second().second(), ht.p_data.second().second());
if (AllocatorPropagateOnContainerSwap<A>)
if (AllocatorPropagateOnContainerSwap<A>) {
swap_adl(p_data.second().first(), ht.p_data.second().first());
}
}
public:
~Hashtable() {
if (p_size) allocator_deallocate(get_cpalloc(),
p_data.first(), p_size + 1);
if (p_size) {
allocator_deallocate(get_cpalloc(), p_data.first(), p_size + 1);
}
delete_chunks(p_chunks);
}
@ -478,7 +530,9 @@ public:
}
void clear() {
if (!p_len) return;
if (!p_len) {
return;
}
clear_buckets();
p_len = 0;
p_unused = nullptr;
@ -498,10 +552,13 @@ public:
Size bucket_size(Size n) const {
Size ret = 0;
if (n >= p_size) return ret;
if (n >= p_size) {
return ret;
}
Chain **cp = p_data.first();
for (Chain *c = cp[n], *e = cp[n + 1]; c != e; c = c->next)
for (Chain *c = cp[n], *e = cp[n + 1]; c != e; c = c->next) {
++ret;
}
return ret;
}
@ -540,26 +597,38 @@ public:
Size erase(const K &key) {
Size h = 0;
Chain *c = find(key, h);
if (!c) return 0;
if (!c) {
return 0;
}
Chain **cp = p_data.first();
Size olen = p_len;
for (Chain *e = cp[h + 1]; c != e; c = c->next) {
if (!get_eq()(key, B::get_key(c->value))) break;
if (!get_eq()(key, B::get_key(c->value))) {
break;
}
--p_len;
Size hh = h;
Chain *next = c->next;
for (; cp[hh] == c; --hh) {
cp[hh] = next;
if (!hh) break;
if (!hh) {
break;
}
}
if (c->prev) {
c->prev->next = next;
}
if (next) {
next->prev = c->prev;
}
if (c->prev) c->prev->next = next;
if (next) next->prev = c->prev;
c->next = p_unused;
c->prev = nullptr;
p_unused = c;
allocator_destroy(get_alloc(), &c->value);
allocator_construct(get_alloc(), &c->value);
if (!Multihash) return 1;
if (!Multihash) {
return 1;
}
}
return olen - p_len;
}
@ -567,11 +636,18 @@ public:
Size count(const K &key) {
Size h = 0;
Chain *c = find(key, h);
if (!c) return 0;
if (!c) {
return 0;
}
Size ret = 1;
if (!Multihash) return ret;
for (c = c->next; c; c = c->next)
if (get_eq()(key, B::get_key(c->value))) ++ret;
if (!Multihash) {
return ret;
}
for (c = c->next; c; c = c->next) {
if (get_eq()(key, B::get_key(c->value))) {
++ret;
}
}
return ret;
}
@ -582,7 +658,9 @@ public:
ConstRange find(const K &key) const {
Size h = 0;
return ConstRange(reinterpret_cast<detail::HashChain<const E> *>(find(key, h)));
return ConstRange(reinterpret_cast<detail::HashChain<const E> *>(
find(key, h)
));
}
float load_factor() const { return float(p_len) / p_size; }
@ -591,7 +669,9 @@ public:
void rehash(Size count) {
Size fbcount = Size(p_len / max_load_factor());
if (fbcount > count) count = fbcount;
if (fbcount > count) {
count = fbcount;
}
Chain **och = p_data.first();
Size osize = p_size;
@ -608,8 +688,9 @@ public:
p = pp;
}
if (och && osize) allocator_deallocate(get_cpalloc(),
och, osize + 1);
if (och && osize) {
allocator_deallocate(get_cpalloc(), och, osize + 1);
}
}
void reserve(Size count) {
@ -617,35 +698,51 @@ public:
}
Range iter() {
if (!p_len) return Range();
if (!p_len) {
return Range();
}
return Range(*p_data.first());
}
ConstRange iter() const {
using Chain = detail::HashChain<const E>;
if (!p_len) return ConstRange();
if (!p_len) {
return ConstRange();
}
return ConstRange(reinterpret_cast<Chain *>(*p_data.first()));
}
ConstRange citer() const {
using Chain = detail::HashChain<const E>;
if (!p_len) return ConstRange();
if (!p_len) {
return ConstRange();
}
return ConstRange(reinterpret_cast<Chain *>(*p_data.first()));
}
LocalRange iter(Size n) {
if (n >= p_size) return LocalRange();
if (n >= p_size) {
return LocalRange();
}
return LocalRange(p_data.first()[n], p_data.first()[n + 1]);
}
ConstLocalRange iter(Size n) const {
using Chain = detail::HashChain<const E>;
if (n >= p_size) return ConstLocalRange();
return ConstLocalRange(reinterpret_cast<Chain *>(p_data.first()[n]),
reinterpret_cast<Chain *>(p_data.first()[n + 1]));
if (n >= p_size) {
return ConstLocalRange();
}
return ConstLocalRange(
reinterpret_cast<Chain *>(p_data.first()[n]),
reinterpret_cast<Chain *>(p_data.first()[n + 1])
);
}
ConstLocalRange citer(Size n) const {
using Chain = detail::HashChain<const E>;
if (n >= p_size) return ConstLocalRange();
return ConstLocalRange(reinterpret_cast<Chain *>(p_data.first()[n]),
reinterpret_cast<Chain *>(p_data.first()[n + 1]));
if (n >= p_size) {
return ConstLocalRange();
}
return ConstLocalRange(
reinterpret_cast<Chain *>(p_data.first()[n]),
reinterpret_cast<Chain *>(p_data.first()[n + 1])
);
}
};
} /* namespace detail */

View File

@ -92,7 +92,9 @@ struct UniqueLock {
UniqueLock(MutexType &m, AdoptLock): p_mtx(&m), p_owns(true) {}
~UniqueLock() {
if (p_owns) p_mtx->unlock();
if (p_owns) {
p_mtx->unlock();
}
}
UniqueLock(const UniqueLock &) = delete;
@ -104,7 +106,9 @@ struct UniqueLock {
}
UniqueLock &operator=(UniqueLock &&u) {
if (p_owns) p_mtx->unlock();
if (p_owns) {
p_mtx->unlock();
}
p_mtx = u.p_mtx;
p_owns = u.p_owns;
u.p_mtx = nullptr;
@ -113,24 +117,27 @@ struct UniqueLock {
}
bool lock() {
if (!p_mtx || p_owns) return false;
bool ret = p_mtx->lock();
if (ret) p_owns = true;
return ret;
if (!p_mtx || p_owns) {
return false;
}
return (p_owns = p_mtx->lock());
}
int try_lock() {
if (!p_mtx || p_owns) return 1;
if (!p_mtx || p_owns) {
return 1;
}
int ret = p_mtx->try_lock();
if (ret) return ret;
p_owns = (ret == 0);
return ret;
}
bool unlock() {
if (!p_mtx || p_owns) return false;
if (!p_mtx || !p_owns) {
return false;
}
bool ret = p_mtx->unlock();
if (ret) p_owns = false;
p_owns = !ret;
return ret;
}
@ -176,8 +183,9 @@ struct Condition {
}
bool wait(UniqueLock<Mutex> &l) {
if (!l.owns_lock())
if (!l.owns_lock()) {
return false;
}
return !pthread_cond_wait(&p_cnd, l.mutex()->native_handle());
}

View File

@ -12,21 +12,29 @@
namespace ostd {
template<typename ...A> class Tuple;
template<typename T, typename U> struct Pair;
template<typename T, Size I> struct Array;
template<typename ...A>
class Tuple;
template<typename T, typename U>
struct Pair;
template<typename T, Size I>
struct Array;
/* tuple size */
template<typename T> constexpr Size TupleSize = detail::Undefined<T>();
template<typename T>
constexpr Size TupleSize = detail::Undefined<T>();
template<typename T> constexpr Size TupleSize<const T> = TupleSize<T>;
template<typename T> constexpr Size TupleSize<volatile T> = TupleSize<T>;
template<typename T> constexpr Size TupleSize<const volatile T> = TupleSize<T>;
template<typename T>
constexpr Size TupleSize<const T> = TupleSize<T>;
template<typename T>
constexpr Size TupleSize<volatile T> = TupleSize<T>;
template<typename T>
constexpr Size TupleSize<const volatile T> = TupleSize<T>;
/* tuple element */
template<Size I, typename T> struct TupleElementBase;
template<Size I, typename T>
struct TupleElementBase;
template<Size I, typename T>
struct TupleElementBase<I, const T> {
using Type = AddConst<typename TupleElementBase<I, T>::Type>;
@ -45,15 +53,20 @@ using TupleElement = typename TupleElementBase<I, T>::Type;
/* is tuple-like */
template<typename T> constexpr bool IsTupleLike = false;
template<typename T>
constexpr bool IsTupleLike = false;
template<typename T> constexpr bool IsTupleLike<const T> = IsTupleLike<T>;
template<typename T> constexpr bool IsTupleLike<volatile T> = IsTupleLike<T>;
template<typename T> constexpr bool IsTupleLike<const volatile T> = IsTupleLike<T>;
template<typename T>
constexpr bool IsTupleLike<const T> = IsTupleLike<T>;
template<typename T>
constexpr bool IsTupleLike<volatile T> = IsTupleLike<T>;
template<typename T>
constexpr bool IsTupleLike<const volatile T> = IsTupleLike<T>;
/* tuple specializations */
template<typename ...A> constexpr bool IsTupleLike<Tuple<A...>> = true;
template<typename ...A>
constexpr bool IsTupleLike<Tuple<A...>> = true;
template<Size I, typename ...A>
inline TupleElement<I, Tuple<A...>> &get(Tuple<A...> &);
@ -69,7 +82,8 @@ inline const TupleElement<I, Tuple<A...>> &&get(const Tuple<A...> &&);
/* pair specializations */
template<typename T, typename U> constexpr bool IsTupleLike<Pair<T, U>> = true;
template<typename T, typename U>
constexpr bool IsTupleLike<Pair<T, U>> = true;
template<Size I, typename T, typename U>
inline TupleElement<I, Pair<T, U>> &get(Pair<T, U> &);
@ -85,7 +99,8 @@ inline const TupleElement<I, Pair<T, U>> &&get(const Pair<T, U> &&);
/* array specializations */
template<typename T, Size I> constexpr bool IsTupleLike<Array<T, I>> = true;
template<typename T, Size I>
constexpr bool IsTupleLike<Array<T, I>> = true;
template<Size I, typename T, Size S>
inline T &get(Array<T, S> &);
@ -102,14 +117,16 @@ inline const T &&get(const Array<T, S> &&);
/* make tuple indices */
namespace detail {
template<Size ...> struct TupleIndices {};
template<Size ...>
struct TupleIndices {};
template<Size S, typename T, Size E> struct MakeTupleIndicesBase;
template<Size S, typename T, Size E>
struct MakeTupleIndicesBase;
template<Size S, Size ...I, Size E>
struct MakeTupleIndicesBase<S, TupleIndices<I...>, E> {
using Type = typename MakeTupleIndicesBase<S + 1,
TupleIndices<I..., S>, E>::Type;
using Type =
typename MakeTupleIndicesBase<S + 1, TupleIndices<I..., S>, E>::Type;
};
template<Size E, Size ...I>
@ -130,10 +147,12 @@ namespace detail {
/* tuple types */
namespace detail {
template<typename ...T> struct TupleTypes {};
template<typename ...T>
struct TupleTypes {};
}
template<Size I> struct TupleElementBase<I, detail::TupleTypes<>> {
template<Size I>
struct TupleElementBase<I, detail::TupleTypes<>> {
public:
static_assert(I == 0, "TupleElement index out of range");
static_assert(I != 0, "TupleElement index out of range");
@ -148,14 +167,15 @@ public:
template<Size I, typename H, typename ...T>
struct TupleElementBase<I, detail::TupleTypes<H, T...>> {
public:
using Type = typename TupleElementBase<I - 1,
detail::TupleTypes<T...>>::Type;
using Type =
typename TupleElementBase<I - 1, detail::TupleTypes<T...>>::Type;
};
template<typename ...T> constexpr Size TupleSize<detail::TupleTypes<T...>>
= sizeof...(T);
template<typename ...T>
constexpr Size TupleSize<detail::TupleTypes<T...>> = sizeof...(T);
template<typename ...T> constexpr bool IsTupleLike<detail::TupleTypes<T...>> = true;
template<typename ...T>
constexpr bool IsTupleLike<detail::TupleTypes<T...>> = true;
/* make tuple types */
@ -166,10 +186,17 @@ namespace detail {
template<typename ...TS, typename T, Size S, Size E>
struct MakeTupleTypesBase<TupleTypes<TS...>, T, S, E> {
using TR = RemoveReference<T>;
using Type = typename MakeTupleTypesBase<TupleTypes<TS...,
Conditional<IsLvalueReference<T>,
TupleElement<S, TR> &,
TupleElement<S, TR>>>, T, S + 1, E>::Type;
using Type = typename MakeTupleTypesBase<
TupleTypes<
TS...,
Conditional<
IsLvalueReference<T>,
TupleElement<S, TR> &,
TupleElement<S, TR>
>
>,
T, S + 1, E
>::Type;
};
template<typename ...TS, typename T, Size E>
@ -194,9 +221,11 @@ namespace detail {
constexpr bool TupleConvertibleBase = false;
template<typename T, typename ...TT, typename U, typename ...UU>
constexpr bool TupleConvertibleBase<TupleTypes<T, TT...>, TupleTypes<U, UU...>>
= IsConvertible<T, U> && TupleConvertibleBase<TupleTypes<TT...>,
TupleTypes<UU...>>;
constexpr bool TupleConvertibleBase<
TupleTypes<T, TT...>, TupleTypes<U, UU...>
> =
IsConvertible<T, U> &&
TupleConvertibleBase<TupleTypes<TT...>, TupleTypes<UU...>>;
template<>
constexpr bool TupleConvertibleBase<TupleTypes<>, TupleTypes<>> = true;
@ -205,17 +234,20 @@ namespace detail {
constexpr bool TupleConvertibleApply = false;
template<typename T, typename U>
constexpr bool TupleConvertibleApply<true, T, U>
= TupleConvertibleBase<MakeTupleTypes<T>, MakeTupleTypes<U>>;
constexpr bool TupleConvertibleApply<true, T, U> =
TupleConvertibleBase<MakeTupleTypes<T>, MakeTupleTypes<U>>;
template<typename T, typename U, bool = IsTupleLike<RemoveReference<T>>,
bool = IsTupleLike<U>>
template<
typename T, typename U, bool = IsTupleLike<RemoveReference<T>>,
bool = IsTupleLike<U>
>
constexpr bool TupleConvertible = false;
template<typename T, typename U>
constexpr bool TupleConvertible<T, U, true, true> = TupleConvertibleApply<
TupleSize<RemoveReference<T>> == TupleSize<U>, T, U
>;
constexpr bool TupleConvertible<T, U, true, true> =
TupleConvertibleApply<
TupleSize<RemoveReference<T>> == TupleSize<U>, T, U
>;
}
/* tuple constructible */
@ -225,9 +257,11 @@ namespace detail {
constexpr bool TupleConstructibleBase = false;
template<typename T, typename ...TT, typename U, typename ...UU>
constexpr bool TupleConstructibleBase<TupleTypes<T, TT...>, TupleTypes<U, UU...>>
= IsConstructible<U, T> && TupleConstructibleBase<TupleTypes<TT...>,
TupleTypes<UU...>>;
constexpr bool TupleConstructibleBase<
TupleTypes<T, TT...>, TupleTypes<U, UU...>
> =
IsConstructible<U, T> &&
TupleConstructibleBase<TupleTypes<TT...>, TupleTypes<UU...>>;
template<>
constexpr bool TupleConstructibleBase<TupleTypes<>, TupleTypes<>> = true;
@ -236,17 +270,20 @@ namespace detail {
constexpr bool TupleConstructibleApply = false;
template<typename T, typename U>
constexpr bool TupleConstructibleApply<true, T, U>
= TupleConstructibleBase<MakeTupleTypes<T>, MakeTupleTypes<U>>;
constexpr bool TupleConstructibleApply<true, T, U> =
TupleConstructibleBase<MakeTupleTypes<T>, MakeTupleTypes<U>>;
template<typename T, typename U, bool = IsTupleLike<RemoveReference<T>>,
bool = IsTupleLike<U>>
template<
typename T, typename U, bool = IsTupleLike<RemoveReference<T>>,
bool = IsTupleLike<U>
>
constexpr bool TupleConstructible = false;
template<typename T, typename U>
constexpr bool TupleConstructible<T, U, true, true> = TupleConstructibleApply<
TupleSize<RemoveReference<T>> == TupleSize<U>, T, U
>;
constexpr bool TupleConstructible<T, U, true, true> =
TupleConstructibleApply<
TupleSize<RemoveReference<T>> == TupleSize<U>, T, U
>;
}
/* tuple assignable */
@ -256,9 +293,11 @@ namespace detail {
constexpr bool TupleAssignableBase = false;
template<typename T, typename ...TT, typename U, typename ...UU>
constexpr bool TupleAssignableBase<TupleTypes<T, TT...>, TupleTypes<U, UU...>>
= IsAssignable<U &, T> && TupleAssignableBase<TupleTypes<TT...>,
TupleTypes<UU...>>;
constexpr bool TupleAssignableBase<
TupleTypes<T, TT...>, TupleTypes<U, UU...>
> =
IsAssignable<U &, T> &&
TupleAssignableBase<TupleTypes<TT...>, TupleTypes<UU...>>;
template<>
constexpr bool TupleAssignableBase<TupleTypes<>, TupleTypes<>> = true;
@ -267,17 +306,20 @@ namespace detail {
constexpr bool TupleAssignableApply = false;
template<typename T, typename U>
constexpr bool TupleAssignableApply<true, T, U>
= TupleAssignableBase<MakeTupleTypes<T>, MakeTupleTypes<U>>;
constexpr bool TupleAssignableApply<true, T, U> =
TupleAssignableBase<MakeTupleTypes<T>, MakeTupleTypes<U>>;
template<typename T, typename U, bool = IsTupleLike<RemoveReference<T>>,
bool = IsTupleLike<U>>
template<
typename T, typename U, bool = IsTupleLike<RemoveReference<T>>,
bool = IsTupleLike<U>
>
constexpr bool TupleAssignable = false;
template<typename T, typename U>
constexpr bool TupleAssignable<T, U, true, true> = TupleAssignableApply<
TupleSize<RemoveReference<T>> == TupleSize<U>, T, U
>;
constexpr bool TupleAssignable<T, U, true, true> =
TupleAssignableApply<
TupleSize<RemoveReference<T>> == TupleSize<U>, T, U
>;
}
} /* namespace ostd */

View File

@ -49,7 +49,9 @@ struct FileStream: Stream {
}
bool open(ConstCharRange path, StreamMode mode = StreamMode::read) {
if (p_f || (path.size() > FILENAME_MAX)) return false;
if (p_f || (path.size() > FILENAME_MAX)) {
return false;
}
char buf[FILENAME_MAX + 1];
memcpy(buf, &path[0], path.size());
buf[path.size()] = '\0';
@ -57,15 +59,18 @@ struct FileStream: Stream {
#ifndef OSTD_PLATFORM_WIN32
p_f = fopen(buf, detail::filemodes[Size(mode)]);
#else
if (fopen_s(&p_f, buf, detail::filemodes[Size(mode)]) != 0)
if (fopen_s(&p_f, buf, detail::filemodes[Size(mode)]) != 0) {
return false;
}
#endif
p_owned = !!p_f;
return is_open();
}
bool open(FILE *f) {
if (p_f) return false;
if (p_f) {
return false;
}
p_f = f;
p_owned = false;
return is_open();
@ -75,7 +80,9 @@ struct FileStream: Stream {
bool is_owned() const { return p_owned; }
void close() {
if (p_f && p_owned) fclose(p_f);
if (p_f && p_owned) {
fclose(p_f);
}
p_f = nullptr;
p_owned = false;
}
@ -144,9 +151,11 @@ namespace detail {
}
template<typename T>
inline void write_impl(T const &v, EnableIf<
!IsConstructible<ConstCharRange, T const &>, IoNat
> = IoNat()) {
inline void write_impl(
T const &v, EnableIf<
!IsConstructible<ConstCharRange, T const &>, IoNat
> = IoNat()
) {
write(ostd::to_string(v));
}
}
@ -178,10 +187,12 @@ inline void writeln(T const &v, A const &...args) {
template<typename ...A>
inline void writef(ConstCharRange fmt, A const &...args) {
char buf[512];
Ptrdiff need = format(detail::FormatOutRange<sizeof(buf)>(buf),
fmt, args...);
if (need < 0) return;
else if (Size(need) < sizeof(buf)) {
Ptrdiff need = format(
detail::FormatOutRange<sizeof(buf)>(buf), fmt, args...
);
if (need < 0) {
return;
} else if (Size(need) < sizeof(buf)) {
fwrite(buf, 1, need, stdout);
return;
}

View File

@ -40,7 +40,8 @@ namespace detail {
template<
typename T, typename H, typename C, typename A, bool IsMultihash
> struct KeysetImpl: detail::Hashtable<detail::KeysetBase<T, A>,
>
struct KeysetImpl: detail::Hashtable<detail::KeysetBase<T, A>,
T, KeysetKey<T>, T, H, C, A, IsMultihash
> {
private:
@ -65,20 +66,24 @@ namespace detail {
using ConstLocalRange = BucketRange<T const>;
using Allocator = A;
explicit KeysetImpl(Size size, H const &hf = H(),
C const &eqf = C(), A const &alloc = A()
explicit KeysetImpl(
Size size, H const &hf = H(), C const &eqf = C(),
A const &alloc = A()
): Base(size, hf, eqf, alloc) {}
KeysetImpl(): KeysetImpl(0) {}
explicit KeysetImpl(A const &alloc): KeysetImpl(0, H(), C(), alloc) {}
KeysetImpl(Size size, A const &alloc):
KeysetImpl(size, H(), C(), alloc) {}
KeysetImpl(size, H(), C(), alloc)
{}
KeysetImpl(Size size, H const &hf, A const &alloc):
KeysetImpl(size, hf, C(), alloc) {}
KeysetImpl(size, hf, C(), alloc)
{}
KeysetImpl(KeysetImpl const &m): Base(m,
allocator_container_copy(m.get_alloc())) {}
KeysetImpl(KeysetImpl const &m):
Base(m, allocator_container_copy(m.get_alloc())
{}
KeysetImpl(KeysetImpl const &m, A const &alloc): Base(m, alloc) {}
@ -87,33 +92,45 @@ namespace detail {
template<typename R, typename = EnableIf<
IsInputRange<R> && IsConvertible<RangeReference<R>, Value>
>> KeysetImpl(R range, Size size = 0, H const &hf = H(),
>>
KeysetImpl(
R range, Size size = 0, H const &hf = H(),
C const &eqf = C(), A const &alloc = A()
): Base(size ? size : detail::estimate_hrsize(range),
hf, eqf, alloc) {
for (; !range.empty(); range.pop_front())
):
Base(size ? size : detail::estimate_hrsize(range), hf, eqf, alloc)
{
for (; !range.empty(); range.pop_front()) {
Base::emplace(range.front());
}
Base::rehash_up();
}
template<typename R>
KeysetImpl(R range, Size size, A const &alloc)
: KeysetImpl(range, size, H(), C(), alloc) {}
KeysetImpl(R range, Size size, A const &alloc):
KeysetImpl(range, size, H(), C(), alloc)
{}
template<typename R>
KeysetImpl(R range, Size size, H const &hf, A const &alloc)
: KeysetImpl(range, size, hf, C(), alloc) {}
KeysetImpl(R range, Size size, H const &hf, A const &alloc):
KeysetImpl(range, size, hf, C(), alloc)
{}
KeysetImpl(InitializerList<Value> init, Size size = 0,
KeysetImpl(
InitializerList<Value> init, Size size = 0,
H const &hf = H(), C const &eqf = C(), A const &alloc = A()
): KeysetImpl(iter(init), size, hf, eqf, alloc) {}
):
KeysetImpl(iter(init), size, hf, eqf, alloc)
{}
KeysetImpl(InitializerList<Value> init, Size size, A const &alloc)
: KeysetImpl(iter(init), size, H(), C(), alloc) {}
KeysetImpl(InitializerList<Value> init, Size size, A const &alloc):
KeysetImpl(iter(init), size, H(), C(), alloc)
{}
KeysetImpl(InitializerList<Value> init, Size size, H const &hf,
A const &alloc
): KeysetImpl(iter(init), size, hf, C(), alloc) {}
KeysetImpl(
InitializerList<Value> init, Size size, H const &hf, A const &alloc
):
KeysetImpl(iter(init), size, hf, C(), alloc)
{}
KeysetImpl &operator=(KeysetImpl const &m) {
Base::operator=(m);
@ -127,7 +144,8 @@ namespace detail {
template<typename R, typename = EnableIf<
IsInputRange<R> && IsConvertible<RangeReference<R>, Value>
>> KeysetImpl &operator=(R range) {
>>
KeysetImpl &operator=(R range) {
Base::assign_range(range);
return *this;
}
@ -166,14 +184,16 @@ template<
typename H = ToHash<detail::KeysetKey<T>>,
typename C = EqualWithCstr<detail::KeysetKey<T>>,
typename A = Allocator<T>
> using Keyset = detail::KeysetImpl<T, H, C, A, false>;
>
using Keyset = detail::KeysetImpl<T, H, C, A, false>;
template<
typename T,
typename H = ToHash<detail::KeysetKey<T>>,
typename C = EqualWithCstr<detail::KeysetKey<T>>,
typename A = Allocator<T>
> using Multikeyset = detail::KeysetImpl<T, H, C, A, true>;
>
using Multikeyset = detail::KeysetImpl<T, H, C, A, true>;
} /* namespace ostd */

View File

@ -40,7 +40,8 @@ namespace detail {
template<
typename K, typename T, typename H,
typename C, typename A, bool IsMultihash
> struct MapImpl: detail::Hashtable<detail::MapBase<K, T, A>,
>
struct MapImpl: detail::Hashtable<detail::MapBase<K, T, A>,
Pair<K const, T>, K, T, H, C, A, IsMultihash
> {
private:
@ -65,20 +66,26 @@ namespace detail {
using ConstLocalRange = BucketRange<Pair<K const, T> const>;
using Allocator = A;
explicit MapImpl(Size size, H const &hf = H(),
explicit MapImpl(
Size size, H const &hf = H(),
C const &eqf = C(), A const &alloc = A()
): Base(size, hf, eqf, alloc) {}
):
Base(size, hf, eqf, alloc)
{}
MapImpl(): MapImpl(0) {}
explicit MapImpl(A const &alloc): MapImpl(0, H(), C(), alloc) {}
MapImpl(Size size, A const &alloc):
MapImpl(size, H(), C(), alloc) {}
MapImpl(size, H(), C(), alloc)
{}
MapImpl(Size size, H const &hf, A const &alloc):
MapImpl(size, hf, C(), alloc) {}
MapImpl(size, hf, C(), alloc)
{}
MapImpl(MapImpl const &m): Base(m,
allocator_container_copy(m.get_alloc())) {}
MapImpl(MapImpl const &m):
Base(m, allocator_container_copy(m.get_alloc()))
{}
MapImpl(MapImpl const &m, A const &alloc): Base(m, alloc) {}
@ -87,33 +94,45 @@ namespace detail {
template<typename R, typename = EnableIf<
IsInputRange<R> && IsConvertible<RangeReference<R>, Value>
>> MapImpl(R range, Size size = 0, H const &hf = H(),
>>
MapImpl(
R range, Size size = 0, H const &hf = H(),
C const &eqf = C(), A const &alloc = A()
): Base(size ? size : detail::estimate_hrsize(range),
hf, eqf, alloc) {
for (; !range.empty(); range.pop_front())
):
Base(size ? size : detail::estimate_hrsize(range), hf, eqf, alloc)
{
for (; !range.empty(); range.pop_front()) {
Base::emplace(range.front());
}
Base::rehash_up();
}
template<typename R>
MapImpl(R range, Size size, A const &alloc)
: MapImpl(range, size, H(), C(), alloc) {}
MapImpl(R range, Size size, A const &alloc):
MapImpl(range, size, H(), C(), alloc)
{}
template<typename R>
MapImpl(R range, Size size, H const &hf, A const &alloc)
: MapImpl(range, size, hf, C(), alloc) {}
MapImpl(R range, Size size, H const &hf, A const &alloc):
MapImpl(range, size, hf, C(), alloc)
{}
MapImpl(InitializerList<Value> init, Size size = 0,
MapImpl(
InitializerList<Value> init, Size size = 0,
H const &hf = H(), C const &eqf = C(), A const &alloc = A()
): MapImpl(iter(init), size, hf, eqf, alloc) {}
):
MapImpl(iter(init), size, hf, eqf, alloc)
{}
MapImpl(InitializerList<Value> init, Size size, A const &alloc)
: MapImpl(iter(init), size, H(), C(), alloc) {}
MapImpl(InitializerList<Value> init, Size size, A const &alloc):
MapImpl(iter(init), size, H(), C(), alloc)
{}
MapImpl(InitializerList<Value> init, Size size, H const &hf,
A const &alloc
): MapImpl(iter(init), size, hf, C(), alloc) {}
MapImpl(
InitializerList<Value> init, Size size, H const &hf, A const &alloc
):
MapImpl(iter(init), size, hf, C(), alloc)
{}
MapImpl &operator=(MapImpl const &m) {
Base::operator=(m);
@ -127,7 +146,8 @@ namespace detail {
template<typename R, typename = EnableIf<
IsInputRange<R> && IsConvertible<RangeReference<R>, Value>
>> MapImpl &operator=(R range) {
>>
MapImpl &operator=(R range) {
Base::assign_range(range);
return *this;
}
@ -166,14 +186,16 @@ template<
typename H = ToHash<K>,
typename C = EqualWithCstr<K>,
typename A = Allocator<Pair<K const, T>>
> using Map = detail::MapImpl<K, T, H, C, A, false>;
>
using Map = detail::MapImpl<K, T, H, C, A, false>;
template<
typename K, typename T,
typename H = ToHash<K>,
typename C = EqualWithCstr<K>,
typename A = Allocator<Pair<K const, T>>
> using Multimap = detail::MapImpl<K, T, H, C, A, true>;
>
using Multimap = detail::MapImpl<K, T, H, C, A, true>;
} /* namespace ostd */

View File

@ -37,22 +37,28 @@ namespace detail {
constexpr MaybeStorage(): p_null_state('\0') {}
MaybeStorage(MaybeStorage const &v): p_engaged(v.p_engaged) {
if (p_engaged) ::new(address_of(p_value)) Value(v.p_value);
if (p_engaged) {
::new(address_of(p_value)) Value(v.p_value);
}
}
MaybeStorage(MaybeStorage &&v): p_engaged(v.p_engaged) {
if (p_engaged)
if (p_engaged) {
::new(address_of(p_value)) Value(move(v.p_value));
}
}
constexpr MaybeStorage(Value const &v): p_value(v), p_engaged(true) {}
constexpr MaybeStorage(Value &&v): p_value(move(v)), p_engaged(true) {}
template<typename ...A> constexpr MaybeStorage(InPlace, A &&...args):
p_value(forward<A>(args)...), p_engaged(true) {}
p_value(forward<A>(args)...), p_engaged(true)
{}
~MaybeStorage() {
if (p_engaged) p_value.~Value();
if (p_engaged) {
p_value.~Value();
}
}
};
@ -69,21 +75,26 @@ namespace detail {
constexpr MaybeStorage(): p_null_state('\0') {}
MaybeStorage(MaybeStorage const &v): p_engaged(v.p_engaged) {
if (p_engaged) ::new(address_of(p_value)) Value(v.p_value);
if (p_engaged) {
::new(address_of(p_value)) Value(v.p_value);
}
}
MaybeStorage(MaybeStorage &&v): p_engaged(v.p_engaged) {
if (p_engaged)
if (p_engaged) {
::new(address_of(p_value)) Value(move(v.p_value));
}
}
constexpr MaybeStorage(Value const &v): p_value(v), p_engaged(true) {}
constexpr MaybeStorage(Value &&v):
p_value(move(v)), p_engaged(true) {}
p_value(move(v)), p_engaged(true)
{}
template<typename ...A>
constexpr MaybeStorage(InPlace, A &&...args):
p_value(forward<A>(args)...), p_engaged(true) {}
p_value(forward<A>(args)...), p_engaged(true)
{}
};
}
@ -93,16 +104,26 @@ class Maybe: private detail::MaybeStorage<T> {
public:
using Value = T;
static_assert(!IsReference<T>,
"Initialization of Maybe with a reference type is not allowed.");
static_assert(!IsSame<RemoveCv<T>, InPlace>,
"Initialization of Maybe with InPlace is not allowed.");
static_assert(!IsSame<RemoveCv<T>, Nothing>,
"Initialization of Maybe with Nothing is not allowed.");
static_assert(IsObject<T>,
"Initialization of Maybe with non-object type is not allowed.");
static_assert(IsDestructible<T>,
"Initialization of Maybe with a non-destructible object is not allowed.");
static_assert(
!IsReference<T>,
"Initialization of Maybe with a reference type is not allowed."
);
static_assert(
!IsSame<RemoveCv<T>, InPlace>,
"Initialization of Maybe with InPlace is not allowed."
);
static_assert(
!IsSame<RemoveCv<T>, Nothing>,
"Initialization of Maybe with Nothing is not allowed."
);
static_assert(
IsObject<T>,
"Initialization of Maybe with non-object type is not allowed."
);
static_assert(
IsDestructible<T>,
"Initialization of Maybe with a non-destructible object is not allowed."
);
constexpr Maybe() {}
Maybe(Maybe const &) = default;
@ -112,14 +133,16 @@ public:
constexpr Maybe(Value &&v): Base(move(v)) {}
template<typename ...A, typename = EnableIf<IsConstructible<T, A...>>>
constexpr explicit Maybe(InPlace, A &&...args): Base(in_place,
forward<A>(args)...) {}
constexpr explicit Maybe(InPlace, A &&...args):
Base(in_place, forward<A>(args)...)
{}
template<typename U, typename ...A, typename = EnableIf<
IsConstructible<T, std::initializer_list<U> &, A...>>>
constexpr explicit
Maybe(InPlace, std::initializer_list<U> il, A &&...args):
Base(in_place, il, forward<A>(args)...) {}
IsConstructible<T, std::initializer_list<U> &, A...>>
>
constexpr explicit Maybe(InPlace, std::initializer_list<U> il, A &&...args):
Base(in_place, il, forward<A>(args)...)
{}
~Maybe() = default;
@ -133,12 +156,15 @@ public:
Maybe &operator=(Maybe const &v) {
if (this->p_engaged == v.p_engaged) {
if (this->p_engaged) this->p_value = v.p_value;
if (this->p_engaged) {
this->p_value = v.p_value;
}
} else {
if (this->p_engaged)
if (this->p_engaged) {
this->p_value.~Value();
else
} else {
::new(address_of(this->p_value)) Value(v.p_value);
}
this->p_engaged = v.p_engaged;
}
return *this;
@ -146,11 +172,13 @@ public:
Maybe &operator=(Maybe &&v) {
if (this->p_engaged == v.p_engaged) {
if (this->p_engaged) this->p_value = move(v.p_value);
if (this->p_engaged) {
this->p_value = move(v.p_value);
}
} else {
if (this->p_engaged)
if (this->p_engaged) {
this->p_value.~Value();
else {
} else {
::new(address_of(this->p_value)) Value(move(v.p_value));
}
this->p_engaged = v.p_engaged;
@ -217,26 +245,35 @@ public:
template<typename U>
constexpr Value value_or(U &&v) const & {
static_assert(IsCopyConstructible<Value>,
"Maybe<T>::value_or: T must be copy constructible");
static_assert(IsConvertible<U, Value>,
"Maybe<T>::value_or: U must be convertible to T");
static_assert(
IsCopyConstructible<Value>,
"Maybe<T>::value_or: T must be copy constructible"
);
static_assert(
IsConvertible<U, Value>,
"Maybe<T>::value_or: U must be convertible to T"
);
return this->p_engaged ? this->p_value : Value(forward<U>(v));
}
template<typename U>
Value value_or(U &&v) && {
static_assert(IsMoveConstructible<Value>,
"Maybe<T>::value_or: T must be copy constructible");
static_assert(IsConvertible<U, Value>,
"Maybe<T>::value_or: U must be convertible to T");
return this->p_engaged ? move(this->p_value)
: Value(forward<U>(v));
static_assert(
IsMoveConstructible<Value>,
"Maybe<T>::value_or: T must be copy constructible"
);
static_assert(
IsConvertible<U, Value>,
"Maybe<T>::value_or: U must be convertible to T"
);
return this->p_engaged ? move(this->p_value) : Value(forward<U>(v));
}
void swap(Maybe &v) {
if (this->p_engaged == v.p_engaged) {
if (this->p_engaged) detail::swap_adl(this->p_value, v.p_value);
if (this->p_engaged) {
detail::swap_adl(this->p_value, v.p_value);
}
} else {
if (this->p_engaged) {
::new(address_of(v.p_value)) Value(move(this->p_value));

View File

@ -16,8 +16,9 @@ namespace ostd {
/* address of */
template<typename T> constexpr T *address_of(T &v) {
return reinterpret_cast<T *>(&const_cast<char &>
(reinterpret_cast<char const volatile &>(v)));
return reinterpret_cast<T *>(
&const_cast<char &>(reinterpret_cast<char const volatile &>(v))
);
}
/* pointer traits */
@ -25,8 +26,10 @@ template<typename T> constexpr T *address_of(T &v) {
namespace detail {
template<typename T>
struct HasElement {
template<typename U> static int test(...);
template<typename U> static char test(typename U::Element * = 0);
template<typename U>
static int test(...);
template<typename U>
static char test(typename U::Element * = 0);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
};
@ -34,7 +37,8 @@ namespace detail {
template<typename T, bool = HasElement<T>::value>
struct PointerElementBase;
template<typename T> struct PointerElementBase<T, true> {
template<typename T>
struct PointerElementBase<T, true> {
using Type = typename T::Element;
};
@ -60,8 +64,10 @@ namespace detail {
template<typename T>
struct HasDifference {
template<typename U> static int test(...);
template<typename U> static char test(typename U::Difference * = 0);
template<typename U>
static int test(...);
template<typename U>
static char test(typename U::Difference * = 0);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
};
@ -71,7 +77,8 @@ namespace detail {
using Type = Ptrdiff;
};
template<typename T> struct PointerDifferenceBase<T, true> {
template<typename T>
struct PointerDifferenceBase<T, true> {
using Type = typename T::Difference;
};
@ -87,9 +94,10 @@ namespace detail {
template<typename T, typename U>
struct HasRebind {
template<typename V> static int test(...);
template<typename V> static char test(
typename V::template Rebind<U> * = 0);
template<typename V>
static int test(...);
template<typename V>
static char test(typename V::template Rebind<U> * = 0);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
};
@ -99,14 +107,16 @@ namespace detail {
using Type = typename T::template Rebind<U>;
};
template<template<typename, typename...> class T, typename U,
template<
template<typename, typename...> class T, typename U,
typename ...A, typename V
>
struct PointerRebindBase<T<U, A...>, V, true> {
using Type = typename T<U, A...>::template Rebind<V>;
};
template<template<typename, typename...> class T, typename U,
template<
template<typename, typename...> class T, typename U,
typename ...A, typename V
>
struct PointerRebindBase<T<U, A...>, V, false> {
@ -153,9 +163,11 @@ namespace detail {
template<typename T>
struct PointerTo {
static T pointer_to(Conditional<IsVoid<PointerElement<T>>,
PointerToNat, PointerElement<T>
> &r) {
static T pointer_to(
Conditional<
IsVoid<PointerElement<T>>, PointerToNat, PointerElement<T>
> &r
) {
return T::pointer_to(r);
}
};
@ -169,9 +181,11 @@ namespace detail {
}
template<typename T>
static T pointer_to(Conditional<IsVoid<PointerElement<T>>,
detail::PointerToNat, PointerElement<T>
> &r) {
static T pointer_to(
Conditional<
IsVoid<PointerElement<T>>, detail::PointerToNat, PointerElement<T>
> &r
) {
return detail::PointerTo<T>::pointer_to(r);
}
@ -181,7 +195,8 @@ template<typename T>
struct DefaultDelete {
constexpr DefaultDelete() = default;
template<typename U> DefaultDelete(DefaultDelete<U> const &) {};
template<typename U>
DefaultDelete(DefaultDelete<U> const &) {};
void operator()(T *p) const {
delete p;
@ -192,12 +207,14 @@ template<typename T>
struct DefaultDelete<T[]> {
constexpr DefaultDelete() = default;
template<typename U> DefaultDelete(DefaultDelete<U[]> const &) {};
template<typename U>
DefaultDelete(DefaultDelete<U[]> const &) {};
void operator()(T *p) const {
delete[] p;
}
template<typename U> void operator()(U *) const = delete;
template<typename U>
void operator()(U *) const = delete;
};
/* box */
@ -208,18 +225,21 @@ namespace detail {
template<typename T>
static char ptr_test(typename T::Pointer * = 0);
template<typename T> constexpr bool HasPtr = sizeof(ptr_test<T>(0)) == 1;
template<typename T>
constexpr bool HasPtr = sizeof(ptr_test<T>(0)) == 1;
template<typename T, typename D, bool = HasPtr<D>>
struct PointerBase {
using Type = typename D::Pointer;
};
template<typename T, typename D> struct PointerBase<T, D, false> {
template<typename T, typename D>
struct PointerBase<T, D, false> {
using Type = T *;
};
template<typename T, typename D> struct PointerType {
template<typename T, typename D>
struct PointerType {
using Type = typename PointerBase<T, RemoveReference<D>>::Type;
};
} /* namespace detail */
@ -249,20 +269,26 @@ public:
}
Box(Pointer p, Conditional<IsReference<D>, D, AddLvalueReference<D const>> d):
p_stor(p, d) {}
p_stor(p, d)
{}
Box(Pointer p, RemoveReference<D> &&d):
p_stor(p, move(d)) {
p_stor(p, move(d))
{
static_assert(!IsReference<D>, "rvalue deleter cannot be a ref");
}
Box(Box &&u): p_stor(u.release(), forward<D>(u.get_deleter())) {}
template<typename TT, typename DD>
Box(Box<TT, DD> &&u, EnableIf<!IsArray<TT>
&& IsConvertible<typename Box<TT, DD>::Pointer, Pointer>
&& IsConvertible<DD, D> && (!IsReference<D> || IsSame<D, DD>)
> = Nat()): p_stor(u.release(), forward<DD>(u.get_deleter())) {}
Box(
Box<TT, DD> &&u, EnableIf<
!IsArray<TT> &&
IsConvertible<typename Box<TT, DD>::Pointer, Pointer> &&
IsConvertible<DD, D> && (!IsReference<D> || IsSame<D, DD>),
Nat
> = Nat()
): p_stor(u.release(), forward<DD>(u.get_deleter())) {}
Box &operator=(Box &&u) {
reset(u.release());
@ -271,9 +297,10 @@ public:
}
template<typename TT, typename DD>
EnableIf<!IsArray<TT>
&& IsConvertible<typename Box<TT, DD>::Pointer, Pointer>
&& IsAssignable<D &, DD &&>,
EnableIf<
!IsArray<TT> &&
IsConvertible<typename Box<TT, DD>::Pointer, Pointer> &&
IsAssignable<D &, DD &&>,
Box &
> operator=(Box<TT, DD> &&u) {
reset(u.release());
@ -309,7 +336,9 @@ public:
void reset(Pointer p = nullptr) {
Pointer tmp = p_stor.first();
p_stor.first() = p;
if (tmp) p_stor.second()(tmp);
if (tmp) {
p_stor.second()(tmp);
}
}
void swap(Box &u) {
@ -324,14 +353,16 @@ namespace detail {
template<typename T, typename U, bool = IsSame<
RemoveCv<PointerElement<T>>,
RemoveCv<PointerElement<U>>
>> constexpr bool SameOrLessCvQualifiedBase = IsConvertible<T, U>;
>>
constexpr bool SameOrLessCvQualifiedBase = IsConvertible<T, U>;
template<typename T, typename U>
constexpr bool SameOrLessCvQualifiedBase<T, U, false> = false;
template<typename T, typename U, bool = IsPointer<T>
|| IsSame<T, U> || detail::HasElement<T>::value
> constexpr bool SameOrLessCvQualified = SameOrLessCvQualifiedBase<T, U>;
template<typename T, typename U, bool =
IsPointer<T> || IsSame<T, U> || detail::HasElement<T>::value
>
constexpr bool SameOrLessCvQualified = SameOrLessCvQualifiedBase<T, U>;
template<typename T, typename U>
constexpr bool SameOrLessCvQualified<T, U, false> = false;
@ -366,30 +397,39 @@ public:
template<typename U> Box(U p, Conditional<
IsReference<D>, D, AddLvalueReference<D const>
> d, EnableIf<detail::SameOrLessCvQualified<U, Pointer>, Nat> = Nat()):
p_stor(p, d) {}
p_stor(p, d)
{}
Box(Nullptr, Conditional<IsReference<D>, D, AddLvalueReference<D const>> d):
p_stor(nullptr, d) {}
p_stor(nullptr, d)
{}
template<typename U> Box(U p, RemoveReference<D> &&d,
EnableIf<detail::SameOrLessCvQualified<U, Pointer>, Nat> = Nat()):
p_stor(p, move(d)) {
p_stor(p, move(d))
{
static_assert(!IsReference<D>, "rvalue deleter cannot be a ref");
}
Box(Nullptr, RemoveReference<D> &&d):
p_stor(nullptr, move(d)) {
p_stor(nullptr, move(d))
{
static_assert(!IsReference<D>, "rvalue deleter cannot be a ref");
}
Box(Box &&u): p_stor(u.release(), forward<D>(u.get_deleter())) {}
template<typename TT, typename DD>
Box(Box<TT, DD> &&u, EnableIf<IsArray<TT>
&& detail::SameOrLessCvQualified<typename Box<TT, DD>::Pointer,
Pointer>
&& IsConvertible<DD, D> && (!IsReference<D> || IsSame<D, DD>)> = Nat()
): p_stor(u.release(), forward<DD>(u.get_deleter())) {}
Box(
Box<TT, DD> &&u, EnableIf<
IsArray<TT> &&
detail::SameOrLessCvQualified<typename Box<TT, DD>::Pointer,Pointer> &&
IsConvertible<DD, D> && (!IsReference<D> || IsSame<D, DD>),
Nat
> = Nat()
):
p_stor(u.release(), forward<DD>(u.get_deleter()))
{}
Box &operator=(Box &&u) {
reset(u.release());
@ -398,10 +438,10 @@ public:
}
template<typename TT, typename DD>
EnableIf<IsArray<TT>
&& detail::SameOrLessCvQualified<typename Box<TT, DD>::Pointer,
Pointer>
&& IsAssignable<D &, DD &&>,
EnableIf<
IsArray<TT> &&
detail::SameOrLessCvQualified<typename Box<TT, DD>::Pointer, Pointer> &&
IsAssignable<D &, DD &&>,
Box &
> operator=(Box<TT, DD> &&u) {
reset(u.release());
@ -435,18 +475,23 @@ public:
return p;
}
template<typename U> EnableIf<
template<typename U>
EnableIf<
detail::SameOrLessCvQualified<U, Pointer>, void
> reset(U p) {
Pointer tmp = p_stor.first();
p_stor.first() = p;
if (tmp) p_stor.second()(tmp);
if (tmp) {
p_stor.second()(tmp);
}
}
void reset(Nullptr) {
Pointer tmp = p_stor.first();
p_stor.first() = nullptr;
if (tmp) p_stor.second()(tmp);
if (tmp) {
p_stor.second()(tmp);
}
}
void reset() {
@ -462,15 +507,18 @@ private:
};
namespace detail {
template<typename T> struct BoxIf {
template<typename T>
struct BoxIf {
using BoxType = Box<T>;
};
template<typename T> struct BoxIf<T[]> {
template<typename T>
struct BoxIf<T[]> {
using BoxUnknownSize = Box<T[]>;
};
template<typename T, Size N> struct BoxIf<T[N]> {
template<typename T, Size N>
struct BoxIf<T[N]> {
using BoxKnownSize = void;
};
}
@ -490,25 +538,31 @@ typename detail::BoxIf<T>::BoxKnownSize make_box(A &&...args) = delete;
/* allocator */
template<typename> struct Allocator;
template<typename>
struct Allocator;
template<> struct Allocator<void> {
template<>
struct Allocator<void> {
using Value = void;
using Pointer = void *;
using ConstPointer = void const *;
template<typename U> using Rebind = Allocator<U>;
template<typename U>
using Rebind = Allocator<U>;
};
template<> struct Allocator<void const> {
template<>
struct Allocator<void const> {
using Value = void const;
using Pointer = void const *;
using ConstPointer = void const *;
template<typename U> using Rebind = Allocator<U>;
template<typename U>
using Rebind = Allocator<U>;
};
template<typename T> struct Allocator {
template<typename T>
struct Allocator {
using Size = ostd::Size;
using Difference = Ptrdiff;
using Value = T;
@ -517,10 +571,12 @@ template<typename T> struct Allocator {
using Pointer = T *;
using ConstPointer = T const *;
template<typename U> using Rebind = Allocator<U>;
template<typename U>
using Rebind = Allocator<U>;
Allocator() {}
template<typename U> Allocator(Allocator<U> const &) {}
template<typename U>
Allocator(Allocator<U> const &) {}
Pointer address(Reference v) const {
return address_of(v);
@ -545,7 +601,8 @@ template<typename T> struct Allocator {
void destroy(Pointer p) { p->~T(); }
};
template<typename T> struct Allocator<T const> {
template<typename T>
struct Allocator<T const> {
using Size = ostd::Size;
using Difference = Ptrdiff;
using Value = T const;
@ -554,10 +611,12 @@ template<typename T> struct Allocator<T const> {
using Pointer = T const *;
using ConstPointer = T const *;
template<typename U> using Rebind = Allocator<U>;
template<typename U>
using Rebind = Allocator<U>;
Allocator() {}
template<typename U> Allocator(Allocator<U> const &) {}
template<typename U>
Allocator(Allocator<U> const &) {}
ConstPointer address(ConstReference v) const {
return address_of(v);
@ -594,14 +653,14 @@ bool operator!=(Allocator<T> const &, Allocator<U> const &) {
namespace detail {
template<typename T>
struct ConstPtrTest {
template<typename U> static char test(
typename U::ConstPointer * = 0);
template<typename U> static int test(...);
template<typename U>
static char test(typename U::ConstPointer * = 0);
template<typename U>
static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
};
template<typename T, typename P, typename A,
bool = ConstPtrTest<A>::value>
template<typename T, typename P, typename A, bool = ConstPtrTest<A>::value>
struct ConstPointer {
using Type = typename A::ConstPointer;
};
@ -613,9 +672,10 @@ namespace detail {
template<typename T>
struct VoidPtrTest {
template<typename U> static char test(
typename U::VoidPointer * = 0);
template<typename U> static int test(...);
template<typename U>
static char test(typename U::VoidPointer * = 0);
template<typename U>
static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
};
@ -649,8 +709,10 @@ namespace detail {
template<typename T>
struct SizeTest {
template<typename U> static char test(typename U::Size * = 0);
template<typename U> static int test(...);
template<typename U>
static char test(typename U::Size * = 0);
template<typename U>
static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
};
@ -698,8 +760,10 @@ using AllocatorConstVoidPointer = typename detail::ConstVoidPointer<
namespace detail {
template<typename T>
struct DiffTest {
template<typename U> static char test(typename U::Difference * = 0);
template<typename U> static int test(...);
template<typename U>
static char test(typename U::Difference * = 0);
template<typename U>
static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
};
@ -734,14 +798,16 @@ namespace detail {
using Type = typename T::template Rebind<U>;
};
template<template<typename, typename...> class A, typename T,
template<
template<typename, typename...> class A, typename T,
typename ...Args, typename U
>
struct AllocTraitsRebindType<A<T, Args...>, U, true> {
using Type = typename A<T, Args...>::template Rebind<U>;
};
template<template<typename, typename...> class A, typename T,
template<
template<typename, typename...> class A, typename T,
typename ...Args, typename U
>
struct AllocTraitsRebindType<A<T, Args...>, U, false> {
@ -759,57 +825,62 @@ using AllocatorRebind = typename detail::AllocTraitsRebindType<
namespace detail {
template<typename T>
struct PropagateOnContainerCopyAssignmentTest {
template<typename U> static char test(
decltype(U::PropagateOnContainerCopyAssignment) * = 0);
template<typename U> static int test(...);
template<typename U>
static char test(decltype(U::PropagateOnContainerCopyAssignment) * = 0);
template<typename U>
static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
};
template<typename A, bool = PropagateOnContainerCopyAssignmentTest<
A
>::value> constexpr bool PropagateOnContainerCopyAssignmentBase = false;
template<typename A, bool =
PropagateOnContainerCopyAssignmentTest<A>::value
>
constexpr bool PropagateOnContainerCopyAssignmentBase = false;
template<typename A>
constexpr bool PropagateOnContainerCopyAssignmentBase<A, true>
= A::PropagateOnContainerCopyAssignment;
constexpr bool PropagateOnContainerCopyAssignmentBase<A, true> =
A::PropagateOnContainerCopyAssignment;
} /* namespace detail */
template<typename A>
constexpr bool AllocatorPropagateOnContainerCopyAssignment
= detail::PropagateOnContainerCopyAssignmentBase<A>;
constexpr bool AllocatorPropagateOnContainerCopyAssignment =
detail::PropagateOnContainerCopyAssignmentBase<A>;
/* allocator propagate on container move assignment */
namespace detail {
template<typename T>
struct PropagateOnContainerMoveAssignmentTest {
template<typename U> static char test(
decltype(U::PropagateOnContainerMoveAssignment) * = 0);
template<typename U> static int test(...);
template<typename U>
static char test(decltype(U::PropagateOnContainerMoveAssignment) * = 0);
template<typename U>
static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
};
template<typename A, bool = PropagateOnContainerMoveAssignmentTest<
A
>::value> constexpr bool PropagateOnContainerMoveAssignmentBase = false;
template<typename A, bool =
PropagateOnContainerMoveAssignmentTest<A>::value
>
constexpr bool PropagateOnContainerMoveAssignmentBase = false;
template<typename A>
constexpr bool PropagateOnContainerMoveAssignmentBase<A, true>
= A::PropagateOnContainerMoveAssignment;
constexpr bool PropagateOnContainerMoveAssignmentBase<A, true> =
A::PropagateOnContainerMoveAssignment;
} /* namespace detail */
template<typename A>
constexpr bool AllocatorPropagateOnContainerMoveAssignment
= detail::PropagateOnContainerMoveAssignmentBase<A>;
constexpr bool AllocatorPropagateOnContainerMoveAssignment =
detail::PropagateOnContainerMoveAssignmentBase<A>;
/* allocator propagate on container swap */
namespace detail {
template<typename T>
struct PropagateOnContainerSwapTest {
template<typename U> static char test(
decltype(U::PropagateOnContainerSwap) * = 0);
template<typename U> static int test(...);
template<typename U>
static char test(decltype(U::PropagateOnContainerSwap) * = 0);
template<typename U>
static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
};
@ -817,21 +888,23 @@ namespace detail {
constexpr bool PropagateOnContainerSwapBase = false;
template<typename A>
constexpr bool PropagateOnContainerSwapBase<A, true>
= A::PropagateOnContainerSwap;
constexpr bool PropagateOnContainerSwapBase<A, true> =
A::PropagateOnContainerSwap;
} /* namespace detail */
template<typename A>
constexpr bool AllocatorPropagateOnContainerSwap
= detail::PropagateOnContainerSwapBase<A>;
constexpr bool AllocatorPropagateOnContainerSwap =
detail::PropagateOnContainerSwapBase<A>;
/* allocator is always equal */
namespace detail {
template<typename T>
struct IsAlwaysEqualTest {
template<typename U> static char test(decltype(U::IsAlwaysEqual) * = 0);
template<typename U> static int test(...);
template<typename U>
static char test(decltype(U::IsAlwaysEqual) * = 0);
template<typename U>
static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
};
@ -848,56 +921,58 @@ constexpr bool AllocatorIsAlwaysEqual = detail::IsAlwaysEqualBase<A>;
/* allocator allocate */
template<typename A>
inline AllocatorPointer<A>
allocator_allocate(A &a, AllocatorSize<A> n) {
inline AllocatorPointer<A> allocator_allocate(A &a, AllocatorSize<A> n) {
return a.allocate(n);
}
namespace detail {
template<typename A, typename S, typename CVP>
auto allocate_hint_test(A &&a, S &&sz, CVP &&p)
-> decltype(a.allocate(sz, p), True());
auto allocate_hint_test(A &&a, S &&sz, CVP &&p) ->
decltype(a.allocate(sz, p), True());
template<typename A, typename S, typename CVP>
auto allocate_hint_test(A const &, S &&, CVP &&)
-> False;
auto allocate_hint_test(A const &, S &&, CVP &&) -> False;
template<typename A, typename S, typename CVP>
constexpr bool AllocateHintTest
= IsSame<decltype(allocate_hint_test(declval<A>(),
declval<S>(),
declval<CVP>())), True
constexpr bool AllocateHintTest =
IsSame<
decltype(allocate_hint_test(
declval<A>(), declval<S>(), declval<CVP>()
)), True
>;
template<typename A>
inline AllocatorPointer<A> allocate(A &a, AllocatorSize<A> n,
AllocatorConstVoidPointer<A> h,
True) {
inline AllocatorPointer<A> allocate(
A &a, AllocatorSize<A> n, AllocatorConstVoidPointer<A> h, True
) {
return a.allocate(n, h);
}
template<typename A>
inline AllocatorPointer<A> allocate(A &a, AllocatorSize<A> n,
AllocatorConstVoidPointer<A>,
False) {
inline AllocatorPointer<A> allocate(
A &a, AllocatorSize<A> n, AllocatorConstVoidPointer<A>, False
) {
return a.allocate(n);
}
} /* namespace detail */
template<typename A>
inline AllocatorPointer<A>
allocator_allocate(A &a, AllocatorSize<A> n,
AllocatorConstVoidPointer<A> h) {
return detail::allocate(a, n, h, BoolConstant<detail::AllocateHintTest<
inline AllocatorPointer<A> allocator_allocate(
A &a, AllocatorSize<A> n, AllocatorConstVoidPointer<A> h
) {
return detail::allocate(
a, n, h, BoolConstant<detail::AllocateHintTest<
A, AllocatorSize<A>, AllocatorConstVoidPointer<A>
>>());
>>()
);
}
/* allocator deallocate */
template<typename A>
inline void allocator_deallocate(A &a, AllocatorPointer<A> p,
AllocatorSize<A> n) {
inline void allocator_deallocate(
A &a, AllocatorPointer<A> p, AllocatorSize<A> n
) {
a.deallocate(p, n);
}
@ -905,19 +980,18 @@ inline void allocator_deallocate(A &a, AllocatorPointer<A> p,
namespace detail {
template<typename A, typename T, typename ...Args>
auto construct_test(A &&a, T *p, Args &&...args)
-> decltype(a.construct(p, forward<Args>(args)...),
True());
auto construct_test(A &&a, T *p, Args &&...args) ->
decltype(a.construct(p, forward<Args>(args)...), True());
template<typename A, typename T, typename ...Args>
auto construct_test(A const &, T *, Args &&...)
-> False;
auto construct_test(A const &, T *, Args &&...) -> False;
template<typename A, typename T, typename ...Args>
constexpr bool ConstructTest
= IsSame<decltype(construct_test(declval<A>(),
declval<T>(),
declval<Args>()...)), True
constexpr bool ConstructTest =
IsSame<
decltype(construct_test(
declval<A>(), declval<T>(), declval<Args>()...
)), True
>;
template<typename A, typename T, typename ...Args>
@ -933,8 +1007,10 @@ namespace detail {
template<typename A, typename T, typename ...Args>
inline void allocator_construct(A &a, T *p, Args &&...args) {
detail::construct(BoolConstant<detail::ConstructTest<A, T *, Args...>>(),
a, p, forward<Args>(args)...);
detail::construct(
BoolConstant<detail::ConstructTest<A, T *, Args...>>(),
a, p, forward<Args>(args)...
);
}
/* allocator destroy */
@ -947,8 +1023,8 @@ namespace detail {
auto destroy_test(A const &, P &&) -> False;
template<typename A, typename P>
constexpr bool DestroyTest
= IsSame<decltype(destroy_test(declval<A>(), declval<P>())), True>;
constexpr bool DestroyTest =
IsSame<decltype(destroy_test(declval<A>(), declval<P>())), True>;
template<typename A, typename T>
inline void destroy(True, A &a, T *p) {
@ -976,8 +1052,8 @@ namespace detail {
auto alloc_max_size_test(A const &) -> False;
template<typename A>
constexpr bool AllocMaxSizeTest
= IsSame<decltype(alloc_max_size_test(declval<A &>())), True>;
constexpr bool AllocMaxSizeTest =
IsSame<decltype(alloc_max_size_test(declval<A &>())), True>;
template<typename A>
inline AllocatorSize<A> alloc_max_size(True, A const &a) {
@ -992,9 +1068,9 @@ namespace detail {
template<typename A>
inline AllocatorSize<A> allocator_max_size(A const &a) {
return detail::alloc_max_size(BoolConstant<
detail::AllocMaxSizeTest<A const>
>(), a);
return detail::alloc_max_size(
BoolConstant<detail::AllocMaxSizeTest<A const>>(), a
);
}
/* allocator container copy */
@ -1007,8 +1083,8 @@ namespace detail {
auto alloc_copy_test(A const &) -> False;
template<typename A>
constexpr bool AllocCopyTest
= IsSame<decltype(alloc_copy_test(declval<A &>())), True>;
constexpr bool AllocCopyTest =
IsSame<decltype(alloc_copy_test(declval<A &>())), True>;
template<typename A>
inline AllocatorType<A> alloc_container_copy(True, A const &a) {
@ -1023,9 +1099,9 @@ namespace detail {
template<typename A>
inline AllocatorType<A> allocator_container_copy(A const &a) {
return detail::alloc_container_copy(BoolConstant<
detail::AllocCopyTest<A const>
>(), a);
return detail::alloc_container_copy(
BoolConstant<detail::AllocCopyTest<A const>>(), a
);
}
/* allocator arg */
@ -1037,9 +1113,12 @@ constexpr AllocatorArg allocator_arg = AllocatorArg();
/* uses allocator */
namespace detail {
template<typename T> struct HasAllocatorType {
template<typename U> static char test(typename U::Allocator *);
template<typename U> static int test(...);
template<typename T>
struct HasAllocatorType {
template<typename U>
static char test(typename U::Allocator *);
template<typename U>
static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == 1);
};
@ -1067,8 +1146,8 @@ namespace detail {
}
template<typename T, typename A, typename ...Args>
constexpr int UsesAllocatorConstructor
= detail::UsesAllocCtor<T, A, Args...>::value;
constexpr int UsesAllocatorConstructor =
detail::UsesAllocCtor<T, A, Args...>::value;
} /* namespace ostd */

View File

@ -136,7 +136,9 @@ inline uint32_t endian_swap32(uint32_t x) {
return (x << 24) | (x >> 24) | ((x >> 8) & 0xFF00) | ((x << 8) & 0xFF0000);
}
inline uint64_t endian_swap64(uint64_t x) {
return endian_swap32(uint32_t(x >> 32)) | (uint64_t(endian_swap32(uint32_t(x))) << 32);
return endian_swap32(
uint32_t(x >> 32)) | (uint64_t(endian_swap32(uint32_t(x))) << 32
);
}
#endif

View File

@ -25,14 +25,17 @@ struct RandomAccessRangeTag: BidirectionalRangeTag {};
struct FiniteRandomAccessRangeTag: RandomAccessRangeTag {};
struct ContiguousRangeTag: FiniteRandomAccessRangeTag {};
template<typename T> struct RangeHalf;
template<typename T>
struct RangeHalf;
#define OSTD_RANGE_TRAIT(Name) \
namespace detail { \
template<typename T> \
struct Range##Name##Test { \
template<typename U> static char test(RemoveReference<typename U::Name> *); \
template<typename U> static int test(...); \
template<typename U> \
static char test(RemoveReference<typename U::Name> *); \
template<typename U> \
static int test(...); \
static constexpr bool value = (sizeof(test<T>(0)) == sizeof(char)); \
}; \
template<typename T, bool = Range##Name##Test<T>::value> \
@ -54,24 +57,25 @@ OSTD_RANGE_TRAIT(Difference)
#undef OSTD_RANGE_TRAIT
namespace detail {
template<typename U> static char is_range_test(typename U::Category *,
typename U::Size *,
typename U::Difference *,
typename U::Value *,
RemoveReference<
typename U::Reference
> *);
template<typename U> static int is_range_test(...);
template<typename U>
static char is_range_test(
typename U::Category *, typename U::Size *,
typename U::Difference *, typename U::Value *,
RemoveReference<typename U::Reference> *
);
template<typename U>
static int is_range_test(...);
template<typename T> constexpr bool IsRangeTest
= (sizeof(is_range_test<T>(0, 0, 0, 0, 0)) == sizeof(char));
template<typename T> constexpr bool IsRangeTest =
(sizeof(is_range_test<T>(0, 0, 0, 0, 0)) == sizeof(char));
}
// is input range
namespace detail {
template<typename T> constexpr bool IsInputRangeCore
= IsConvertible<RangeCategory<T>, InputRangeTag>;
template<typename T>
constexpr bool IsInputRangeCore =
IsConvertible<RangeCategory<T>, InputRangeTag>;
template<typename T, bool = detail::IsRangeTest<T>>
constexpr bool IsInputRangeBase = false;
@ -86,8 +90,9 @@ constexpr bool IsInputRange = detail::IsInputRangeBase<T>;
// is forward range
namespace detail {
template<typename T> constexpr bool IsForwardRangeCore
= IsConvertible<RangeCategory<T>, ForwardRangeTag>;
template<typename T>
constexpr bool IsForwardRangeCore =
IsConvertible<RangeCategory<T>, ForwardRangeTag>;
template<typename T, bool = detail::IsRangeTest<T>>
constexpr bool IsForwardRangeBase = false;
@ -102,8 +107,9 @@ constexpr bool IsForwardRange = detail::IsForwardRangeBase<T>;
// is bidirectional range
namespace detail {
template<typename T> constexpr bool IsBidirectionalRangeCore
= IsConvertible<RangeCategory<T>, BidirectionalRangeTag>;
template<typename T>
constexpr bool IsBidirectionalRangeCore =
IsConvertible<RangeCategory<T>, BidirectionalRangeTag>;
template<typename T, bool = detail::IsRangeTest<T>>
constexpr bool IsBidirectionalRangeBase = false;
@ -113,14 +119,15 @@ namespace detail {
detail::IsBidirectionalRangeCore<T>;
}
template<typename T> constexpr bool IsBidirectionalRange
= detail::IsBidirectionalRangeBase<T>;
template<typename T> constexpr bool IsBidirectionalRange =
detail::IsBidirectionalRangeBase<T>;
// is random access range
namespace detail {
template<typename T> constexpr bool IsRandomAccessRangeCore
= IsConvertible<RangeCategory<T>, RandomAccessRangeTag>;
template<typename T>
constexpr bool IsRandomAccessRangeCore =
IsConvertible<RangeCategory<T>, RandomAccessRangeTag>;
template<typename T, bool = detail::IsRangeTest<T>>
constexpr bool IsRandomAccessRangeBase = false;
@ -130,14 +137,15 @@ namespace detail {
detail::IsRandomAccessRangeCore<T>;
}
template<typename T> constexpr bool IsRandomAccessRange
= detail::IsRandomAccessRangeBase<T>;
template<typename T> constexpr bool IsRandomAccessRange =
detail::IsRandomAccessRangeBase<T>;
// is finite random access range
namespace detail {
template<typename T> constexpr bool IsFiniteRandomAccessRangeCore
= IsConvertible<RangeCategory<T>, FiniteRandomAccessRangeTag>;
template<typename T>
constexpr bool IsFiniteRandomAccessRangeCore =
IsConvertible<RangeCategory<T>, FiniteRandomAccessRangeTag>;
template<typename T, bool = detail::IsRangeTest<T>>
constexpr bool IsFiniteRandomAccessRangeBase = false;
@ -147,19 +155,20 @@ namespace detail {
detail::IsFiniteRandomAccessRangeCore<T>;
}
template<typename T> constexpr bool IsFiniteRandomAccessRange
= detail::IsFiniteRandomAccessRangeBase<T>;
template<typename T> constexpr bool IsFiniteRandomAccessRange =
detail::IsFiniteRandomAccessRangeBase<T>;
// is infinite random access range
template<typename T> constexpr bool IsInfiniteRandomAccessRange
= IsRandomAccessRange<T> && !IsFiniteRandomAccessRange<T>;
template<typename T> constexpr bool IsInfiniteRandomAccessRange =
IsRandomAccessRange<T> && !IsFiniteRandomAccessRange<T>;
// is contiguous range
namespace detail {
template<typename T> constexpr bool IsContiguousRangeCore
= IsConvertible<RangeCategory<T>, ContiguousRangeTag>;
template<typename T>
constexpr bool IsContiguousRangeCore =
IsConvertible<RangeCategory<T>, ContiguousRangeTag>;
template<typename T, bool = detail::IsRangeTest<T>>
constexpr bool IsContiguousRangeBase = false;
@ -169,26 +178,32 @@ namespace detail {
detail::IsContiguousRangeCore<T>;
}
template<typename T> constexpr bool IsContiguousRange
= detail::IsContiguousRangeBase<T>;
template<typename T> constexpr bool IsContiguousRange =
detail::IsContiguousRangeBase<T>;
// is output range
namespace detail {
template<typename T, typename P>
struct OutputRangeTest {
template<typename U, bool (U::*)(P)> struct Test {};
template<typename U> static char test(Test<U, &U::put> *);
template<typename U> static int test(...);
template<typename U, bool (U::*)(P)>
struct Test {};
template<typename U>
static char test(Test<U, &U::put> *);
template<typename U>
static int test(...);
static constexpr bool value = (sizeof(test<T>(0)) == sizeof(char));
};
template<typename T> constexpr bool IsOutputRangeCore
= IsConvertible<RangeCategory<T>, OutputRangeTag> ||
(IsInputRange<T> &&
(detail::OutputRangeTest<T, RangeValue<T> const &>::value ||
detail::OutputRangeTest<T, RangeValue<T> &&>::value ||
detail::OutputRangeTest<T, RangeValue<T> >::value));
template<typename T>
constexpr bool IsOutputRangeCore =
IsConvertible<RangeCategory<T>, OutputRangeTag> || (
IsInputRange<T> && (
detail::OutputRangeTest<T, RangeValue<T> const &>::value ||
detail::OutputRangeTest<T, RangeValue<T> &&>::value ||
detail::OutputRangeTest<T, RangeValue<T> >::value
)
);
template<typename T, bool = detail::IsRangeTest<T>>
constexpr bool IsOutputRangeBase = false;
@ -204,13 +219,33 @@ namespace detail {
template<typename T>
struct RangeIterator {
RangeIterator(): p_range() {}
explicit RangeIterator(T const &range) {
RangeIterator(): p_range(), p_init(false) {}
explicit RangeIterator(T const &range): p_range(), p_init(true) {
::new(&get_ref()) T(range);
}
explicit RangeIterator(T &&range) {
explicit RangeIterator(T &&range): p_range(), p_init(true) {
::new(&get_ref()) T(move(range));
}
RangeIterator(const RangeIterator &v): p_range(), p_init(true) {
::new(&get_ref()) T(v.get_ref());
}
RangeIterator(RangeIterator &&v): p_range(), p_init(true) {
::new(&get_ref()) T(move(v.get_ref()));
}
RangeIterator &operator=(const RangeIterator &v) {
destroy();
::new(&get_ref()) T(v.get_ref());
p_init = true;
return *this;
}
RangeIterator &operator=(RangeIterator &&v) {
destroy();
swap(v);
return *this;
}
~RangeIterator() {
destroy();
}
RangeIterator &operator++() {
get_ref().pop_front();
return *this;
@ -219,16 +254,28 @@ namespace detail {
return get_ref().front();
}
bool operator!=(RangeIterator) const { return !get_ref().empty(); }
void swap(RangeIterator &v) {
detail::swap_adl(get_ref(). v.get_ref());
detail::swap_adl(p_init, v.p_init);
}
private:
T &get_ref() { return *reinterpret_cast<T *>(&p_range); }
T const &get_ref() const { return *reinterpret_cast<T const *>(&p_range); }
void destroy() {
if (p_init) {
get_ref().~T();
p_init = false;
}
}
AlignedStorage<sizeof(T), alignof(T)> p_range;
bool p_init;
};
}
// range half
template<typename T> struct HalfRange;
template<typename T>
struct HalfRange;
namespace detail {
template<typename R, bool = IsBidirectionalRange<typename R::Range>>
@ -239,11 +286,15 @@ namespace detail {
using Diff = RangeDifference<typename R::Range>;
static Diff add_n(R &half, Diff n) {
if (n < 0) return -half.prev_n(n);
if (n < 0) {
return -half.prev_n(n);
}
return half.next_n(n);
}
static Diff sub_n(R &half, Diff n) {
if (n < 0) return -half.next_n(n);
if (n < 0) {
return -half.next_n(n);
}
return half.prev_n(n);
}
};
@ -253,11 +304,15 @@ namespace detail {
using Diff = RangeDifference<typename R::Range>;
static Diff add_n(R &half, Diff n) {
if (n < 0) return 0;
if (n < 0) {
return 0;
}
return half.next_n(n);
}
static Diff sub_n(R &half, Diff n) {
if (n < 0) return 0;
if (n < 0) {
return 0;
}
return half.prev_n(n);
}
};
@ -393,44 +448,65 @@ inline RangeDifference<R> operator-(R const &lhs, R const &rhs) {
namespace detail {
template<typename R>
RangeSize<R> pop_front_n(R &range, RangeSize<R> n) {
for (RangeSize<R> i = 0; i < n; ++i)
if (!range.pop_front()) return i;
for (RangeSize<R> i = 0; i < n; ++i) {
if (!range.pop_front()) {
return i;
}
}
return n;
}
template<typename R>
RangeSize<R> pop_back_n(R &range, RangeSize<R> n) {
for (RangeSize<R> i = 0; i < n; ++i)
if (!range.pop_back()) return i;
for (RangeSize<R> i = 0; i < n; ++i) {
if (!range.pop_back()) {
return i;
}
}
return n;
}
template<typename R>
RangeSize<R> push_front_n(R &range, RangeSize<R> n) {
for (RangeSize<R> i = 0; i < n; ++i)
if (!range.push_front()) return i;
for (RangeSize<R> i = 0; i < n; ++i) {
if (!range.push_front()) {
return i;
}
}
return n;
}
template<typename R>
RangeSize<R> push_back_n(R &range, RangeSize<R> n) {
for (RangeSize<R> i = 0; i < n; ++i)
if (!range.push_back()) return i;
for (RangeSize<R> i = 0; i < n; ++i) {
if (!range.push_back()) {
return i;
}
}
return n;
}
}
template<typename> struct ReverseRange;
template<typename> struct MoveRange;
template<typename> struct EnumeratedRange;
template<typename> struct TakeRange;
template<typename> struct ChunksRange;
template<typename ...> struct JoinRange;
template<typename ...> struct ZipRange;
template<typename>
struct ReverseRange;
template<typename>
struct MoveRange;
template<typename>
struct EnumeratedRange;
template<typename>
struct TakeRange;
template<typename>
struct ChunksRange;
template<typename ...>
struct JoinRange;
template<typename ...>
struct ZipRange;
template<typename B, typename C, typename V, typename R = V &,
typename S = Size, typename D = Ptrdiff
> struct InputRange {
template<
typename B, typename C, typename V, typename R = V &,
typename S = Size, typename D = Ptrdiff
>
struct InputRange {
using Category = C;
using Size = S;
using Difference = D;
@ -510,8 +586,9 @@ template<typename B, typename C, typename V, typename R = V &,
B r(*static_cast<B const *>(this));
Size on = n;
for (; n && !r.empty(); --n) {
if (!orange.put(r.front()))
if (!orange.put(r.front())) {
break;
}
r.pop_front();
}
return (on - n);
@ -629,11 +706,14 @@ inline auto join(R &&range) {
template<typename R1, typename ...R>
inline auto join(R1 &&r1, R &&...rr) {
return [ranges = forward_as_tuple(forward<R1>(r1), forward<R>(rr)...)]
(auto &&obj) mutable {
return [
ranges = forward_as_tuple(forward<R1>(r1), forward<R>(rr)...)
] (auto &&obj) mutable {
using Index = detail::MakeTupleIndices<sizeof...(R) + 1>;
return detail::join_proxy(forward<decltype(obj )>(obj),
forward<decltype(ranges)>(ranges), Index());
return detail::join_proxy(
forward<decltype(obj)>(obj),
forward<decltype(ranges)>(ranges), Index()
);
};
}
@ -646,11 +726,14 @@ inline auto zip(R &&range) {
template<typename R1, typename ...R>
inline auto zip(R1 &&r1, R &&...rr) {
return [ranges = forward_as_tuple(forward<R1>(r1), forward<R>(rr)...)]
(auto &&obj) mutable {
return [
ranges = forward_as_tuple(forward<R1>(r1), forward<R>(rr)...)
] (auto &&obj) mutable {
using Index = detail::MakeTupleIndices<sizeof...(R) + 1>;
return detail::zip_proxy(forward<decltype(obj )>(obj),
forward<decltype(ranges)>(ranges), Index());
return detail::zip_proxy(
forward<decltype(obj)>(obj),
forward<decltype(ranges)>(ranges), Index()
);
};
}
@ -669,9 +752,11 @@ inline auto citer(T const &r) -> decltype(r.iter()) {
return r.iter();
}
template<typename B, typename V, typename R = V &,
typename S = Size, typename D = Ptrdiff
> struct OutputRange {
template<
typename B, typename V, typename R = V &,
typename S = Size, typename D = Ptrdiff
>
struct OutputRange {
using Category = OutputRangeTag;
using Size = S;
using Difference = D;
@ -700,14 +785,18 @@ private:
T p_end;
public:
HalfRange() = delete;
HalfRange(HalfRange const &range): p_beg(range.p_beg),
p_end(range.p_end) {}
HalfRange(HalfRange &&range): p_beg(move(range.p_beg)),
p_end(move(range.p_end)) {}
HalfRange(T const &beg, T const &end): p_beg(beg),
p_end(end) {}
HalfRange(T &&beg, T &&end): p_beg(move(beg)),
p_end(move(end)) {}
HalfRange(HalfRange const &range):
p_beg(range.p_beg), p_end(range.p_end)
{}
HalfRange(HalfRange &&range):
p_beg(move(range.p_beg)), p_end(move(range.p_end))
{}
HalfRange(T const &beg, T const &end):
p_beg(beg),p_end(end)
{}
HalfRange(T &&beg, T &&end):
p_beg(move(beg)), p_end(move(end))
{}
HalfRange &operator=(HalfRange const &range) {
p_beg = range.p_beg;
@ -724,14 +813,18 @@ public:
bool empty() const { return p_beg == p_end; }
bool pop_front() {
if (empty()) return false;
if (empty()) {
return false;
}
return p_beg.next();
}
bool push_front() {
return p_beg.prev();
}
bool pop_back() {
if (empty()) return false;
if (empty()) {
return false;
}
return p_end.prev();
}
bool push_back() {
@ -757,8 +850,7 @@ public:
RangeSize<Rtype> size() const { return p_end - p_beg; }
HalfRange<Rtype>
slice(RangeSize<Rtype> start, RangeSize<Rtype> end) const {
HalfRange<Rtype> slice(RangeSize<Rtype> start, RangeSize<Rtype> end) const {
return HalfRange<Rtype>(p_beg + start, p_beg + end);
}
@ -815,7 +907,7 @@ public:
Rsize size() const { return p_range.size(); }
bool equals_front(ReverseRange const &r) const {
return p_range.equals_back(r.p_range);
return p_range.equals_back(r.p_range);
}
bool equals_back(ReverseRange const &r) const {
return p_range.equals_front(r.p_range);
@ -931,10 +1023,12 @@ public:
template<typename T>
struct NumberRange: InputRange<NumberRange<T>, ForwardRangeTag, T, T> {
NumberRange() = delete;
NumberRange(NumberRange const &it): p_a(it.p_a), p_b(it.p_b),
p_step(it.p_step) {}
NumberRange(T a, T b, T step = T(1)): p_a(a), p_b(b),
p_step(step) {}
NumberRange(NumberRange const &it):
p_a(it.p_a), p_b(it.p_b), p_step(it.p_step)
{}
NumberRange(T a, T b, T step = T(1)):
p_a(a), p_b(b), p_step(step)
{}
NumberRange(T v): p_a(0), p_b(v), p_step(1) {}
bool empty() const { return p_a * p_step >= p_b * p_step; }
@ -988,7 +1082,9 @@ public:
bool empty() const { return p_beg == p_end; }
bool pop_front() {
if (p_beg == p_end) return false;
if (p_beg == p_end) {
return false;
}
++p_beg;
return true;
}
@ -1022,7 +1118,9 @@ public:
/* satisfy BidirectionalRange */
bool pop_back() {
if (p_end == p_beg) return false;
if (p_end == p_beg) {
return false;
}
--p_end;
return true;
}
@ -1065,39 +1163,50 @@ public:
/* satisfy OutputRange */
bool put(T const &v) {
if (empty()) return false;
if (empty()) {
return false;
}
*(p_beg++) = v;
return true;
}
bool put(T &&v) {
if (empty()) return false;
if (empty()) {
return false;
}
*(p_beg++) = move(v);
return true;
}
Size put_n(T const *p, Size n) {
Size ret = size();
if (n < ret) ret = n;
if (n < ret) {
ret = n;
}
if (IsPod<T>) {
memcpy(p_beg, p, ret * sizeof(T));
p_beg += ret;
return ret;
}
for (Size i = ret; i; --i)
for (Size i = ret; i; --i) {
*p_beg++ = *p++;
}
return ret;
}
template<typename R>
EnableIf<IsOutputRange<R>, Size> copy(R &&orange, Size n = -1) {
Size c = size();
if (n < c) c = n;
if (n < c) {
c = n;
}
return orange.put_n(p_beg, c);
}
Size copy(RemoveCv<T> *p, Size n = -1) {
Size c = size();
if (n < c) c = n;
if (n < c) {
c = n;
}
if (IsPod<T>) {
memcpy(p_beg, data(), c * sizeof(T));
return c;
@ -1163,10 +1272,12 @@ public:
EnumeratedRange(T const &range): p_range(range), p_index(0) {}
EnumeratedRange(EnumeratedRange const &it):
p_range(it.p_range), p_index(it.p_index) {}
p_range(it.p_range), p_index(it.p_index)
{}
EnumeratedRange(EnumeratedRange &&it):
p_range(move(it.p_range)), p_index(it.p_index) {}
p_range(move(it.p_range)), p_index(it.p_index)
{}
EnumeratedRange &operator=(EnumeratedRange const &v) {
p_range = v.p_range;
@ -1224,12 +1335,15 @@ private:
RangeSize<T> p_remaining;
public:
TakeRange() = delete;
TakeRange(T const &range, RangeSize<T> rem): p_range(range),
p_remaining(rem) {}
TakeRange(TakeRange const &it): p_range(it.p_range),
p_remaining(it.p_remaining) {}
TakeRange(TakeRange &&it): p_range(move(it.p_range)),
p_remaining(it.p_remaining) {}
TakeRange(T const &range, RangeSize<T> rem):
p_range(range), p_remaining(rem)
{}
TakeRange(TakeRange const &it):
p_range(it.p_range), p_remaining(it.p_remaining)
{}
TakeRange(TakeRange &&it):
p_range(move(it.p_range)), p_remaining(it.p_remaining)
{}
TakeRange &operator=(TakeRange const &v) {
p_range = v.p_range; p_remaining = v.p_remaining; return *this;
@ -1273,12 +1387,15 @@ private:
RangeSize<T> p_chunksize;
public:
ChunksRange() = delete;
ChunksRange(T const &range, RangeSize<T> chs): p_range(range),
p_chunksize(chs) {}
ChunksRange(ChunksRange const &it): p_range(it.p_range),
p_chunksize(it.p_chunksize) {}
ChunksRange(ChunksRange &&it): p_range(move(it.p_range)),
p_chunksize(it.p_chunksize) {}
ChunksRange(T const &range, RangeSize<T> chs):
p_range(range), p_chunksize(chs)
{}
ChunksRange(ChunksRange const &it):
p_range(it.p_range), p_chunksize(it.p_chunksize)
{}
ChunksRange(ChunksRange &&it):
p_range(move(it.p_range)), p_chunksize(it.p_chunksize)
{}
ChunksRange &operator=(ChunksRange const &v) {
p_range = v.p_range; p_chunksize = v.p_chunksize; return *this;
@ -1308,8 +1425,9 @@ namespace detail {
struct JoinRangeEmpty {
template<typename T>
static bool empty(T const &tup) {
if (!ostd::get<I>(tup).empty())
if (!ostd::get<I>(tup).empty()) {
return false;
}
return JoinRangeEmpty<I + 1, N>::empty(tup);
}
};
@ -1326,8 +1444,9 @@ namespace detail {
struct TupleRangeEqual {
template<typename T>
static bool equal(T const &tup1, T const &tup2) {
if (!ostd::get<I>(tup1).equals_front(ostd::get<I>(tup2)))
if (!ostd::get<I>(tup1).equals_front(ostd::get<I>(tup2))) {
return false;
}
return TupleRangeEqual<I + 1, N>::equal(tup1, tup2);
}
};
@ -1408,8 +1527,9 @@ public:
}
bool equals_front(JoinRange const &r) const {
return detail::TupleRangeEqual<0, sizeof...(R)>::equal(p_ranges,
r.p_ranges);
return detail::TupleRangeEqual<0, sizeof...(R)>::equal(
p_ranges, r.p_ranges
);
}
bool pop_front() {
@ -1417,8 +1537,9 @@ public:
}
CommonType<RangeReference<R>...> front() const {
return detail::JoinRangeFront<0, sizeof...(R),
CommonType<RangeReference<R>...>>::front(p_ranges);
return detail::JoinRangeFront<
0, sizeof...(R), CommonType<RangeReference<R>...>
>::front(p_ranges);
}
};
@ -1440,8 +1561,9 @@ namespace detail {
struct ZipRangeEmpty {
template<typename T>
static bool empty(T const &tup) {
if (ostd::get<I>(tup).empty())
if (ostd::get<I>(tup).empty()) {
return true;
}
return ZipRangeEmpty<I + 1, N>::empty(tup);
}
};
@ -1458,8 +1580,9 @@ namespace detail {
struct ZipRangePop {
template<typename T>
static bool pop(T &tup) {
return ostd::get<I>(tup).pop_front() &&
ZipRangePop<I + 1, N>::pop(tup);
return (
ostd::get<I>(tup).pop_front() && ZipRangePop<I + 1, N>::pop(tup)
);
}
};
@ -1516,8 +1639,9 @@ public:
}
bool equals_front(ZipRange const &r) const {
return detail::TupleRangeEqual<0, sizeof...(R)>::equal(p_ranges,
r.p_ranges);
return detail::TupleRangeEqual<0, sizeof...(R)>::equal(
p_ranges, r.p_ranges
);
}
bool pop_front() {

View File

@ -17,7 +17,8 @@
namespace ostd {
namespace detail {
template<typename T, typename A> struct SetBase {
template<typename T, typename A>
struct SetBase {
static inline T const &get_key(T const &e) {
return e;
}
@ -54,20 +55,26 @@ namespace detail {
using ConstLocalRange = BucketRange<T const>;
using Allocator = A;
explicit SetImpl(Size size, H const &hf = H(),
explicit SetImpl(
Size size, H const &hf = H(),
C const &eqf = C(), A const &alloc = A()
): Base(size, hf, eqf, alloc) {}
):
Base(size, hf, eqf, alloc)
{}
SetImpl(): SetImpl(0) {}
explicit SetImpl(A const &alloc): SetImpl(0, H(), C(), alloc) {}
SetImpl(Size size, A const &alloc):
SetImpl(size, H(), C(), alloc) {}
SetImpl(size, H(), C(), alloc)
{}
SetImpl(Size size, H const &hf, A const &alloc):
SetImpl(size, hf, C(), alloc) {}
SetImpl(size, hf, C(), alloc)
{}
SetImpl(SetImpl const &m): Base(m,
allocator_container_copy(m.get_alloc())) {}
SetImpl(SetImpl const &m):
Base(m, allocator_container_copy(m.get_alloc()))
{}
SetImpl(SetImpl const &m, A const &alloc): Base(m, alloc) {}
@ -76,33 +83,45 @@ namespace detail {
template<typename R, typename = EnableIf<
IsInputRange<R> && IsConvertible<RangeReference<R>, Value>
>> SetImpl(R range, Size size = 0, H const &hf = H(),
>>
SetImpl(
R range, Size size = 0, H const &hf = H(),
C const &eqf = C(), A const &alloc = A()
): Base(size ? size : detail::estimate_hrsize(range),
hf, eqf, alloc) {
for (; !range.empty(); range.pop_front())
):
Base(size ? size : detail::estimate_hrsize(range), hf, eqf, alloc)
{
for (; !range.empty(); range.pop_front()) {
Base::emplace(range.front());
}
Base::rehash_up();
}
template<typename R>
SetImpl(R range, Size size, A const &alloc)
: SetImpl(range, size, H(), C(), alloc) {}
SetImpl(R range, Size size, A const &alloc):
SetImpl(range, size, H(), C(), alloc)
{}
template<typename R>
SetImpl(R range, Size size, H const &hf, A const &alloc)
: SetImpl(range, size, hf, C(), alloc) {}
SetImpl(R range, Size size, H const &hf, A const &alloc):
SetImpl(range, size, hf, C(), alloc)
{}
SetImpl(InitializerList<Value> init, Size size = 0,
SetImpl(
InitializerList<Value> init, Size size = 0,
H const &hf = H(), C const &eqf = C(), A const &alloc = A()
): SetImpl(iter(init), size, hf, eqf, alloc) {}
):
SetImpl(iter(init), size, hf, eqf, alloc)
{}
SetImpl(InitializerList<Value> init, Size size, A const &alloc)
: SetImpl(iter(init), size, H(), C(), alloc) {}
SetImpl(InitializerList<Value> init, Size size, A const &alloc):
SetImpl(iter(init), size, H(), C(), alloc)
{}
SetImpl(InitializerList<Value> init, Size size, H const &hf,
A const &alloc
): SetImpl(iter(init), size, hf, C(), alloc) {}
SetImpl(
InitializerList<Value> init, Size size, H const &hf, A const &alloc
):
SetImpl(iter(init), size, hf, C(), alloc)
{}
SetImpl &operator=(SetImpl const &m) {
Base::operator=(m);
@ -116,7 +135,8 @@ namespace detail {
template<typename R, typename = EnableIf<
IsInputRange<R> && IsConvertible<RangeReference<R>, Value>
>> SetImpl &operator=(R range) {
>>
SetImpl &operator=(R range) {
Base::assign_range(range);
return *this;
}
@ -137,14 +157,16 @@ template<
typename H = ToHash<T>,
typename C = EqualWithCstr<T>,
typename A = Allocator<T>
> using Set = detail::SetImpl<T, H, C, A, false>;
>
using Set = detail::SetImpl<T, H, C, A, false>;
template<
typename T,
typename H = ToHash<T>,
typename C = EqualWithCstr<T>,
typename A = Allocator<T>
> using Multiset = detail::SetImpl<T, H, C, A, true>;
>
using Multiset = detail::SetImpl<T, H, C, A, true>;
} /* namespace ostd */

View File

@ -68,9 +68,11 @@ private:
}
template<typename T>
inline bool write_impl(T const &v, EnableIf<
!IsConstructible<ConstCharRange, T const &>, StNat
> = StNat()) {
inline bool write_impl(
T const &v, EnableIf<
!IsConstructible<ConstCharRange, T const &>, StNat
> = StNat()
) {
return write(ostd::to_string(v));
}
@ -85,7 +87,9 @@ public:
virtual Offset size() {
Offset p = tell();
if ((p < 0) || !seek(0, StreamSeek::end)) return -1;
if ((p < 0) || !seek(0, StreamSeek::end)) {
return -1;
}
Offset e = tell();
return ((p == e) || seek(p, StreamSeek::set)) ? e : -1;
}
@ -134,12 +138,14 @@ public:
template<typename ...A>
bool writef(ConstCharRange fmt, A const &...args) {
char buf[512];
Ptrdiff need = format(detail::FormatOutRange<sizeof(buf)>(buf),
fmt, args...);
if (need < 0)
Ptrdiff need = format(
detail::FormatOutRange<sizeof(buf)>(buf), fmt, args...
);
if (need < 0) {
return false;
else if (Size(need) < sizeof(buf))
} else if (Size(need) < sizeof(buf)) {
return write_bytes(buf, need) == Size(need);
}
Vector<char> s;
s.reserve(need);
format(detail::UnsafeWritefRange(s.data()), fmt, args...);
@ -154,23 +160,28 @@ public:
template<typename T = char>
StreamRange<T> iter();
template<typename T> Size put(T const *v, Size count) {
template<typename T>
Size put(T const *v, Size count) {
return write_bytes(v, count * sizeof(T)) / sizeof(T);
}
template<typename T> bool put(T v) {
template<typename T>
bool put(T v) {
return write_bytes(&v, sizeof(T)) == sizeof(T);
}
template<typename T> Size get(T *v, Size count) {
template<typename T>
Size get(T *v, Size count) {
return read_bytes(v, count * sizeof(T)) / sizeof(T);
}
template<typename T> bool get(T &v) {
template<typename T>
bool get(T &v) {
return read_bytes(&v, sizeof(T)) == sizeof(T);
}
template<typename T> T get() {
template<typename T>
T get() {
T r;
return get(r) ? r : T();
}
@ -189,7 +200,9 @@ struct StreamRange<T, true>: InputRange<
}
bool pop_front() {
if (empty()) return false;
if (empty()) {
return false;
}
T val;
return !!p_stream->read_bytes(&val, sizeof(T));
}

View File

@ -18,7 +18,8 @@
namespace ostd {
static constexpr Size npos = -1;
template<typename T, typename A = Allocator<T>> class StringBase;
template<typename T, typename A = Allocator<T>>
class StringBase;
template<typename T>
struct CharRangeBase: InputRange<
@ -39,25 +40,28 @@ public:
/* TODO: traits for utf-16/utf-32 string lengths, for now assume char */
template<typename U>
CharRangeBase(U beg, EnableIf<IsConvertible<U, T *> && !IsArray<U>, Nat>
= Nat()): p_beg(beg), p_end(static_cast<T *>(beg)
+ (beg ? strlen(beg) : 0)) {}
CharRangeBase(
U beg, EnableIf<IsConvertible<U, T *> && !IsArray<U>, Nat> = Nat()
): p_beg(beg), p_end(static_cast<T *>(beg) + (beg ? strlen(beg) : 0)) {}
CharRangeBase(Nullptr): p_beg(nullptr), p_end(nullptr) {}
template<typename U, Size N>
CharRangeBase(U (&beg)[N], EnableIf<IsConvertible<U *, T *>, Nat> = Nat()):
p_beg(beg), p_end(beg + N - (beg[N - 1] == '\0')) {}
p_beg(beg), p_end(beg + N - (beg[N - 1] == '\0'))
{}
template<typename U, typename A>
CharRangeBase(StringBase<U, A> const &s, EnableIf<
IsConvertible<U *, T *>, Nat
> = Nat()): p_beg(s.data()),
p_end(s.data() + s.size()) {}
> = Nat()):
p_beg(s.data()), p_end(s.data() + s.size())
{}
template<typename U, typename = EnableIf<IsConvertible<U *, T *>>>
CharRangeBase(CharRangeBase<U> const &v):
p_beg(&v[0]), p_end(&v[v.size()]) {}
p_beg(&v[0]), p_end(&v[v.size()])
{}
CharRangeBase &operator=(CharRangeBase const &v) {
p_beg = v.p_beg; p_end = v.p_end; return *this;
@ -75,7 +79,9 @@ public:
bool empty() const { return p_beg == p_end; }
bool pop_front() {
if (p_beg == p_end) return false;
if (p_beg == p_end) {
return false;
}
++p_beg;
return true;
}
@ -104,7 +110,9 @@ public:
}
bool pop_back() {
if (p_end == p_beg) return false;
if (p_end == p_beg) {
return false;
}
--p_end;
return true;
}
@ -141,7 +149,9 @@ public:
T &operator[](Size i) const { return p_beg[i]; }
bool put(T v) {
if (empty()) return false;
if (empty()) {
return false;
}
*(p_beg++) = v;
return true;
}
@ -209,8 +219,9 @@ inline bool operator>=(ConstCharRange lhs, ConstCharRange rhs) {
}
inline bool starts_with(ConstCharRange a, ConstCharRange b) {
if (a.size() < b.size())
if (a.size() < b.size()) {
return false;
}
return a.slice(0, b.size()) == b;
}
@ -225,7 +236,9 @@ class StringBase {
void ctor_from_range(R &range, EnableIf<
IsFiniteRandomAccessRange<R> && IsSame<T, RemoveCv<RangeValue<R>>>, bool
> = true) {
if (range.empty()) return;
if (range.empty()) {
return;
}
RangeSize<R> l = range.size();
reserve(l);
p_len = l;
@ -238,12 +251,16 @@ class StringBase {
!IsFiniteRandomAccessRange<R> || !IsSame<T, RemoveCv<RangeValue<R>>>,
bool
> = true) {
if (range.empty()) return;
if (range.empty()) {
return;
}
Size i = 0;
for (; !range.empty(); range.pop_front()) {
reserve(i + 1);
allocator_construct(p_buf.second(), &p_buf.first()[i],
range.front());
allocator_construct(
p_buf.second(), &p_buf.first()[i],
range.front()
);
++i;
p_len = i;
}
@ -262,42 +279,60 @@ public:
using ConstRange = CharRangeBase<T const>;
using Allocator = A;
StringBase(A const &a = A()): p_len(0), p_cap(0),
p_buf(reinterpret_cast<Pointer>(&p_len), a) {}
StringBase(A const &a = A()):
p_len(0), p_cap(0),
p_buf(reinterpret_cast<Pointer>(&p_len), a)
{}
explicit StringBase(Size n, T val = T(), A const &al = A()):
StringBase(al) {
if (!n) return;
StringBase(al)
{
if (!n) {
return;
}
p_buf.first() = allocator_allocate(p_buf.second(), n + 1);
p_len = p_cap = n;
Pointer cur = p_buf.first(), last = p_buf.first() + n;
while (cur != last) *cur++ = val;
while (cur != last) {
*cur++ = val;
}
*cur = '\0';
}
StringBase(StringBase const &s): p_len(0), p_cap(0),
p_buf(reinterpret_cast<Pointer>(&p_len),
allocator_container_copy(s.p_buf.second())) {
if (!s.p_len) return;
StringBase(StringBase const &s):
p_len(0), p_cap(0), p_buf(reinterpret_cast<Pointer>(&p_len),
allocator_container_copy(s.p_buf.second()))
{
if (!s.p_len) {
return;
}
reserve(s.p_len);
p_len = s.p_len;
memcpy(p_buf.first(), s.p_buf.first(), (p_len + 1) * sizeof(T));
}
StringBase(StringBase const &s, A const &a): p_len(0), p_cap(0),
p_buf(reinterpret_cast<Pointer>(&p_len), a) {
if (!s.p_len) return;
StringBase(StringBase const &s, A const &a):
p_len(0), p_cap(0), p_buf(reinterpret_cast<Pointer>(&p_len), a)
{
if (!s.p_len) {
return;
}
reserve(s.p_len);
p_len = s.p_len;
memcpy(p_buf.first(), s.p_buf.first(), (p_len + 1) * sizeof(T));
}
StringBase(StringBase &&s): p_len(s.p_len), p_cap(s.p_cap),
p_buf(s.p_buf.first(), move(s.p_buf.second())) {
StringBase(StringBase &&s):
p_len(s.p_len), p_cap(s.p_cap),
p_buf(s.p_buf.first(), move(s.p_buf.second()))
{
s.p_len = s.p_cap = 0;
s.p_buf.first() = reinterpret_cast<Pointer>(&s.p_len);
}
StringBase(StringBase &&s, A const &a): p_len(0), p_cap(0),
p_buf(reinterpret_cast<Pointer>(&p_len), a) {
if (!s.p_len) return;
StringBase(StringBase &&s, A const &a):
p_len(0), p_cap(0), p_buf(reinterpret_cast<Pointer>(&p_len), a)
{
if (!s.p_len) {
return;
}
if (a != s.p_buf.second()) {
reserve(s.p_cap);
p_len = s.p_len;
@ -311,8 +346,9 @@ public:
s.p_buf.first() = &s.p_cap;
}
StringBase(StringBase const &s, Size pos, Size len = npos,
A const &a = A()): StringBase(a) {
StringBase(
StringBase const &s, Size pos, Size len = npos, A const &a = A()
): StringBase(a) {
Size end = (len == npos) ? s.size() : (pos + len);
Size nch = (end - pos);
reserve(nch);
@ -323,7 +359,9 @@ public:
/* TODO: traits for utf-16/utf-32 string lengths, for now assume char */
StringBase(ConstRange v, A const &a = A()): StringBase(a) {
if (!v.size()) return;
if (!v.size()) {
return;
}
reserve(v.size());
memcpy(p_buf.first(), &v[0], v.size());
p_buf.first()[v.size()] = '\0';
@ -342,23 +380,30 @@ public:
template<typename R, typename = EnableIf<
IsInputRange<R> && IsConvertible<RangeReference<R>, Value>
>> StringBase(R range, A const &a = A()): StringBase(a) {
>>
StringBase(R range, A const &a = A()): StringBase(a) {
ctor_from_range(range);
}
~StringBase() {
if (!p_cap) return;
if (!p_cap) {
return;
}
allocator_deallocate(p_buf.second(), p_buf.first(), p_cap + 1);
}
void clear() {
if (!p_len) return;
if (!p_len) {
return;
}
p_len = 0;
*p_buf.first() = '\0';
}
StringBase &operator=(StringBase const &v) {
if (this == &v) return *this;
if (this == &v) {
return *this;
}
clear();
if (AllocatorPropagateOnContainerCopyAssignment<A>) {
if ((p_buf.second() != v.p_buf.second()) && p_cap) {
@ -373,40 +418,51 @@ public:
if (p_len) {
memcpy(p_buf.first(), v.p_buf.first(), p_len);
p_buf.first()[p_len] = '\0';
} else p_buf.first() = reinterpret_cast<Pointer>(&p_len);
} else {
p_buf.first() = reinterpret_cast<Pointer>(&p_len);
}
return *this;
}
StringBase &operator=(StringBase &&v) {
clear();
if (p_cap) allocator_deallocate(p_buf.second(), p_buf.first(), p_cap);
if (AllocatorPropagateOnContainerMoveAssignment<A>)
if (p_cap) {
allocator_deallocate(p_buf.second(), p_buf.first(), p_cap);
}
if (AllocatorPropagateOnContainerMoveAssignment<A>) {
p_buf.second() = v.p_buf.second();
}
p_len = v.p_len;
p_cap = v.p_cap;
p_buf.~StrPair();
new (&p_buf) StrPair(v.disown(), move(v.p_buf.second()));
if (!p_cap) p_buf.first() = reinterpret_cast<Pointer>(&p_len);
if (!p_cap) {
p_buf.first() = reinterpret_cast<Pointer>(&p_len);
}
return *this;
}
StringBase &operator=(ConstRange v) {
reserve(v.size());
if (v.size()) memcpy(p_buf.first(), &v[0], v.size());
if (v.size()) {
memcpy(p_buf.first(), &v[0], v.size());
}
p_buf.first()[v.size()] = '\0';
p_len = v.size();
return *this;
}
template<typename U>
EnableIf<IsConvertible<U, Value const *> && !IsArray<U>, StringBase &>
operator=(U v) {
EnableIf<
IsConvertible<U, Value const *> && !IsArray<U>, StringBase &
> operator=(U v) {
return operator=(ConstRange(v));
}
template<typename U, Size N>
EnableIf<IsConvertible<U *, Value const *>, StringBase &>
operator=(U (&v)[N]) {
EnableIf<
IsConvertible<U *, Value const *>, StringBase &
> operator=(U (&v)[N]) {
return operator=(ConstRange(v));
}
@ -433,7 +489,9 @@ public:
}
void reserve(Size n) {
if (n <= p_cap) return;
if (n <= p_cap) {
return;
}
Size oc = p_cap;
if (!oc) {
p_cap = max(n, Size(8));
@ -495,7 +553,9 @@ public:
}
StringBase &append(ConstRange r) {
if (!r.size()) return *this;
if (!r.size()) {
return *this;
}
reserve(p_len + r.size());
memcpy(p_buf.first() + p_len, &r[0], r.size());
p_len += r.size();
@ -504,9 +564,13 @@ public:
}
StringBase &append(Size n, T c) {
if (!n) return *this;
if (!n) {
return *this;
}
reserve(p_len + n);
for (Size i = 0; i < n; ++i) p_buf.first()[p_len + i] = c;
for (Size i = 0; i < n; ++i) {
p_buf.first()[p_len + i] = c;
}
p_len += n;
p_buf.first()[p_len] = '\0';
return *this;
@ -559,8 +623,9 @@ public:
detail::swap_adl(p_len, v.p_len);
detail::swap_adl(p_cap, v.p_cap);
detail::swap_adl(p_buf.first(), v.p_buf.first());
if (AllocatorPropagateOnContainerSwap<A>)
if (AllocatorPropagateOnContainerSwap<A>) {
detail::swap_adl(p_buf.second(), v.p_buf.second());
}
}
Size to_hash() const {
@ -576,7 +641,8 @@ using String = StringBase<char>;
/* string literals */
inline namespace literals { inline namespace string_literals {
inline namespace literals {
inline namespace string_literals {
inline String operator "" _s(char const *str, Size len) {
return String(ConstCharRange(str, len));
}
@ -584,11 +650,14 @@ inline namespace literals { inline namespace string_literals {
inline ConstCharRange operator "" _S(char const *str, Size len) {
return ConstCharRange(str, len);
}
} }
}
}
namespace detail {
template<typename T, bool = IsConvertible<T, ConstCharRange>,
bool = IsConvertible<T, char>>
template<
typename T, bool = IsConvertible<T, ConstCharRange>,
bool = IsConvertible<T, char>
>
struct ConcatPut;
template<typename T, bool B>
@ -611,14 +680,19 @@ namespace detail {
template<typename R, typename T, typename F>
bool concat(R &&sink, T const &v, ConstCharRange sep, F func) {
auto range = ostd::iter(v);
if (range.empty()) return true;
if (range.empty()) {
return true;
}
for (;;) {
if (!detail::ConcatPut<
decltype(func(range.front()))
>::put(sink, func(range.front())))
>::put(sink, func(range.front()))) {
return false;
}
range.pop_front();
if (range.empty()) break;
if (range.empty()) {
break;
}
sink.put_n(&sep[0], sep.size());
}
return true;
@ -627,13 +701,18 @@ bool concat(R &&sink, T const &v, ConstCharRange sep, F func) {
template<typename R, typename T>
bool concat(R &&sink, T const &v, ConstCharRange sep = " ") {
auto range = ostd::iter(v);
if (range.empty()) return true;
if (range.empty()) {
return true;
}
for (;;) {
ConstCharRange ret = range.front();
if (!ret.size() || (sink.put_n(&ret[0], ret.size()) != ret.size()))
if (!ret.size() || (sink.put_n(&ret[0], ret.size()) != ret.size())) {
return false;
}
range.pop_front();
if (range.empty()) break;
if (range.empty()) {
break;
}
sink.put_n(&sep[0], sep.size());
}
return true;
@ -674,7 +753,7 @@ namespace detail {
};
template<typename T, typename R>
auto test_stringify(int) ->
static auto test_stringify(int) ->
BoolConstant<IsSame<decltype(declval<T>().stringify()), String>>;
template<typename T, typename R>
@ -682,14 +761,15 @@ namespace detail {
(declval<R &>())) *);
template<typename, typename>
False test_stringify(...);
static False test_stringify(...);
template<typename T, typename R>
constexpr bool StringifyTest = decltype(test_stringify<T, R>(0))::value;
template<typename T>
True test_iterable(decltype(ostd::iter(declval<T>())) *);
template<typename> static False test_iterable(...);
static True test_iterable(decltype(ostd::iter(declval<T>())) *);
template<typename>
static False test_iterable(...);
template<typename T>
constexpr bool IterableTest = decltype(test_iterable<T>(0))::value;
@ -710,7 +790,9 @@ struct ToString<T, EnableIf<detail::IterableTest<T>>> {
RemoveConst<RemoveReference<
RangeReference<decltype(ostd::iter(v))>
>>
>())) ret += x.get();
>())) {
ret += x.get();
}
ret += "}";
return ret;
}
@ -726,7 +808,9 @@ struct ToString<T, EnableIf<
String operator()(T const &v) const {
auto app = appender<String>();
detail::TostrRange<AppenderRange<String>> sink(app);
if (!v.to_string(sink)) return String();
if (!v.to_string(sink)) {
return String();
}
return move(app.get());
}
};
@ -738,18 +822,19 @@ namespace detail {
int n = snprintf(buf, sizeof(buf), fmt, v);
s.clear();
s.reserve(n);
if (n >= int(sizeof(buf)))
if (n >= int(sizeof(buf))) {
snprintf(s.data(), n + 1, fmt, v);
else if (n > 0)
} else if (n > 0) {
memcpy(s.data(), buf, n + 1);
else {
} else {
s.clear();
}
*reinterpret_cast<Size *>(&s) = n;
}
}
template<> struct ToString<bool> {
template<>
struct ToString<bool> {
using Argument = bool;
using Result = String;
String operator()(bool b) {
@ -757,7 +842,8 @@ template<> struct ToString<bool> {
}
};
template<> struct ToString<char> {
template<>
struct ToString<char> {
using Argument = char;
using Result = String;
String operator()(char c) {
@ -768,7 +854,8 @@ template<> struct ToString<char> {
};
#define OSTD_TOSTR_NUM(T, fmt) \
template<> struct ToString<T> { \
template<> \
struct ToString<T> { \
using Argument = T; \
using Result = String; \
String operator()(T v) { \
@ -794,7 +881,8 @@ OSTD_TOSTR_NUM(ldouble, "%Lf")
#undef OSTD_TOSTR_NUM
template<typename T> struct ToString<T *> {
template<typename T>
struct ToString<T *> {
using Argument = T *;
using Result = String;
String operator()(Argument v) {
@ -804,7 +892,8 @@ template<typename T> struct ToString<T *> {
}
};
template<> struct ToString<char const *> {
template<>
struct ToString<char const *> {
using Argument = char const *;
using Result = String;
String operator()(char const *s) {
@ -812,7 +901,8 @@ template<> struct ToString<char const *> {
}
};
template<> struct ToString<char *> {
template<>
struct ToString<char *> {
using Argument = char *;
using Result = String;
String operator()(char *s) {
@ -820,7 +910,8 @@ template<> struct ToString<char *> {
}
};
template<> struct ToString<String> {
template<>
struct ToString<String> {
using Argument = String;
using Result = String;
String operator()(Argument const &s) {
@ -828,7 +919,8 @@ template<> struct ToString<String> {
}
};
template<> struct ToString<CharRange> {
template<>
struct ToString<CharRange> {
using Argument = CharRange;
using Result = String;
String operator()(Argument const &s) {
@ -836,7 +928,8 @@ template<> struct ToString<CharRange> {
}
};
template<> struct ToString<ConstCharRange> {
template<>
struct ToString<ConstCharRange> {
using Argument = ConstCharRange;
using Result = String;
String operator()(Argument const &s) {
@ -844,7 +937,8 @@ template<> struct ToString<ConstCharRange> {
}
};
template<typename T, typename U> struct ToString<Pair<T, U>> {
template<typename T, typename U>
struct ToString<Pair<T, U>> {
using Argument = Pair<T, U>;
using Result = String;
String operator()(Argument const &v) {
@ -864,7 +958,8 @@ namespace detail {
static void append(String &ret, T const &tup) {
ret += ", ";
ret += ToString<RemoveCv<RemoveReference<
decltype(ostd::get<I>(tup))>>>()(ostd::get<I>(tup));
decltype(ostd::get<I>(tup))
>>>()(ostd::get<I>(tup));
TupleToString<I + 1, N>::append(ret, tup);
}
};
@ -880,13 +975,15 @@ namespace detail {
template<typename T>
static void append(String &ret, T const &tup) {
ret += ToString<RemoveCv<RemoveReference<
decltype(ostd::get<0>(tup))>>>()(ostd::get<0>(tup));
decltype(ostd::get<0>(tup))
>>>()(ostd::get<0>(tup));
TupleToString<1, N>::append(ret, tup);
}
};
}
template<typename ...T> struct ToString<Tuple<T...>> {
template<typename ...T>
struct ToString<Tuple<T...>> {
using Argument = Tuple<T...>;
using Result = String;
String operator()(Argument const &v) {
@ -948,15 +1045,21 @@ public:
}
TempCString(R input, RemoveCv<RangeValue<R>> *sbuf, Size bufsize)
: p_buf(nullptr), p_allocated(false) {
if (input.empty()) return;
if (input.empty()) {
return;
}
if (input.size() >= bufsize) {
p_buf = new RemoveCv<RangeValue<R>>[input.size() + 1];
p_allocated = true;
} else p_buf = sbuf;
} else {
p_buf = sbuf;
}
p_buf[input.copy(p_buf)] = '\0';
}
~TempCString() {
if (p_allocated) delete[] p_buf;
if (p_allocated) {
delete[] p_buf;
}
}
TempCString &operator=(TempCString const &) = delete;
@ -975,8 +1078,9 @@ public:
};
template<typename R>
inline TempCString<R> to_temp_cstr(R input, RemoveCv<RangeValue<R>> *buf,
Size bufsize) {
inline TempCString<R> to_temp_cstr(
R input, RemoveCv<RangeValue<R>> *buf, Size bufsize
) {
return TempCString<R>(input, buf, bufsize);
}

View File

@ -109,30 +109,38 @@ struct Thread {
Thread(): p_thread(0) {}
Thread(Thread &&o): p_thread(o.p_thread) { o.p_thread = 0; }
template<typename F, typename ...A,
typename = EnableIf<!IsSame<Decay<F>, Thread>>>
template<
typename F, typename ...A, typename = EnableIf<!IsSame<Decay<F>, Thread>>
>
Thread(F &&func, A &&...args) {
using FuncT = Tuple<Decay<F>, Decay<A>...>;
Box<FuncT> p(new FuncT(detail::decay_copy(forward<F>(func)),
detail::decay_copy(forward<A>(args))...));
int res = pthread_create(&p_thread, 0, &detail::thread_proxy<FuncT>, p.get());
if (!res)
Box<FuncT> p(new FuncT(
detail::decay_copy(forward<F>(func)),
detail::decay_copy(forward<A>(args))...
));
int res = pthread_create(
&p_thread, 0, &detail::thread_proxy<FuncT>, p.get()
);
if (!res) {
p.release();
else
} else {
p_thread = 0;
}
}
Thread &operator=(Thread &&other) {
if (joinable())
if (joinable()) {
abort();
}
p_thread = other.p_thread;
other.p_thread = 0;
return *this;
}
~Thread() {
if (joinable())
if (joinable()) {
abort();
}
}
explicit operator bool() const { return joinable(); }
@ -152,8 +160,9 @@ struct Thread {
bool detach() {
bool ret = false;
if (p_thread)
if (p_thread) {
ret = !pthread_detach(p_thread);
}
p_thread = 0;
return ret;
}
@ -174,8 +183,9 @@ struct Thread {
#elif defined(_SC_NPROCESSORS_ONLN)
count = ostd::uint(sysconf(_SC_NPROCESSORS_ONLN));
#endif
if (count <= 0)
if (count <= 0) {
count = 1;
}
}
return count;
}

View File

@ -17,7 +17,8 @@ namespace ostd {
/* tuple size */
template<typename ...T> constexpr Size TupleSize<Tuple<T...>> = sizeof...(T);
template<typename ...T>
constexpr Size TupleSize<Tuple<T...>> = sizeof...(T);
/* tuple element */
@ -32,71 +33,100 @@ namespace detail {
template<Size I, typename H, bool = IsEmpty<H>>
struct TupleLeaf {
constexpr TupleLeaf(): p_value() {
static_assert(!IsReference<H>,
"attempt to default construct a reference element in a tuple");
static_assert(
!IsReference<H>,
"attempt to default construct a reference element in a tuple"
);
}
template<typename A>
TupleLeaf(Constant<int, 0>, A const &): p_value() {
static_assert(!IsReference<H>,
"attempt to default construct a reference element in a tuple");
static_assert(
!IsReference<H>,
"attempt to default construct a reference element in a tuple"
);
}
template<typename A>
TupleLeaf(Constant<int, 1>, A const &a): p_value(allocator_arg, a) {
static_assert(!IsReference<H>,
"attempt to default construct a reference element in a tuple");
static_assert(
!IsReference<H>,
"attempt to default construct a reference element in a tuple"
);
}
template<typename A>
TupleLeaf(Constant<int, 2>, A const &a): p_value(a) {
static_assert(!IsReference<H>,
"attempt to default construct a reference element in a tuple");
static_assert(
!IsReference<H>,
"attempt to default construct a reference element in a tuple"
);
}
template<typename T, typename = EnableIf<
!IsSame<Decay<T>, TupleLeaf> && IsConstructible<H, T>
>>
explicit TupleLeaf(T &&t): p_value(forward<T>(t)) {
static_assert(!IsReference<H> ||
(IsLvalueReference<H> &&
(IsLvalueReference<T> ||
IsSame<RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>>)) ||
(IsRvalueReference<H> &&
!IsLvalueReference<T>),
"attempt to construct a reference element in a tuple with an rvalue");
static_assert(
!IsReference<H> || (
IsLvalueReference<H> && (
IsLvalueReference<T> || IsSame<
RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>
>
)
) || (IsRvalueReference<H> && !IsLvalueReference<T>),
"attempt to construct a reference element in a tuple with an rvalue"
);
}
template<typename T, typename A>
explicit TupleLeaf(Constant<int, 0>, A const &, T &&t):
p_value(forward<T>(t)) {
static_assert(!IsLvalueReference<H> ||
(IsLvalueReference<H> &&
(IsLvalueReference<T> ||
IsSame<RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>>)),
"attempt to construct a reference element in a tuple with an rvalue");
p_value(forward<T>(t))
{
static_assert(
!IsLvalueReference<H> || (
IsLvalueReference<H> && (
IsLvalueReference<T> || IsSame<
RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>
>
)
),
"attempt to construct a reference element in a tuple with an rvalue"
);
}
template<typename T, typename A>
explicit TupleLeaf(Constant<int, 1>, A const &a, T &&t):
p_value(allocator_arg, a, forward<T>(t)) {
static_assert(!IsLvalueReference<H> ||
(IsLvalueReference<H> &&
(IsLvalueReference<T> ||
IsSame<RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>>)),
"attempt to construct a reference element in a tuple with an rvalue");
p_value(allocator_arg, a, forward<T>(t))
{
static_assert(
!IsLvalueReference<H> || (
IsLvalueReference<H> && (
IsLvalueReference<T> || IsSame<
RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>
>
)
),
"attempt to construct a reference element in a tuple with an rvalue"
);
}
template<typename T, typename A>
explicit TupleLeaf(Constant<int, 2>, A const &a, T &&t):
p_value(forward<T>(t), a) {
static_assert(!IsLvalueReference<H> ||
(IsLvalueReference<H> &&
(IsLvalueReference<T> ||
IsSame<RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>>)),
"attempt to construct a reference element in a tuple with an rvalue");
p_value(forward<T>(t), a)
{
static_assert(
!IsLvalueReference<H> || (
IsLvalueReference<H> && (
IsLvalueReference<T> || IsSame<
RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>
>
)
),
"attempt to construct a reference element in a tuple with an rvalue"
);
}
TupleLeaf(TupleLeaf const &) = default;
@ -129,26 +159,31 @@ namespace detail {
template<typename A>
TupleLeaf(Constant<int, 1>, A const &a):
H(allocator_arg, a) {}
H(allocator_arg, a)
{}
template<typename A>
TupleLeaf(Constant<int, 2>, A const &a): H(a) {}
template<typename T, typename = EnableIf<
!IsSame<Decay<T>, TupleLeaf> && IsConstructible<H, T>
>> explicit TupleLeaf(T &&t): H(forward<T>(t)) {}
>>
explicit TupleLeaf(T &&t): H(forward<T>(t)) {}
template<typename T, typename A>
explicit TupleLeaf(Constant<int, 0>, A const &, T &&t):
H(forward<T>(t)) {}
H(forward<T>(t))
{}
template<typename T, typename A>
explicit TupleLeaf(Constant<int, 1>, A const &a, T &&t):
H(allocator_arg, a, forward<T>(t)) {}
H(allocator_arg, a, forward<T>(t))
{}
template<typename T, typename A>
explicit TupleLeaf(Constant<int, 2>, A const &a, T &&t):
H(forward<T>(t), a) {}
H(forward<T>(t), a)
{}
TupleLeaf(TupleLeaf const &) = default;
TupleLeaf(TupleLeaf &&) = default;
@ -187,58 +222,73 @@ namespace detail {
constexpr bool TupleAllDefaultConstructible = detail::Undefined<T>();
template<typename ...A>
constexpr bool TupleAllDefaultConstructible<TupleTypes<A...>>
= TupleAll<IsDefaultConstructible<A>...>;
constexpr bool TupleAllDefaultConstructible<TupleTypes<A...>> =
TupleAll<IsDefaultConstructible<A>...>;
}
/* tuple implementation */
namespace detail {
template<typename, typename ...> struct TupleBase;
template<typename, typename ...>
struct TupleBase;
template<Size ...I, typename ...A>
struct TupleBase<TupleIndices<I...>, A...>: TupleLeaf<I, A>... {
constexpr TupleBase() {}
template<Size ...Ia, typename ...Aa,
Size ...Ib, typename ...Ab, typename ...T>
explicit TupleBase(TupleIndices<Ia...>, TupleTypes<Aa...>,
TupleIndices<Ib...>, TupleTypes<Ab...>,
T &&...t):
template<
Size ...Ia, typename ...Aa, Size ...Ib,
typename ...Ab, typename ...T
>
explicit TupleBase(
TupleIndices<Ia...>, TupleTypes<Aa...>,
TupleIndices<Ib...>, TupleTypes<Ab...>, T &&...t
):
TupleLeaf<Ia, Aa>(forward<T>(t))...,
TupleLeaf<Ib, Ab>()... {}
TupleLeaf<Ib, Ab>()...
{}
template<typename Alloc, Size ...Ia, typename ...Aa,
Size ...Ib, typename ...Ab, typename ...T>
explicit TupleBase(AllocatorArg, Alloc const &a,
TupleIndices<Ia...>, TupleTypes<Aa...>,
TupleIndices<Ib...>, TupleTypes<Ab...>,
T &&...t):
TupleLeaf<Ia, Aa>(UsesAllocatorConstructor<Aa, Alloc, T>, a,
forward<T>(t))...,
template<
typename Alloc, Size ...Ia, typename ...Aa,
Size ...Ib, typename ...Ab, typename ...T
>
explicit TupleBase(
AllocatorArg, Alloc const &a,
TupleIndices<Ia...>, TupleTypes<Aa...>,
TupleIndices<Ib...>, TupleTypes<Ab...>, T &&...t
):
TupleLeaf<Ia, Aa>(
UsesAllocatorConstructor<Aa, Alloc, T>, a,
forward<T>(t)
)...,
TupleLeaf<Ib, Ab>(UsesAllocatorConstructor<Ab, Alloc>, a)...
{}
template<typename T, typename = EnableIf<
TupleConstructible<T, Tuple<A...>>
>> TupleBase(T &&t): TupleLeaf<I, A>(forward<
TupleElement<I, MakeTupleTypes<T>>
>(get<I>(t)))... {}
>>
TupleBase(T &&t):
TupleLeaf<I, A>(
forward<TupleElement<I, MakeTupleTypes<T>>>(get<I>(t))
)...
{}
template<typename Alloc, typename T, typename = EnableIf<
TupleConvertible<T, Tuple<A...>>
>> TupleBase(AllocatorArg, Alloc const &a, T &&t):
TupleLeaf<I, A>(UsesAllocatorConstructor<
A, Alloc, TupleElement<I, MakeTupleTypes<T>>
>, a, forward<TupleElement<I, MakeTupleTypes<T>>>(get<I>(t)))...
>>
TupleBase(AllocatorArg, Alloc const &a, T &&t):
TupleLeaf<I, A>(
UsesAllocatorConstructor<
A, Alloc, TupleElement<I, MakeTupleTypes<T>>
>, a, forward<TupleElement<I, MakeTupleTypes<T>>>(get<I>(t))
)...
{}
template<typename T>
EnableIf<TupleAssignable<T, Tuple<A...>>, TupleBase &>
operator=(T &&t) {
tuple_swallow(TupleLeaf<I, A>::operator=(forward<
TupleElement<I, MakeTupleTypes<T>>
>(get<I>(t)))...);
EnableIf<TupleAssignable<T, Tuple<A...>>, TupleBase &> operator=(T &&t) {
tuple_swallow(TupleLeaf<I, A>::operator=(
forward<TupleElement<I, MakeTupleTypes<T>>>(get<I>(t))
)...);
return *this;
}
@ -246,19 +296,23 @@ namespace detail {
TupleBase(TupleBase &&) = default;
TupleBase &operator=(TupleBase const &t) {
tuple_swallow(TupleLeaf<I, A>::operator=((
static_cast<TupleLeaf<I, A> const &>(t)).get())...);
tuple_swallow(TupleLeaf<I, A>::operator=(
(static_cast<TupleLeaf<I, A> const &>(t)).get()
)...);
return *this;
}
TupleBase &operator=(TupleBase &&t) {
tuple_swallow(TupleLeaf<I, A>::operator=(forward<A>
((static_cast<TupleLeaf<I, A> &>(t)).get()))...);
tuple_swallow(TupleLeaf<I, A>::operator=(
forward<A>((static_cast<TupleLeaf<I, A> &>(t)).get())
)...);
return *this;
}
void swap(TupleBase &t) {
tuple_swallow(TupleLeaf<I, A>::swap(static_cast<TupleLeaf<I, A> &>(t))...);
tuple_swallow(
TupleLeaf<I, A>::swap(static_cast<TupleLeaf<I, A> &>(t))...
);
}
};
} /* namespace detail */
@ -283,110 +337,130 @@ class Tuple {
public:
template<bool D = true, typename = EnableIf<
detail::TupleAll<(D && IsDefaultConstructible<A>)...>
>> Tuple() {}
>>
Tuple() {}
explicit Tuple(A const &...t):
p_base(detail::MakeTupleIndices<sizeof...(A)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A)>(),
detail::MakeTupleIndices<0>(),
detail::MakeTupleTypes<Tuple, 0>(), t...) {}
template<typename Alloc>
Tuple(AllocatorArg, Alloc const &a, A const &...t):
p_base(allocator_arg, a,
p_base(
detail::MakeTupleIndices<sizeof...(A)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A)>(),
detail::MakeTupleIndices<0>(),
detail::MakeTupleTypes<Tuple, 0>(), t...) {}
detail::MakeTupleTypes<Tuple, 0>(), t...
)
{}
template<typename Alloc>
Tuple(AllocatorArg, Alloc const &a, A const &...t):
p_base(
allocator_arg, a,
detail::MakeTupleIndices<sizeof...(A)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A)>(),
detail::MakeTupleIndices<0>(),
detail::MakeTupleTypes<Tuple, 0>(), t...
)
{}
template<typename ...T, EnableIf<
(sizeof...(T) <= sizeof...(A)) &&
detail::TupleConvertible<
Tuple<T...>,
detail::MakeTupleTypes<Tuple,
(sizeof...(T) < sizeof...(A)) ? sizeof...(T)
: sizeof...(A)
detail::MakeTupleTypes<
Tuple,
(sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A)
>
> &&
detail::TupleAllDefaultConstructible<
detail::MakeTupleTypes<Tuple, sizeof...(A),
(sizeof...(T) < sizeof...(A)) ? sizeof...(T)
: sizeof...(A)
detail::MakeTupleTypes<
Tuple, sizeof...(A),
(sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A)
>
>, bool
> = true>
Tuple(T &&...t):
p_base(detail::MakeTupleIndices<sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(T)>(),
detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(),
forward<T>(t)...) {}
p_base(
detail::MakeTupleIndices<sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(T)>(),
detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(),
forward<T>(t)...
)
{}
template<typename ...T, EnableIf<
(sizeof...(T) <= sizeof...(A)) &&
detail::TupleConstructible<
Tuple<T...>,
detail::MakeTupleTypes<Tuple,
(sizeof...(T) < sizeof...(A)) ? sizeof...(T)
: sizeof...(A)
detail::MakeTupleTypes<
Tuple,
(sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A)
>
> &&
!detail::TupleConvertible<
Tuple<T...>,
detail::MakeTupleTypes<Tuple,
(sizeof...(T) < sizeof...(A)) ? sizeof...(T)
: sizeof...(A)
detail::MakeTupleTypes<
Tuple,
(sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A)
>
> &&
detail::TupleAllDefaultConstructible<
detail::MakeTupleTypes<Tuple, sizeof...(A),
(sizeof...(T) < sizeof...(A)) ? sizeof...(T)
: sizeof...(A)
detail::MakeTupleTypes<
Tuple, sizeof...(A),
(sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A)
>
>, bool
> = true>
Tuple(T &&...t):
p_base(detail::MakeTupleIndices<sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(T)>(),
detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(),
forward<T>(t)...) {}
p_base(
detail::MakeTupleIndices<sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(T)>(),
detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(),
forward<T>(t)...
)
{}
template<typename Alloc, typename ...T, typename = EnableIf<
(sizeof...(T) <= sizeof...(A)) &&
detail::TupleConvertible<
Tuple<T...>,
detail::MakeTupleTypes<Tuple,
(sizeof...(T) < sizeof...(A)) ? sizeof...(T)
: sizeof...(A)
detail::MakeTupleTypes<
Tuple,
(sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A)
>
> &&
detail::TupleAllDefaultConstructible<
detail::MakeTupleTypes<Tuple, sizeof...(A),
(sizeof...(T) < sizeof...(A)) ? sizeof...(T)
: sizeof...(A)
detail::MakeTupleTypes<
Tuple, sizeof...(A),
(sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A)
>
>
>> Tuple(AllocatorArg, Alloc const &a, T &&...t):
p_base(allocator_arg, a, detail::MakeTupleIndices<sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(T)>(),
detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(),
forward<T>(t)...) {}
p_base(
allocator_arg, a, detail::MakeTupleIndices<sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(T)>(),
detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(),
forward<T>(t)...
)
{}
template<typename T, EnableIf<
detail::TupleConvertible<T, Tuple>, bool
> = true> Tuple(T &&t): p_base(forward<T>(t)) {}
> = true>
Tuple(T &&t): p_base(forward<T>(t)) {}
template<typename T, EnableIf<
detail::TupleConstructible<T, Tuple> &&
!detail::TupleConvertible<T, Tuple>, bool
> = true> Tuple(T &&t): p_base(forward<T>(t)) {}
> = true>
Tuple(T &&t): p_base(forward<T>(t)) {}
template<typename Alloc, typename T, typename = EnableIf<
detail::TupleConvertible<T, Tuple>
>> Tuple(AllocatorArg, Alloc const &a, T &&t):
p_base(allocator_arg, a, forward<T>(t)) {}
>>
Tuple(AllocatorArg, Alloc const &a, T &&t):
p_base(allocator_arg, a, forward<T>(t))
{}
template<typename T, typename = EnableIf<detail::TupleAssignable<T, Tuple>>>
Tuple &operator=(T &&t) {
@ -473,8 +547,7 @@ namespace detail {
}
template<typename ...T>
inline Tuple<typename detail::MakeTupleReturn<T>::Type...>
make_tuple(T &&...t) {
inline Tuple<typename detail::MakeTupleReturn<T>::Type...> make_tuple(T &&...t) {
return Tuple<typename detail::MakeTupleReturn<T>::Type...>(forward<T>(t)...);
}

File diff suppressed because it is too large Load Diff

View File

@ -43,7 +43,8 @@ inline T exchange(T &v, U &&nv) {
/* declval */
template<typename T> AddRvalueReference<T> declval();
template<typename T>
AddRvalueReference<T> declval();
/* swap */
@ -54,33 +55,38 @@ namespace detail {
template<typename>
False test_swap(...);
template<typename T> inline void swap_fb(T &a, T &b, EnableIf<
decltype(test_swap<T>(0))::value, bool
> = true) {
template<typename T>
inline void swap_fb(
T &a, T &b, EnableIf<decltype(test_swap<T>(0))::value, bool> = true
) {
a.swap(b);
}
template<typename T> inline void swap_fb(T &a, T &b, EnableIf<
!decltype(test_swap<T>(0))::value, bool
> = true) {
template<typename T>
inline void swap_fb(
T &a, T &b, EnableIf<!decltype(test_swap<T>(0))::value, bool> = true
) {
T c(move(a));
a = move(b);
b = move(c);
}
}
template<typename T> inline void swap(T &a, T &b) {
template<typename T>
inline void swap(T &a, T &b) {
detail::swap_fb(a, b);
}
template<typename T, Size N> inline void swap(T (&a)[N], T (&b)[N]) {
template<typename T, Size N>
inline void swap(T (&a)[N], T (&b)[N]) {
for (Size i = 0; i < N; ++i) {
swap(a[i], b[i]);
}
}
namespace detail {
template<typename T> inline void swap_adl(T &a, T &b) {
template<typename T>
inline void swap_adl(T &a, T &b) {
using ostd::swap;
swap(a, b);
}
@ -103,14 +109,16 @@ struct Pair {
template<typename TT, typename UU>
Pair(TT &&x, UU &&y):
first(forward<TT>(x)), second(forward<UU>(y)) {}
first(forward<TT>(x)), second(forward<UU>(y))
{}
template<typename TT, typename UU>
Pair(Pair<TT, UU> const &v): first(v.first), second(v.second) {}
template<typename TT, typename UU>
Pair(Pair<TT, UU> &&v):
first(move(v.first)), second(move(v.second)) {}
first(move(v.first)), second(move(v.second))
{}
Pair &operator=(Pair const &v) {
first = v.first;
@ -144,7 +152,8 @@ struct Pair {
}
};
template<typename T> struct ReferenceWrapper;
template<typename T>
struct ReferenceWrapper;
namespace detail {
template<typename T>
@ -164,12 +173,13 @@ namespace detail {
} /* namespace detail */
template<typename T, typename U>
inline Pair<typename detail::MakePairRet<T>::Type,
typename detail::MakePairRet<U>::Type
> make_pair(T &&a, U &&b) {
return Pair<typename detail::MakePairRet<T>::Type,
typename detail::MakePairRet<U>::Type
>(forward<T>(a), forward<U>(b));;
inline Pair<
typename detail::MakePairRet<T>::Type, typename detail::MakePairRet<U>::Type
> make_pair(T &&a, U &&b) {
return Pair<
typename detail::MakePairRet<T>::Type,
typename detail::MakePairRet<U>::Type
>(forward<T>(a), forward<U>(b));
}
template<typename T, typename U>
@ -222,9 +232,11 @@ struct TupleElementBase<1, Pair<T, U>> {
};
namespace detail {
template<Size> struct GetPair;
template<Size>
struct GetPair;
template<> struct GetPair<0> {
template<>
struct GetPair<0> {
template<typename T, typename U>
static T &get(Pair<T, U> &p) { return p.first; }
template<typename T, typename U>
@ -237,7 +249,8 @@ namespace detail {
}
};
template<> struct GetPair<1> {
template<>
struct GetPair<1> {
template<typename T, typename U>
static U &get(Pair<T, U> &p) { return p.second; }
template<typename T, typename U>
@ -275,7 +288,8 @@ namespace detail {
template<typename T, typename U,
bool = IsSame<RemoveCv<T>, RemoveCv<U>>,
bool = IsEmpty<T>, bool = IsEmpty<U>
> constexpr Size CompressedPairSwitch = detail::Undefined<T>();
>
constexpr Size CompressedPairSwitch = detail::Undefined<T>();
/* neither empty */
template<typename T, typename U, bool Same>
@ -306,8 +320,9 @@ namespace detail {
U p_second;
template<typename TT, typename UU>
CompressedPairBase(TT &&a, UU &&b): p_first(forward<TT>(a)),
p_second(forward<UU>(b)) {}
CompressedPairBase(TT &&a, UU &&b):
p_first(forward<TT>(a)), p_second(forward<UU>(b))
{}
T &first() { return p_first; }
T const &first() const { return p_first; }
@ -326,8 +341,9 @@ namespace detail {
U p_second;
template<typename TT, typename UU>
CompressedPairBase(TT &&a, UU &&b): T(forward<TT>(a)),
p_second(forward<UU>(b)) {}
CompressedPairBase(TT &&a, UU &&b):
T(forward<TT>(a)), p_second(forward<UU>(b))
{}
T &first() { return *this; }
T const &first() const { return *this; }
@ -345,8 +361,9 @@ namespace detail {
T p_first;
template<typename TT, typename UU>
CompressedPairBase(TT &&a, UU &&b): U(forward<UU>(b)),
p_first(forward<TT>(a)) {}
CompressedPairBase(TT &&a, UU &&b):
U(forward<UU>(b)), p_first(forward<TT>(a))
{}
T &first() { return p_first; }
T const &first() const { return p_first; }
@ -362,8 +379,9 @@ namespace detail {
template<typename T, typename U>
struct CompressedPairBase<T, U, 3>: T, U {
template<typename TT, typename UU>
CompressedPairBase(TT &&a, UU &&b): T(forward<TT>(a)),
U(forward<UU>(b)) {}
CompressedPairBase(TT &&a, UU &&b):
T(forward<TT>(a)), U(forward<UU>(b))
{}
T &first() { return *this; }
T const &first() const { return *this; }
@ -379,8 +397,9 @@ namespace detail {
using Base = CompressedPairBase<T, U>;
template<typename TT, typename UU>
CompressedPair(TT &&a, UU &&b): Base(forward<TT>(a),
forward<UU>(b)) {}
CompressedPair(TT &&a, UU &&b):
Base(forward<TT>(a), forward<UU>(b))
{}
T &first() { return Base::first(); }
T const &first() const { return Base::first(); }

View File

@ -26,7 +26,9 @@ class Vector {
VecPair p_buf;
void insert_base(Size idx, Size n) {
if (p_len + n > p_cap) reserve(p_len + n);
if (p_len + n > p_cap) {
reserve(p_len + n);
}
p_len += n;
for (Size i = p_len - 1; i > idx + n - 1; --i) {
p_buf.first()[i] = move(p_buf.first()[i - n]);
@ -34,10 +36,12 @@ class Vector {
}
template<typename R>
void ctor_from_range(R &range, EnableIf<
IsFiniteRandomAccessRange<R> && IsPod<T> &&
IsSame<T, RemoveCv<RangeValue<R>>>, bool
> = true) {
void ctor_from_range(
R &range, EnableIf<
IsFiniteRandomAccessRange<R> && IsPod<T> &&
IsSame<T, RemoveCv<RangeValue<R>>>, bool
> = true
) {
RangeSize<R> l = range.size();
reserve(l);
p_len = l;
@ -45,15 +49,18 @@ class Vector {
}
template<typename R>
void ctor_from_range(R &range, EnableIf<
!IsFiniteRandomAccessRange<R> || !IsPod<T> ||
!IsSame<T, RemoveCv<RangeValue<R>>>, bool
> = true) {
void ctor_from_range(
R &range, EnableIf<
!IsFiniteRandomAccessRange<R> || !IsPod<T> ||
!IsSame<T, RemoveCv<RangeValue<R>>>, bool
> = true
) {
Size i = 0;
for (; !range.empty(); range.pop_front()) {
reserve(i + 1);
allocator_construct(p_buf.second(), &p_buf.first()[i],
range.front());
allocator_construct(
p_buf.second(), &p_buf.first()[i], range.front()
);
++i;
p_len = i;
}
@ -86,16 +93,22 @@ public:
Vector(A const &a = A()): p_len(0), p_cap(0), p_buf(nullptr, a) {}
explicit Vector(Size n, T const &val = T(), A const &al = A()): Vector(al) {
if (!n) return;
if (!n) {
return;
}
p_buf.first() = allocator_allocate(p_buf.second(), n);
p_len = p_cap = n;
Pointer cur = p_buf.first(), last = p_buf.first() + n;
while (cur != last)
while (cur != last) {
allocator_construct(p_buf.second(), cur++, val);
}
}
Vector(Vector const &v): p_len(0), p_cap(0), p_buf(nullptr,
allocator_container_copy(v.p_buf.second())) {
Vector(Vector const &v):
p_len(0), p_cap(0), p_buf(nullptr, allocator_container_copy(
v.p_buf.second())
)
{
reserve(v.p_cap);
p_len = v.p_len;
copy_contents(v);
@ -107,8 +120,11 @@ public:
copy_contents(v);
}
Vector(Vector &&v): p_len(v.p_len), p_cap(v.p_cap), p_buf(v.p_buf.first(),
move(v.p_buf.second())) {
Vector(Vector &&v):
p_len(v.p_len), p_cap(v.p_cap), p_buf(
v.p_buf.first(), move(v.p_buf.second())
)
{
v.p_buf.first() = nullptr;
v.p_len = v.p_cap = 0;
}
@ -140,18 +156,21 @@ public:
if (IsPod<T>) {
memcpy(p_buf.first(), &r[0], r.size() * sizeof(T));
} else {
for (Size i = 0; i < r.size(); ++i)
for (Size i = 0; i < r.size(); ++i) {
allocator_construct(p_buf.second(), &p_buf.first()[i], r[i]);
}
}
p_len = r.size();
}
Vector(InitializerList<T> v, A const &a = A()):
Vector(ConstRange(v.begin(), v.size()), a) {}
Vector(ConstRange(v.begin(), v.size()), a)
{}
template<typename R, typename = EnableIf<
IsInputRange<R> && IsConvertible<RangeReference<R>, Value>
>> Vector(R range, A const &a = A()): Vector(a) {
>>
Vector(R range, A const &a = A()): Vector(a) {
ctor_from_range(range);
}
@ -163,14 +182,17 @@ public:
void clear() {
if (p_len > 0 && !IsPod<T>) {
Pointer cur = p_buf.first(), last = p_buf.first() + p_len;
while (cur != last)
while (cur != last) {
allocator_destroy(p_buf.second(), cur++);
}
}
p_len = 0;
}
Vector &operator=(Vector const &v) {
if (this == &v) return *this;
if (this == &v) {
return *this;
}
clear();
if (AllocatorPropagateOnContainerCopyAssignment<A>) {
if (p_buf.second() != v.p_buf.second() && p_cap) {
@ -187,10 +209,12 @@ public:
Vector &operator=(Vector &&v) {
clear();
if (p_buf.first())
if (p_buf.first()) {
allocator_deallocate(p_buf.second(), p_buf.first(), p_cap);
if (AllocatorPropagateOnContainerMoveAssignment<A>)
}
if (AllocatorPropagateOnContainerMoveAssignment<A>) {
p_buf.second() = v.p_buf.second();
}
p_len = v.p_len;
p_cap = v.p_cap;
p_buf.~VecPair();
@ -218,7 +242,8 @@ public:
template<typename R, typename = EnableIf<
IsInputRange<R> && IsConvertible<RangeReference<R>, Value>
>> Vector &operator=(R range) {
>>
Vector &operator=(R range) {
clear();
ctor_from_range(range);
return *this;
@ -239,13 +264,16 @@ public:
} else {
Pointer first = p_buf.first() + l;
Pointer last = p_buf.first() + p_len;
while (first != last)
while (first != last) {
allocator_construct(p_buf.second(), first++, v);
}
}
}
void reserve(Size n) {
if (n <= p_cap) return;
if (n <= p_cap) {
return;
}
Size oc = p_cap;
if (!oc) {
p_cap = max(n, Size(8));
@ -274,28 +302,38 @@ public:
T const &operator[](Size i) const { return p_buf.first()[i]; }
T *at(Size i) {
if (!in_range(i)) return nullptr;
if (!in_range(i)) {
return nullptr;
}
return &p_buf.first()[i];
}
T const *at(Size i) const {
if (!in_range(i)) return nullptr;
if (!in_range(i)) {
return nullptr;
}
return &p_buf.first()[i];
}
T &push(T const &v) {
if (p_len == p_cap) reserve(p_len + 1);
if (p_len == p_cap) {
reserve(p_len + 1);
}
allocator_construct(p_buf.second(), &p_buf.first()[p_len], v);
return p_buf.first()[p_len++];
}
T &push(T &&v) {
if (p_len == p_cap) reserve(p_len + 1);
if (p_len == p_cap) {
reserve(p_len + 1);
}
allocator_construct(p_buf.second(), &p_buf.first()[p_len], move(v));
return p_buf.first()[p_len++];
}
T &push() {
if (p_len == p_cap) reserve(p_len + 1);
if (p_len == p_cap) {
reserve(p_len + 1);
}
allocator_construct(p_buf.second(), &p_buf.first()[p_len]);
return p_buf.first()[p_len++];
}
@ -305,9 +343,11 @@ public:
if (IsPod<T>) {
memcpy(p_buf.first() + p_len, v, n * sizeof(T));
} else {
for (Size i = 0; i < n; ++i)
allocator_construct(p_buf.second(),
&p_buf.first()[p_len + i], v[i]);
for (Size i = 0; i < n; ++i) {
allocator_construct(
p_buf.second(), &p_buf.first()[p_len + i], v[i]
);
}
}
p_len += n;
return Range(&p_buf.first()[p_len - n], &p_buf.first()[p_len]);
@ -315,9 +355,12 @@ public:
template<typename ...U>
T &emplace_back(U &&...args) {
if (p_len == p_cap) reserve(p_len + 1);
allocator_construct(p_buf.second(), &p_buf.first()[p_len],
forward<U>(args)...);
if (p_len == p_cap) {
reserve(p_len + 1);
}
allocator_construct(
p_buf.second(), &p_buf.first()[p_len], forward<U>(args)...
);
return p_buf.first()[p_len++];
}
@ -415,8 +458,9 @@ public:
detail::swap_adl(p_len, v.p_len);
detail::swap_adl(p_cap, v.p_cap);
detail::swap_adl(p_buf.first(), v.p_buf.first());
if (AllocatorPropagateOnContainerSwap<A>)
if (AllocatorPropagateOnContainerSwap<A>) {
detail::swap_adl(p_buf.second(), v.p_buf.second());
}
}
A get_allocator() const {