libostd/ostd/string.hh

718 lines
18 KiB
C++
Raw Normal View History

2017-01-30 00:54:06 +01:00
/* String utilities for OctaSTD.
2015-05-27 22:43:13 +02:00
*
* This file is part of OctaSTD. See COPYING.md for futher information.
*/
2015-07-13 21:08:55 +02:00
#ifndef OSTD_STRING_HH
#define OSTD_STRING_HH
2015-05-27 22:43:13 +02:00
2015-05-27 23:15:24 +02:00
#include <stdio.h>
2015-05-27 22:43:13 +02:00
#include <stddef.h>
2016-09-02 01:06:13 +02:00
#include <ctype.h>
2015-05-27 22:43:13 +02:00
2017-01-29 21:22:40 +01:00
#include <string>
#include <string_view>
#include <type_traits>
2017-02-08 01:06:50 +01:00
#include <functional>
2017-01-29 21:22:40 +01:00
2015-07-13 21:08:55 +02:00
#include "ostd/utility.hh"
#include "ostd/range.hh"
#include "ostd/vector.hh"
2017-01-25 01:44:22 +01:00
#include "ostd/algorithm.hh"
2015-05-27 22:43:13 +02:00
2015-07-13 21:07:14 +02:00
namespace ostd {
template<typename T, typename TR = std::char_traits<std::remove_const_t<T>>>
2015-07-21 23:06:23 +02:00
struct CharRangeBase: InputRange<
CharRangeBase<T>, ContiguousRangeTag, T
> {
2015-07-21 22:16:38 +02:00
private:
struct Nat {};
public:
2015-07-21 23:06:23 +02:00
CharRangeBase(): p_beg(nullptr), p_end(nullptr) {};
2017-02-09 21:27:20 +01:00
CharRangeBase(T *beg, T *end): p_beg(beg), p_end(end) {}
template<typename U>
CharRangeBase(
2017-02-09 20:56:15 +01:00
U beg, std::enable_if_t<
std::is_convertible_v<U, T *> && !std::is_array_v<U>, Nat
> = Nat()
2017-02-09 21:39:03 +01:00
): p_beg(beg), p_end(static_cast<T *>(beg) + (beg ? TR::length(beg) : 0)) {}
2017-01-30 19:19:09 +01:00
CharRangeBase(std::nullptr_t): p_beg(nullptr), p_end(nullptr) {}
2017-01-30 19:11:39 +01:00
template<typename U, size_t N>
2017-02-09 20:56:15 +01:00
CharRangeBase(U (&beg)[N], std::enable_if_t<
std::is_convertible_v<U *, T *>, Nat
> = Nat()):
p_beg(beg), p_end(beg + N - (beg[N - 1] == '\0'))
{}
2017-02-09 21:39:03 +01:00
template<typename STR, typename A>
CharRangeBase(std::basic_string<std::remove_const_t<T>, STR, A> const &s):
p_beg(s.data()), p_end(s.data() + s.size())
{}
2017-02-09 20:56:15 +01:00
template<typename U, typename = std::enable_if_t<
std::is_convertible_v<U *, T *>
>>
2016-06-23 20:18:35 +02:00
CharRangeBase(CharRangeBase<U> const &v):
p_beg(&v[0]), p_end(&v[v.size()])
{}
2015-06-17 03:00:39 +02:00
2016-06-23 20:18:35 +02:00
CharRangeBase &operator=(CharRangeBase const &v) {
p_beg = v.p_beg; p_end = v.p_end; return *this;
}
2017-02-09 21:39:03 +01:00
template<typename STR, typename A>
CharRangeBase &operator=(std::basic_string<T, STR, A> const &s) {
p_beg = s.data(); p_end = s.data() + s.size(); return *this;
}
2017-02-09 21:39:03 +01:00
2015-07-21 23:06:23 +02:00
CharRangeBase &operator=(T *s) {
2017-02-09 21:39:03 +01:00
p_beg = s; p_end = s + (s ? TR::length(s) : 0); return *this;
}
bool empty() const { return p_beg == p_end; }
bool pop_front() {
if (p_beg == p_end) {
return false;
}
++p_beg;
return true;
}
bool push_front() { --p_beg; return true; }
2017-01-30 19:11:39 +01:00
size_t pop_front_n(size_t n) {
size_t olen = p_end - p_beg;
p_beg += n;
if (p_beg > p_end) {
p_beg = p_end;
return olen;
}
return n;
}
2017-01-30 19:11:39 +01:00
size_t push_front_n(size_t n) { p_beg -= n; return true; }
T &front() const { return *p_beg; }
2016-06-23 20:18:35 +02:00
bool equals_front(CharRangeBase const &range) const {
return p_beg == range.p_beg;
}
2017-01-30 19:11:39 +01:00
ptrdiff_t distance_front(CharRangeBase const &range) const {
return range.p_beg - p_beg;
}
bool pop_back() {
if (p_end == p_beg) {
return false;
}
--p_end;
return true;
}
bool push_back() { ++p_end; return true; }
2017-01-30 19:11:39 +01:00
size_t pop_back_n(size_t n) {
size_t olen = p_end - p_beg;
p_end -= n;
if (p_end < p_beg) {
p_end = p_beg;
return olen;
}
return n;
}
2017-01-30 19:11:39 +01:00
size_t push_back_n(size_t n) { p_end += n; return true; }
T &back() const { return *(p_end - 1); }
2016-06-23 20:18:35 +02:00
bool equals_back(CharRangeBase const &range) const {
return p_end == range.p_end;
}
2017-01-30 19:11:39 +01:00
ptrdiff_t distance_back(CharRangeBase const &range) const {
return range.p_end - p_end;
}
2017-01-30 19:11:39 +01:00
size_t size() const { return p_end - p_beg; }
2017-01-30 19:11:39 +01:00
CharRangeBase slice(size_t start, size_t end) const {
2015-07-21 23:06:23 +02:00
return CharRangeBase(p_beg + start, p_beg + end);
}
2017-01-30 19:11:39 +01:00
T &operator[](size_t i) const { return p_beg[i]; }
2015-07-01 22:12:45 +02:00
bool put(T v) {
if (empty()) {
return false;
}
*(p_beg++) = v;
2015-07-01 22:12:45 +02:00
return true;
}
2017-01-30 19:11:39 +01:00
size_t put_n(T const *p, size_t n) {
size_t an = ostd::min(n, size());
2017-02-09 21:39:03 +01:00
TR::copy(p_beg, p, an);
2016-03-23 23:11:15 +01:00
p_beg += an;
return an;
}
T *data() { return p_beg; }
2016-06-23 20:18:35 +02:00
T const *data() const { return p_beg; }
/* non-range */
2016-06-23 20:18:35 +02:00
int compare(CharRangeBase<T const> s) const {
2017-01-30 19:11:39 +01:00
size_t s1 = size(), s2 = s.size();
2016-08-18 01:34:20 +02:00
int ret;
2016-08-17 19:18:12 +02:00
if (!s1 || !s2) {
2016-08-18 01:34:20 +02:00
goto diffsize;
2016-08-17 19:18:12 +02:00
}
2017-02-09 21:39:03 +01:00
if ((ret = TR::compare(data(), s.data(), ostd::min(s1, s2)))) {
2016-08-18 01:34:20 +02:00
return ret;
}
diffsize:
return (s1 < s2) ? -1 : ((s1 > s2) ? 1 : 0);
}
2016-09-02 01:06:13 +02:00
int case_compare(CharRangeBase<T const> s) const {
2017-01-30 19:11:39 +01:00
size_t s1 = size(), s2 = s.size();
for (size_t i = 0, ms = ostd::min(s1, s2); i < ms; ++i) {
2016-09-02 01:06:13 +02:00
int d = toupper(p_beg[i]) - toupper(s[i]);
if (d) {
return d;
}
}
return (s1 < s2) ? -1 : ((s1 > s2) ? 1 : 0);
}
2016-03-23 23:32:30 +01:00
template<typename R>
2017-02-09 20:56:15 +01:00
std::enable_if_t<IsOutputRange<R>, size_t> copy(R &&orange, size_t n = -1) {
2016-03-23 23:32:30 +01:00
return orange.put_n(data(), ostd::min(n, size()));
}
2017-02-09 20:56:15 +01:00
size_t copy(std::remove_cv_t<T> *p, size_t n = -1) {
2017-01-30 19:11:39 +01:00
size_t c = ostd::min(n, size());
2017-02-09 21:39:03 +01:00
TR::copy(p, data(), c);
2016-03-23 23:32:30 +01:00
return c;
}
2017-01-29 21:22:40 +01:00
/* that way we can assign, append etc to std::string */
2017-02-09 20:56:15 +01:00
operator std::basic_string_view<std::remove_cv_t<T>>() const {
return std::basic_string_view<std::remove_cv_t<T>>{data(), size()};
2017-01-29 21:22:40 +01:00
}
private:
T *p_beg, *p_end;
};
using CharRange = CharRangeBase<char>;
2016-06-23 20:18:35 +02:00
using ConstCharRange = CharRangeBase<char const>;
inline bool operator==(ConstCharRange lhs, ConstCharRange rhs) {
return !lhs.compare(rhs);
}
inline bool operator!=(ConstCharRange lhs, ConstCharRange rhs) {
return lhs.compare(rhs);
}
inline bool operator<(ConstCharRange lhs, ConstCharRange rhs) {
return lhs.compare(rhs) < 0;
}
inline bool operator>(ConstCharRange lhs, ConstCharRange rhs) {
return lhs.compare(rhs) > 0;
}
inline bool operator<=(ConstCharRange lhs, ConstCharRange rhs) {
return lhs.compare(rhs) <= 0;
}
inline bool operator>=(ConstCharRange lhs, ConstCharRange rhs) {
return lhs.compare(rhs) >= 0;
}
inline bool starts_with(ConstCharRange a, ConstCharRange b) {
if (a.size() < b.size()) {
return false;
}
return a.slice(0, b.size()) == b;
}
template<typename T, typename TR, typename A>
struct ranged_traits<std::basic_string<T, TR, A>> {
static CharRangeBase<T> iter(std::basic_string<T, TR, A> &v) {
2017-02-09 21:27:20 +01:00
return CharRangeBase<T>{v.data(), v.data() + v.size()};
2017-01-29 21:22:40 +01:00
}
};
template<typename T, typename TR, typename A>
struct ranged_traits<std::basic_string<T, TR, A> const> {
static CharRangeBase<T const> iter(std::basic_string<T, TR, A> const &v) {
2017-02-09 21:27:20 +01:00
return CharRangeBase<T const>{v.data(), v.data() + v.size()};
2017-01-29 21:22:40 +01:00
}
};
template<
typename T, typename TR = std::char_traits<T>,
typename A = std::allocator<T>, typename R
>
inline std::basic_string<T, TR, A> make_string(R range, A const &alloc = A{}) {
std::basic_string<T, TR, A> ret{alloc};
using C = RangeCategory<R>;
if constexpr(std::is_convertible_v<C, FiniteRandomAccessRangeTag>) {
/* finite random access or contiguous */
auto h = range.half();
ret.reserve(range.size());
ret.insert(ret.end(), h, h + range.size());
} else {
/* infinite random access and below */
for (; !range.empty(); range.pop_front()) {
ret.push_back(range.front());
}
}
2017-01-30 00:54:06 +01:00
return ret;
2017-01-29 15:56:02 +01:00
}
template<
2017-02-09 20:56:15 +01:00
typename R, typename TR = std::char_traits<std::remove_cv_t<RangeValue<R>>>,
typename A = std::allocator<std::remove_cv_t<RangeValue<R>>>
>
2017-02-09 20:56:15 +01:00
inline std::basic_string<std::remove_cv_t<RangeValue<R>>, TR, A> make_string(
R range, A const &alloc = A{}
) {
2017-02-09 20:56:15 +01:00
return make_string<std::remove_cv_t<RangeValue<R>>, TR, A>(
std::move(range), alloc
);
2017-01-30 00:54:06 +01:00
}
2015-06-04 00:07:57 +02:00
2015-07-18 02:02:13 +02:00
/* string literals */
inline namespace literals {
inline namespace string_literals {
2017-01-30 19:11:39 +01:00
inline ConstCharRange operator "" _sr(char const *str, size_t len) {
2017-02-09 21:27:20 +01:00
return ConstCharRange(str, str + len);
}
}
}
2015-07-18 02:02:13 +02:00
namespace detail {
template<
2017-02-09 20:56:15 +01:00
typename T, bool = std::is_convertible_v<T, ConstCharRange>,
bool = std::is_convertible_v<T, char>
>
struct ConcatPut;
template<typename T, bool B>
struct ConcatPut<T, true, B> {
template<typename R>
static bool put(R &sink, ConstCharRange v) {
return v.size() && (sink.put_n(&v[0], v.size()) == v.size());
}
};
template<typename T>
struct ConcatPut<T, false, true> {
template<typename R>
static bool put(R &sink, char v) {
return sink.put(v);
}
};
}
template<typename R, typename T, typename F>
2016-06-23 20:18:35 +02:00
bool concat(R &&sink, T const &v, ConstCharRange sep, F func) {
2015-07-13 21:07:14 +02:00
auto range = ostd::iter(v);
if (range.empty()) {
return true;
}
2015-06-04 00:07:57 +02:00
for (;;) {
if (!detail::ConcatPut<
decltype(func(range.front()))
>::put(sink, func(range.front()))) {
return false;
}
2015-06-04 00:07:57 +02:00
range.pop_front();
if (range.empty()) {
break;
}
sink.put_n(&sep[0], sep.size());
2015-06-04 00:07:57 +02:00
}
return true;
2015-06-04 00:07:57 +02:00
}
2015-05-28 20:58:05 +02:00
template<typename R, typename T>
2016-06-23 20:18:35 +02:00
bool concat(R &&sink, T const &v, ConstCharRange sep = " ") {
2015-07-13 21:07:14 +02:00
auto range = ostd::iter(v);
if (range.empty()) {
return true;
}
2015-06-04 00:07:57 +02:00
for (;;) {
ConstCharRange ret = range.front();
if (!ret.size() || (sink.put_n(&ret[0], ret.size()) != ret.size())) {
return false;
}
2015-06-04 00:07:57 +02:00
range.pop_front();
if (range.empty()) {
break;
}
sink.put_n(&sep[0], sep.size());
2015-05-28 20:58:05 +02:00
}
return true;
2015-06-04 00:07:57 +02:00
}
template<typename R, typename T, typename F>
bool concat(R &&sink, std::initializer_list<T> v, ConstCharRange sep, F func) {
return concat(sink, ostd::iter(v), sep, func);
2015-07-12 16:55:41 +02:00
}
template<typename R, typename T>
2015-07-25 03:07:51 +02:00
bool concat(R &&sink, std::initializer_list<T> v, ConstCharRange sep = " ") {
return concat(sink, ostd::iter(v), sep);
2015-06-04 00:07:57 +02:00
}
namespace detail {
template<typename R>
struct TostrRange: OutputRange<TostrRange<R>, char> {
TostrRange() = delete;
TostrRange(R &out): p_out(out), p_written(0) {}
bool put(char v) {
bool ret = p_out.put(v);
p_written += ret;
return ret;
}
2017-01-30 19:11:39 +01:00
size_t put_n(char const *v, size_t n) {
size_t ret = p_out.put_n(v, n);
p_written += ret;
return ret;
}
2017-01-30 19:11:39 +01:00
size_t put_string(ConstCharRange r) {
return put_n(&r[0], r.size());
}
2017-01-30 19:11:39 +01:00
size_t get_written() const { return p_written; }
private:
R &p_out;
2017-01-30 19:11:39 +01:00
size_t p_written;
};
template<typename T, typename R>
2017-02-09 20:56:15 +01:00
static auto test_stringify(int) -> std::integral_constant<
bool, std::is_same_v<decltype(std::declval<T>().stringify()), std::string>
>;
template<typename T, typename R>
2017-02-09 20:56:15 +01:00
static std::true_type test_stringify(
decltype(std::declval<T const &>().to_string(std::declval<R &>())) *
);
template<typename, typename>
2017-02-09 20:56:15 +01:00
static std::false_type test_stringify(...);
template<typename T, typename R>
constexpr bool StringifyTest = decltype(test_stringify<T, R>(0))::value;
2015-07-11 20:54:51 +02:00
template<typename T>
2017-02-09 20:56:15 +01:00
static std::true_type test_iterable(decltype(ostd::iter(std::declval<T>())) *);
template<typename>
2017-02-09 20:56:15 +01:00
static std::false_type test_iterable(...);
template<typename T>
constexpr bool IterableTest = decltype(test_iterable<T>(0))::value;
2015-06-04 00:07:57 +02:00
}
2015-05-28 03:38:52 +02:00
template<typename T, typename = void>
struct ToString;
template<typename T>
2017-02-09 20:56:15 +01:00
struct ToString<T, std::enable_if_t<detail::IterableTest<T>>> {
using Argument = std::remove_cv_t<std::remove_reference_t<T>>;
2017-01-30 00:54:06 +01:00
using Result = std::string;
2015-05-28 03:38:52 +02:00
2017-01-30 00:54:06 +01:00
std::string operator()(T const &v) const {
std::string ret("{");
auto x = appender<std::string>();
if (concat(x, ostd::iter(v), ", ", ToString<
2017-02-09 20:56:15 +01:00
std::remove_const_t<std::remove_reference_t<
2015-07-13 21:07:14 +02:00
RangeReference<decltype(ostd::iter(v))>
>>
>())) {
ret += x.get();
}
2015-06-04 00:07:57 +02:00
ret += "}";
return ret;
2015-06-04 00:07:57 +02:00
}
};
2015-05-28 20:58:05 +02:00
template<typename T>
2017-02-09 20:56:15 +01:00
struct ToString<T, std::enable_if_t<
2017-01-30 00:54:06 +01:00
detail::StringifyTest<T, detail::TostrRange<AppenderRange<std::string>>>
>> {
2017-02-09 20:56:15 +01:00
using Argument = std::remove_cv_t<std::remove_reference_t<T>>;
2017-01-30 00:54:06 +01:00
using Result = std::string;
2015-05-28 03:38:52 +02:00
2017-01-30 00:54:06 +01:00
std::string operator()(T const &v) const {
auto app = appender<std::string>();
detail::TostrRange<AppenderRange<std::string>> sink(app);
if (!v.to_string(sink)) {
2017-01-30 00:54:06 +01:00
return std::string{};
}
2017-01-25 01:44:22 +01:00
return std::move(app.get());
2015-06-04 00:07:57 +02:00
}
};
2015-05-27 23:15:24 +02:00
template<>
struct ToString<bool> {
2015-06-08 01:55:08 +02:00
using Argument = bool;
2017-01-30 00:54:06 +01:00
using Result = std::string;
std::string operator()(bool b) {
return b ? "true" : "false";
2015-06-04 00:07:57 +02:00
}
};
template<>
struct ToString<char> {
2015-06-08 01:55:08 +02:00
using Argument = char;
2017-01-30 00:54:06 +01:00
using Result = std::string;
std::string operator()(char c) {
std::string ret;
ret += c;
return ret;
2015-06-04 00:07:57 +02:00
}
};
2017-01-30 00:54:06 +01:00
#define OSTD_TOSTR_NUM(T) \
template<> \
struct ToString<T> { \
2015-06-08 01:55:08 +02:00
using Argument = T; \
2017-01-30 00:54:06 +01:00
using Result = std::string; \
std::string operator()(T v) { \
return std::to_string(v); \
2015-06-04 00:07:57 +02:00
} \
};
2017-01-30 00:54:06 +01:00
OSTD_TOSTR_NUM(sbyte)
OSTD_TOSTR_NUM(short)
OSTD_TOSTR_NUM(int)
OSTD_TOSTR_NUM(long)
OSTD_TOSTR_NUM(float)
OSTD_TOSTR_NUM(double)
OSTD_TOSTR_NUM(byte)
OSTD_TOSTR_NUM(ushort)
OSTD_TOSTR_NUM(uint)
OSTD_TOSTR_NUM(ulong)
OSTD_TOSTR_NUM(llong)
OSTD_TOSTR_NUM(ullong)
OSTD_TOSTR_NUM(ldouble)
2015-07-13 21:08:55 +02:00
#undef OSTD_TOSTR_NUM
2015-06-04 00:07:57 +02:00
template<typename T>
struct ToString<T *> {
2015-06-08 01:55:08 +02:00
using Argument = T *;
2017-01-30 00:54:06 +01:00
using Result = std::string;
std::string operator()(Argument v) {
char buf[16];
sprintf(buf, "%p", v);
return buf;
2015-05-28 20:58:05 +02:00
}
2015-06-04 00:07:57 +02:00
};
2015-05-28 20:58:05 +02:00
template<>
struct ToString<char const *> {
2016-06-23 20:18:35 +02:00
using Argument = char const *;
2017-01-30 00:54:06 +01:00
using Result = std::string;
std::string operator()(char const *s) {
return s;
2015-07-10 02:17:08 +02:00
}
};
template<>
struct ToString<char *> {
2015-07-11 21:18:46 +02:00
using Argument = char *;
2017-01-30 00:54:06 +01:00
using Result = std::string;
std::string operator()(char *s) {
2015-06-04 00:07:57 +02:00
return s;
}
};
2017-01-29 21:22:40 +01:00
template<>
struct ToString<std::string> {
using Argument = std::string;
2017-01-30 00:54:06 +01:00
using Result = std::string;
std::string operator()(Argument const &s) {
return s;
2017-01-29 21:22:40 +01:00
}
};
template<>
struct ToString<CharRange> {
2015-07-21 23:06:23 +02:00
using Argument = CharRange;
2017-01-30 00:54:06 +01:00
using Result = std::string;
std::string operator()(Argument const &s) {
return std::string{s};
}
};
template<>
struct ToString<ConstCharRange> {
2015-07-21 23:06:23 +02:00
using Argument = ConstCharRange;
2017-01-30 00:54:06 +01:00
using Result = std::string;
std::string operator()(Argument const &s) {
return std::string{s};
}
};
template<typename T, typename U>
struct ToString<std::pair<T, U>> {
using Argument = std::pair<T, U>;
2017-01-30 00:54:06 +01:00
using Result = std::string;
std::string operator()(Argument const &v) {
std::string ret{"{"};
2017-02-09 20:56:15 +01:00
ret += ToString<std::remove_cv_t<std::remove_reference_t<T>>>()(v.first);
2015-06-04 00:07:57 +02:00
ret += ", ";
2017-02-09 20:56:15 +01:00
ret += ToString<std::remove_cv_t<std::remove_reference_t<U>>>()(v.second);
2016-03-28 00:49:27 +02:00
ret += "}";
return ret;
}
};
namespace detail {
2017-01-30 19:11:39 +01:00
template<size_t I, size_t N>
2016-03-28 00:49:27 +02:00
struct TupleToString {
template<typename T>
2017-01-30 00:54:06 +01:00
static void append(std::string &ret, T const &tup) {
2016-03-28 00:49:27 +02:00
ret += ", ";
2017-02-09 20:56:15 +01:00
ret += ToString<std::remove_cv_t<std::remove_reference_t<
2017-01-28 19:06:52 +01:00
decltype(std::get<I>(tup))
>>>()(std::get<I>(tup));
2016-03-28 00:49:27 +02:00
TupleToString<I + 1, N>::append(ret, tup);
}
};
2017-01-30 19:11:39 +01:00
template<size_t N>
2016-03-28 00:49:27 +02:00
struct TupleToString<N, N> {
template<typename T>
2017-01-30 00:54:06 +01:00
static void append(std::string &, T const &) {}
2016-03-28 00:49:27 +02:00
};
2017-01-30 19:11:39 +01:00
template<size_t N>
2016-03-28 00:49:27 +02:00
struct TupleToString<0, N> {
template<typename T>
2017-01-30 00:54:06 +01:00
static void append(std::string &ret, T const &tup) {
2017-02-09 20:56:15 +01:00
ret += ToString<std::remove_cv_t<std::remove_reference_t<
2017-01-28 19:06:52 +01:00
decltype(std::get<0>(tup))
>>>()(std::get<0>(tup));
2016-03-28 00:49:27 +02:00
TupleToString<1, N>::append(ret, tup);
}
};
}
2017-01-28 18:30:31 +01:00
template<typename ...T>
struct ToString<std::tuple<T...>> {
using Argument = std::tuple<T...>;
2017-01-30 00:54:06 +01:00
using Result = std::string;
std::string operator()(Argument const &v) {
std::string ret("{");
2017-01-28 18:30:31 +01:00
detail::TupleToString<0, sizeof...(T)>::append(ret, v);
ret += "}";
return ret;
}
};
template<typename T>
2016-06-23 20:18:35 +02:00
typename ToString<T>::Result to_string(T const &v) {
2017-02-09 20:56:15 +01:00
return ToString<std::remove_cv_t<std::remove_reference_t<T>>>()(v);
2015-05-27 22:43:13 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename T>
2017-01-30 00:54:06 +01:00
std::string to_string(std::initializer_list<T> init) {
2015-07-11 22:54:58 +02:00
return to_string(iter(init));
2015-06-04 00:07:57 +02:00
}
template<typename R>
struct TempCString {
private:
2017-02-09 20:56:15 +01:00
std::remove_cv_t<RangeValue<R>> *p_buf;
bool p_allocated;
public:
TempCString() = delete;
2016-06-23 20:18:35 +02:00
TempCString(TempCString const &) = delete;
TempCString(TempCString &&s): p_buf(s.p_buf), p_allocated(s.p_allocated) {
s.p_buf = nullptr;
s.p_allocated = false;
}
2017-02-09 20:56:15 +01:00
TempCString(R input, std::remove_cv_t<RangeValue<R>> *sbuf, size_t bufsize)
: p_buf(nullptr), p_allocated(false) {
if (input.empty()) {
return;
}
if (input.size() >= bufsize) {
2017-02-09 20:56:15 +01:00
p_buf = new std::remove_cv_t<RangeValue<R>>[input.size() + 1];
p_allocated = true;
} else {
p_buf = sbuf;
}
p_buf[input.copy(p_buf)] = '\0';
}
~TempCString() {
if (p_allocated) {
delete[] p_buf;
}
}
2016-06-23 20:18:35 +02:00
TempCString &operator=(TempCString const &) = delete;
TempCString &operator=(TempCString &&s) {
swap(s);
return *this;
}
2017-02-09 20:56:15 +01:00
operator std::remove_cv_t<RangeValue<R>> const *() const { return p_buf; }
std::remove_cv_t<RangeValue<R>> const *get() const { return p_buf; }
void swap(TempCString &s) {
2017-01-29 15:56:02 +01:00
using std::swap;
swap(p_buf, s.p_buf);
swap(p_allocated, s.p_allocated);
}
};
2017-01-29 15:56:02 +01:00
template<typename R>
inline void swap(TempCString<R> &a, TempCString<R> &b) {
a.swap(b);
}
template<typename R>
inline TempCString<R> to_temp_cstr(
2017-02-09 20:56:15 +01:00
R input, std::remove_cv_t<RangeValue<R>> *buf, size_t bufsize
) {
return TempCString<R>(input, buf, bufsize);
}
2015-07-13 21:07:14 +02:00
} /* namespace ostd */
2015-06-04 00:07:57 +02:00
2017-01-29 21:22:40 +01:00
namespace std {
template<>
struct hash<ostd::CharRange> {
2017-01-30 19:30:49 +01:00
size_t operator()(ostd::CharRange const &v) const {
2017-01-29 21:22:40 +01:00
return hash<std::string_view>{}(v);
}
};
template<>
struct hash<ostd::ConstCharRange> {
2017-01-30 19:30:49 +01:00
size_t operator()(ostd::ConstCharRange const &v) const {
2017-01-29 21:22:40 +01:00
return hash<std::string_view>{}(v);
}
};
}
2016-02-07 22:17:15 +01:00
#endif