refactoring, style updates, various fixes

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

View file

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

View file

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

View file

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

View file

@ -9,14 +9,18 @@ void print_result(Uint32 x) {
int main() { int main() {
FileStream wtest{"test.bin", StreamMode::write}; 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(); wtest.close();
FileStream rtest{"test.bin"}; FileStream rtest{"test.bin"};
writefln("stream size: %d", rtest.size()); 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); print_result(x);
}
return 0; return 0;
} }

View file

@ -9,7 +9,8 @@ int main() {
FileStream wtest{"test.txt", StreamMode::write}; FileStream wtest{"test.txt", StreamMode::write};
String smpl = "This is a test file for later read.\n" String smpl =
"This is a test file for later read.\n"
"It contains some sample text in order to see whether " "It contains some sample text in order to see whether "
"things actually read correctly.\n\n\n" "things actually read correctly.\n\n\n"
"" ""

View file

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

View file

@ -31,7 +31,8 @@ namespace detail {
T p_value; T p_value;
}; };
template<typename T> T atomic_create(); template<typename T>
T atomic_create();
template<typename T, typename U> template<typename T, typename U>
EnableIf<sizeof(T()->value = atomic_create<U>()), char> EnableIf<sizeof(T()->value = atomic_create<U>()), char>
@ -41,8 +42,8 @@ namespace detail {
int test_atomic_assignable(...); int test_atomic_assignable(...);
template<typename T, typename U> template<typename T, typename U>
constexpr bool CanAtomicAssign constexpr bool CanAtomicAssign =
= (sizeof(test_atomic_assignable<T, U>(1)) == sizeof(char)); (sizeof(test_atomic_assignable<T, U>(1)) == sizeof(char));
template<typename T> template<typename T>
static inline EnableIf< static inline EnableIf<
@ -59,7 +60,9 @@ namespace detail {
char volatile *to = reinterpret_cast<char volatile *>(&a->p_value); char volatile *to = reinterpret_cast<char volatile *>(&a->p_value);
char volatile *end = to + sizeof(T); char volatile *end = to + sizeof(T);
char *from = reinterpret_cast<char *>(&v); char *from = reinterpret_cast<char *>(&v);
while (to != end) *to++ =*from++; while (to != end) {
*to++ =*from++;
}
} }
template<typename T> template<typename T>
@ -88,21 +91,25 @@ static constexpr Size AtomicPointerLockFree = __GCC_ATOMIC_POINTER_LOCK_FREE;
namespace detail { namespace detail {
static inline constexpr int to_gcc_order(MemoryOrder ord) { static inline constexpr int to_gcc_order(MemoryOrder ord) {
return ((ord == MemoryOrder::relaxed) ? __ATOMIC_RELAXED : return (
((ord == MemoryOrder::relaxed) ? __ATOMIC_RELAXED :
((ord == MemoryOrder::acquire) ? __ATOMIC_ACQUIRE : ((ord == MemoryOrder::acquire) ? __ATOMIC_ACQUIRE :
((ord == MemoryOrder::release) ? __ATOMIC_RELEASE : ((ord == MemoryOrder::release) ? __ATOMIC_RELEASE :
((ord == MemoryOrder::seq_cst) ? __ATOMIC_SEQ_CST : ((ord == MemoryOrder::seq_cst) ? __ATOMIC_SEQ_CST :
((ord == MemoryOrder::acq_rel) ? __ATOMIC_ACQ_REL : ((ord == MemoryOrder::acq_rel) ? __ATOMIC_ACQ_REL :
__ATOMIC_CONSUME))))); __ATOMIC_CONSUME)))))
);
} }
static inline constexpr int to_gcc_failure_order(MemoryOrder ord) { static inline constexpr int to_gcc_failure_order(MemoryOrder ord) {
return ((ord == MemoryOrder::relaxed) ? __ATOMIC_RELAXED : return (
((ord == MemoryOrder::relaxed) ? __ATOMIC_RELAXED :
((ord == MemoryOrder::acquire) ? __ATOMIC_ACQUIRE : ((ord == MemoryOrder::acquire) ? __ATOMIC_ACQUIRE :
((ord == MemoryOrder::release) ? __ATOMIC_RELAXED : ((ord == MemoryOrder::release) ? __ATOMIC_RELAXED :
((ord == MemoryOrder::seq_cst) ? __ATOMIC_SEQ_CST : ((ord == MemoryOrder::seq_cst) ? __ATOMIC_SEQ_CST :
((ord == MemoryOrder::acq_rel) ? __ATOMIC_ACQUIRE : ((ord == MemoryOrder::acq_rel) ? __ATOMIC_ACQUIRE :
__ATOMIC_CONSUME))))); __ATOMIC_CONSUME)))))
);
} }
static inline void atomic_thread_fence(MemoryOrder ord) { static inline void atomic_thread_fence(MemoryOrder ord) {
@ -119,8 +126,9 @@ namespace detail {
} }
template<typename T> template<typename T>
static inline void atomic_store(AtomicBase<T> volatile *a, static inline void atomic_store(
T v, MemoryOrder ord) { AtomicBase<T> volatile *a, T v, MemoryOrder ord
) {
__atomic_store(&a->p_value, &v, to_gcc_order(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, AtomicBase<T> volatile *a, T *expected, T v,
MemoryOrder success, MemoryOrder failure MemoryOrder success, MemoryOrder failure
) { ) {
return __atomic_compare_exchange(&a->p_value, expected, &v, false, return __atomic_compare_exchange(
to_gcc_order(success), to_gcc_failure_order(failure)); &a->p_value, expected, &v, false,
to_gcc_order(success), to_gcc_failure_order(failure)
);
} }
template<typename T> template<typename T>
@ -172,8 +182,10 @@ namespace detail {
AtomicBase<T> *a, T *expected, T v, AtomicBase<T> *a, T *expected, T v,
MemoryOrder success, MemoryOrder failure MemoryOrder success, MemoryOrder failure
) { ) {
return __atomic_compare_exchange(&a->p_value, expected, &v, false, return __atomic_compare_exchange(
to_gcc_order(success), to_gcc_failure_order(failure)); &a->p_value, expected, &v, false,
to_gcc_order(success), to_gcc_failure_order(failure)
);
} }
template<typename T> template<typename T>
@ -181,8 +193,10 @@ namespace detail {
AtomicBase<T> volatile *a, T *expected, T v, AtomicBase<T> volatile *a, T *expected, T v,
MemoryOrder success, MemoryOrder failure MemoryOrder success, MemoryOrder failure
) { ) {
return __atomic_compare_exchange(&a->p_value, expected, &v, true, return __atomic_compare_exchange(
to_gcc_order(success), to_gcc_failure_order(failure)); &a->p_value, expected, &v, true,
to_gcc_order(success), to_gcc_failure_order(failure)
);
} }
template<typename T> template<typename T>
@ -190,8 +204,10 @@ namespace detail {
AtomicBase<T> *a, T *expected, T v, AtomicBase<T> *a, T *expected, T v,
MemoryOrder success, MemoryOrder failure MemoryOrder success, MemoryOrder failure
) { ) {
return __atomic_compare_exchange(&a->p_value, expected, &v, true, return __atomic_compare_exchange(
to_gcc_order(success), to_gcc_failure_order(failure)); &a->p_value, expected, &v, true,
to_gcc_order(success), to_gcc_failure_order(failure)
);
} }
template<typename T> template<typename T>
@ -200,84 +216,96 @@ namespace detail {
template<typename T> template<typename T>
struct SkipAmt<T *> { static constexpr Size value = sizeof(T); }; struct SkipAmt<T *> { static constexpr Size value = sizeof(T); };
template<typename T> struct SkipAmt<T[]> {}; template<typename T>
template<typename T, Size N> struct SkipAmt<T[N]> {}; struct SkipAmt<T[]> {};
template<typename T, Size N>
struct SkipAmt<T[N]> {};
template<typename T, typename U> template<typename T, typename U>
static inline T atomic_fetch_add(AtomicBase<T> volatile *a, static inline T atomic_fetch_add(
U d, MemoryOrder ord) { AtomicBase<T> volatile *a, U d, MemoryOrder ord
return __atomic_fetch_add(&a->p_value, d * SkipAmt<T>::value, ) {
to_gcc_order(ord)); return __atomic_fetch_add(
&a->p_value, d * SkipAmt<T>::value, to_gcc_order(ord)
);
} }
template<typename T, typename U> template<typename T, typename U>
static inline T atomic_fetch_add(AtomicBase<T> *a, static inline T atomic_fetch_add(
U d, MemoryOrder ord) { AtomicBase<T> *a, U d, MemoryOrder ord
return __atomic_fetch_add(&a->p_value, d * SkipAmt<T>::value, ) {
to_gcc_order(ord)); return __atomic_fetch_add(
&a->p_value, d * SkipAmt<T>::value, to_gcc_order(ord)
);
} }
template<typename T, typename U> template<typename T, typename U>
static inline T atomic_fetch_sub(AtomicBase<T> volatile *a, static inline T atomic_fetch_sub(
U d, MemoryOrder ord) { AtomicBase<T> volatile *a, U d, MemoryOrder ord
return __atomic_fetch_sub(&a->p_value, d * SkipAmt<T>::value, ) {
to_gcc_order(ord)); return __atomic_fetch_sub(
&a->p_value, d * SkipAmt<T>::value, to_gcc_order(ord)
);
} }
template<typename T, typename U> template<typename T, typename U>
static inline T atomic_fetch_sub(AtomicBase<T> *a, static inline T atomic_fetch_sub(
U d, MemoryOrder ord) { AtomicBase<T> *a, U d, MemoryOrder ord
return __atomic_fetch_sub(&a->p_value, d * SkipAmt<T>::value, ) {
to_gcc_order(ord)); return __atomic_fetch_sub(
&a->p_value, d * SkipAmt<T>::value, to_gcc_order(ord)
);
} }
template<typename T> template<typename T>
static inline T atomic_fetch_and(AtomicBase<T> volatile *a, static inline T atomic_fetch_and(
T pattern, MemoryOrder ord) { AtomicBase<T> volatile *a, T pattern, MemoryOrder ord
return __atomic_fetch_and(&a->p_value, pattern, ) {
to_gcc_order(ord)); return __atomic_fetch_and(&a->p_value, pattern, to_gcc_order(ord));
} }
template<typename T> template<typename T>
static inline T atomic_fetch_and(AtomicBase<T> *a, static inline T atomic_fetch_and(
T pattern, MemoryOrder ord) { AtomicBase<T> *a, T pattern, MemoryOrder ord
return __atomic_fetch_and(&a->p_value, pattern, ) {
to_gcc_order(ord)); return __atomic_fetch_and(&a->p_value, pattern, to_gcc_order(ord));
} }
template<typename T> template<typename T>
static inline T atomic_fetch_or(AtomicBase<T> volatile *a, static inline T atomic_fetch_or(
T pattern, MemoryOrder ord) { AtomicBase<T> volatile *a, T pattern, MemoryOrder ord
return __atomic_fetch_or(&a->p_value, pattern, ) {
to_gcc_order(ord)); return __atomic_fetch_or(&a->p_value, pattern, to_gcc_order(ord));
} }
template<typename T> template<typename T>
static inline T atomic_fetch_or(AtomicBase<T> *a, static inline T atomic_fetch_or(
T pattern, MemoryOrder ord) { AtomicBase<T> *a, T pattern, MemoryOrder ord
return __atomic_fetch_or(&a->p_value, pattern, ) {
to_gcc_order(ord)); return __atomic_fetch_or(&a->p_value, pattern, to_gcc_order(ord));
} }
template<typename T> template<typename T>
static inline T atomic_fetch_xor(AtomicBase<T> volatile *a, static inline T atomic_fetch_xor(
T pattern, MemoryOrder ord) { AtomicBase<T> volatile *a, T pattern, MemoryOrder ord
return __atomic_fetch_xor(&a->p_value, pattern, ) {
to_gcc_order(ord)); return __atomic_fetch_xor(&a->p_value, pattern, to_gcc_order(ord));
} }
template<typename T> template<typename T>
static inline T atomic_fetch_xor(AtomicBase<T> *a, static inline T atomic_fetch_xor(
T pattern, MemoryOrder ord) { AtomicBase<T> *a, T pattern, MemoryOrder ord
return __atomic_fetch_xor(&a->p_value, pattern, ) {
to_gcc_order(ord)); return __atomic_fetch_xor(&a->p_value, pattern, to_gcc_order(ord));
} }
} /* namespace detail */ } /* namespace detail */
#else #else
# error Unsupported compiler # error Unsupported compiler
#endif #endif
template <typename T> inline T kill_dependency(T v) { template <typename T>
inline T kill_dependency(T v) {
return v; return v;
} }
@ -330,45 +358,47 @@ namespace detail {
return atomic_exchange(&p_a, v, ord); return atomic_exchange(&p_a, v, ord);
} }
bool compare_exchange_weak(T &e, T v, MemoryOrder s, bool compare_exchange_weak(
MemoryOrder f) volatile { T &e, T v, MemoryOrder s, MemoryOrder f
) volatile {
return atomic_compare_exchange_weak(&p_a, &e, v, s, f); return atomic_compare_exchange_weak(&p_a, &e, v, s, f);
} }
bool compare_exchange_weak(T &e, T v, MemoryOrder s, bool compare_exchange_weak(T &e, T v, MemoryOrder s, MemoryOrder f) {
MemoryOrder f) {
return atomic_compare_exchange_weak(&p_a, &e, v, s, f); return atomic_compare_exchange_weak(&p_a, &e, v, s, f);
} }
bool compare_exchange_strong(T &e, T v, MemoryOrder s, bool compare_exchange_strong(
MemoryOrder f) volatile { T &e, T v, MemoryOrder s, MemoryOrder f
) volatile {
return atomic_compare_exchange_strong(&p_a, &e, v, s, f); return atomic_compare_exchange_strong(&p_a, &e, v, s, f);
} }
bool compare_exchange_strong(T &e, T v, MemoryOrder s, bool compare_exchange_strong(T &e, T v, MemoryOrder s, MemoryOrder f) {
MemoryOrder f) {
return atomic_compare_exchange_strong(&p_a, &e, v, s, f); return atomic_compare_exchange_strong(&p_a, &e, v, s, f);
} }
bool compare_exchange_weak(T &e, T v, MemoryOrder ord bool compare_exchange_weak(
= MemoryOrder::seq_cst) T &e, T v, MemoryOrder ord = MemoryOrder::seq_cst
volatile { ) volatile {
return atomic_compare_exchange_weak(&p_a, &e, v, ord, ord); return atomic_compare_exchange_weak(&p_a, &e, v, ord, ord);
} }
bool compare_exchange_weak(T &e, T v, MemoryOrder ord bool compare_exchange_weak(
= MemoryOrder::seq_cst) { T &e, T v, MemoryOrder ord = MemoryOrder::seq_cst
) {
return atomic_compare_exchange_weak(&p_a, &e, v, ord, ord); return atomic_compare_exchange_weak(&p_a, &e, v, ord, ord);
} }
bool compare_exchange_strong(T &e, T v, MemoryOrder ord bool compare_exchange_strong(
= MemoryOrder::seq_cst) T &e, T v, MemoryOrder ord = MemoryOrder::seq_cst
volatile { ) volatile {
return atomic_compare_exchange_strong(&p_a, &e, v, ord, ord); return atomic_compare_exchange_strong(&p_a, &e, v, ord, ord);
} }
bool compare_exchange_strong(T &e, T v, MemoryOrder ord bool compare_exchange_strong(
= MemoryOrder::seq_cst) { T &e, T v, MemoryOrder ord = MemoryOrder::seq_cst
) {
return atomic_compare_exchange_strong(&p_a, &e, v, ord, ord); return atomic_compare_exchange_strong(&p_a, &e, v, ord, ord);
} }
}; };
@ -581,20 +611,17 @@ inline T atomic_exchange(Atomic<T> *a, T v) {
} }
template <typename T> template <typename T>
inline T atomic_exchange_explicit(Atomic<T> volatile *a, T v, inline T atomic_exchange_explicit(Atomic<T> volatile *a, T v, MemoryOrder ord) {
MemoryOrder ord) {
return a->exchange(v, ord); return a->exchange(v, ord);
} }
template <typename T> template <typename T>
inline T atomic_exchange_explicit(Atomic<T> *a, T v, inline T atomic_exchange_explicit(Atomic<T> *a, T v, MemoryOrder ord) {
MemoryOrder ord) {
return a->exchange(v, ord); return a->exchange(v, ord);
} }
template <typename T> template <typename T>
inline bool atomic_compare_exchange_weak(Atomic<T> volatile *a, inline bool atomic_compare_exchange_weak(Atomic<T> volatile *a, T *e, T v) {
T *e, T v) {
return a->compare_exchange_weak(*e, 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> template <typename T>
inline bool atomic_compare_exchange_strong(Atomic<T> volatile *a, inline bool atomic_compare_exchange_strong(Atomic<T> volatile *a, T *e, T v) {
T *e, T v) {
return a->compare_exchange_strong(*e, 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> template <typename T>
inline bool atomic_compare_exchange_weak_explicit(Atomic<T> volatile *a, inline bool atomic_compare_exchange_weak_explicit(
T *e, T v, Atomic<T> volatile *a, T *e, T v, MemoryOrder s, MemoryOrder f
MemoryOrder s, ) {
MemoryOrder f) {
return a->compare_exchange_weak(*e, v, s, f); return a->compare_exchange_weak(*e, v, s, f);
} }
template <typename T> template <typename T>
inline bool atomic_compare_exchange_weak_explicit(Atomic<T> *a, T *e, inline bool atomic_compare_exchange_weak_explicit(
T v, Atomic<T> *a, T *e, T v, MemoryOrder s, MemoryOrder f
MemoryOrder s, ) {
MemoryOrder f) {
return a->compare_exchange_weak(*e, v, s, f); return a->compare_exchange_weak(*e, v, s, f);
} }
template <typename T> template <typename T>
inline bool atomic_compare_exchange_strong_explicit(Atomic<T> volatile *a, inline bool atomic_compare_exchange_strong_explicit(
T *e, T v, Atomic<T> volatile *a, T *e, T v, MemoryOrder s, MemoryOrder f
MemoryOrder s, ) {
MemoryOrder f) {
return a->compare_exchange_strong(*e, v, s, f); return a->compare_exchange_strong(*e, v, s, f);
} }
template <typename T> template <typename T>
inline bool atomic_compare_exchange_strong_explicit(Atomic<T> *a, T *e, inline bool atomic_compare_exchange_strong_explicit(
T v, Atomic<T> *a, T *e, T v, MemoryOrder s, MemoryOrder f
MemoryOrder s, ) {
MemoryOrder f) {
return a->compare_exchange_strong(*e, v, s, f); return a->compare_exchange_strong(*e, v, s, f);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_add(
atomic_fetch_add(Atomic<T> volatile *a, T op) { Atomic<T> volatile *a, T op
) {
return a->fetch_add(op); return a->fetch_add(op);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_add(
atomic_fetch_add(Atomic<T> *a, T op) { Atomic<T> *a, T op
) {
return a->fetch_add(op); return a->fetch_add(op);
} }
@ -669,39 +693,44 @@ inline T *atomic_fetch_add(Atomic<T *> *a, Ptrdiff op) {
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_add_explicit(
atomic_fetch_add_explicit(Atomic<T> volatile *a, T op, Atomic<T> volatile *a, T op, MemoryOrder ord
MemoryOrder ord) { ) {
return a->fetch_add(op, ord); return a->fetch_add(op, ord);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_add_explicit(
atomic_fetch_add_explicit(Atomic<T> *a, T op, MemoryOrder ord) { Atomic<T> *a, T op, MemoryOrder ord
) {
return a->fetch_add(op, ord); return a->fetch_add(op, ord);
} }
template <typename T> template <typename T>
inline T *atomic_fetch_add_explicit(Atomic<T *> volatile *a, inline T *atomic_fetch_add_explicit(
Ptrdiff op, MemoryOrder ord) { Atomic<T *> volatile *a, Ptrdiff op, MemoryOrder ord
) {
return a->fetch_add(op, ord); return a->fetch_add(op, ord);
} }
template <typename T> template <typename T>
inline T *atomic_fetch_add_explicit(Atomic<T *> *a, Ptrdiff op, inline T *atomic_fetch_add_explicit(
MemoryOrder ord) { Atomic<T *> *a, Ptrdiff op, MemoryOrder ord
) {
return a->fetch_add(op, ord); return a->fetch_add(op, ord);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_sub(
atomic_fetch_sub(Atomic<T> volatile *a, T op) { Atomic<T> volatile *a, T op
) {
return a->fetch_sub(op); return a->fetch_sub(op);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_sub(
atomic_fetch_sub(Atomic<T> *a, T op) { Atomic<T> *a, T op
) {
return a->fetch_sub(op); return a->fetch_sub(op);
} }
@ -716,102 +745,114 @@ inline T *atomic_fetch_sub(Atomic<T *> *a, Ptrdiff op) {
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_sub_explicit(
atomic_fetch_sub_explicit(Atomic<T> volatile *a, T op, Atomic<T> volatile *a, T op, MemoryOrder ord
MemoryOrder ord) { ) {
return a->fetch_sub(op, ord); return a->fetch_sub(op, ord);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_sub_explicit(
atomic_fetch_sub_explicit(Atomic<T> *a, T op, MemoryOrder ord) { Atomic<T> *a, T op, MemoryOrder ord
) {
return a->fetch_sub(op, ord); return a->fetch_sub(op, ord);
} }
template <typename T> template <typename T>
inline T *atomic_fetch_sub_explicit(Atomic<T *> volatile *a, inline T *atomic_fetch_sub_explicit(
Ptrdiff op, MemoryOrder ord) { Atomic<T *> volatile *a, Ptrdiff op, MemoryOrder ord
) {
return a->fetch_sub(op, ord); return a->fetch_sub(op, ord);
} }
template <typename T> template <typename T>
inline T *atomic_fetch_sub_explicit(Atomic<T *> *a, Ptrdiff op, inline T *atomic_fetch_sub_explicit(
MemoryOrder ord) { Atomic<T *> *a, Ptrdiff op, MemoryOrder ord
) {
return a->fetch_sub(op, ord); return a->fetch_sub(op, ord);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_and(
atomic_fetch_and(Atomic<T> volatile *a, T op) { Atomic<T> volatile *a, T op
) {
return a->fetch_and(op); return a->fetch_and(op);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_and(
atomic_fetch_and(Atomic<T> *a, T op) { Atomic<T> *a, T op
) {
return a->fetch_and(op); return a->fetch_and(op);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_and_explicit(
atomic_fetch_and_explicit(Atomic<T> volatile *a, T op, Atomic<T> volatile *a, T op, MemoryOrder ord
MemoryOrder ord) { ) {
return a->fetch_and(op, ord); return a->fetch_and(op, ord);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_and_explicit(
atomic_fetch_and_explicit(Atomic<T> *a, T op, MemoryOrder ord) { Atomic<T> *a, T op, MemoryOrder ord
) {
return a->fetch_and(op, ord); return a->fetch_and(op, ord);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_or(
atomic_fetch_or(Atomic<T> volatile *a, T op) { Atomic<T> volatile *a, T op
) {
return a->fetch_or(op); return a->fetch_or(op);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_or(
atomic_fetch_or(Atomic<T> *a, T op) { Atomic<T> *a, T op
) {
return a->fetch_or(op); return a->fetch_or(op);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_or_explicit(
atomic_fetch_or_explicit(Atomic<T> volatile *a, T op, Atomic<T> volatile *a, T op, MemoryOrder ord
MemoryOrder ord) { ) {
return a->fetch_or(op, ord); return a->fetch_or(op, ord);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_or_explicit(
atomic_fetch_or_explicit(Atomic<T> *a, T op, MemoryOrder ord) { Atomic<T> *a, T op, MemoryOrder ord
) {
return a->fetch_or(op, ord); return a->fetch_or(op, ord);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_xor(
atomic_fetch_xor(Atomic<T> volatile *a, T op) { Atomic<T> volatile *a, T op
) {
return a->fetch_xor(op); return a->fetch_xor(op);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_xor(
atomic_fetch_xor(Atomic<T> *a, T op) { Atomic<T> *a, T op
) {
return a->fetch_xor(op); return a->fetch_xor(op);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_xor_explicit(
atomic_fetch_xor_explicit(Atomic<T> volatile *a, T op, Atomic<T> volatile *a, T op, MemoryOrder ord
MemoryOrder ord) { ) {
return a->fetch_xor(op, ord); return a->fetch_xor(op, ord);
} }
template <typename T> template <typename T>
inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> inline EnableIf<IsIntegral<T> && !IsSame<T, bool>, T> atomic_fetch_xor_explicit(
atomic_fetch_xor_explicit(Atomic<T> *a, T op, MemoryOrder ord) { Atomic<T> *a, T op, MemoryOrder ord
) {
return a->fetch_xor(op, 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(); return a->test_and_set();
} }
inline bool atomic_flag_test_and_set_explicit(AtomicFlag volatile *a, inline bool atomic_flag_test_and_set_explicit(
MemoryOrder ord) { AtomicFlag volatile *a, MemoryOrder ord
) {
return a->test_and_set(ord); return a->test_and_set(ord);
} }
inline bool atomic_flag_test_and_set_explicit(AtomicFlag *a, inline bool atomic_flag_test_and_set_explicit(AtomicFlag *a, MemoryOrder ord) {
MemoryOrder ord) {
return a->test_and_set(ord); return a->test_and_set(ord);
} }
@ -870,8 +911,7 @@ inline void atomic_flag_clear(AtomicFlag *a) {
a->clear(); a->clear();
} }
inline void atomic_flag_clear_explicit(AtomicFlag volatile *a, inline void atomic_flag_clear_explicit(AtomicFlag volatile *a, MemoryOrder ord) {
MemoryOrder ord) {
a->clear(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)); auto tbuf = to_temp_cstr(name, buf, sizeof(buf));
#ifndef OSTD_PLATFORM_WIN32 #ifndef OSTD_PLATFORM_WIN32
char const *ret = getenv(tbuf.get()); char const *ret = getenv(tbuf.get());
if (!ret) return ostd::nothing; if (!ret) {
return ostd::nothing;
}
return ostd::move(String(ret)); return ostd::move(String(ret));
#else #else
String rbuf; String rbuf;
for (;;) { for (;;) {
auto ret = GetEnvironmentVariable(tbuf.get(), rbuf.data(), auto ret = GetEnvironmentVariable(
rbuf.capacity() + 1); tbuf.get(), rbuf.data(), rbuf.capacity() + 1
if (!ret) return ostd::nothing; );
if (!ret) {
return ostd::nothing;
}
if (ret <= rbuf.capacity()) { if (ret <= rbuf.capacity()) {
rbuf.advance(ret); rbuf.advance(ret);
break; break;
@ -42,13 +47,15 @@ inline Maybe<String> env_get(ConstCharRange name) {
#endif #endif
} }
inline bool env_set(ConstCharRange name, ConstCharRange value, inline bool env_set(
bool update = true) { ConstCharRange name, ConstCharRange value, bool update = true
) {
char sbuf[2048]; char sbuf[2048];
char *buf = sbuf; char *buf = sbuf;
bool alloc = (name.size() + value.size() + 2) > sizeof(sbuf); bool alloc = (name.size() + value.size() + 2) > sizeof(sbuf);
if (alloc) if (alloc) {
buf = new char[name.size() + value.size() + 2]; buf = new char[name.size() + value.size() + 2];
}
memcpy(buf, name.data(), name.size()); memcpy(buf, name.data(), name.size());
buf[name.size()] = '\0'; buf[name.size()] = '\0';
memcpy(&buf[name.size() + 1], value.data(), value.size()); 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 #ifndef OSTD_PLATFORM_WIN32
bool ret = !setenv(buf, &buf[name.size() + 1], update); bool ret = !setenv(buf, &buf[name.size() + 1], update);
#else #else
if (!update && GetEnvironmentVariable(buf, nullptr, 0)) if (!update && GetEnvironmentVariable(buf, nullptr, 0)) {
return true; return true;
}
bool ret = !!SetEnvironmentVariable(buf, &buf[name.size() + 1]); bool ret = !!SetEnvironmentVariable(buf, &buf[name.size() + 1]);
#endif #endif
if (alloc) if (alloc) {
delete[] buf; delete[] buf;
}
return ret; return ret;
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -17,7 +17,8 @@ namespace ostd {
/* tuple size */ /* tuple size */
template<typename ...T> constexpr Size TupleSize<Tuple<T...>> = sizeof...(T); template<typename ...T>
constexpr Size TupleSize<Tuple<T...>> = sizeof...(T);
/* tuple element */ /* tuple element */
@ -32,71 +33,100 @@ namespace detail {
template<Size I, typename H, bool = IsEmpty<H>> template<Size I, typename H, bool = IsEmpty<H>>
struct TupleLeaf { struct TupleLeaf {
constexpr TupleLeaf(): p_value() { constexpr TupleLeaf(): p_value() {
static_assert(!IsReference<H>, static_assert(
"attempt to default construct a reference element in a tuple"); !IsReference<H>,
"attempt to default construct a reference element in a tuple"
);
} }
template<typename A> template<typename A>
TupleLeaf(Constant<int, 0>, A const &): p_value() { TupleLeaf(Constant<int, 0>, A const &): p_value() {
static_assert(!IsReference<H>, static_assert(
"attempt to default construct a reference element in a tuple"); !IsReference<H>,
"attempt to default construct a reference element in a tuple"
);
} }
template<typename A> template<typename A>
TupleLeaf(Constant<int, 1>, A const &a): p_value(allocator_arg, a) { TupleLeaf(Constant<int, 1>, A const &a): p_value(allocator_arg, a) {
static_assert(!IsReference<H>, static_assert(
"attempt to default construct a reference element in a tuple"); !IsReference<H>,
"attempt to default construct a reference element in a tuple"
);
} }
template<typename A> template<typename A>
TupleLeaf(Constant<int, 2>, A const &a): p_value(a) { TupleLeaf(Constant<int, 2>, A const &a): p_value(a) {
static_assert(!IsReference<H>, static_assert(
"attempt to default construct a reference element in a tuple"); !IsReference<H>,
"attempt to default construct a reference element in a tuple"
);
} }
template<typename T, typename = EnableIf< template<typename T, typename = EnableIf<
!IsSame<Decay<T>, TupleLeaf> && IsConstructible<H, T> !IsSame<Decay<T>, TupleLeaf> && IsConstructible<H, T>
>> >>
explicit TupleLeaf(T &&t): p_value(forward<T>(t)) { explicit TupleLeaf(T &&t): p_value(forward<T>(t)) {
static_assert(!IsReference<H> || static_assert(
(IsLvalueReference<H> && !IsReference<H> || (
(IsLvalueReference<T> || IsLvalueReference<H> && (
IsSame<RemoveReference<T>, IsLvalueReference<T> || IsSame<
ReferenceWrapper<RemoveReference<H>>>)) || RemoveReference<T>,
(IsRvalueReference<H> && ReferenceWrapper<RemoveReference<H>>
!IsLvalueReference<T>), >
"attempt to construct a reference element in a tuple with an rvalue"); )
) || (IsRvalueReference<H> && !IsLvalueReference<T>),
"attempt to construct a reference element in a tuple with an rvalue"
);
} }
template<typename T, typename A> template<typename T, typename A>
explicit TupleLeaf(Constant<int, 0>, A const &, T &&t): explicit TupleLeaf(Constant<int, 0>, A const &, T &&t):
p_value(forward<T>(t)) { p_value(forward<T>(t))
static_assert(!IsLvalueReference<H> || {
(IsLvalueReference<H> && static_assert(
(IsLvalueReference<T> || !IsLvalueReference<H> || (
IsSame<RemoveReference<T>, IsLvalueReference<H> && (
ReferenceWrapper<RemoveReference<H>>>)), IsLvalueReference<T> || IsSame<
"attempt to construct a reference element in a tuple with an rvalue"); RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>
>
)
),
"attempt to construct a reference element in a tuple with an rvalue"
);
} }
template<typename T, typename A> template<typename T, typename A>
explicit TupleLeaf(Constant<int, 1>, A const &a, T &&t): explicit TupleLeaf(Constant<int, 1>, A const &a, T &&t):
p_value(allocator_arg, a, forward<T>(t)) { p_value(allocator_arg, a, forward<T>(t))
static_assert(!IsLvalueReference<H> || {
(IsLvalueReference<H> && static_assert(
(IsLvalueReference<T> || !IsLvalueReference<H> || (
IsSame<RemoveReference<T>, IsLvalueReference<H> && (
ReferenceWrapper<RemoveReference<H>>>)), IsLvalueReference<T> || IsSame<
"attempt to construct a reference element in a tuple with an rvalue"); RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>
>
)
),
"attempt to construct a reference element in a tuple with an rvalue"
);
} }
template<typename T, typename A> template<typename T, typename A>
explicit TupleLeaf(Constant<int, 2>, A const &a, T &&t): explicit TupleLeaf(Constant<int, 2>, A const &a, T &&t):
p_value(forward<T>(t), a) { p_value(forward<T>(t), a)
static_assert(!IsLvalueReference<H> || {
(IsLvalueReference<H> && static_assert(
(IsLvalueReference<T> || !IsLvalueReference<H> || (
IsSame<RemoveReference<T>, IsLvalueReference<H> && (
ReferenceWrapper<RemoveReference<H>>>)), IsLvalueReference<T> || IsSame<
"attempt to construct a reference element in a tuple with an rvalue"); RemoveReference<T>,
ReferenceWrapper<RemoveReference<H>>
>
)
),
"attempt to construct a reference element in a tuple with an rvalue"
);
} }
TupleLeaf(TupleLeaf const &) = default; TupleLeaf(TupleLeaf const &) = default;
@ -129,26 +159,31 @@ namespace detail {
template<typename A> template<typename A>
TupleLeaf(Constant<int, 1>, A const &a): TupleLeaf(Constant<int, 1>, A const &a):
H(allocator_arg, a) {} H(allocator_arg, a)
{}
template<typename A> template<typename A>
TupleLeaf(Constant<int, 2>, A const &a): H(a) {} TupleLeaf(Constant<int, 2>, A const &a): H(a) {}
template<typename T, typename = EnableIf< template<typename T, typename = EnableIf<
!IsSame<Decay<T>, TupleLeaf> && IsConstructible<H, T> !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> template<typename T, typename A>
explicit TupleLeaf(Constant<int, 0>, A const &, T &&t): explicit TupleLeaf(Constant<int, 0>, A const &, T &&t):
H(forward<T>(t)) {} H(forward<T>(t))
{}
template<typename T, typename A> template<typename T, typename A>
explicit TupleLeaf(Constant<int, 1>, A const &a, T &&t): 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> template<typename T, typename A>
explicit TupleLeaf(Constant<int, 2>, A const &a, T &&t): 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 const &) = default;
TupleLeaf(TupleLeaf &&) = default; TupleLeaf(TupleLeaf &&) = default;
@ -187,58 +222,73 @@ namespace detail {
constexpr bool TupleAllDefaultConstructible = detail::Undefined<T>(); constexpr bool TupleAllDefaultConstructible = detail::Undefined<T>();
template<typename ...A> template<typename ...A>
constexpr bool TupleAllDefaultConstructible<TupleTypes<A...>> constexpr bool TupleAllDefaultConstructible<TupleTypes<A...>> =
= TupleAll<IsDefaultConstructible<A>...>; TupleAll<IsDefaultConstructible<A>...>;
} }
/* tuple implementation */ /* tuple implementation */
namespace detail { namespace detail {
template<typename, typename ...> struct TupleBase; template<typename, typename ...>
struct TupleBase;
template<Size ...I, typename ...A> template<Size ...I, typename ...A>
struct TupleBase<TupleIndices<I...>, A...>: TupleLeaf<I, A>... { struct TupleBase<TupleIndices<I...>, A...>: TupleLeaf<I, A>... {
constexpr TupleBase() {} constexpr TupleBase() {}
template<Size ...Ia, typename ...Aa, template<
Size ...Ib, typename ...Ab, typename ...T> Size ...Ia, typename ...Aa, Size ...Ib,
explicit TupleBase(TupleIndices<Ia...>, TupleTypes<Aa...>, typename ...Ab, typename ...T
TupleIndices<Ib...>, TupleTypes<Ab...>, >
T &&...t): explicit TupleBase(
TupleLeaf<Ia, Aa>(forward<T>(t))...,
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<Ia...>, TupleTypes<Aa...>,
TupleIndices<Ib...>, TupleTypes<Ab...>, TupleIndices<Ib...>, TupleTypes<Ab...>, T &&...t
T &&...t): ):
TupleLeaf<Ia, Aa>(UsesAllocatorConstructor<Aa, Alloc, T>, a, TupleLeaf<Ia, Aa>(forward<T>(t))...,
forward<T>(t))..., 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)
)...,
TupleLeaf<Ib, Ab>(UsesAllocatorConstructor<Ab, Alloc>, a)... TupleLeaf<Ib, Ab>(UsesAllocatorConstructor<Ab, Alloc>, a)...
{} {}
template<typename T, typename = EnableIf< template<typename T, typename = EnableIf<
TupleConstructible<T, Tuple<A...>> TupleConstructible<T, Tuple<A...>>
>> TupleBase(T &&t): TupleLeaf<I, A>(forward< >>
TupleElement<I, MakeTupleTypes<T>> TupleBase(T &&t):
>(get<I>(t)))... {} TupleLeaf<I, A>(
forward<TupleElement<I, MakeTupleTypes<T>>>(get<I>(t))
)...
{}
template<typename Alloc, typename T, typename = EnableIf< template<typename Alloc, typename T, typename = EnableIf<
TupleConvertible<T, Tuple<A...>> TupleConvertible<T, Tuple<A...>>
>> TupleBase(AllocatorArg, Alloc const &a, T &&t): >>
TupleLeaf<I, A>(UsesAllocatorConstructor< TupleBase(AllocatorArg, Alloc const &a, T &&t):
TupleLeaf<I, A>(
UsesAllocatorConstructor<
A, Alloc, TupleElement<I, MakeTupleTypes<T>> A, Alloc, TupleElement<I, MakeTupleTypes<T>>
>, a, forward<TupleElement<I, MakeTupleTypes<T>>>(get<I>(t)))... >, a, forward<TupleElement<I, MakeTupleTypes<T>>>(get<I>(t))
)...
{} {}
template<typename T> template<typename T>
EnableIf<TupleAssignable<T, Tuple<A...>>, TupleBase &> EnableIf<TupleAssignable<T, Tuple<A...>>, TupleBase &> operator=(T &&t) {
operator=(T &&t) { tuple_swallow(TupleLeaf<I, A>::operator=(
tuple_swallow(TupleLeaf<I, A>::operator=(forward< forward<TupleElement<I, MakeTupleTypes<T>>>(get<I>(t))
TupleElement<I, MakeTupleTypes<T>> )...);
>(get<I>(t)))...);
return *this; return *this;
} }
@ -246,19 +296,23 @@ namespace detail {
TupleBase(TupleBase &&) = default; TupleBase(TupleBase &&) = default;
TupleBase &operator=(TupleBase const &t) { TupleBase &operator=(TupleBase const &t) {
tuple_swallow(TupleLeaf<I, A>::operator=(( tuple_swallow(TupleLeaf<I, A>::operator=(
static_cast<TupleLeaf<I, A> const &>(t)).get())...); (static_cast<TupleLeaf<I, A> const &>(t)).get()
)...);
return *this; return *this;
} }
TupleBase &operator=(TupleBase &&t) { TupleBase &operator=(TupleBase &&t) {
tuple_swallow(TupleLeaf<I, A>::operator=(forward<A> tuple_swallow(TupleLeaf<I, A>::operator=(
((static_cast<TupleLeaf<I, A> &>(t)).get()))...); forward<A>((static_cast<TupleLeaf<I, A> &>(t)).get())
)...);
return *this; return *this;
} }
void swap(TupleBase &t) { 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 */ } /* namespace detail */
@ -283,110 +337,130 @@ class Tuple {
public: public:
template<bool D = true, typename = EnableIf< template<bool D = true, typename = EnableIf<
detail::TupleAll<(D && IsDefaultConstructible<A>)...> detail::TupleAll<(D && IsDefaultConstructible<A>)...>
>> Tuple() {} >>
Tuple() {}
explicit Tuple(A const &...t): explicit Tuple(A const &...t):
p_base(detail::MakeTupleIndices<sizeof...(A)>(), p_base(
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,
detail::MakeTupleIndices<sizeof...(A)>(), detail::MakeTupleIndices<sizeof...(A)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A)>(), detail::MakeTupleTypes<Tuple, sizeof...(A)>(),
detail::MakeTupleIndices<0>(), 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< template<typename ...T, EnableIf<
(sizeof...(T) <= sizeof...(A)) && (sizeof...(T) <= sizeof...(A)) &&
detail::TupleConvertible< detail::TupleConvertible<
Tuple<T...>, Tuple<T...>,
detail::MakeTupleTypes<Tuple, detail::MakeTupleTypes<
(sizeof...(T) < sizeof...(A)) ? sizeof...(T) Tuple,
: sizeof...(A) (sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A)
> >
> && > &&
detail::TupleAllDefaultConstructible< detail::TupleAllDefaultConstructible<
detail::MakeTupleTypes<Tuple, sizeof...(A), detail::MakeTupleTypes<
(sizeof...(T) < sizeof...(A)) ? sizeof...(T) Tuple, sizeof...(A),
: sizeof...(A) (sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A)
> >
>, bool >, bool
> = true> > = true>
Tuple(T &&...t): Tuple(T &&...t):
p_base(detail::MakeTupleIndices<sizeof...(T)>(), p_base(
detail::MakeTupleIndices<sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(T)>(), detail::MakeTupleTypes<Tuple, sizeof...(T)>(),
detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(), detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(), detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(),
forward<T>(t)...) {} forward<T>(t)...
)
{}
template<typename ...T, EnableIf< template<typename ...T, EnableIf<
(sizeof...(T) <= sizeof...(A)) && (sizeof...(T) <= sizeof...(A)) &&
detail::TupleConstructible< detail::TupleConstructible<
Tuple<T...>, Tuple<T...>,
detail::MakeTupleTypes<Tuple, detail::MakeTupleTypes<
(sizeof...(T) < sizeof...(A)) ? sizeof...(T) Tuple,
: sizeof...(A) (sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A)
> >
> && > &&
!detail::TupleConvertible< !detail::TupleConvertible<
Tuple<T...>, Tuple<T...>,
detail::MakeTupleTypes<Tuple, detail::MakeTupleTypes<
(sizeof...(T) < sizeof...(A)) ? sizeof...(T) Tuple,
: sizeof...(A) (sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A)
> >
> && > &&
detail::TupleAllDefaultConstructible< detail::TupleAllDefaultConstructible<
detail::MakeTupleTypes<Tuple, sizeof...(A), detail::MakeTupleTypes<
(sizeof...(T) < sizeof...(A)) ? sizeof...(T) Tuple, sizeof...(A),
: sizeof...(A) (sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A)
> >
>, bool >, bool
> = true> > = true>
Tuple(T &&...t): Tuple(T &&...t):
p_base(detail::MakeTupleIndices<sizeof...(T)>(), p_base(
detail::MakeTupleIndices<sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(T)>(), detail::MakeTupleTypes<Tuple, sizeof...(T)>(),
detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(), detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(), detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(),
forward<T>(t)...) {} forward<T>(t)...
)
{}
template<typename Alloc, typename ...T, typename = EnableIf< template<typename Alloc, typename ...T, typename = EnableIf<
(sizeof...(T) <= sizeof...(A)) && (sizeof...(T) <= sizeof...(A)) &&
detail::TupleConvertible< detail::TupleConvertible<
Tuple<T...>, Tuple<T...>,
detail::MakeTupleTypes<Tuple, detail::MakeTupleTypes<
(sizeof...(T) < sizeof...(A)) ? sizeof...(T) Tuple,
: sizeof...(A) (sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A)
> >
> && > &&
detail::TupleAllDefaultConstructible< detail::TupleAllDefaultConstructible<
detail::MakeTupleTypes<Tuple, sizeof...(A), detail::MakeTupleTypes<
(sizeof...(T) < sizeof...(A)) ? sizeof...(T) Tuple, sizeof...(A),
: sizeof...(A) (sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A)
> >
> >
>> Tuple(AllocatorArg, Alloc const &a, T &&...t): >> Tuple(AllocatorArg, Alloc const &a, T &&...t):
p_base(allocator_arg, a, detail::MakeTupleIndices<sizeof...(T)>(), p_base(
allocator_arg, a, detail::MakeTupleIndices<sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(T)>(), detail::MakeTupleTypes<Tuple, sizeof...(T)>(),
detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(), detail::MakeTupleIndices<sizeof...(A), sizeof...(T)>(),
detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(), detail::MakeTupleTypes<Tuple, sizeof...(A), sizeof...(T)>(),
forward<T>(t)...) {} forward<T>(t)...
)
{}
template<typename T, EnableIf< template<typename T, EnableIf<
detail::TupleConvertible<T, Tuple>, bool 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< template<typename T, EnableIf<
detail::TupleConstructible<T, Tuple> && detail::TupleConstructible<T, Tuple> &&
!detail::TupleConvertible<T, Tuple>, bool !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< template<typename Alloc, typename T, typename = EnableIf<
detail::TupleConvertible<T, Tuple> 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>>> template<typename T, typename = EnableIf<detail::TupleAssignable<T, Tuple>>>
Tuple &operator=(T &&t) { Tuple &operator=(T &&t) {
@ -473,8 +547,7 @@ namespace detail {
} }
template<typename ...T> template<typename ...T>
inline Tuple<typename detail::MakeTupleReturn<T>::Type...> inline Tuple<typename detail::MakeTupleReturn<T>::Type...> make_tuple(T &&...t) {
make_tuple(T &&...t) {
return Tuple<typename detail::MakeTupleReturn<T>::Type...>(forward<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 */ /* declval */
template<typename T> AddRvalueReference<T> declval(); template<typename T>
AddRvalueReference<T> declval();
/* swap */ /* swap */
@ -54,33 +55,38 @@ namespace detail {
template<typename> template<typename>
False test_swap(...); False test_swap(...);
template<typename T> inline void swap_fb(T &a, T &b, EnableIf< template<typename T>
decltype(test_swap<T>(0))::value, bool inline void swap_fb(
> = true) { T &a, T &b, EnableIf<decltype(test_swap<T>(0))::value, bool> = true
) {
a.swap(b); a.swap(b);
} }
template<typename T> inline void swap_fb(T &a, T &b, EnableIf< template<typename T>
!decltype(test_swap<T>(0))::value, bool inline void swap_fb(
> = true) { T &a, T &b, EnableIf<!decltype(test_swap<T>(0))::value, bool> = true
) {
T c(move(a)); T c(move(a));
a = move(b); a = move(b);
b = move(c); 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); 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) { for (Size i = 0; i < N; ++i) {
swap(a[i], b[i]); swap(a[i], b[i]);
} }
} }
namespace detail { 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; using ostd::swap;
swap(a, b); swap(a, b);
} }
@ -103,14 +109,16 @@ struct Pair {
template<typename TT, typename UU> template<typename TT, typename UU>
Pair(TT &&x, UU &&y): 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> template<typename TT, typename UU>
Pair(Pair<TT, UU> const &v): first(v.first), second(v.second) {} Pair(Pair<TT, UU> const &v): first(v.first), second(v.second) {}
template<typename TT, typename UU> template<typename TT, typename UU>
Pair(Pair<TT, UU> &&v): 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) { Pair &operator=(Pair const &v) {
first = v.first; first = v.first;
@ -144,7 +152,8 @@ struct Pair {
} }
}; };
template<typename T> struct ReferenceWrapper; template<typename T>
struct ReferenceWrapper;
namespace detail { namespace detail {
template<typename T> template<typename T>
@ -164,12 +173,13 @@ namespace detail {
} /* namespace detail */ } /* namespace detail */
template<typename T, typename U> template<typename T, typename U>
inline Pair<typename detail::MakePairRet<T>::Type, inline Pair<
typename detail::MakePairRet<U>::Type typename detail::MakePairRet<T>::Type, typename detail::MakePairRet<U>::Type
> make_pair(T &&a, U &&b) { > make_pair(T &&a, U &&b) {
return Pair<typename detail::MakePairRet<T>::Type, return Pair<
typename detail::MakePairRet<T>::Type,
typename detail::MakePairRet<U>::Type typename detail::MakePairRet<U>::Type
>(forward<T>(a), forward<U>(b));; >(forward<T>(a), forward<U>(b));
} }
template<typename T, typename U> template<typename T, typename U>
@ -222,9 +232,11 @@ struct TupleElementBase<1, Pair<T, U>> {
}; };
namespace detail { namespace detail {
template<Size> struct GetPair; template<Size>
struct GetPair;
template<> struct GetPair<0> { template<>
struct GetPair<0> {
template<typename T, typename U> template<typename T, typename U>
static T &get(Pair<T, U> &p) { return p.first; } static T &get(Pair<T, U> &p) { return p.first; }
template<typename T, typename U> template<typename T, typename U>
@ -237,7 +249,8 @@ namespace detail {
} }
}; };
template<> struct GetPair<1> { template<>
struct GetPair<1> {
template<typename T, typename U> template<typename T, typename U>
static U &get(Pair<T, U> &p) { return p.second; } static U &get(Pair<T, U> &p) { return p.second; }
template<typename T, typename U> template<typename T, typename U>
@ -275,7 +288,8 @@ namespace detail {
template<typename T, typename U, template<typename T, typename U,
bool = IsSame<RemoveCv<T>, RemoveCv<U>>, bool = IsSame<RemoveCv<T>, RemoveCv<U>>,
bool = IsEmpty<T>, bool = IsEmpty<U> bool = IsEmpty<T>, bool = IsEmpty<U>
> constexpr Size CompressedPairSwitch = detail::Undefined<T>(); >
constexpr Size CompressedPairSwitch = detail::Undefined<T>();
/* neither empty */ /* neither empty */
template<typename T, typename U, bool Same> template<typename T, typename U, bool Same>
@ -306,8 +320,9 @@ namespace detail {
U p_second; U p_second;
template<typename TT, typename UU> template<typename TT, typename UU>
CompressedPairBase(TT &&a, UU &&b): p_first(forward<TT>(a)), CompressedPairBase(TT &&a, UU &&b):
p_second(forward<UU>(b)) {} p_first(forward<TT>(a)), p_second(forward<UU>(b))
{}
T &first() { return p_first; } T &first() { return p_first; }
T const &first() const { return p_first; } T const &first() const { return p_first; }
@ -326,8 +341,9 @@ namespace detail {
U p_second; U p_second;
template<typename TT, typename UU> template<typename TT, typename UU>
CompressedPairBase(TT &&a, UU &&b): T(forward<TT>(a)), CompressedPairBase(TT &&a, UU &&b):
p_second(forward<UU>(b)) {} T(forward<TT>(a)), p_second(forward<UU>(b))
{}
T &first() { return *this; } T &first() { return *this; }
T const &first() const { return *this; } T const &first() const { return *this; }
@ -345,8 +361,9 @@ namespace detail {
T p_first; T p_first;
template<typename TT, typename UU> template<typename TT, typename UU>
CompressedPairBase(TT &&a, UU &&b): U(forward<UU>(b)), CompressedPairBase(TT &&a, UU &&b):
p_first(forward<TT>(a)) {} U(forward<UU>(b)), p_first(forward<TT>(a))
{}
T &first() { return p_first; } T &first() { return p_first; }
T const &first() const { return p_first; } T const &first() const { return p_first; }
@ -362,8 +379,9 @@ namespace detail {
template<typename T, typename U> template<typename T, typename U>
struct CompressedPairBase<T, U, 3>: T, U { struct CompressedPairBase<T, U, 3>: T, U {
template<typename TT, typename UU> template<typename TT, typename UU>
CompressedPairBase(TT &&a, UU &&b): T(forward<TT>(a)), CompressedPairBase(TT &&a, UU &&b):
U(forward<UU>(b)) {} T(forward<TT>(a)), U(forward<UU>(b))
{}
T &first() { return *this; } T &first() { return *this; }
T const &first() const { return *this; } T const &first() const { return *this; }
@ -379,8 +397,9 @@ namespace detail {
using Base = CompressedPairBase<T, U>; using Base = CompressedPairBase<T, U>;
template<typename TT, typename UU> template<typename TT, typename UU>
CompressedPair(TT &&a, UU &&b): Base(forward<TT>(a), CompressedPair(TT &&a, UU &&b):
forward<UU>(b)) {} Base(forward<TT>(a), forward<UU>(b))
{}
T &first() { return Base::first(); } T &first() { return Base::first(); }
T const &first() const { return Base::first(); } T const &first() const { return Base::first(); }

View file

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