Skip to content

Instantly share code, notes, and snippets.

@nekko1119
Last active June 30, 2016 03:29
Show Gist options
  • Save nekko1119/a08ea4c98741f21462bfabf466098c22 to your computer and use it in GitHub Desktop.
Save nekko1119/a08ea4c98741f21462bfabf466098c22 to your computer and use it in GitHub Desktop.
https://t.co/hZ7tAsTcwV の作りかけ
#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 non­member 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 non­member 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