Last active
June 30, 2016 03:29
-
-
Save nekko1119/a08ea4c98741f21462bfabf466098c22 to your computer and use it in GitHub Desktop.
https://t.co/hZ7tAsTcwV の作りかけ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <algorithm> // std::min | |
#include <cstddef> // std::size_t, std::ptrdiff_t | |
#include <iterator> // std::reverse_iterator | |
#include <stdexcept> // std::out_of_range | |
#include <utility> // std::index_sequence, std::forward | |
namespace experimental { | |
namespace detail { | |
constexpr std::size_t strlen(char const* str, std::size_t n) { | |
return *str ? strlen(++str, n + 1) : n; | |
} | |
constexpr std::size_t strlen(char const* str) { | |
return strlen(str, 0U); | |
} | |
#if defined(_MSC_VER) | |
constexpr int compare(char const* left, char const* right, std::size_t pos, std::size_t length) { | |
return pos == length ? 0 | |
: left[pos] == right[pos] ? compare(left, right, pos + 1, length) | |
: left[pos] < right[pos] ? -1 : 1; | |
} | |
#else | |
constexpr int compare(char const* left, char const* right, std::size_t pos, std::size_t length) { | |
return pos == length ? 0 | |
: *left == *right ? compare(left + 1, right + 1, pos + 1, length) | |
: *left < *right ? -1 : 1; | |
} | |
#endif | |
constexpr int compare(int compared, std::size_t left_len, std::size_t right_len) { | |
return compared != 0 ? compared | |
: left_len < right_len ? -1 | |
: right_len < left_len ? 1 : 0; | |
} | |
} | |
template <typename CharT, std::size_t N> | |
class basic_fixed_string { | |
CharT data_[N + 1]; | |
public: | |
// types | |
using value_type = CharT; | |
using size_type = std::size_t; | |
using difference_type = std::ptrdiff_t; | |
using reference = value_type&; | |
using const_reference = const value_type&; | |
using pointer = value_type*; | |
using const_pointer = value_type const*; | |
using iterator = pointer; | |
using const_iterator = const_pointer; | |
using reverse_iterator = std::reverse_iterator<iterator>; | |
using const_reverse_iterator = std::reverse_iterator<const_iterator>; | |
static constexpr size_type npos = static_cast<size_type>(-1); | |
// construct/copy/conversions | |
constexpr basic_fixed_string() noexcept = default; | |
constexpr basic_fixed_string(basic_fixed_string const&) noexcept = default; | |
constexpr basic_fixed_string(value_type const (&str)[N + 1]) noexcept | |
: basic_fixed_string{std::make_index_sequence<N + 1>(), str} | |
{} | |
// differ from p0259r0 spec | |
basic_fixed_string& operator=(basic_fixed_string const&) = delete; | |
// iterators | |
#if !defined(_MSC_VER) | |
constexpr iterator begin() noexcept { | |
return this->data_; | |
} | |
#endif | |
constexpr const_iterator begin() const noexcept { | |
return this->data_; | |
} | |
#if !defined(_MSC_VER) | |
constexpr iterator end() noexcept { | |
return this->data_ + N; | |
} | |
#endif | |
constexpr const_iterator end() const noexcept { | |
return this->data_ + N; | |
} | |
// there is not constexpr reverse_iterator yet. since C++17 | |
#if !defined(_MSC_VER) | |
/*constexpr*/ reverse_iterator rbegin() noexcept { | |
return std::make_reverse_iterator(this->data_ + N); | |
} | |
#endif | |
/*constexpr*/ const_reverse_iterator rbegin() const noexcept { | |
return std::make_reverse_iterator(this->data_ + N); | |
} | |
#if !defined(_MSC_VER) | |
/*constexpr*/ reverse_iterator rend() noexcept { | |
return std::make_reverse_iterator(this->data_); | |
} | |
#endif | |
/*constexpr*/ const_reverse_iterator rend() const noexcept { | |
return std::make_reverse_iterator(this->data_ + N); | |
} | |
// capacity | |
constexpr size_type size() const noexcept { | |
return N; | |
} | |
constexpr size_type length() const noexcept { | |
return this->size(); | |
} | |
constexpr bool empty() const noexcept { | |
return N == 0; | |
} | |
// element access | |
#if !defined(_MSC_VER) | |
constexpr reference operator[](size_type pos) noexcept { | |
return this->data_[pos]; | |
} | |
#endif | |
constexpr const_reference operator[](size_type pos) const noexcept { | |
return this->data_[pos]; | |
} | |
constexpr const_pointer data() const noexcept { | |
return this->data_; | |
} | |
constexpr const_pointer c_str() const noexcept { | |
return this->data(); | |
} | |
template <std::size_t M> | |
constexpr int compare(basic_fixed_string<CharT, M> const& right) const noexcept { | |
return this->compare(0, size(), right.begin(), right.size()); | |
} | |
constexpr int compare(size_type pos, size_type left_len, CharT const* str, size_type right_len) const { | |
return pos > this->size() ? throw std::out_of_range{"pos must be smaller than size"} : detail::compare(detail::compare(this->data(), str, pos, std::min(left_len, right_len)), left_len, right_len); | |
} | |
private: | |
template <typename Str, std::size_t... Indices> | |
constexpr basic_fixed_string(std::index_sequence<Indices...>, Str const& str) noexcept | |
: data_{(Indices < N ? static_cast<value_type>(str[Indices]) : value_type{})...} | |
{} | |
public: | |
// for detail::concat | |
template <typename... Args, std::size_t... Indices> | |
constexpr basic_fixed_string(std::index_sequence<Indices...>, Args&&... args) noexcept | |
: data_{(Indices < N ? static_cast<value_type>(std::forward<Args>(args)) : value_type{})...} | |
{} | |
}; | |
namespace detail { | |
template <typename CharT, std::size_t L, std::size_t R, std::size_t... Indices> | |
constexpr basic_fixed_string<CharT, L + R - 1> concat( | |
basic_fixed_string<CharT, L> const& left, std::size_t left_size, | |
CharT const (&right)[R], std::size_t right_size, | |
std::index_sequence<Indices...>) { | |
return basic_fixed_string<CharT, L + R - 1>{ | |
std::make_index_sequence<L + R - 1>(), | |
(Indices < left_size ? left[Indices] : Indices < left_size + right_size ? right[Indices - left_size] : CharT{})... | |
}; | |
} | |
template <typename CharT, std::size_t L, std::size_t R, std::size_t... Indices> | |
constexpr basic_fixed_string<CharT, L + R - 1> concat( | |
CharT const (&left)[L], std::size_t left_size, | |
basic_fixed_string<CharT, R> const& right, std::size_t right_size, | |
std::index_sequence<Indices...>) { | |
return basic_fixed_string<CharT, L + R - 1>{ | |
std::make_index_sequence<L + R - 1>(), | |
(Indices < left_size ? left[Indices] : Indices < left_size + right_size ? right[Indices - left_size] : CharT{})... | |
}; | |
} | |
template <typename IntT> | |
constexpr IntT abs(IntT value) { | |
return value < 0 ? -value : value; | |
} | |
template <typename IntT> | |
constexpr IntT pow10(IntT exponent) { | |
return exponent ? 10 * pow10(exponent - 1) : 1; | |
} | |
template <typename IntT> | |
constexpr int digits10_i(IntT value) noexcept { | |
return value ? 1 + digits10_i(value / 10) : 0; | |
} | |
template <typename IntT> | |
constexpr int digits10(IntT value) noexcept { | |
return value ? 1 + digits10_i(value / 10) : 1; | |
} | |
template <typename IntT> | |
constexpr int displayed_digits10(IntT value) noexcept { | |
return digits10(value) + +(value < 0); | |
} | |
template <typename IntT, IntT value> | |
constexpr char to_char() noexcept { | |
static_assert(IntT{0} <= value && value <= IntT{9}, "value must be the single digit"); | |
return '0' + value; | |
} | |
template <typename IntT> | |
constexpr int digits10_at(IntT value, int digits) noexcept { | |
return abs(value / pow10(digits) % 10); | |
} | |
template <int value, int digits, std::size_t... Indices> | |
constexpr basic_fixed_string<char, displayed_digits10(value)> to_fixed_string_i(std::index_sequence<Indices...> seq) noexcept { | |
return value < 0 ? basic_fixed_string<char, displayed_digits10(value)>{ | |
std::make_index_sequence<sizeof...(Indices) + 1>(), | |
'-', (Indices < digits ? to_char<int, digits10_at(value, digits - 1 - Indices)>() : char {})... | |
} : basic_fixed_string<char, displayed_digits10(value)>{ | |
seq, | |
(Indices < digits ? to_char<int, digits10_at(value, digits - 1 - Indices)>() : char {})... | |
}; | |
} | |
} | |
// basic_fixed_string nonmember concatenation functions | |
template <typename CharT, std::size_t L, std::size_t R> | |
constexpr basic_fixed_string<CharT, L + R - 1> operator+(basic_fixed_string<CharT, L> const& left, CharT const(&right)[R]) noexcept { | |
return detail::concat(left, left.size(), right, R - 1, std::make_index_sequence<L + R - 1>()); | |
} | |
template <typename CharT, std::size_t L, std::size_t R> | |
constexpr basic_fixed_string<CharT, L + R - 1> operator+(CharT const(&left)[L], basic_fixed_string<CharT, R> const& right) noexcept { | |
return detail::concat(left, L - 1, right, right.size(), std::make_index_sequence<L + R - 1>()); | |
} | |
// basic_fixed_string nonmember comparison functions | |
template <typename CharT, std::size_t L, std::size_t R> | |
constexpr bool operator==(basic_fixed_string<CharT, L> const& left, basic_fixed_string<CharT, R> const& right) noexcept { | |
return left.compare(right) == 0; | |
} | |
template <typename CharT, std::size_t L, std::size_t R> | |
constexpr bool operator==(basic_fixed_string<CharT, L> const& left, CharT const(&right)[R]) noexcept { | |
return left.compare(0, left.size(), right, R - 1) == 0; | |
} | |
template <typename CharT, std::size_t L, std::size_t R> | |
constexpr bool operator==(CharT const(&left)[L], basic_fixed_string<CharT, R> const& right) noexcept { | |
return right.compare(0, right.size(), left, L - 1) == 0; | |
} | |
template <typename CharT, std::size_t L, std::size_t R> | |
constexpr bool operator!=(basic_fixed_string<CharT, L> const& left, basic_fixed_string<CharT, R> const& right) noexcept { | |
return !(left == right); | |
} | |
template <typename CharT, std::size_t L, std::size_t R> | |
constexpr bool operator!=(basic_fixed_string<CharT, L> const& left, CharT const(&right)[R]) noexcept { | |
return !(left == right); | |
} | |
template <typename CharT, std::size_t L, std::size_t R> | |
constexpr bool operator!=(CharT const(&left)[L], basic_fixed_string<CharT, R> const& right) noexcept { | |
return !(left == right); | |
} | |
// basic_fixed_string type aliases | |
template <std::size_t N> | |
using fixed_string = basic_fixed_string<char, N>; | |
template <std::size_t N> | |
using fixed_u16string = basic_fixed_string<char16_t, N>; | |
template <std::size_t N> | |
using fixed_u32string = basic_fixed_string<char32_t, N>; | |
template <std::size_t N> | |
using fixed_wstring = basic_fixed_string<wchar_t, N>; | |
// numeric conversions | |
template <int value> | |
constexpr fixed_string<detail::displayed_digits10(value)> to_fixed_string_i() noexcept { | |
return detail::to_fixed_string_i<value, detail::digits10(value)>(std::make_index_sequence<detail::digits10(value)>()); | |
} | |
// creation helper function | |
template <typename CharT, std::size_t N> | |
constexpr basic_fixed_string<CharT, N - 1> make_fixed_string(CharT const (&str)[N]) { | |
return basic_fixed_string<CharT, N - 1>{str}; | |
} | |
} | |
#include <iostream> | |
int main() { | |
{ | |
auto constexpr str = experimental::make_fixed_string("abc"); | |
auto constexpr str2 = str + "def"; | |
static_assert(str == "abc", ""); | |
static_assert("abc" == str, ""); | |
static_assert(str == str, ""); | |
static_assert(str != "abcd", ""); | |
static_assert("abcd" != str, ""); | |
static_assert(str != str2, ""); | |
for (auto const it : str2) { | |
std::cout << it << "\n"; | |
} | |
} | |
{ | |
auto constexpr str = experimental::to_fixed_string_i<12345>(); | |
static_assert(str == "12345", ""); | |
static_assert(str.size() == 5, ""); | |
} | |
{ | |
auto constexpr str = experimental::to_fixed_string_i<-12345>(); | |
static_assert(str == "-12345", ""); | |
static_assert(str.size() == 6, ""); | |
} | |
{ | |
//auto constexpr str = experimental::make_fixed_string("abc"); | |
//static_assert(str + "def" == "abcdef", ""); | |
//static_assert("def" + str == "defabc", ""); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment