Make basic_static_string usable as a NTTP

This commit is contained in:
Krystian Stasiowski
2024-01-10 07:29:27 -05:00
committed by Gennaro Prota
parent 3a410b8472
commit 67efdf6a9b
3 changed files with 219 additions and 128 deletions

View File

@@ -314,103 +314,125 @@ copy_with_traits(
template<std::size_t N, typename CharT, typename Traits>
class static_string_base
{
private:
using derived_type = basic_static_string<N, CharT, Traits>;
friend derived_type;
using size_type = smallest_width<N>;
using value_type = typename Traits::char_type;
using pointer = value_type*;
using const_pointer = const value_type*;
public:
BOOST_STATIC_STRING_CPP11_CONSTEXPR
static_string_base() noexcept { };
BOOST_STATIC_STRING_CPP14_CONSTEXPR
pointer
data_impl() noexcept
struct size
{
return data_;
}
class basic_static_string
{
friend derived_type;
BOOST_STATIC_STRING_CPP14_CONSTEXPR
const_pointer
data_impl() const noexcept
BOOST_STATIC_STRING_CPP11_CONSTEXPR
size_type
size_impl() const noexcept
{
return size;
}
BOOST_STATIC_STRING_CPP14_CONSTEXPR
size_type
size_impl(std::size_t n) noexcept
{
// Functions that set size will throw
// if the new size would exceed max_size()
// therefore we can guarantee that this will
// not lose data.
return size = static_cast<size_type>(n);
}
public:
size_type size = 0;
};
};
struct data
{
return data_;
}
class basic_static_string
{
friend derived_type;
BOOST_STATIC_STRING_CPP11_CONSTEXPR
std::size_t
size_impl() const noexcept
{
return size_;
}
BOOST_STATIC_STRING_CPP14_CONSTEXPR
pointer
data_impl() noexcept
{
return data;
}
BOOST_STATIC_STRING_CPP14_CONSTEXPR
std::size_t
set_size(std::size_t n) noexcept
{
// Functions that set size will throw
// if the new size would exceed max_size()
// therefore we can guarantee that this will
// not lose data.
return size_ = size_type(n);
}
BOOST_STATIC_STRING_CPP11_CONSTEXPR
const_pointer
data_impl() const noexcept
{
return data;
}
BOOST_STATIC_STRING_CPP14_CONSTEXPR
void
term_impl() noexcept
{
Traits::assign(data_[size_], value_type());
}
size_type size_ = 0;
value_type data_[N + 1]{};
public:
value_type data[N + 1]{};
};
};
};
// Optimization for when the size is 0
template<typename CharT, typename Traits>
class static_string_base<0, CharT, Traits>
{
private:
using derived_type = basic_static_string<0, CharT, Traits>;
friend derived_type;
using size_type = std::size_t;
using value_type = typename Traits::char_type;
using pointer = value_type*;
public:
BOOST_STATIC_STRING_CPP11_CONSTEXPR
static_string_base() noexcept { }
// Modifying the null terminator is UB
BOOST_STATIC_STRING_CPP11_CONSTEXPR
pointer
data_impl() const noexcept
struct size
{
return const_cast<pointer>(&null_);
}
class basic_static_string
{
friend derived_type;
BOOST_STATIC_STRING_CPP11_CONSTEXPR
std::size_t
size_impl() const noexcept
BOOST_STATIC_STRING_CPP11_CONSTEXPR
size_type
size_impl() const noexcept
{
return 0;
}
BOOST_STATIC_STRING_CPP11_CONSTEXPR
size_type
size_impl(std::size_t) const noexcept
{
return 0;
}
};
};
struct data
{
return 0;
}
class basic_static_string
{
friend derived_type;
BOOST_STATIC_STRING_CPP11_CONSTEXPR
std::size_t
set_size(std::size_t) const noexcept
{
return 0;
}
BOOST_STATIC_STRING_CPP11_CONSTEXPR
pointer
data_impl() const noexcept
{
return const_cast<pointer>(&data);
}
BOOST_STATIC_STRING_CPP14_CONSTEXPR
void
term_impl() const noexcept { }
private:
static constexpr const value_type null_{};
public:
static constexpr value_type data{};
};
};
};
// This is only needed in C++14 and lower.
// see http://eel.is/c++draft/depr.static.constexpr
#ifndef BOOST_STATIC_STRING_CPP17
#if 0
template<typename CharT, typename Traits>
constexpr
const
@@ -419,6 +441,13 @@ static_string_base<0, CharT, Traits>::
null_;
#endif
template<typename CharT, typename Traits>
constexpr
typename static_string_base<0, CharT, Traits>::value_type
static_string_base<0, CharT, Traits>::data::basic_static_string::data;
#endif
template<typename CharT, typename Traits>
BOOST_STATIC_STRING_CPP14_CONSTEXPR
inline
@@ -1054,7 +1083,11 @@ template<std::size_t N, typename CharT,
typename Traits = std::char_traits<CharT>>
class basic_static_string
#ifndef BOOST_STATIC_STRING_DOCS
: private detail::static_string_base<N, CharT, Traits>
// : public detail::static_string_base<N, CharT, Traits>
: public detail::static_string_base<
N, CharT, Traits>::size::basic_static_string
, public detail::static_string_base<
N, CharT, Traits>::data::basic_static_string
#endif
{
private:
@@ -2339,7 +2372,7 @@ public:
void
clear() noexcept
{
this->set_size(0);
this->size_impl(0);
term();
}
@@ -2931,7 +2964,7 @@ public:
pop_back() noexcept
{
BOOST_STATIC_STRING_ASSERT(!empty());
this->set_size(size() - 1);
this->size_impl(size() - 1);
term();
}
@@ -3107,7 +3140,7 @@ public:
InputIterator first,
InputIterator last)
{
this->set_size(size() + read_back(true, first, last));
this->size_impl(size() + read_back(true, first, last));
return term();
}
@@ -5584,11 +5617,22 @@ public:
}
private:
BOOST_STATIC_STRING_CPP14_CONSTEXPR
void term_impl(std::true_type) noexcept
{
traits_type::assign(data()[size()], value_type());
}
BOOST_STATIC_STRING_CPP14_CONSTEXPR
void term_impl(std::false_type) noexcept
{
}
BOOST_STATIC_STRING_CPP14_CONSTEXPR
basic_static_string&
term() noexcept
{
this->term_impl();
term_impl(std::integral_constant<bool, N != 0>());
return *this;
}
@@ -5596,7 +5640,7 @@ private:
basic_static_string&
assign_char(value_type ch, std::true_type) noexcept
{
this->set_size(1);
this->size_impl(1);
traits_type::assign(data()[0], ch);
return term();
}
@@ -5670,7 +5714,7 @@ private:
const_pointer s,
size_type count) noexcept
{
this->set_size(count);
this->size_impl(count);
traits_type::copy(data(), s, size() + 1);
return *this;
}
@@ -6591,7 +6635,7 @@ assign(
if (count > max_size())
detail::throw_exception<std::length_error>(
"count > max_size()");
this->set_size(count);
this->size_impl(count);
traits_type::assign(data(), size(), ch);
return term();
}
@@ -6608,7 +6652,7 @@ assign(
if (count > max_size())
detail::throw_exception<std::length_error>(
"count > max_size()");
this->set_size(count);
this->size_impl(count);
traits_type::move(data(), s, size());
return term();
}
@@ -6630,13 +6674,13 @@ assign(
{
if (i >= max_size())
{
this->set_size(i);
this->size_impl(i);
term();
detail::throw_exception<std::length_error>("n > max_size()");
}
traits_type::assign(*ptr, *first);
}
this->set_size(ptr - data());
this->size_impl(ptr - data());
return term();
}
@@ -6658,7 +6702,7 @@ insert(
const auto index = pos - curr_data;
traits_type::move(&curr_data[index + count], &curr_data[index], curr_size - index + 1);
traits_type::assign(&curr_data[index], count, ch);
this->set_size(curr_size + count);
this->size_impl(curr_size + count);
return &curr_data[index];
}
@@ -6711,7 +6755,7 @@ insert(
traits_type::copy(dest, src, count);
}
}
this->set_size(curr_size + count);
this->size_impl(curr_size + count);
return curr_data + index;
}
@@ -6735,7 +6779,7 @@ insert(
const auto count = read_back(false, first, last);
const std::size_t index = pos - curr_data;
std::rotate(&curr_data[index], &curr_data[curr_size + 1], &curr_data[curr_size + count + 1]);
this->set_size(curr_size + count);
this->size_impl(curr_size + count);
return curr_data + index;
}
@@ -6751,7 +6795,7 @@ erase(
const auto curr_data = data();
const std::size_t index = first - curr_data;
traits_type::move(&curr_data[index], last, (end() - last) + 1);
this->set_size(size() - std::size_t(last - first));
this->size_impl(size() - std::size_t(last - first));
return curr_data + index;
}
@@ -6767,7 +6811,7 @@ push_back(
detail::throw_exception<std::length_error>(
"curr_size >= max_size()");
traits_type::assign(data()[curr_size], ch);
this->set_size(curr_size + 1);
this->size_impl(curr_size + 1);
term();
}
@@ -6785,7 +6829,7 @@ append(
detail::throw_exception<std::length_error>(
"count > max_size() - size()");
traits_type::assign(end(), count, ch);
this->set_size(curr_size + count);
this->size_impl(curr_size + count);
return term();
}
@@ -6803,7 +6847,7 @@ append(
detail::throw_exception<std::length_error>(
"count > max_size() - size()");
traits_type::copy(end(), s, count);
this->set_size(curr_size + count);
this->size_impl(curr_size + count);
return term();
}
@@ -6819,7 +6863,7 @@ resize(size_type n, value_type c)
const auto curr_size = size();
if(n > curr_size)
traits_type::assign(data() + curr_size, n - curr_size, c);
this->set_size(n);
this->size_impl(n);
term();
}
@@ -6839,7 +6883,7 @@ resize_and_overwrite(
CharT* p = data();
const auto new_size = std::move(op)(p, n);
BOOST_STATIC_STRING_ASSERT(new_size >= 0 && size_type(new_size) <= n);
this->set_size(size_type(new_size));
this->size_impl(size_type(new_size));
term();
}
@@ -6851,9 +6895,9 @@ swap(basic_static_string& s) noexcept
{
const auto curr_size = size();
basic_static_string tmp(s);
s.set_size(curr_size);
s.size_impl(curr_size);
traits_type::copy(&s.data()[0], data(), curr_size + 1);
this->set_size(tmp.size());
this->size_impl(tmp.size());
traits_type::copy(data(), tmp.data(), size() + 1);
}
@@ -6872,10 +6916,8 @@ swap(basic_static_string<M, CharT, Traits>& s)
detail::throw_exception<std::length_error>(
"s.size() > max_size()");
basic_static_string tmp(s);
s.set_size(curr_size);
traits_type::copy(&s.data()[0], data(), curr_size + 1);
this->set_size(tmp.size());
traits_type::copy(data(), &tmp.data()[0], size() + 1);
s.assign_unchecked(data(), curr_size);
assign_unchecked(tmp.data(), tmp.size());
}
template<std::size_t N, typename CharT, typename Traits>
@@ -6898,7 +6940,7 @@ replace(
const auto pos = i1 - curr_data;
traits_type::move(&curr_data[pos + n], i2, (end() - i2) + 1);
traits_type::assign(&curr_data[pos], n, c);
this->set_size((curr_size - n1) + n);
this->size_impl((curr_size - n1) + n);
return *this;
}
@@ -6959,7 +7001,7 @@ replace(
traits_type::move(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
}
}
this->set_size((curr_size - n1) + n2);
this->size_impl((curr_size - n1) + n2);
return *this;
}
@@ -6991,7 +7033,7 @@ replace(
// Move everything from the end of the splice point to the end of the rotated string to
// the begining of the splice point
traits_type::move(&curr_data[pos + n2], &curr_data[pos + n2 + n1], ((curr_size - n1) + n2) - pos);
this->set_size((curr_size - n1) + n2);
this->size_impl((curr_size - n1) + n2);
return *this;
}
@@ -7163,7 +7205,7 @@ replace_unchecked(
"replaced string exceeds max_size()");
traits_type::move(&curr_data[pos + n2], i2, (end() - i2) + 1);
traits_type::copy(&curr_data[pos], s, n2);
this->set_size((curr_size - n1) + n2);
this->size_impl((curr_size - n1) + n2);
return *this;
}
@@ -7185,7 +7227,7 @@ insert_unchecked(
const std::size_t index = pos - curr_data;
traits_type::move(&curr_data[index + count], pos, (end() - pos) + 1);
traits_type::copy(&curr_data[index], s, count);
this->set_size(curr_size + count);
this->size_impl(curr_size + count);
return curr_data + index;
}

View File

@@ -4,16 +4,6 @@
namespace boost {
namespace static_strings {
static_assert(std::is_base_of<
detail::static_string_base<0, char, std::char_traits<char>>,
static_string<0>>::value,
"the zero size optimization shall be used for N = 0");
static_assert(std::is_base_of<
detail::static_string_base<(std::numeric_limits<char>::max)() + 1, char, std::char_traits<char>>,
static_string<(std::numeric_limits<char>::max)() + 1>>::value,
"the minimum size type optimization shall be used for N > 0");
static_assert(!detail::is_input_iterator<int>::value, "is_input_iterator is incorrect");
static_assert(!detail::is_input_iterator<double>::value, "is_input_iterator is incorrect");
static_assert(detail::is_input_iterator<int*>::value, "is_input_iterator is incorrect");

View File

@@ -22,38 +22,74 @@ struct cxper_char_traits
using int_type = int;
using state_type = std::mbstate_t;
static constexpr void assign(char_type& a, const char_type& b) noexcept { a = b; }
static constexpr bool eq(char_type a, char_type b) noexcept { return a == b; }
static constexpr bool lt(char_type a, char_type b) noexcept { return a < b; }
static constexpr void assign(char_type& a, const char_type& b) noexcept
{
a = b;
}
static constexpr bool eq(char_type a, char_type b) noexcept
{
return a == b;
}
static constexpr bool lt(char_type a, char_type b) noexcept
{
return a < b;
}
static constexpr int compare(const char_type* a, const char_type* b, std::size_t n)
{
for (; n--; ++a, ++b)
{
if(lt(*a, *b))
return 1;
else if(lt(*b, *a))
return -1;
}
return 0;
}
static constexpr int compare(const char_type*, const char_type*, std::size_t) { return 0; }
static constexpr std::size_t length(const char_type* s)
{
std::size_t n = 0;
while (*(s++));
return n;
auto ptr = s;
while (!eq(*ptr, char_type()))
++ptr;
return ptr - s;
}
static constexpr const char_type* find(const char_type*, std::size_t, const char_type&){ return 0; }
static constexpr const char_type* find(const char_type* s, std::size_t n, const char_type& ch)
{
for (; n--; ++s)
{
if (eq(*s, ch))
return s;
}
return nullptr;
}
static constexpr char_type* move(char_type* dest, const char_type* src, std::size_t n)
{
const auto temp = dest;
while (n--)
*(dest++) = *(src++);
return temp;
if (detail::ptr_in_range(src, src + n, dest))
{
while (n--)
assign(dest[n], src[n]);
return dest;
}
return copy(dest, src, n);
}
static constexpr char_type* copy(char_type* dest, const char_type* src, std::size_t n)
{
const auto temp = dest;
while (n--)
*(dest++) = *(src++);
return temp;
for (auto ptr = dest; n--;)
assign(*ptr++, *src++);
return dest;
}
static constexpr char_type* assign(char_type* dest, std::size_t n, char_type ch)
{
const auto temp = dest;
while (n--)
*(dest++) = ch;
return temp;
for (auto ptr = dest; n--;)
assign(*ptr++, ch);
return dest;
}
};
#else
@@ -623,5 +659,28 @@ testConstantEvaluation()
cstatic_string().empty();
#endif
}
#ifdef BOOST_STATIC_STRING_CPP20
template<basic_static_string<32, char, cxper_char_traits> X>
struct nttp_primary
{
static constexpr bool value = false;
};
template<>
struct nttp_primary<"test string">
{
static constexpr bool value = true;
};
static_assert(!nttp_primary<"random string">::value,
"structural equality broken");
static_assert(nttp_primary<"test string">::value,
"structural equality broken");
#endif
} // static_strings
} // boost