2017-01-29 23:54:06 +00:00
|
|
|
/* String utilities for OctaSTD.
|
2015-05-27 20:43:13 +00:00
|
|
|
*
|
|
|
|
* This file is part of OctaSTD. See COPYING.md for futher information.
|
|
|
|
*/
|
|
|
|
|
2015-07-13 19:08:55 +00:00
|
|
|
#ifndef OSTD_STRING_HH
|
|
|
|
#define OSTD_STRING_HH
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-05-27 21:15:24 +00:00
|
|
|
#include <stdio.h>
|
2015-05-27 20:43:13 +00:00
|
|
|
#include <stddef.h>
|
2016-09-01 23:06:13 +00:00
|
|
|
#include <ctype.h>
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2017-01-29 20:22:40 +00:00
|
|
|
#include <string>
|
|
|
|
#include <string_view>
|
2017-02-01 19:56:19 +00:00
|
|
|
#include <type_traits>
|
2017-02-08 00:06:50 +00:00
|
|
|
#include <functional>
|
2017-02-16 19:39:05 +00:00
|
|
|
#include <utility>
|
2017-01-29 20:22:40 +00:00
|
|
|
|
2015-07-13 19:08:55 +00:00
|
|
|
#include "ostd/range.hh"
|
|
|
|
#include "ostd/vector.hh"
|
2017-01-25 00:44:22 +00:00
|
|
|
#include "ostd/algorithm.hh"
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-07-13 19:07:14 +00:00
|
|
|
namespace ostd {
|
2015-06-09 17:59:25 +00:00
|
|
|
|
2017-02-12 22:02:49 +00:00
|
|
|
template<typename T, typename TR = std::char_traits<std::remove_const_t<T>>>
|
2017-02-16 19:02:55 +00:00
|
|
|
struct basic_char_range: input_range<basic_char_range<T>> {
|
2017-02-16 19:39:05 +00:00
|
|
|
using range_category = contiguous_range_tag;
|
2017-02-16 19:02:55 +00:00
|
|
|
using value_type = T;
|
|
|
|
using reference = T &;
|
|
|
|
using size_type = size_t;
|
|
|
|
using difference_type = ptrdiff_t;
|
2017-02-13 22:04:02 +00:00
|
|
|
|
2015-07-21 20:16:38 +00:00
|
|
|
private:
|
2017-02-17 16:50:44 +00:00
|
|
|
struct nat {};
|
2015-07-21 20:16:38 +00:00
|
|
|
|
|
|
|
public:
|
2017-02-16 17:48:14 +00:00
|
|
|
basic_char_range(): p_beg(nullptr), p_end(nullptr) {};
|
|
|
|
basic_char_range(T *beg, T *end): p_beg(beg), p_end(end) {}
|
|
|
|
basic_char_range(std::nullptr_t): p_beg(nullptr), p_end(nullptr) {}
|
2015-08-06 23:08:59 +00:00
|
|
|
|
2017-02-17 16:50:44 +00:00
|
|
|
template<typename U>
|
|
|
|
basic_char_range(U &&beg, std::enable_if_t<
|
|
|
|
std::is_convertible_v<U, T *>, nat
|
|
|
|
> = nat{}): p_beg(beg) {
|
|
|
|
if constexpr(std::is_array_v<std::remove_reference_t<U>>) {
|
|
|
|
size_t N = std::extent_v<std::remove_reference_t<U>>;
|
|
|
|
p_end = beg + N - (beg[N - 1] == '\0');
|
|
|
|
} else {
|
|
|
|
p_end = beg + (beg ? TR::length(beg) : 0);
|
|
|
|
}
|
|
|
|
}
|
2015-07-01 19:09:02 +00:00
|
|
|
|
2017-02-09 20:39:03 +00:00
|
|
|
template<typename STR, typename A>
|
2017-02-16 17:48:14 +00:00
|
|
|
basic_char_range(std::basic_string<std::remove_const_t<T>, STR, A> const &s):
|
2016-07-31 19:40:25 +00:00
|
|
|
p_beg(s.data()), p_end(s.data() + s.size())
|
|
|
|
{}
|
2015-06-09 17:59:25 +00:00
|
|
|
|
2017-02-17 16:50:44 +00:00
|
|
|
template<typename U, typename TTR, typename = std::enable_if_t<
|
2017-02-09 19:56:15 +00:00
|
|
|
std::is_convertible_v<U *, T *>
|
|
|
|
>>
|
2017-02-17 16:50:44 +00:00
|
|
|
basic_char_range(basic_char_range<U, TTR> const &v):
|
2016-07-31 19:40:25 +00:00
|
|
|
p_beg(&v[0]), p_end(&v[v.size()])
|
|
|
|
{}
|
2015-06-17 01:00:39 +00:00
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
basic_char_range &operator=(basic_char_range const &v) {
|
2015-06-09 17:59:25 +00:00
|
|
|
p_beg = v.p_beg; p_end = v.p_end; return *this;
|
|
|
|
}
|
2015-07-01 19:09:02 +00:00
|
|
|
|
2017-02-09 20:39:03 +00:00
|
|
|
template<typename STR, typename A>
|
2017-02-16 17:48:14 +00:00
|
|
|
basic_char_range &operator=(std::basic_string<T, STR, A> const &s) {
|
2015-06-09 17:59:25 +00:00
|
|
|
p_beg = s.data(); p_end = s.data() + s.size(); return *this;
|
|
|
|
}
|
2017-02-09 20:39:03 +00:00
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
basic_char_range &operator=(T *s) {
|
2017-02-09 20:39:03 +00:00
|
|
|
p_beg = s; p_end = s + (s ? TR::length(s) : 0); return *this;
|
2015-06-09 17:59:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool empty() const { return p_beg == p_end; }
|
|
|
|
|
|
|
|
bool pop_front() {
|
2016-07-31 19:40:25 +00:00
|
|
|
if (p_beg == p_end) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-06-09 17:59:25 +00:00
|
|
|
++p_beg;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool push_front() { --p_beg; return true; }
|
|
|
|
|
2017-01-30 18:11:39 +00:00
|
|
|
size_t pop_front_n(size_t n) {
|
|
|
|
size_t olen = p_end - p_beg;
|
2015-06-09 17:59:25 +00:00
|
|
|
p_beg += n;
|
|
|
|
if (p_beg > p_end) {
|
|
|
|
p_beg = p_end;
|
|
|
|
return olen;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2017-01-30 18:11:39 +00:00
|
|
|
size_t push_front_n(size_t n) { p_beg -= n; return true; }
|
2015-06-09 17:59:25 +00:00
|
|
|
|
|
|
|
T &front() const { return *p_beg; }
|
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
bool equals_front(basic_char_range const &range) const {
|
2015-06-09 17:59:25 +00:00
|
|
|
return p_beg == range.p_beg;
|
|
|
|
}
|
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
ptrdiff_t distance_front(basic_char_range const &range) const {
|
2015-06-09 17:59:25 +00:00
|
|
|
return range.p_beg - p_beg;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool pop_back() {
|
2016-07-31 19:40:25 +00:00
|
|
|
if (p_end == p_beg) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-06-09 17:59:25 +00:00
|
|
|
--p_end;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool push_back() { ++p_end; return true; }
|
|
|
|
|
2017-01-30 18:11:39 +00:00
|
|
|
size_t pop_back_n(size_t n) {
|
|
|
|
size_t olen = p_end - p_beg;
|
2015-06-09 17:59:25 +00:00
|
|
|
p_end -= n;
|
|
|
|
if (p_end < p_beg) {
|
|
|
|
p_end = p_beg;
|
|
|
|
return olen;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2017-01-30 18:11:39 +00:00
|
|
|
size_t push_back_n(size_t n) { p_end += n; return true; }
|
2015-06-09 17:59:25 +00:00
|
|
|
|
|
|
|
T &back() const { return *(p_end - 1); }
|
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
bool equals_back(basic_char_range const &range) const {
|
2015-06-09 17:59:25 +00:00
|
|
|
return p_end == range.p_end;
|
|
|
|
}
|
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
ptrdiff_t distance_back(basic_char_range const &range) const {
|
2015-06-09 17:59:25 +00:00
|
|
|
return range.p_end - p_end;
|
|
|
|
}
|
|
|
|
|
2017-01-30 18:11:39 +00:00
|
|
|
size_t size() const { return p_end - p_beg; }
|
2015-06-09 17:59:25 +00:00
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
basic_char_range slice(size_t start, size_t end) const {
|
|
|
|
return basic_char_range(p_beg + start, p_beg + end);
|
2015-06-09 17:59:25 +00:00
|
|
|
}
|
|
|
|
|
2017-01-30 18:11:39 +00:00
|
|
|
T &operator[](size_t i) const { return p_beg[i]; }
|
2015-06-09 17:59:25 +00:00
|
|
|
|
2015-07-01 20:12:45 +00:00
|
|
|
bool put(T v) {
|
2016-07-31 19:40:25 +00:00
|
|
|
if (empty()) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-06-09 17:59:25 +00:00
|
|
|
*(p_beg++) = v;
|
2015-07-01 20:12:45 +00:00
|
|
|
return true;
|
2015-06-09 17:59:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
T *data() { return p_beg; }
|
2016-06-23 18:18:35 +00:00
|
|
|
T const *data() const { return p_beg; }
|
2015-06-09 17:59:25 +00:00
|
|
|
|
2015-07-24 18:43:39 +00:00
|
|
|
/* non-range */
|
2017-02-16 17:48:14 +00:00
|
|
|
int compare(basic_char_range<T const> s) const {
|
2017-01-30 18:11:39 +00:00
|
|
|
size_t s1 = size(), s2 = s.size();
|
2016-08-17 23:34:20 +00:00
|
|
|
int ret;
|
2016-08-17 17:18:12 +00:00
|
|
|
if (!s1 || !s2) {
|
2016-08-17 23:34:20 +00:00
|
|
|
goto diffsize;
|
2016-08-17 17:18:12 +00:00
|
|
|
}
|
2017-02-09 20:39:03 +00:00
|
|
|
if ((ret = TR::compare(data(), s.data(), ostd::min(s1, s2)))) {
|
2016-08-17 23:34:20 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
diffsize:
|
|
|
|
return (s1 < s2) ? -1 : ((s1 > s2) ? 1 : 0);
|
2015-07-24 18:43:39 +00:00
|
|
|
}
|
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
int case_compare(basic_char_range<T const> s) const {
|
2017-01-30 18:11:39 +00:00
|
|
|
size_t s1 = size(), s2 = s.size();
|
|
|
|
for (size_t i = 0, ms = ostd::min(s1, s2); i < ms; ++i) {
|
2016-09-01 23:06:13 +00: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 22:32:30 +00:00
|
|
|
template<typename R>
|
2017-02-16 19:02:55 +00:00
|
|
|
std::enable_if_t<is_output_range<R>, size_t> copy(R &&orange, size_t n = -1) {
|
2017-02-13 22:04:02 +00:00
|
|
|
return range_put_n(orange, data(), ostd::min(n, size()));
|
2016-03-23 22:32:30 +00:00
|
|
|
}
|
|
|
|
|
2017-02-09 19:56:15 +00:00
|
|
|
size_t copy(std::remove_cv_t<T> *p, size_t n = -1) {
|
2017-01-30 18:11:39 +00:00
|
|
|
size_t c = ostd::min(n, size());
|
2017-02-09 20:39:03 +00:00
|
|
|
TR::copy(p, data(), c);
|
2016-03-23 22:32:30 +00:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2017-01-29 20:22:40 +00:00
|
|
|
/* that way we can assign, append etc to std::string */
|
2017-02-09 19:56:15 +00: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 20:22:40 +00:00
|
|
|
}
|
|
|
|
|
2015-06-09 17:59:25 +00:00
|
|
|
private:
|
|
|
|
T *p_beg, *p_end;
|
|
|
|
};
|
|
|
|
|
2017-02-13 22:04:02 +00:00
|
|
|
template<typename T, typename TR>
|
2017-02-16 17:48:14 +00:00
|
|
|
inline size_t range_put_n(basic_char_range<T, TR> &range, T const *p, size_t n) {
|
2017-02-13 22:04:02 +00:00
|
|
|
size_t an = ostd::min(n, range.size());
|
|
|
|
TR::copy(range.data(), p, an);
|
|
|
|
range.pop_front_n(an);
|
|
|
|
return an;
|
|
|
|
}
|
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
using char_range = basic_char_range<char>;
|
|
|
|
using string_range = basic_char_range<char const>;
|
2015-07-24 18:43:39 +00:00
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
/* comparisons between ranges */
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator==(
|
|
|
|
basic_char_range<T, TR> lhs, basic_char_range<T, TR> rhs
|
|
|
|
) {
|
|
|
|
return !lhs.compare(rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator!=(
|
|
|
|
basic_char_range<T, TR> lhs, basic_char_range<T, TR> rhs
|
|
|
|
) {
|
|
|
|
return lhs.compare(rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator<(
|
|
|
|
basic_char_range<T, TR> lhs, basic_char_range<T, TR> rhs
|
|
|
|
) {
|
|
|
|
return lhs.compare(rhs) < 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator>(
|
|
|
|
basic_char_range<T, TR> lhs, basic_char_range<T, TR> rhs
|
|
|
|
) {
|
|
|
|
return lhs.compare(rhs) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator<=(
|
|
|
|
basic_char_range<T, TR> lhs, basic_char_range<T, TR> rhs
|
|
|
|
) {
|
|
|
|
return lhs.compare(rhs) <= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator>=(
|
|
|
|
basic_char_range<T, TR> lhs, basic_char_range<T, TR> rhs
|
|
|
|
) {
|
|
|
|
return lhs.compare(rhs) >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* comparisons between mutable ranges and char arrays */
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator==(basic_char_range<T, TR> lhs, T const *rhs) {
|
|
|
|
return !lhs.compare(rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator!=(basic_char_range<T, TR> lhs, T const *rhs) {
|
|
|
|
return lhs.compare(rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator<(basic_char_range<T, TR> lhs, T const *rhs) {
|
|
|
|
return lhs.compare(rhs) < 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator>(basic_char_range<T, TR> lhs, T const *rhs) {
|
|
|
|
return lhs.compare(rhs) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator<=(basic_char_range<T, TR> lhs, T const *rhs) {
|
|
|
|
return lhs.compare(rhs) <= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator>=(basic_char_range<T, TR> lhs, T const *rhs) {
|
|
|
|
return lhs.compare(rhs) >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator==(T const *lhs, basic_char_range<T, TR> rhs) {
|
|
|
|
return !rhs.compare(lhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator!=(T const *lhs, basic_char_range<T, TR> rhs) {
|
|
|
|
return rhs.compare(lhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator<(T const *lhs, basic_char_range<T, TR> rhs) {
|
|
|
|
return rhs.compare(lhs) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator>(T const *lhs, basic_char_range<T, TR> rhs) {
|
|
|
|
return rhs.compare(lhs) < 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator<=(T const *lhs, basic_char_range<T, TR> rhs) {
|
|
|
|
return rhs.compare(lhs) >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator>=(T const *lhs, basic_char_range<T, TR> rhs) {
|
|
|
|
return rhs.compare(lhs) <= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* comparisons between immutable ranges and char arrays */
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator==(basic_char_range<T const, TR> lhs, T const *rhs) {
|
2015-07-24 18:43:39 +00:00
|
|
|
return !lhs.compare(rhs);
|
|
|
|
}
|
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator!=(basic_char_range<T const, TR> lhs, T const *rhs) {
|
2015-07-25 01:34:07 +00:00
|
|
|
return lhs.compare(rhs);
|
2015-07-24 18:43:39 +00:00
|
|
|
}
|
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator<(basic_char_range<T const, TR> lhs, T const *rhs) {
|
2015-07-24 18:43:39 +00:00
|
|
|
return lhs.compare(rhs) < 0;
|
|
|
|
}
|
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator>(basic_char_range<T const, TR> lhs, T const *rhs) {
|
2015-07-24 18:43:39 +00:00
|
|
|
return lhs.compare(rhs) > 0;
|
|
|
|
}
|
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator<=(basic_char_range<T const, TR> lhs, T const *rhs) {
|
2015-07-24 18:43:39 +00:00
|
|
|
return lhs.compare(rhs) <= 0;
|
|
|
|
}
|
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator>=(basic_char_range<T const, TR> lhs, T const *rhs) {
|
2015-07-24 18:43:39 +00:00
|
|
|
return lhs.compare(rhs) >= 0;
|
|
|
|
}
|
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator==(T const *lhs, basic_char_range<T const, TR> rhs) {
|
|
|
|
return !rhs.compare(lhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator!=(T const *lhs, basic_char_range<T const, TR> rhs) {
|
|
|
|
return rhs.compare(lhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator<(T const *lhs, basic_char_range<T const, TR> rhs) {
|
|
|
|
return rhs.compare(lhs) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator>(T const *lhs, basic_char_range<T const, TR> rhs) {
|
|
|
|
return rhs.compare(lhs) < 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator<=(T const *lhs, basic_char_range<T const, TR> rhs) {
|
|
|
|
return rhs.compare(lhs) >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename TR>
|
|
|
|
inline bool operator>=(T const *lhs, basic_char_range<T const, TR> rhs) {
|
|
|
|
return rhs.compare(lhs) <= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool starts_with(string_range a, string_range b
|
|
|
|
) {
|
2016-07-31 19:40:25 +00:00
|
|
|
if (a.size() < b.size()) {
|
2015-12-31 15:36:41 +00:00
|
|
|
return false;
|
2016-07-31 19:40:25 +00:00
|
|
|
}
|
2015-12-31 15:36:41 +00:00
|
|
|
return a.slice(0, b.size()) == b;
|
|
|
|
}
|
|
|
|
|
2017-02-01 19:56:19 +00:00
|
|
|
template<typename T, typename TR, typename A>
|
|
|
|
struct ranged_traits<std::basic_string<T, TR, A>> {
|
2017-02-16 17:48:14 +00:00
|
|
|
using range = basic_char_range<T, TR>;
|
2017-02-15 18:13:52 +00:00
|
|
|
|
|
|
|
static range iter(std::basic_string<T, TR, A> &v) {
|
|
|
|
return range{v.data(), v.data() + v.size()};
|
2017-01-29 20:22:40 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-02-01 19:56:19 +00:00
|
|
|
template<typename T, typename TR, typename A>
|
|
|
|
struct ranged_traits<std::basic_string<T, TR, A> const> {
|
2017-02-16 17:48:14 +00:00
|
|
|
using range = basic_char_range<T const, TR>;
|
2017-02-15 18:13:52 +00:00
|
|
|
|
|
|
|
static range iter(std::basic_string<T, TR, A> const &v) {
|
|
|
|
return range{v.data(), v.data() + v.size()};
|
2017-01-29 20:22:40 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-02-01 19:56:19 +00: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};
|
2017-02-16 19:02:55 +00:00
|
|
|
using C = range_category_t<R>;
|
|
|
|
if constexpr(std::is_convertible_v<C, finite_random_access_range_tag>) {
|
2017-02-01 19:56:19 +00:00
|
|
|
/* 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());
|
|
|
|
}
|
2015-07-12 02:11:05 +00:00
|
|
|
}
|
2017-01-29 23:54:06 +00:00
|
|
|
return ret;
|
2017-01-29 14:56:02 +00:00
|
|
|
}
|
|
|
|
|
2017-02-01 19:56:19 +00:00
|
|
|
template<
|
2017-02-16 19:02:55 +00:00
|
|
|
typename R, typename TR = std::char_traits<std::remove_cv_t<range_value_t<R>>>,
|
|
|
|
typename A = std::allocator<std::remove_cv_t<range_value_t<R>>>
|
2017-02-01 19:56:19 +00:00
|
|
|
>
|
2017-02-16 19:02:55 +00:00
|
|
|
inline std::basic_string<std::remove_cv_t<range_value_t<R>>, TR, A> make_string(
|
2017-02-01 19:56:19 +00:00
|
|
|
R range, A const &alloc = A{}
|
|
|
|
) {
|
2017-02-16 19:02:55 +00:00
|
|
|
return make_string<std::remove_cv_t<range_value_t<R>>, TR, A>(
|
2017-02-09 19:56:15 +00:00
|
|
|
std::move(range), alloc
|
|
|
|
);
|
2017-01-29 23:54:06 +00:00
|
|
|
}
|
2015-06-03 22:07:57 +00:00
|
|
|
|
2015-07-18 00:02:13 +00:00
|
|
|
/* string literals */
|
|
|
|
|
2016-07-31 19:40:25 +00:00
|
|
|
inline namespace literals {
|
|
|
|
inline namespace string_literals {
|
2017-02-16 17:48:14 +00:00
|
|
|
inline string_range operator "" _sr(char const *str, size_t len) {
|
|
|
|
return string_range(str, str + len);
|
2015-07-21 23:13:44 +00:00
|
|
|
}
|
2016-07-31 19:40:25 +00:00
|
|
|
}
|
|
|
|
}
|
2015-07-18 00:02:13 +00:00
|
|
|
|
2015-07-23 01:04:54 +00:00
|
|
|
namespace detail {
|
2016-07-31 19:40:25 +00:00
|
|
|
template<
|
2017-02-16 17:48:14 +00:00
|
|
|
typename T, bool = std::is_convertible_v<T, string_range>,
|
2017-02-09 19:56:15 +00:00
|
|
|
bool = std::is_convertible_v<T, char>
|
2016-07-31 19:40:25 +00:00
|
|
|
>
|
2015-07-23 01:04:54 +00:00
|
|
|
struct ConcatPut;
|
|
|
|
|
|
|
|
template<typename T, bool B>
|
|
|
|
struct ConcatPut<T, true, B> {
|
|
|
|
template<typename R>
|
2017-02-16 17:48:14 +00:00
|
|
|
static bool put(R &sink, string_range v) {
|
2017-02-13 22:04:02 +00:00
|
|
|
return v.size() && (range_put_n(sink, &v[0], v.size()) == v.size());
|
2015-07-23 01:04:54 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
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>
|
2017-02-16 17:48:14 +00:00
|
|
|
bool concat(R &&sink, T const &v, string_range sep, F func) {
|
2015-07-13 19:07:14 +00:00
|
|
|
auto range = ostd::iter(v);
|
2016-07-31 19:40:25 +00:00
|
|
|
if (range.empty()) {
|
|
|
|
return true;
|
|
|
|
}
|
2015-06-03 22:07:57 +00:00
|
|
|
for (;;) {
|
2015-07-23 01:04:54 +00:00
|
|
|
if (!detail::ConcatPut<
|
|
|
|
decltype(func(range.front()))
|
2016-07-31 19:40:25 +00:00
|
|
|
>::put(sink, func(range.front()))) {
|
2015-07-23 01:04:54 +00:00
|
|
|
return false;
|
2016-07-31 19:40:25 +00:00
|
|
|
}
|
2015-06-03 22:07:57 +00:00
|
|
|
range.pop_front();
|
2016-07-31 19:40:25 +00:00
|
|
|
if (range.empty()) {
|
|
|
|
break;
|
|
|
|
}
|
2017-02-13 22:04:02 +00:00
|
|
|
range_put_n(sink, &sep[0], sep.size());
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-07-23 01:04:54 +00:00
|
|
|
return true;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-28 18:58:05 +00:00
|
|
|
|
2015-07-23 01:04:54 +00:00
|
|
|
template<typename R, typename T>
|
2017-02-16 17:48:14 +00:00
|
|
|
bool concat(R &&sink, T const &v, string_range sep = " ") {
|
2015-07-13 19:07:14 +00:00
|
|
|
auto range = ostd::iter(v);
|
2016-07-31 19:40:25 +00:00
|
|
|
if (range.empty()) {
|
|
|
|
return true;
|
|
|
|
}
|
2015-06-03 22:07:57 +00:00
|
|
|
for (;;) {
|
2017-02-16 17:48:14 +00:00
|
|
|
string_range ret = range.front();
|
2017-02-13 22:04:02 +00:00
|
|
|
if (!ret.size() || (range_put_n(sink, &ret[0], ret.size()) != ret.size())) {
|
2015-07-23 01:04:54 +00:00
|
|
|
return false;
|
2016-07-31 19:40:25 +00:00
|
|
|
}
|
2015-06-03 22:07:57 +00:00
|
|
|
range.pop_front();
|
2016-07-31 19:40:25 +00:00
|
|
|
if (range.empty()) {
|
|
|
|
break;
|
|
|
|
}
|
2017-02-13 22:04:02 +00:00
|
|
|
range_put_n(sink, &sep[0], sep.size());
|
2015-05-28 18:58:05 +00:00
|
|
|
}
|
2015-07-23 01:04:54 +00:00
|
|
|
return true;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
|
|
|
|
2015-07-23 01:04:54 +00:00
|
|
|
template<typename R, typename T, typename F>
|
2017-02-16 17:48:14 +00:00
|
|
|
bool concat(R &&sink, std::initializer_list<T> v, string_range sep, F func) {
|
2015-07-23 01:04:54 +00:00
|
|
|
return concat(sink, ostd::iter(v), sep, func);
|
2015-07-12 14:55:41 +00:00
|
|
|
}
|
|
|
|
|
2015-07-23 01:04:54 +00:00
|
|
|
template<typename R, typename T>
|
2017-02-16 17:48:14 +00:00
|
|
|
bool concat(R &&sink, std::initializer_list<T> v, string_range sep = " ") {
|
2015-07-23 01:04:54 +00:00
|
|
|
return concat(sink, ostd::iter(v), sep);
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace detail {
|
2015-07-22 23:40:07 +00:00
|
|
|
template<typename R>
|
2017-02-16 19:02:55 +00:00
|
|
|
struct tostr_range: output_range<tostr_range<R>> {
|
|
|
|
using value_type = char;
|
|
|
|
using reference = char &;
|
|
|
|
using size_type = size_t;
|
|
|
|
using difference_type = ptrdiff_t;
|
2017-02-13 22:04:02 +00:00
|
|
|
|
|
|
|
template<typename RR>
|
2017-02-16 19:02:55 +00:00
|
|
|
friend size_t range_put_n(tostr_range<RR> &range, char const *p, size_t n);
|
2017-02-13 22:04:02 +00:00
|
|
|
|
2017-02-16 19:02:55 +00:00
|
|
|
tostr_range() = delete;
|
|
|
|
tostr_range(R &out): p_out(out), p_written(0) {}
|
2015-07-22 23:40:07 +00:00
|
|
|
bool put(char v) {
|
|
|
|
bool ret = p_out.put(v);
|
|
|
|
p_written += ret;
|
|
|
|
return ret;
|
|
|
|
}
|
2017-02-16 17:48:14 +00:00
|
|
|
size_t put_string(string_range r) {
|
2017-02-13 22:04:02 +00:00
|
|
|
size_t ret = range_put_n(p_out, r.data(), r.size());
|
2015-07-22 23:40:07 +00:00
|
|
|
p_written += ret;
|
|
|
|
return ret;
|
|
|
|
}
|
2017-01-30 18:11:39 +00:00
|
|
|
size_t get_written() const { return p_written; }
|
2015-07-22 23:40:07 +00:00
|
|
|
private:
|
|
|
|
R &p_out;
|
2017-01-30 18:11:39 +00:00
|
|
|
size_t p_written;
|
2015-07-22 23:40:07 +00:00
|
|
|
};
|
|
|
|
|
2017-02-13 22:04:02 +00:00
|
|
|
template<typename R>
|
2017-02-16 19:02:55 +00:00
|
|
|
inline size_t range_put_n(tostr_range<R> &range, char const *p, size_t n) {
|
2017-02-13 22:04:02 +00:00
|
|
|
size_t ret = range_put_n(range.p_out, p, n);
|
|
|
|
range.p_written += ret;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-07-22 23:40:07 +00:00
|
|
|
template<typename T, typename R>
|
2017-02-09 19:56:15 +00:00
|
|
|
static std::true_type test_stringify(
|
|
|
|
decltype(std::declval<T const &>().to_string(std::declval<R &>())) *
|
|
|
|
);
|
2015-07-22 23:40:07 +00:00
|
|
|
|
|
|
|
template<typename, typename>
|
2017-02-09 19:56:15 +00:00
|
|
|
static std::false_type test_stringify(...);
|
2015-07-11 16:26:41 +00:00
|
|
|
|
2015-07-22 23:40:07 +00:00
|
|
|
template<typename T, typename R>
|
2017-02-16 19:39:05 +00:00
|
|
|
constexpr bool stringify_test = decltype(test_stringify<T, R>(0))::value;
|
2015-07-11 18:54:51 +00:00
|
|
|
|
|
|
|
template<typename T>
|
2017-02-09 19:56:15 +00:00
|
|
|
static std::true_type test_iterable(decltype(ostd::iter(std::declval<T>())) *);
|
2016-07-31 19:40:25 +00:00
|
|
|
template<typename>
|
2017-02-09 19:56:15 +00:00
|
|
|
static std::false_type test_iterable(...);
|
2015-07-11 16:26:41 +00:00
|
|
|
|
|
|
|
template<typename T>
|
2017-02-16 19:39:05 +00:00
|
|
|
constexpr bool iterable_test = decltype(test_iterable<T>(0))::value;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-28 01:38:52 +00:00
|
|
|
|
2015-07-11 16:26:41 +00:00
|
|
|
template<typename T, typename = void>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct to_string;
|
2015-07-11 16:26:41 +00:00
|
|
|
|
|
|
|
template<typename T>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct to_string<T, std::enable_if_t<detail::iterable_test<T>>> {
|
2017-01-29 23:54:06 +00:00
|
|
|
std::string operator()(T const &v) const {
|
|
|
|
std::string ret("{");
|
|
|
|
auto x = appender<std::string>();
|
2017-02-16 19:39:05 +00:00
|
|
|
if (concat(x, ostd::iter(v), ", ", to_string<
|
2017-02-09 19:56:15 +00:00
|
|
|
std::remove_const_t<std::remove_reference_t<
|
2017-02-16 19:02:55 +00:00
|
|
|
range_reference_t<decltype(ostd::iter(v))>
|
2015-07-05 22:59:36 +00:00
|
|
|
>>
|
2016-07-31 19:40:25 +00:00
|
|
|
>())) {
|
|
|
|
ret += x.get();
|
|
|
|
}
|
2015-06-03 22:07:57 +00:00
|
|
|
ret += "}";
|
2015-06-25 17:59:26 +00:00
|
|
|
return ret;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-07-11 16:26:41 +00:00
|
|
|
};
|
2015-05-28 18:58:05 +00:00
|
|
|
|
2015-07-11 16:26:41 +00:00
|
|
|
template<typename T>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct to_string<T, std::enable_if_t<
|
|
|
|
detail::stringify_test<T, detail::tostr_range<appender_range<std::string>>>
|
2015-07-22 23:40:07 +00:00
|
|
|
>> {
|
2017-01-29 23:54:06 +00:00
|
|
|
std::string operator()(T const &v) const {
|
|
|
|
auto app = appender<std::string>();
|
2017-02-16 19:02:55 +00:00
|
|
|
detail::tostr_range<appender_range<std::string>> sink(app);
|
2016-07-31 19:40:25 +00:00
|
|
|
if (!v.to_string(sink)) {
|
2017-01-29 23:54:06 +00:00
|
|
|
return std::string{};
|
2016-07-31 19:40:25 +00:00
|
|
|
}
|
2017-01-25 00:44:22 +00:00
|
|
|
return std::move(app.get());
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
|
|
|
};
|
2015-05-27 21:15:24 +00:00
|
|
|
|
2016-07-31 19:40:25 +00:00
|
|
|
template<>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct to_string<bool> {
|
2017-01-29 23:54:06 +00:00
|
|
|
std::string operator()(bool b) {
|
2015-07-22 20:00:20 +00:00
|
|
|
return b ? "true" : "false";
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-07-31 19:40:25 +00:00
|
|
|
template<>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct to_string<char> {
|
2017-01-29 23:54:06 +00:00
|
|
|
std::string operator()(char c) {
|
|
|
|
std::string ret;
|
|
|
|
ret += c;
|
2015-06-25 17:59:26 +00:00
|
|
|
return ret;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-29 23:54:06 +00:00
|
|
|
#define OSTD_TOSTR_NUM(T) \
|
2016-07-31 19:40:25 +00:00
|
|
|
template<> \
|
2017-02-16 19:39:05 +00:00
|
|
|
struct to_string<T> { \
|
2017-01-29 23:54:06 +00:00
|
|
|
std::string operator()(T v) { \
|
|
|
|
return std::to_string(v); \
|
2015-06-03 22:07:57 +00:00
|
|
|
} \
|
|
|
|
};
|
|
|
|
|
2017-01-29 23:54:06 +00: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 19:08:55 +00:00
|
|
|
|
|
|
|
#undef OSTD_TOSTR_NUM
|
2015-06-03 22:07:57 +00:00
|
|
|
|
2016-07-31 19:40:25 +00:00
|
|
|
template<typename T>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct to_string<T *> {
|
|
|
|
std::string operator()(T *v) {
|
2017-01-29 23:54:06 +00:00
|
|
|
char buf[16];
|
|
|
|
sprintf(buf, "%p", v);
|
|
|
|
return buf;
|
2015-05-28 18:58:05 +00:00
|
|
|
}
|
2015-06-03 22:07:57 +00:00
|
|
|
};
|
2015-05-28 18:58:05 +00:00
|
|
|
|
2016-07-31 19:40:25 +00:00
|
|
|
template<>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct to_string<char const *> {
|
2017-01-29 23:54:06 +00:00
|
|
|
std::string operator()(char const *s) {
|
|
|
|
return s;
|
2015-07-10 00:17:08 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-07-31 19:40:25 +00:00
|
|
|
template<>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct to_string<char *> {
|
2017-01-29 23:54:06 +00:00
|
|
|
std::string operator()(char *s) {
|
2015-06-03 22:07:57 +00:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-29 20:22:40 +00:00
|
|
|
template<>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct to_string<std::string> {
|
|
|
|
std::string operator()(std::string const &s) {
|
2017-01-29 23:54:06 +00:00
|
|
|
return s;
|
2017-01-29 20:22:40 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-07-31 19:40:25 +00:00
|
|
|
template<>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct to_string<char_range> {
|
|
|
|
std::string operator()(char_range const &s) {
|
2017-01-29 23:54:06 +00:00
|
|
|
return std::string{s};
|
2015-06-09 17:59:25 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-07-31 19:40:25 +00:00
|
|
|
template<>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct to_string<string_range> {
|
|
|
|
std::string operator()(string_range const &s) {
|
2017-01-29 23:54:06 +00:00
|
|
|
return std::string{s};
|
2015-07-21 19:25:09 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-07-31 19:40:25 +00:00
|
|
|
template<typename T, typename U>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct to_string<std::pair<T, U>> {
|
|
|
|
std::string operator()(std::pair<T, U> const &v) {
|
2017-01-29 23:54:06 +00:00
|
|
|
std::string ret{"{"};
|
2017-02-16 19:39:05 +00:00
|
|
|
ret += to_string<std::remove_cv_t<std::remove_reference_t<T>>>()(v.first);
|
2015-06-03 22:07:57 +00:00
|
|
|
ret += ", ";
|
2017-02-16 19:39:05 +00:00
|
|
|
ret += to_string<std::remove_cv_t<std::remove_reference_t<U>>>()(v.second);
|
2016-03-27 22:49:27 +00:00
|
|
|
ret += "}";
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace detail {
|
2017-01-30 18:11:39 +00:00
|
|
|
template<size_t I, size_t N>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct tuple_to_str {
|
2016-03-27 22:49:27 +00:00
|
|
|
template<typename T>
|
2017-01-29 23:54:06 +00:00
|
|
|
static void append(std::string &ret, T const &tup) {
|
2016-03-27 22:49:27 +00:00
|
|
|
ret += ", ";
|
2017-02-16 19:39:05 +00:00
|
|
|
ret += to_string<std::remove_cv_t<std::remove_reference_t<
|
2017-01-28 18:06:52 +00:00
|
|
|
decltype(std::get<I>(tup))
|
|
|
|
>>>()(std::get<I>(tup));
|
2017-02-16 19:39:05 +00:00
|
|
|
tuple_to_str<I + 1, N>::append(ret, tup);
|
2016-03-27 22:49:27 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-30 18:11:39 +00:00
|
|
|
template<size_t N>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct tuple_to_str<N, N> {
|
2016-03-27 22:49:27 +00:00
|
|
|
template<typename T>
|
2017-01-29 23:54:06 +00:00
|
|
|
static void append(std::string &, T const &) {}
|
2016-03-27 22:49:27 +00:00
|
|
|
};
|
|
|
|
|
2017-01-30 18:11:39 +00:00
|
|
|
template<size_t N>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct tuple_to_str<0, N> {
|
2016-03-27 22:49:27 +00:00
|
|
|
template<typename T>
|
2017-01-29 23:54:06 +00:00
|
|
|
static void append(std::string &ret, T const &tup) {
|
2017-02-16 19:39:05 +00:00
|
|
|
ret += to_string<std::remove_cv_t<std::remove_reference_t<
|
2017-01-28 18:06:52 +00:00
|
|
|
decltype(std::get<0>(tup))
|
|
|
|
>>>()(std::get<0>(tup));
|
2017-02-16 19:39:05 +00:00
|
|
|
tuple_to_str<1, N>::append(ret, tup);
|
2016-03-27 22:49:27 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-01-28 17:30:31 +00:00
|
|
|
template<typename ...T>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct to_string<std::tuple<T...>> {
|
|
|
|
std::string operator()(std::tuple<T...> const &v) {
|
2017-01-29 23:54:06 +00:00
|
|
|
std::string ret("{");
|
2017-02-16 19:39:05 +00:00
|
|
|
detail::tuple_to_str<0, sizeof...(T)>::append(ret, v);
|
2017-01-28 17:30:31 +00:00
|
|
|
ret += "}";
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-03-21 21:21:41 +00:00
|
|
|
template<typename R>
|
2017-02-16 19:39:05 +00:00
|
|
|
struct temp_c_string {
|
2016-03-19 19:52:46 +00:00
|
|
|
private:
|
2017-02-16 19:02:55 +00:00
|
|
|
std::remove_cv_t<range_value_t<R>> *p_buf;
|
2016-03-19 19:52:46 +00:00
|
|
|
bool p_allocated;
|
|
|
|
|
|
|
|
public:
|
2017-02-16 19:39:05 +00:00
|
|
|
temp_c_string() = delete;
|
|
|
|
temp_c_string(temp_c_string const &) = delete;
|
|
|
|
temp_c_string(temp_c_string &&s): p_buf(s.p_buf), p_allocated(s.p_allocated) {
|
2016-03-19 19:52:46 +00:00
|
|
|
s.p_buf = nullptr;
|
|
|
|
s.p_allocated = false;
|
|
|
|
}
|
2017-02-16 19:39:05 +00:00
|
|
|
temp_c_string(R input, std::remove_cv_t<range_value_t<R>> *sbuf, size_t bufsize)
|
2016-03-19 19:52:46 +00:00
|
|
|
: p_buf(nullptr), p_allocated(false) {
|
2016-07-31 19:40:25 +00:00
|
|
|
if (input.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-03-19 19:52:46 +00:00
|
|
|
if (input.size() >= bufsize) {
|
2017-02-16 19:02:55 +00:00
|
|
|
p_buf = new std::remove_cv_t<range_value_t<R>>[input.size() + 1];
|
2016-03-19 19:52:46 +00:00
|
|
|
p_allocated = true;
|
2016-07-31 19:40:25 +00:00
|
|
|
} else {
|
|
|
|
p_buf = sbuf;
|
|
|
|
}
|
2016-03-21 21:21:41 +00:00
|
|
|
p_buf[input.copy(p_buf)] = '\0';
|
2016-03-19 19:52:46 +00:00
|
|
|
}
|
2017-02-16 19:39:05 +00:00
|
|
|
~temp_c_string() {
|
2016-07-31 19:40:25 +00:00
|
|
|
if (p_allocated) {
|
|
|
|
delete[] p_buf;
|
|
|
|
}
|
2016-03-19 19:52:46 +00:00
|
|
|
}
|
|
|
|
|
2017-02-16 19:39:05 +00:00
|
|
|
temp_c_string &operator=(temp_c_string const &) = delete;
|
|
|
|
temp_c_string &operator=(temp_c_string &&s) {
|
2016-03-19 19:52:46 +00:00
|
|
|
swap(s);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2017-02-16 19:02:55 +00:00
|
|
|
operator std::remove_cv_t<range_value_t<R>> const *() const { return p_buf; }
|
|
|
|
std::remove_cv_t<range_value_t<R>> const *get() const { return p_buf; }
|
2016-03-19 19:52:46 +00:00
|
|
|
|
2017-02-16 19:39:05 +00:00
|
|
|
void swap(temp_c_string &s) {
|
2017-01-29 14:56:02 +00:00
|
|
|
using std::swap;
|
|
|
|
swap(p_buf, s.p_buf);
|
|
|
|
swap(p_allocated, s.p_allocated);
|
2016-03-19 19:52:46 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-29 14:56:02 +00:00
|
|
|
template<typename R>
|
2017-02-16 19:39:05 +00:00
|
|
|
inline void swap(temp_c_string<R> &a, temp_c_string<R> &b) {
|
2017-01-29 14:56:02 +00:00
|
|
|
a.swap(b);
|
|
|
|
}
|
|
|
|
|
2016-03-21 21:21:41 +00:00
|
|
|
template<typename R>
|
2017-02-16 19:39:05 +00:00
|
|
|
inline temp_c_string<R> to_temp_cstr(
|
2017-02-16 19:02:55 +00:00
|
|
|
R input, std::remove_cv_t<range_value_t<R>> *buf, size_t bufsize
|
2016-07-31 19:40:25 +00:00
|
|
|
) {
|
2017-02-16 19:39:05 +00:00
|
|
|
return temp_c_string<R>(input, buf, bufsize);
|
2016-03-19 19:52:46 +00:00
|
|
|
}
|
|
|
|
|
2015-07-13 19:07:14 +00:00
|
|
|
} /* namespace ostd */
|
2015-06-03 22:07:57 +00:00
|
|
|
|
2017-01-29 20:22:40 +00:00
|
|
|
namespace std {
|
|
|
|
|
2017-02-16 17:48:14 +00:00
|
|
|
template<typename T, typename TR>
|
|
|
|
struct hash<ostd::basic_char_range<T, TR>> {
|
|
|
|
size_t operator()(ostd::basic_char_range<T, TR> const &v) const {
|
|
|
|
return hash<std::basic_string_view<std::remove_const_t<T>, TR>>{}(v);
|
2017-01-29 20:22:40 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-02-07 21:17:15 +00:00
|
|
|
#endif
|