From 06411e7f8b64c0154706a8d39dc426c9fea394b0 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian@gmail.com>
Date: Wed, 10 Jan 2024 04:28:25 -0500
Subject: [PATCH 1/4] add build directory and CMake preset files to gitignore

---
 .gitignore | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore
index 74f33d3..9006ccd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,15 @@
 bin/
 bin64/
+build/
 
 # Because of CMake and VS2017
 Win32/
 x64/
 .vs/
-out/
\ No newline at end of file
+out/
+
+# VS CMake settings
+/CMakeSettings.json
+# CMake presets
+/CMakePresets.json
+/CMakeUserPresets.json

From 6b211959fce26dd1f658e9ec80e47a060e7441cb Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian@gmail.com>
Date: Wed, 10 Jan 2024 07:29:27 -0500
Subject: [PATCH 2/4] static_string can be used as a NTTP

---
 include/boost/static_string/static_string.hpp | 254 ++++++++++--------
 test/compile_fail.hpp                         |  10 -
 2 files changed, 148 insertions(+), 116 deletions(-)

diff --git a/include/boost/static_string/static_string.hpp b/include/boost/static_string/static_string.hpp
index fce1ddb..78463b8 100644
--- a/include/boost/static_string/static_string.hpp
+++ b/include/boost/static_string/static_string.hpp
@@ -310,103 +310,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
-  {
-    return data_;
-  }
-
-  BOOST_STATIC_STRING_CPP14_CONSTEXPR
-  const_pointer
-  data_impl() const noexcept
-  {
-    return data_;
-  }
-
-  BOOST_STATIC_STRING_CPP11_CONSTEXPR
-  std::size_t
-  size_impl() const noexcept
-  {
-    return size_;
-  }
 
-  BOOST_STATIC_STRING_CPP14_CONSTEXPR
-  std::size_t
-  set_size(std::size_t n) noexcept
+  struct size
   {
-    // 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_CPP14_CONSTEXPR
-  void
-  term_impl() noexcept
-  {
-    Traits::assign(data_[size_], value_type());
-  }
-
-  size_type size_ = 0;
-
-  value_type data_[N + 1]{};
+    class basic_static_string
+    {
+      friend derived_type;
+
+      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
+  {
+    class basic_static_string
+    {
+      friend derived_type;
+
+      BOOST_STATIC_STRING_CPP14_CONSTEXPR
+      pointer
+      data_impl() noexcept
+      {
+        return data;
+      }
+
+      BOOST_STATIC_STRING_CPP11_CONSTEXPR
+      const_pointer
+      data_impl() const noexcept
+      {
+        return data;
+      }
+
+    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
-  {
-    return const_cast<pointer>(&null_);
-  }
-
-  BOOST_STATIC_STRING_CPP11_CONSTEXPR
-  std::size_t
-  size_impl() const noexcept
-  {
-    return 0;
-  }
-
-  BOOST_STATIC_STRING_CPP11_CONSTEXPR
-  std::size_t
-  set_size(std::size_t) const noexcept
+  struct size
   {
-    return 0;
-  }
-
-  BOOST_STATIC_STRING_CPP14_CONSTEXPR
-  void
-  term_impl() const noexcept { }
-
-private:
-  static constexpr const value_type null_{};
+    class basic_static_string
+    {
+      friend derived_type;
+
+      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
+  {
+    class basic_static_string
+    {
+      friend derived_type;
+
+      BOOST_STATIC_STRING_CPP11_CONSTEXPR
+      pointer
+      data_impl() const noexcept
+      {
+        return const_cast<pointer>(&data);
+      }
+
+    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
@@ -415,6 +437,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
@@ -919,7 +948,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:
@@ -2211,7 +2244,7 @@ class basic_static_string
   void
   clear() noexcept
   {
-    this->set_size(0);
+    this->size_impl(0);
     term();
   }
 
@@ -2803,7 +2836,7 @@ class basic_static_string
   pop_back() noexcept
   {
     BOOST_STATIC_STRING_ASSERT(!empty());
-    this->set_size(size() - 1);
+    this->size_impl(size() - 1);
     term();
   }
 
@@ -2979,7 +3012,7 @@ class basic_static_string
     InputIterator first,
     InputIterator last)
   {
-    this->set_size(size() + read_back(true, first, last));
+    this->size_impl(size() + read_back(true, first, last));
     return term();
   }
 
@@ -5431,11 +5464,22 @@ class basic_static_string
   }
 
 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;
   }
 
@@ -5443,7 +5487,7 @@ class basic_static_string
   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();
   }
@@ -5517,7 +5561,7 @@ class basic_static_string
     const_pointer s,
     size_type count) noexcept
   {
-    this->set_size(count);
+    this->size_impl(count);
     traits_type::copy(data(), s, size() + 1);
     return *this;
   }
@@ -6434,7 +6478,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();
 }
@@ -6451,7 +6495,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();
 }
@@ -6473,13 +6517,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();
 }
 
@@ -6501,7 +6545,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];
 }
 
@@ -6554,7 +6598,7 @@ insert(
       traits_type::copy(dest, src, count);
     }
   }
-  this->set_size(curr_size + count);
+  this->size_impl(curr_size + count);
   return curr_data + index;
 }
 
@@ -6578,7 +6622,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;
 }
 
@@ -6594,7 +6638,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;
 }
 
@@ -6610,7 +6654,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();
 }
 
@@ -6628,7 +6672,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();
 }
 
@@ -6646,7 +6690,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();
 }
 
@@ -6662,7 +6706,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();
 }
 
@@ -6674,9 +6718,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);
 }
 
@@ -6695,10 +6739,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>
@@ -6721,7 +6763,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;
 }
 
@@ -6782,7 +6824,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;
 }
 
@@ -6814,7 +6856,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;
 }
 
@@ -6986,7 +7028,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;
 }
 
@@ -7008,7 +7050,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;
 }
 
diff --git a/test/compile_fail.hpp b/test/compile_fail.hpp
index d0d0dfd..03510f1 100644
--- a/test/compile_fail.hpp
+++ b/test/compile_fail.hpp
@@ -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");

From 1377ed8d275bdf54b0858889b88422a5d3fafd8f Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian@gmail.com>
Date: Wed, 10 Jan 2024 10:40:57 -0500
Subject: [PATCH 3/4] [FOLD] test static_string as NTTP

---
 test/constexpr_tests.hpp | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/test/constexpr_tests.hpp b/test/constexpr_tests.hpp
index 9b2e83c..392eb3a 100644
--- a/test/constexpr_tests.hpp
+++ b/test/constexpr_tests.hpp
@@ -605,5 +605,28 @@ testConstantEvaluation()
     cstatic_string().empty();
 #endif
 }
+
+#ifdef BOOST_STATIC_STRING_CPP20
+
+template<static_string<32> 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
\ No newline at end of file

From b890bf92d761979b4ad952effcd4b1b4e7488d91 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian@gmail.com>
Date: Tue, 20 Feb 2024 09:26:10 -0500
Subject: [PATCH 4/4] [FOLD]

---
 test/constexpr_tests.hpp | 78 +++++++++++++++++++++++++++++-----------
 1 file changed, 57 insertions(+), 21 deletions(-)

diff --git a/test/constexpr_tests.hpp b/test/constexpr_tests.hpp
index 392eb3a..ad8402e 100644
--- a/test/constexpr_tests.hpp
+++ b/test/constexpr_tests.hpp
@@ -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* s, std::size_t n, const char_type& ch)
+  {
+    for (; n--; ++s)
+    {
+      if (eq(*s, ch))
+        return s;
+    }
+    return nullptr;
   }
-  static constexpr const char_type* find(const char_type*, std::size_t, const char_type&){ return 0; }
+
   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
@@ -608,7 +644,7 @@ testConstantEvaluation()
 
 #ifdef BOOST_STATIC_STRING_CPP20
 
-template<static_string<32> X>
+template<basic_static_string<32, char, cxper_char_traits> X>
 struct nttp_primary
 {
   static constexpr bool value = false;