forked from OctaForge/libostd
initial proper string integration
This commit is contained in:
parent
632147c5fb
commit
343c684820
|
@ -52,7 +52,7 @@ int main() {
|
||||||
return range(v + 1);
|
return range(v + 1);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Map<String, int> m = {
|
Map<std::string, int> m = {
|
||||||
{ "foo", 5 },
|
{ "foo", 5 },
|
||||||
{ "bar", 10 },
|
{ "bar", 10 },
|
||||||
{ "baz", 15 }
|
{ "baz", 15 }
|
||||||
|
@ -81,7 +81,7 @@ int main() {
|
||||||
writefln("%i", Bar{});
|
writefln("%i", Bar{});
|
||||||
|
|
||||||
/* format into string */
|
/* format into string */
|
||||||
auto s = appender<String>();
|
auto s = appender<std::string>();
|
||||||
format(s, "hello %s", "world");
|
format(s, "hello %s", "world");
|
||||||
writeln(s.get());
|
writeln(s.get());
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ int main() {
|
||||||
|
|
||||||
/* prints ABCDEF (ASCII 65, 66, 67, 68, 69, 70) */
|
/* prints ABCDEF (ASCII 65, 66, 67, 68, 69, 70) */
|
||||||
writeln("string gen test");
|
writeln("string gen test");
|
||||||
String s(map(range(6), [](int v) -> char { return v + 65; }));
|
auto s = make_string(map(range(6), [](int v) -> char { return v + 65; }));
|
||||||
writeln(s);
|
writeln(s);
|
||||||
|
|
||||||
/* join a few ranges together - prints 11, 22, 33 ... 99 each on new line */
|
/* join a few ranges together - prints 11, 22, 33 ... 99 each on new line */
|
||||||
|
|
|
@ -23,7 +23,7 @@ int main() {
|
||||||
|
|
||||||
/* prints ABCDEF (ASCII 65, 66, 67, 68, 69, 70) */
|
/* prints ABCDEF (ASCII 65, 66, 67, 68, 69, 70) */
|
||||||
writeln("string gen test");
|
writeln("string gen test");
|
||||||
String s(range(6) | map([](int v) -> char { return v + 65; }));
|
auto s = make_string(range(6) | map([](int v) -> char { return v + 65; }));
|
||||||
writeln(s);
|
writeln(s);
|
||||||
|
|
||||||
/* join a few ranges together - prints 11, 22, 33 ... 99 each on new line */
|
/* join a few ranges together - prints 11, 22, 33 ... 99 each on new line */
|
||||||
|
@ -76,7 +76,7 @@ int main() {
|
||||||
| filter([](auto v) { return v >= 65 && v <= 90; })
|
| filter([](auto v) { return v >= 65 && v <= 90; })
|
||||||
| map ([](auto v) { return char(v); });
|
| map ([](auto v) { return char(v); });
|
||||||
|
|
||||||
writeln(String(r));
|
writeln(make_string(r));
|
||||||
|
|
||||||
/* "list comprehensions" */
|
/* "list comprehensions" */
|
||||||
writeln("list initialization");
|
writeln("list initialization");
|
||||||
|
|
|
@ -9,7 +9,7 @@ int main() {
|
||||||
|
|
||||||
FileStream wtest{"test.txt", StreamMode::write};
|
FileStream wtest{"test.txt", StreamMode::write};
|
||||||
|
|
||||||
String smpl =
|
std::string smpl =
|
||||||
"This is a test file for later read.\n"
|
"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"
|
||||||
|
@ -24,14 +24,14 @@ int main() {
|
||||||
|
|
||||||
writeln("## WHOLE FILE READ ##\n");
|
writeln("## WHOLE FILE READ ##\n");
|
||||||
|
|
||||||
String ts1{test.iter()};
|
auto ts1 = make_string(test.iter());
|
||||||
writefln("-- str beg --\n%s-- str end --", ts1);
|
writefln("-- str beg --\n%s-- str end --", ts1);
|
||||||
|
|
||||||
test.seek(0);
|
test.seek(0);
|
||||||
|
|
||||||
writeln("\n## PART FILE READ ##\n");
|
writeln("\n## PART FILE READ ##\n");
|
||||||
|
|
||||||
String ts2{test.iter().take(25)};
|
auto ts2 = make_string(test.iter().take(25));
|
||||||
writefln("-- str beg --\n%s\n-- str end --", ts2);
|
writefln("-- str beg --\n%s\n-- str end --", ts2);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "ostd/maybe.hh"
|
#include "ostd/maybe.hh"
|
||||||
#include "ostd/string.hh"
|
#include "ostd/string.hh"
|
||||||
|
|
||||||
|
@ -19,7 +21,7 @@
|
||||||
|
|
||||||
namespace ostd {
|
namespace ostd {
|
||||||
|
|
||||||
inline Maybe<String> env_get(ConstCharRange name) {
|
inline Maybe<std::string> env_get(ConstCharRange name) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
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
|
||||||
|
@ -27,23 +29,21 @@ inline Maybe<String> env_get(ConstCharRange name) {
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
return ostd::nothing;
|
return ostd::nothing;
|
||||||
}
|
}
|
||||||
return std::move(String(ret));
|
return std::string{ret};
|
||||||
#else
|
#else
|
||||||
String rbuf;
|
std::vector<char> rbuf;
|
||||||
|
DWORD sz;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto ret = GetEnvironmentVariable(
|
sz = GetEnvironmentVariable(tbuf.get(), rbuf.data(), rbuf.capacity());
|
||||||
tbuf.get(), rbuf.data(), rbuf.capacity() + 1
|
if (!sz) {
|
||||||
);
|
|
||||||
if (!ret) {
|
|
||||||
return ostd::nothing;
|
return ostd::nothing;
|
||||||
}
|
}
|
||||||
if (ret <= rbuf.capacity()) {
|
if (sz < rbuf.capacity()) {
|
||||||
rbuf.advance(ret);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rbuf.reserve(ret - 1);
|
rbuf.reserve(sz);
|
||||||
}
|
}
|
||||||
return std::move(rbuf);
|
return std::string{rbuf.data(), sz};
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,9 +86,9 @@ inline bool env_unset(ConstCharRange name) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifndef OSTD_PLATFORM_WIN32
|
#ifndef OSTD_PLATFORM_WIN32
|
||||||
return !unsetenv(String(name).data());
|
return !unsetenv(std::string{name}.data());
|
||||||
#else
|
#else
|
||||||
return !!SetEnvironmentVariable(String(name).data(), nullptr);
|
return !!SetEnvironmentVariable(std::string{name}.data(), nullptr);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ struct FileInfo {
|
||||||
p_path(std::move(i.p_path)), p_atime(i.p_atime), p_mtime(i.p_mtime),
|
p_path(std::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 = std::string::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;
|
||||||
}
|
}
|
||||||
|
@ -94,23 +94,23 @@ struct FileInfo {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstCharRange path() const { return p_path.iter(); }
|
ConstCharRange path() const { return ostd::iter(p_path); }
|
||||||
|
|
||||||
ConstCharRange filename() const {
|
ConstCharRange filename() const {
|
||||||
return path().slice(
|
return path().slice(
|
||||||
(p_slash == npos) ? 0 : (p_slash + 1), p_path.size()
|
(p_slash == std::string::npos) ? 0 : (p_slash + 1), p_path.size()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstCharRange stem() const {
|
ConstCharRange stem() const {
|
||||||
return path().slice(
|
return path().slice(
|
||||||
(p_slash == npos) ? 0 : (p_slash + 1),
|
(p_slash == std::string::npos) ? 0 : (p_slash + 1),
|
||||||
(p_dot == npos) ? p_path.size() : p_dot
|
(p_dot == std::string::npos) ? p_path.size() : p_dot
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstCharRange extension() const {
|
ConstCharRange extension() const {
|
||||||
return (p_dot == npos)
|
return (p_dot == std::string::npos)
|
||||||
? ConstCharRange()
|
? ConstCharRange()
|
||||||
: path().slice(p_dot, p_path.size());
|
: path().slice(p_dot, p_path.size());
|
||||||
}
|
}
|
||||||
|
@ -118,8 +118,8 @@ struct FileInfo {
|
||||||
FileType type() const { return p_type; }
|
FileType type() const { return p_type; }
|
||||||
|
|
||||||
void normalize() {
|
void normalize() {
|
||||||
path_normalize(p_path.iter());
|
path_normalize(ostd::iter(p_path));
|
||||||
init_from_str(p_path.iter());
|
init_from_str(ostd::iter(p_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t atime() const { return p_atime; }
|
time_t atime() const { return p_atime; }
|
||||||
|
@ -150,24 +150,24 @@ private:
|
||||||
if (lstat(p_path.data(), &st) < 0)
|
if (lstat(p_path.data(), &st) < 0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
p_slash = p_dot = npos;
|
p_slash = p_dot = std::string::npos;
|
||||||
p_type = FileType::unknown;
|
p_type = FileType::unknown;
|
||||||
p_path.clear();
|
p_path.clear();
|
||||||
p_atime = p_mtime = p_ctime = 0;
|
p_atime = p_mtime = p_ctime = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ConstCharRange r = p_path.iter();
|
ConstCharRange r = p_path;
|
||||||
|
|
||||||
ConstCharRange found = find_last(r, PathSeparator);
|
ConstCharRange found = find_last(r, PathSeparator);
|
||||||
if (found.empty()) {
|
if (found.empty()) {
|
||||||
p_slash = npos;
|
p_slash = std::string::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 = std::string::npos;
|
||||||
} else {
|
} else {
|
||||||
p_dot = r.distance_front(found);
|
p_dot = r.distance_front(found);
|
||||||
}
|
}
|
||||||
|
@ -215,9 +215,9 @@ private:
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Size p_slash = npos, p_dot = npos;
|
Size p_slash = std::string::npos, p_dot = std::string::npos;
|
||||||
FileType p_type = FileType::unknown;
|
FileType p_type = FileType::unknown;
|
||||||
String p_path;
|
std::string p_path;
|
||||||
|
|
||||||
time_t p_atime = 0, p_mtime = 0, p_ctime = 0;
|
time_t p_atime = 0, p_mtime = 0, p_ctime = 0;
|
||||||
};
|
};
|
||||||
|
@ -353,7 +353,7 @@ private:
|
||||||
if (!p_de) {
|
if (!p_de) {
|
||||||
return FileInfo();
|
return FileInfo();
|
||||||
}
|
}
|
||||||
String ap = p_path;
|
std::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);
|
||||||
return FileInfo(ap);
|
return FileInfo(ap);
|
||||||
|
@ -361,7 +361,7 @@ private:
|
||||||
|
|
||||||
DIR *p_d;
|
DIR *p_d;
|
||||||
struct dirent *p_de;
|
struct dirent *p_de;
|
||||||
String p_path;
|
std::string p_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
#else /* OSTD_PLATFORM_WIN32 */
|
#else /* OSTD_PLATFORM_WIN32 */
|
||||||
|
@ -514,7 +514,7 @@ private:
|
||||||
if (empty()) {
|
if (empty()) {
|
||||||
return FileInfo();
|
return FileInfo();
|
||||||
}
|
}
|
||||||
String ap = p_path;
|
std::string ap = p_path;
|
||||||
ap += PathSeparator;
|
ap += PathSeparator;
|
||||||
ap += static_cast<char const *>(p_data.cFileName);
|
ap += static_cast<char const *>(p_data.cFileName);
|
||||||
return FileInfo(ap);
|
return FileInfo(ap);
|
||||||
|
@ -522,7 +522,7 @@ private:
|
||||||
|
|
||||||
HANDLE p_handle;
|
HANDLE p_handle;
|
||||||
WIN32_FIND_DATA p_data;
|
WIN32_FIND_DATA p_data;
|
||||||
String p_path;
|
std::string p_path;
|
||||||
};
|
};
|
||||||
#endif /* OSTD_PLATFORM_WIN32 */
|
#endif /* OSTD_PLATFORM_WIN32 */
|
||||||
|
|
||||||
|
@ -570,7 +570,7 @@ namespace detail {
|
||||||
template<Size I>
|
template<Size I>
|
||||||
struct PathJoin {
|
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(std::string &s, T const &a, A const &...b) {
|
||||||
s += a;
|
s += a;
|
||||||
s += PathSeparator;
|
s += PathSeparator;
|
||||||
PathJoin<I - 1>::join(s, b...);
|
PathJoin<I - 1>::join(s, b...);
|
||||||
|
@ -580,7 +580,7 @@ namespace detail {
|
||||||
template<>
|
template<>
|
||||||
struct PathJoin<1> {
|
struct PathJoin<1> {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void join(String &s, T const &a) {
|
static void join(std::string &s, T const &a) {
|
||||||
s += a;
|
s += a;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -588,9 +588,9 @@ namespace detail {
|
||||||
|
|
||||||
template<typename ...A>
|
template<typename ...A>
|
||||||
inline FileInfo path_join(A const &...args) {
|
inline FileInfo path_join(A const &...args) {
|
||||||
String path;
|
std::string path;
|
||||||
detail::PathJoin<sizeof...(A)>::join(path, args...);
|
detail::PathJoin<sizeof...(A)>::join(path, args...);
|
||||||
path_normalize(path.iter());
|
path_normalize(ostd::iter(path));
|
||||||
return FileInfo(path);
|
return FileInfo(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -644,19 +644,19 @@ namespace detail {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline String escape_fmt_str(ConstCharRange val) {
|
inline std::string escape_fmt_str(ConstCharRange val) {
|
||||||
String ret;
|
std::string ret;
|
||||||
ret.push('"');
|
ret.push_back('"');
|
||||||
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_back(val.front());
|
||||||
}
|
}
|
||||||
val.pop_front();
|
val.pop_front();
|
||||||
}
|
}
|
||||||
ret.push('"');
|
ret.push_back('"');
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,7 @@ namespace detail {
|
||||||
!IsConstructible<ConstCharRange, T const &>, IoNat
|
!IsConstructible<ConstCharRange, T const &>, IoNat
|
||||||
> = IoNat()
|
> = IoNat()
|
||||||
) {
|
) {
|
||||||
write(ostd::to_string(v));
|
write_impl(ostd::to_string(v));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1693,8 +1693,8 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct AppenderRange: OutputRange<AppenderRange<T>, typename T::Value,
|
struct AppenderRange: OutputRange<AppenderRange<T>, typename T::value_type,
|
||||||
typename T::Reference, typename T::Size, typename T::Difference> {
|
typename T::reference, typename T::size_type, typename T::difference_type> {
|
||||||
AppenderRange(): p_data() {}
|
AppenderRange(): p_data() {}
|
||||||
AppenderRange(T const &v): p_data(v) {}
|
AppenderRange(T const &v): p_data(v) {}
|
||||||
AppenderRange(T &&v): p_data(std::move(v)) {}
|
AppenderRange(T &&v): p_data(std::move(v)) {}
|
||||||
|
@ -1723,19 +1723,19 @@ struct AppenderRange: OutputRange<AppenderRange<T>, typename T::Value,
|
||||||
|
|
||||||
void clear() { p_data.clear(); }
|
void clear() { p_data.clear(); }
|
||||||
|
|
||||||
void reserve(typename T::Size cap) { p_data.reserve(cap); }
|
void reserve(typename T::size_type cap) { p_data.reserve(cap); }
|
||||||
void resize(typename T::Size len) { p_data.resize(len); }
|
void resize(typename T::size_type len) { p_data.resize(len); }
|
||||||
|
|
||||||
typename T::Size size() const { return p_data.size(); }
|
typename T::size_type size() const { return p_data.size(); }
|
||||||
typename T::Size capacity() const { return p_data.capacity(); }
|
typename T::size_type capacity() const { return p_data.capacity(); }
|
||||||
|
|
||||||
bool put(typename T::ConstReference v) {
|
bool put(typename T::const_reference v) {
|
||||||
p_data.push(v);
|
p_data.push_back(v);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool put(typename T::Value &&v) {
|
bool put(typename T::value_type &&v) {
|
||||||
p_data.push(std::move(v));
|
p_data.push_back(std::move(v));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
643
ostd/string.hh
643
ostd/string.hh
|
@ -1,4 +1,4 @@
|
||||||
/* String for OctaSTD.
|
/* String utilities for OctaSTD.
|
||||||
*
|
*
|
||||||
* This file is part of OctaSTD. See COPYING.md for futher information.
|
* This file is part of OctaSTD. See COPYING.md for futher information.
|
||||||
*/
|
*/
|
||||||
|
@ -21,10 +21,6 @@
|
||||||
#include "ostd/algorithm.hh"
|
#include "ostd/algorithm.hh"
|
||||||
|
|
||||||
namespace ostd {
|
namespace ostd {
|
||||||
static constexpr Size npos = -1;
|
|
||||||
|
|
||||||
template<typename T, typename A = Allocator<T>>
|
|
||||||
class StringBase;
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct CharRangeBase: InputRange<
|
struct CharRangeBase: InputRange<
|
||||||
|
@ -56,8 +52,8 @@ public:
|
||||||
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 TR, typename A>
|
||||||
CharRangeBase(StringBase<U, A> const &s, EnableIf<
|
CharRangeBase(std::basic_string<U, TR, A> const &s, EnableIf<
|
||||||
IsConvertible<U *, T *>, Nat
|
IsConvertible<U *, T *>, Nat
|
||||||
> = Nat()):
|
> = Nat()):
|
||||||
p_beg(s.data()), p_end(s.data() + s.size())
|
p_beg(s.data()), p_end(s.data() + s.size())
|
||||||
|
@ -72,8 +68,8 @@ public:
|
||||||
p_beg = v.p_beg; p_end = v.p_end; return *this;
|
p_beg = v.p_beg; p_end = v.p_end; return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename A>
|
template<typename TR, typename A>
|
||||||
CharRangeBase &operator=(StringBase<T, A> const &s) {
|
CharRangeBase &operator=(std::basic_string<T, TR, A> const &s) {
|
||||||
p_beg = s.data(); p_end = s.data() + s.size(); return *this;
|
p_beg = s.data(); p_end = s.data() + s.size(); return *this;
|
||||||
}
|
}
|
||||||
/* 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 */
|
||||||
|
@ -268,439 +264,26 @@ struct ranged_traits<std::basic_string<T> const> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename A>
|
template<typename T, typename R>
|
||||||
class StringBase {
|
inline std::basic_string<T> make_string(R range) {
|
||||||
using StrPair = detail::CompressedPair<AllocatorPointer<A>, A>;
|
/* TODO: specialize for contiguous ranges and matching value types */
|
||||||
|
std::basic_string<T> ret;
|
||||||
ostd::Size p_len, p_cap;
|
for (; !range.empty(); range.pop_front()) {
|
||||||
StrPair p_buf;
|
ret.push_back(range.front());
|
||||||
|
|
||||||
template<typename R>
|
|
||||||
void ctor_from_range(R &range, EnableIf<
|
|
||||||
IsFiniteRandomAccessRange<R> && IsSame<T, RemoveCv<RangeValue<R>>>, bool
|
|
||||||
> = true) {
|
|
||||||
if (range.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
RangeSize<R> l = range.size();
|
|
||||||
reserve(l);
|
|
||||||
p_len = l;
|
|
||||||
range.copy(p_buf.first(), l);
|
|
||||||
p_buf.first()[l] = '\0';
|
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
template<typename R>
|
|
||||||
void ctor_from_range(R &range, EnableIf<
|
|
||||||
!IsFiniteRandomAccessRange<R> || !IsSame<T, RemoveCv<RangeValue<R>>>,
|
|
||||||
bool
|
|
||||||
> = true) {
|
|
||||||
if (range.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Size i = 0;
|
|
||||||
for (; !range.empty(); range.pop_front()) {
|
|
||||||
reserve(i + 1);
|
|
||||||
allocator_construct(
|
|
||||||
p_buf.second(), &p_buf.first()[i],
|
|
||||||
range.front()
|
|
||||||
);
|
|
||||||
++i;
|
|
||||||
p_len = i;
|
|
||||||
}
|
|
||||||
p_buf.first()[p_len] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using Size = ostd::Size;
|
|
||||||
using Difference = Ptrdiff;
|
|
||||||
using Value = T;
|
|
||||||
using Reference = T &;
|
|
||||||
using ConstReference = T const &;
|
|
||||||
using Pointer = AllocatorPointer<A>;
|
|
||||||
using ConstPointer = AllocatorConstPointer<A>;
|
|
||||||
using Range = CharRangeBase<T>;
|
|
||||||
using ConstRange = CharRangeBase<T const>;
|
|
||||||
using Allocator = A;
|
|
||||||
|
|
||||||
StringBase(A const &a = A()):
|
|
||||||
p_len(0), p_cap(0),
|
|
||||||
p_buf(reinterpret_cast<Pointer>(&p_len), a)
|
|
||||||
{}
|
|
||||||
|
|
||||||
explicit StringBase(Size n, T val = T(), A const &al = A()):
|
|
||||||
StringBase(al)
|
|
||||||
{
|
|
||||||
if (!n) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
p_buf.first() = allocator_allocate(p_buf.second(), n + 1);
|
|
||||||
p_len = p_cap = n;
|
|
||||||
Pointer cur = p_buf.first(), last = p_buf.first() + n;
|
|
||||||
while (cur != last) {
|
|
||||||
*cur++ = val;
|
|
||||||
}
|
|
||||||
*cur = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBase(StringBase const &s):
|
|
||||||
p_len(0), p_cap(0), p_buf(reinterpret_cast<Pointer>(&p_len),
|
|
||||||
allocator_container_copy(s.p_buf.second()))
|
|
||||||
{
|
|
||||||
if (!s.p_len) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
reserve(s.p_len);
|
|
||||||
p_len = s.p_len;
|
|
||||||
memcpy(p_buf.first(), s.p_buf.first(), (p_len + 1) * sizeof(T));
|
|
||||||
}
|
|
||||||
StringBase(StringBase const &s, A const &a):
|
|
||||||
p_len(0), p_cap(0), p_buf(reinterpret_cast<Pointer>(&p_len), a)
|
|
||||||
{
|
|
||||||
if (!s.p_len) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
reserve(s.p_len);
|
|
||||||
p_len = s.p_len;
|
|
||||||
memcpy(p_buf.first(), s.p_buf.first(), (p_len + 1) * sizeof(T));
|
|
||||||
}
|
|
||||||
StringBase(StringBase &&s):
|
|
||||||
p_len(s.p_len), p_cap(s.p_cap),
|
|
||||||
p_buf(s.p_buf.first(), std::move(s.p_buf.second()))
|
|
||||||
{
|
|
||||||
s.p_len = s.p_cap = 0;
|
|
||||||
s.p_buf.first() = reinterpret_cast<Pointer>(&s.p_len);
|
|
||||||
}
|
|
||||||
StringBase(StringBase &&s, A const &a):
|
|
||||||
p_len(0), p_cap(0), p_buf(reinterpret_cast<Pointer>(&p_len), a)
|
|
||||||
{
|
|
||||||
if (!s.p_len) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (a != s.p_buf.second()) {
|
|
||||||
reserve(s.p_cap);
|
|
||||||
p_len = s.p_len;
|
|
||||||
memcpy(p_buf.first(), s.p_buf.first(), (p_len + 1) * sizeof(T));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
p_buf.first() = s.p_buf.first();
|
|
||||||
p_len = s.p_len;
|
|
||||||
p_cap = s.p_cap;
|
|
||||||
s.p_len = s.p_cap = 0;
|
|
||||||
s.p_buf.first() = &s.p_cap;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBase(
|
|
||||||
StringBase const &s, Size pos, Size len = npos, A const &a = A()
|
|
||||||
): StringBase(a) {
|
|
||||||
Size end = (len == npos) ? s.size() : (pos + len);
|
|
||||||
Size nch = (end - pos);
|
|
||||||
reserve(nch);
|
|
||||||
memcpy(p_buf.first(), s.p_buf.first() + pos, nch);
|
|
||||||
p_len += nch;
|
|
||||||
p_buf.first()[p_len] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: traits for utf-16/utf-32 string lengths, for now assume char */
|
|
||||||
StringBase(ConstRange v, A const &a = A()): StringBase(a) {
|
|
||||||
if (!v.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
reserve(v.size());
|
|
||||||
memcpy(p_buf.first(), &v[0], v.size());
|
|
||||||
p_buf.first()[v.size()] = '\0';
|
|
||||||
p_len = v.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
StringBase(U v, EnableIf<
|
|
||||||
IsConvertible<U, Value const *> && !IsArray<U>, A
|
|
||||||
> const &a = A()): StringBase(ConstRange(v), a) {}
|
|
||||||
|
|
||||||
template<typename U, Size N>
|
|
||||||
StringBase(U (&v)[N], EnableIf<
|
|
||||||
IsConvertible<U *, Value const *>, A
|
|
||||||
> const &a = A()): StringBase(ConstRange(v), a) {}
|
|
||||||
|
|
||||||
template<typename R, typename = EnableIf<
|
|
||||||
IsInputRange<R> && IsConvertible<RangeReference<R>, Value>
|
|
||||||
>>
|
|
||||||
StringBase(R range, A const &a = A()): StringBase(a) {
|
|
||||||
ctor_from_range(range);
|
|
||||||
}
|
|
||||||
|
|
||||||
~StringBase() {
|
|
||||||
if (!p_cap) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
allocator_deallocate(p_buf.second(), p_buf.first(), p_cap + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
if (!p_len) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
p_len = 0;
|
|
||||||
*p_buf.first() = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBase &operator=(StringBase const &v) {
|
|
||||||
if (this == &v) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
clear();
|
|
||||||
if (AllocatorPropagateOnContainerCopyAssignment<A>) {
|
|
||||||
if ((p_buf.second() != v.p_buf.second()) && p_cap) {
|
|
||||||
allocator_deallocate(p_buf.second(), p_buf.first(), p_cap);
|
|
||||||
p_cap = 0;
|
|
||||||
p_buf.first() = reinterpret_cast<Pointer>(&p_len);
|
|
||||||
}
|
|
||||||
p_buf.second() = v.p_buf.second();
|
|
||||||
}
|
|
||||||
reserve(v.p_cap);
|
|
||||||
p_len = v.p_len;
|
|
||||||
if (p_len) {
|
|
||||||
memcpy(p_buf.first(), v.p_buf.first(), p_len);
|
|
||||||
p_buf.first()[p_len] = '\0';
|
|
||||||
} else {
|
|
||||||
p_buf.first() = reinterpret_cast<Pointer>(&p_len);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBase &operator=(StringBase &&v) {
|
|
||||||
clear();
|
|
||||||
if (p_cap) {
|
|
||||||
allocator_deallocate(p_buf.second(), p_buf.first(), p_cap);
|
|
||||||
}
|
|
||||||
if (AllocatorPropagateOnContainerMoveAssignment<A>) {
|
|
||||||
p_buf.second() = v.p_buf.second();
|
|
||||||
}
|
|
||||||
p_len = v.p_len;
|
|
||||||
p_cap = v.p_cap;
|
|
||||||
p_buf.~StrPair();
|
|
||||||
new (&p_buf) StrPair(v.release(), std::move(v.p_buf.second()));
|
|
||||||
if (!p_cap) {
|
|
||||||
p_buf.first() = reinterpret_cast<Pointer>(&p_len);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBase &operator=(ConstRange v) {
|
|
||||||
reserve(v.size());
|
|
||||||
if (v.size()) {
|
|
||||||
memcpy(p_buf.first(), &v[0], v.size());
|
|
||||||
}
|
|
||||||
p_buf.first()[v.size()] = '\0';
|
|
||||||
p_len = v.size();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
EnableIf<
|
|
||||||
IsConvertible<U, Value const *> && !IsArray<U>, StringBase &
|
|
||||||
> operator=(U v) {
|
|
||||||
return operator=(ConstRange(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U, Size N>
|
|
||||||
EnableIf<
|
|
||||||
IsConvertible<U *, Value const *>, StringBase &
|
|
||||||
> operator=(U (&v)[N]) {
|
|
||||||
return operator=(ConstRange(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename = EnableIf<
|
|
||||||
IsInputRange<R> && IsConvertible<RangeReference<R>, Value>
|
|
||||||
>> StringBase &operator=(R const &r) {
|
|
||||||
clear();
|
|
||||||
ctor_from_range(r);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void resize(Size n, T v = T()) {
|
|
||||||
if (!n) {
|
|
||||||
clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Size l = p_len;
|
|
||||||
reserve(n);
|
|
||||||
p_len = n;
|
|
||||||
for (Size i = l; i < p_len; ++i) {
|
|
||||||
p_buf.first()[i] = T(v);
|
|
||||||
}
|
|
||||||
p_buf.first()[l] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void reserve(Size n) {
|
|
||||||
if (n <= p_cap) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Size oc = p_cap;
|
|
||||||
if (!oc) {
|
|
||||||
p_cap = max(n, Size(8));
|
|
||||||
} else {
|
|
||||||
while (p_cap < n) p_cap *= 2;
|
|
||||||
}
|
|
||||||
Pointer tmp = allocator_allocate(p_buf.second(), p_cap + 1);
|
|
||||||
if (oc > 0) {
|
|
||||||
memcpy(tmp, p_buf.first(), (p_len + 1) * sizeof(T));
|
|
||||||
allocator_deallocate(p_buf.second(), p_buf.first(), oc + 1);
|
|
||||||
}
|
|
||||||
tmp[p_len] = '\0';
|
|
||||||
p_buf.first() = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
T &operator[](Size i) { return p_buf.first()[i]; }
|
|
||||||
T const &operator[](Size i) const { return p_buf.first()[i]; }
|
|
||||||
|
|
||||||
T &at(Size i) { return p_buf.first()[i]; }
|
|
||||||
T const &at(Size i) const { return p_buf.first()[i]; }
|
|
||||||
|
|
||||||
T &front() { return p_buf.first()[0]; }
|
|
||||||
T const &front() const { return p_buf.first()[0]; };
|
|
||||||
|
|
||||||
T &back() { return p_buf.first()[size() - 1]; }
|
|
||||||
T const &back() const { return p_buf.first()[size() - 1]; }
|
|
||||||
|
|
||||||
Value *data() { return p_buf.first(); }
|
|
||||||
Value const *data() const { return p_buf.first(); }
|
|
||||||
|
|
||||||
Size size() const {
|
|
||||||
return p_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
Size capacity() const {
|
|
||||||
return p_cap;
|
|
||||||
}
|
|
||||||
|
|
||||||
void advance(Size s) { p_len += s; }
|
|
||||||
|
|
||||||
Size length() const {
|
|
||||||
/* TODO: unicode */
|
|
||||||
return size();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty() const { return (size() == 0); }
|
|
||||||
|
|
||||||
Value *release() {
|
|
||||||
Pointer r = p_buf.first();
|
|
||||||
p_buf.first() = nullptr;
|
|
||||||
p_len = p_cap = 0;
|
|
||||||
return reinterpret_cast<Value *>(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
void push(T v) {
|
|
||||||
reserve(p_len + 1);
|
|
||||||
p_buf.first()[p_len++] = v;
|
|
||||||
p_buf.first()[p_len] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBase &append(ConstRange r) {
|
|
||||||
if (!r.size()) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
reserve(p_len + r.size());
|
|
||||||
memcpy(p_buf.first() + p_len, &r[0], r.size());
|
|
||||||
p_len += r.size();
|
|
||||||
p_buf.first()[p_len] = '\0';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBase &append(Size n, T c) {
|
|
||||||
if (!n) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
reserve(p_len + n);
|
|
||||||
for (Size i = 0; i < n; ++i) {
|
|
||||||
p_buf.first()[p_len + i] = c;
|
|
||||||
}
|
|
||||||
p_len += n;
|
|
||||||
p_buf.first()[p_len] = '\0';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename = EnableIf<
|
|
||||||
IsInputRange<R> && IsConvertible<RangeReference<R>, Value> &&
|
|
||||||
!IsConvertible<R, ConstRange>
|
|
||||||
>> StringBase &append(R range) {
|
|
||||||
Size nadd = 0;
|
|
||||||
for (; !range.empty(); range.pop_front()) {
|
|
||||||
reserve(p_len + nadd + 1);
|
|
||||||
p_buf.first()[p_len + nadd++] = range.front();
|
|
||||||
}
|
|
||||||
p_len += nadd;
|
|
||||||
p_buf.first()[p_len] = '\0';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBase &operator+=(ConstRange r) {
|
|
||||||
return append(r);
|
|
||||||
}
|
|
||||||
StringBase &operator+=(T c) {
|
|
||||||
return append(1, c);
|
|
||||||
}
|
|
||||||
template<typename R>
|
|
||||||
StringBase &operator+=(R const &v) {
|
|
||||||
return append(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
int compare(ConstRange r) const {
|
|
||||||
return iter().compare(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
int case_compare(ConstRange r) const {
|
|
||||||
return iter().case_compare(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
Range iter() {
|
|
||||||
return Range(p_buf.first(), size());
|
|
||||||
}
|
|
||||||
ConstRange iter() const {
|
|
||||||
return ConstRange(p_buf.first(), size());
|
|
||||||
}
|
|
||||||
ConstRange citer() const {
|
|
||||||
return ConstRange(p_buf.dfirst(), size());
|
|
||||||
}
|
|
||||||
|
|
||||||
Range iter_cap() {
|
|
||||||
return Range(p_buf.first(), capacity());
|
|
||||||
}
|
|
||||||
|
|
||||||
void swap(StringBase &v) {
|
|
||||||
using std::swap;
|
|
||||||
swap(p_len, v.p_len);
|
|
||||||
swap(p_cap, v.p_cap);
|
|
||||||
swap(p_buf.first(), v.p_buf.first());
|
|
||||||
if (AllocatorPropagateOnContainerSwap<A>) {
|
|
||||||
swap(p_buf.second(), v.p_buf.second());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Size to_hash() const {
|
|
||||||
return iter().to_hash();
|
|
||||||
}
|
|
||||||
|
|
||||||
A get_allocator() const {
|
|
||||||
return p_buf.second();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline void swap(StringBase<T> &a, StringBase<T> &b) {
|
|
||||||
a.swap(b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using String = StringBase<char>;
|
template<typename R>
|
||||||
|
inline std::basic_string<RemoveCv<RangeValue<R>>> make_string(R range) {
|
||||||
|
return make_string<RemoveCv<RangeValue<R>>>(std::move(range));
|
||||||
|
}
|
||||||
|
|
||||||
/* string literals */
|
/* string literals */
|
||||||
|
|
||||||
inline namespace literals {
|
inline namespace literals {
|
||||||
inline namespace string_literals {
|
inline namespace string_literals {
|
||||||
inline String operator "" _s(char const *str, Size len) {
|
inline ConstCharRange operator "" _sr(char const *str, Size len) {
|
||||||
return String(ConstCharRange(str, len));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ConstCharRange operator "" _S(char const *str, Size len) {
|
|
||||||
return ConstCharRange(str, len);
|
return ConstCharRange(str, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -807,7 +390,7 @@ namespace detail {
|
||||||
|
|
||||||
template<typename T, typename R>
|
template<typename T, typename R>
|
||||||
static auto test_stringify(int) ->
|
static auto test_stringify(int) ->
|
||||||
BoolConstant<IsSame<decltype(std::declval<T>().stringify()), String>>;
|
BoolConstant<IsSame<decltype(std::declval<T>().stringify()), std::string>>;
|
||||||
|
|
||||||
template<typename T, typename R>
|
template<typename T, typename R>
|
||||||
static True test_stringify(decltype(std::declval<T const &>().to_string
|
static True test_stringify(decltype(std::declval<T const &>().to_string
|
||||||
|
@ -834,11 +417,11 @@ struct ToString;
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct ToString<T, EnableIf<detail::IterableTest<T>>> {
|
struct ToString<T, EnableIf<detail::IterableTest<T>>> {
|
||||||
using Argument = RemoveCv<RemoveReference<T>>;
|
using Argument = RemoveCv<RemoveReference<T>>;
|
||||||
using Result = String;
|
using Result = std::string;
|
||||||
|
|
||||||
String operator()(T const &v) const {
|
std::string operator()(T const &v) const {
|
||||||
String ret("{");
|
std::string ret("{");
|
||||||
auto x = appender<String>();
|
auto x = appender<std::string>();
|
||||||
if (concat(x, ostd::iter(v), ", ", ToString<
|
if (concat(x, ostd::iter(v), ", ", ToString<
|
||||||
RemoveConst<RemoveReference<
|
RemoveConst<RemoveReference<
|
||||||
RangeReference<decltype(ostd::iter(v))>
|
RangeReference<decltype(ostd::iter(v))>
|
||||||
|
@ -853,44 +436,26 @@ struct ToString<T, EnableIf<detail::IterableTest<T>>> {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct ToString<T, EnableIf<
|
struct ToString<T, EnableIf<
|
||||||
detail::StringifyTest<T, detail::TostrRange<AppenderRange<String>>>
|
detail::StringifyTest<T, detail::TostrRange<AppenderRange<std::string>>>
|
||||||
>> {
|
>> {
|
||||||
using Argument = RemoveCv<RemoveReference<T>>;
|
using Argument = RemoveCv<RemoveReference<T>>;
|
||||||
using Result = String;
|
using Result = std::string;
|
||||||
|
|
||||||
String operator()(T const &v) const {
|
std::string operator()(T const &v) const {
|
||||||
auto app = appender<String>();
|
auto app = appender<std::string>();
|
||||||
detail::TostrRange<AppenderRange<String>> sink(app);
|
detail::TostrRange<AppenderRange<std::string>> sink(app);
|
||||||
if (!v.to_string(sink)) {
|
if (!v.to_string(sink)) {
|
||||||
return String();
|
return std::string{};
|
||||||
}
|
}
|
||||||
return std::move(app.get());
|
return std::move(app.get());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template<typename T>
|
|
||||||
void str_printf(String &s, char const *fmt, T v) {
|
|
||||||
char buf[256];
|
|
||||||
int n = snprintf(buf, sizeof(buf), fmt, v);
|
|
||||||
s.clear();
|
|
||||||
s.reserve(n);
|
|
||||||
if (n >= int(sizeof(buf))) {
|
|
||||||
snprintf(s.data(), n + 1, fmt, v);
|
|
||||||
} else if (n > 0) {
|
|
||||||
memcpy(s.data(), buf, n + 1);
|
|
||||||
} else {
|
|
||||||
s.clear();
|
|
||||||
}
|
|
||||||
*reinterpret_cast<Size *>(&s) = n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct ToString<bool> {
|
struct ToString<bool> {
|
||||||
using Argument = bool;
|
using Argument = bool;
|
||||||
using Result = String;
|
using Result = std::string;
|
||||||
String operator()(bool b) {
|
std::string operator()(bool b) {
|
||||||
return b ? "true" : "false";
|
return b ? "true" : "false";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -898,77 +463,66 @@ struct ToString<bool> {
|
||||||
template<>
|
template<>
|
||||||
struct ToString<char> {
|
struct ToString<char> {
|
||||||
using Argument = char;
|
using Argument = char;
|
||||||
using Result = String;
|
using Result = std::string;
|
||||||
String operator()(char c) {
|
std::string operator()(char c) {
|
||||||
String ret;
|
std::string ret;
|
||||||
ret.push(c);
|
ret += c;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OSTD_TOSTR_NUM(T, fmt) \
|
#define OSTD_TOSTR_NUM(T) \
|
||||||
template<> \
|
template<> \
|
||||||
struct ToString<T> { \
|
struct ToString<T> { \
|
||||||
using Argument = T; \
|
using Argument = T; \
|
||||||
using Result = String; \
|
using Result = std::string; \
|
||||||
String operator()(T v) { \
|
std::string operator()(T v) { \
|
||||||
String ret; \
|
return std::to_string(v); \
|
||||||
detail::str_printf(ret, fmt, v); \
|
|
||||||
return ret; \
|
|
||||||
} \
|
} \
|
||||||
};
|
};
|
||||||
|
|
||||||
OSTD_TOSTR_NUM(sbyte, "%hhd")
|
OSTD_TOSTR_NUM(sbyte)
|
||||||
OSTD_TOSTR_NUM(short, "%hd")
|
OSTD_TOSTR_NUM(short)
|
||||||
OSTD_TOSTR_NUM(int, "%d")
|
OSTD_TOSTR_NUM(int)
|
||||||
OSTD_TOSTR_NUM(long, "%ld")
|
OSTD_TOSTR_NUM(long)
|
||||||
OSTD_TOSTR_NUM(float, "%f")
|
OSTD_TOSTR_NUM(float)
|
||||||
OSTD_TOSTR_NUM(double, "%f")
|
OSTD_TOSTR_NUM(double)
|
||||||
|
|
||||||
OSTD_TOSTR_NUM(byte, "%hhu")
|
OSTD_TOSTR_NUM(byte)
|
||||||
OSTD_TOSTR_NUM(ushort, "%hu")
|
OSTD_TOSTR_NUM(ushort)
|
||||||
OSTD_TOSTR_NUM(uint, "%u")
|
OSTD_TOSTR_NUM(uint)
|
||||||
OSTD_TOSTR_NUM(ulong, "%lu")
|
OSTD_TOSTR_NUM(ulong)
|
||||||
OSTD_TOSTR_NUM(llong, "%lld")
|
OSTD_TOSTR_NUM(llong)
|
||||||
OSTD_TOSTR_NUM(ullong, "%llu")
|
OSTD_TOSTR_NUM(ullong)
|
||||||
OSTD_TOSTR_NUM(ldouble, "%Lf")
|
OSTD_TOSTR_NUM(ldouble)
|
||||||
|
|
||||||
#undef OSTD_TOSTR_NUM
|
#undef OSTD_TOSTR_NUM
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct ToString<T *> {
|
struct ToString<T *> {
|
||||||
using Argument = T *;
|
using Argument = T *;
|
||||||
using Result = String;
|
using Result = std::string;
|
||||||
String operator()(Argument v) {
|
std::string operator()(Argument v) {
|
||||||
String ret;
|
char buf[16];
|
||||||
detail::str_printf(ret, "%p", v);
|
sprintf(buf, "%p", v);
|
||||||
return ret;
|
return buf;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct ToString<char const *> {
|
struct ToString<char const *> {
|
||||||
using Argument = char const *;
|
using Argument = char const *;
|
||||||
using Result = String;
|
using Result = std::string;
|
||||||
String operator()(char const *s) {
|
std::string operator()(char const *s) {
|
||||||
return String(s);
|
return s;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct ToString<char *> {
|
struct ToString<char *> {
|
||||||
using Argument = char *;
|
using Argument = char *;
|
||||||
using Result = String;
|
using Result = std::string;
|
||||||
String operator()(char *s) {
|
std::string operator()(char *s) {
|
||||||
return String(s);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct ToString<String> {
|
|
||||||
using Argument = String;
|
|
||||||
using Result = String;
|
|
||||||
String operator()(Argument const &s) {
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -976,36 +530,36 @@ struct ToString<String> {
|
||||||
template<>
|
template<>
|
||||||
struct ToString<std::string> {
|
struct ToString<std::string> {
|
||||||
using Argument = std::string;
|
using Argument = std::string;
|
||||||
using Result = String;
|
using Result = std::string;
|
||||||
String operator()(Argument const &s) {
|
std::string operator()(Argument const &s) {
|
||||||
return iter(s);
|
return s;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct ToString<CharRange> {
|
struct ToString<CharRange> {
|
||||||
using Argument = CharRange;
|
using Argument = CharRange;
|
||||||
using Result = String;
|
using Result = std::string;
|
||||||
String operator()(Argument const &s) {
|
std::string operator()(Argument const &s) {
|
||||||
return String(s);
|
return std::string{s};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct ToString<ConstCharRange> {
|
struct ToString<ConstCharRange> {
|
||||||
using Argument = ConstCharRange;
|
using Argument = ConstCharRange;
|
||||||
using Result = String;
|
using Result = std::string;
|
||||||
String operator()(Argument const &s) {
|
std::string operator()(Argument const &s) {
|
||||||
return String(s);
|
return std::string{s};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
struct ToString<std::pair<T, U>> {
|
struct ToString<std::pair<T, U>> {
|
||||||
using Argument = std::pair<T, U>;
|
using Argument = std::pair<T, U>;
|
||||||
using Result = String;
|
using Result = std::string;
|
||||||
String operator()(Argument const &v) {
|
std::string operator()(Argument const &v) {
|
||||||
String ret("{");
|
std::string ret{"{"};
|
||||||
ret += ToString<RemoveCv<RemoveReference<T>>>()(v.first);
|
ret += ToString<RemoveCv<RemoveReference<T>>>()(v.first);
|
||||||
ret += ", ";
|
ret += ", ";
|
||||||
ret += ToString<RemoveCv<RemoveReference<U>>>()(v.second);
|
ret += ToString<RemoveCv<RemoveReference<U>>>()(v.second);
|
||||||
|
@ -1018,7 +572,7 @@ namespace detail {
|
||||||
template<Size I, Size N>
|
template<Size I, Size N>
|
||||||
struct TupleToString {
|
struct TupleToString {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void append(String &ret, T const &tup) {
|
static void append(std::string &ret, T const &tup) {
|
||||||
ret += ", ";
|
ret += ", ";
|
||||||
ret += ToString<RemoveCv<RemoveReference<
|
ret += ToString<RemoveCv<RemoveReference<
|
||||||
decltype(std::get<I>(tup))
|
decltype(std::get<I>(tup))
|
||||||
|
@ -1030,13 +584,13 @@ namespace detail {
|
||||||
template<Size N>
|
template<Size N>
|
||||||
struct TupleToString<N, N> {
|
struct TupleToString<N, N> {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void append(String &, T const &) {}
|
static void append(std::string &, T const &) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<Size N>
|
template<Size N>
|
||||||
struct TupleToString<0, N> {
|
struct TupleToString<0, N> {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void append(String &ret, T const &tup) {
|
static void append(std::string &ret, T const &tup) {
|
||||||
ret += ToString<RemoveCv<RemoveReference<
|
ret += ToString<RemoveCv<RemoveReference<
|
||||||
decltype(std::get<0>(tup))
|
decltype(std::get<0>(tup))
|
||||||
>>>()(std::get<0>(tup));
|
>>>()(std::get<0>(tup));
|
||||||
|
@ -1048,9 +602,9 @@ namespace detail {
|
||||||
template<typename ...T>
|
template<typename ...T>
|
||||||
struct ToString<std::tuple<T...>> {
|
struct ToString<std::tuple<T...>> {
|
||||||
using Argument = std::tuple<T...>;
|
using Argument = std::tuple<T...>;
|
||||||
using Result = String;
|
using Result = std::string;
|
||||||
String operator()(Argument const &v) {
|
std::string operator()(Argument const &v) {
|
||||||
String ret("{");
|
std::string ret("{");
|
||||||
detail::TupleToString<0, sizeof...(T)>::append(ret, v);
|
detail::TupleToString<0, sizeof...(T)>::append(ret, v);
|
||||||
ret += "}";
|
ret += "}";
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1063,36 +617,10 @@ typename ToString<T>::Result to_string(T const &v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
String to_string(std::initializer_list<T> init) {
|
std::string to_string(std::initializer_list<T> init) {
|
||||||
return to_string(iter(init));
|
return to_string(iter(init));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: rvalue ref versions for rhs when we have efficient prepend */
|
|
||||||
|
|
||||||
inline String operator+(String const &lhs, ConstCharRange rhs) {
|
|
||||||
String ret(lhs); ret += rhs; return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline String operator+(ConstCharRange lhs, String const &rhs) {
|
|
||||||
String ret(lhs); ret += rhs; return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline String operator+(String const &lhs, char rhs) {
|
|
||||||
String ret(lhs); ret += rhs; return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline String operator+(char lhs, String const &rhs) {
|
|
||||||
String ret(lhs); ret += rhs; return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline String operator+(String &&lhs, ConstCharRange rhs) {
|
|
||||||
String ret(std::move(lhs)); ret += rhs; return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline String operator+(String &&lhs, char rhs) {
|
|
||||||
String ret(std::move(lhs)); ret += rhs; return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R>
|
template<typename R>
|
||||||
struct TempCString {
|
struct TempCString {
|
||||||
private:
|
private:
|
||||||
|
@ -1153,6 +681,17 @@ inline TempCString<R> to_temp_cstr(
|
||||||
return TempCString<R>(input, buf, bufsize);
|
return TempCString<R>(input, buf, bufsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* temporary */
|
||||||
|
template<>
|
||||||
|
struct ToHash<std::string> {
|
||||||
|
using Argument = std::string;
|
||||||
|
using Result = size_t;
|
||||||
|
|
||||||
|
size_t operator()(std::string const &v) const {
|
||||||
|
return std::hash<std::string>{}(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} /* namespace ostd */
|
} /* namespace ostd */
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
|
Loading…
Reference in a new issue