The test I added with available() passed "xyzwv" directly to the 3-arg
append(v, pos, count). That overload's viewable-T constraint excludes
const CharT*-convertible types (to avoid clashing with append(const
CharT*, size_type)), so the C-string literal doesn't match and there is
no viable 3-arg overload. Wrap the literal in std::string_view.
This returns max_size() - size(), i.e. the number of characters that can
still be inserted before the string reaches its capacity. Intended as a
shorthand for capacity-capped writes in combination with the
pos/count-taking overloads of append, assign, and insert:
str.append(sv, 0, str.available());
Addresses the ergonomic complaint in issue #81 without expanding the
overload set.
Closes issue #81.
The constructor taking a const CharT (&)[M] copied M - 1 characters
verbatim via assign(arr, M - 1), preserving any embedded NULs in the
input. This would violate the type's documented "no embedded NULs"
invariant.
const char arr[] = { '1', '2', '\0', '4', '5', '\0' };
static_cstring<5> s(arr);
// data_ holds {'1','2','\0','4','5','\0'} --- embedded NUL stored
Delegate to assign(arr) instead, which uses traits::length() to
determine the size. This matches the behavior of the other
CharT-accepting entry points (assign(const CharT*), the const CharT*
constructor) and makes the invariant self-enforcing at construction.
Note: In practice, this is a bug that would never surface, because the
array constructor is never chosen for static_cstring<N> s(arr)---the
pointer constructor always wins---but the array constructor is needed
for CTAD (deduction guide), so it better be correct.
This also means the test we added is, at the moment, superfluous.
compare(const CharT* s) constructed a temporary basic_static_cstring<N>
from s and delegated to the class-type overload. The constructor throws
std::length_error when traits::length(s) > N, and because compare() is
noexcept, the throw led to std::terminate():
static_cstring<3> s("abc");
s.compare("abcd"); // terminate() via noexcept throw
The free operator==() / operator!=() overloads for const CharT*, which
delegate to compare(), had the same flaw.
The defaulted operators had the wrong semantics, as they compared the
entire data_ buffer. The bug showed up when shrinking:
static_cstring<10> s("hello");
s.assign("hi", 2); // data_[3..4] still "lo"
static_cstring<10> fresh("hi");
assert(s == fresh); // FAILED
This introduces an alternative to basic_static_string designed for use
in POD types: Trivially copyable, having a sizeof == N + 1, with no
embedded NULs.
Placed in example/ to gather user feedback before committing to a public
API. See issue #23.
The iterator-based insert(const_iterator, size_type, value_type)
function relies on traits_type::move() to shift the existing null
terminator to its new position. Clang 3.7's constexpr evaluator does not
handle this correctly, causing the following test to fail:
static_string<3>{"ab"}.insert(2, 1, 'c') == "abc"
Add an explicit term() call, guarded by a preprocessor conditional for
Clang 3.7, to ensure proper null termination.
They were conditioned on detection of C++20 via __cplusplus, but Clang
10 and 11 don't support class types as NTTP, even though they report
C++20 via __cplusplus when -std=c++20 is used.
The config.hpp uses `BOOST_LIBSTDCXX_VERSION` which isn't defined in
standalone mode so `BOOST_STATIC_STRING_NO_CXX17_HDR_STRING_VIEW` will
be defined.
This then causes build failures for code expecting the availability of
string_view.
C++26 specifies that std::to_string() and std::to_wstring() format
floating point values as if using std::format(). This commit updates the
internal conversion helpers to match that behavior, using
std::format_to_n() for efficient, allocation-free formatting directly
into the static_string/static_wstring buffer.
Fallbacks using snprintf()/swprintf() remain active for pre-C++26
builds.
This ensures consistent formatting across standard and Boost APIs.
In the case of the floating point conversions, this effectively avoids a
copy of the buffer contents. In the case of the integer conversions, it
doesn't eliminate the copy, but still removes the extra buffer.
This fixes issue #65.