1
0
forked from Alepha/Alepha
Files
Alepha/ConstexprString.h

151 lines
4.3 KiB
C++

static_assert( __cplusplus > 2020'99 );
#pragma once
#include <Alepha/Alepha.h>
#include <cstddef>
#include <array>
#include <type_traits>
#include <algorithm>
#include <iostream>
namespace Alepha::Hydrogen ::detail:: ConstexprString_m
{
namespace C
{
// While a larger size for the maximum might be desirable, this consumes
// some constant amount of space in the compiler's symbol table. To be
// mindful of that, we want to not get TOO large.
//
// As compared to the GCC extension which uses a variadic length NTTP
// list, this may use less overall memory, in some ways. However, the
// benefit of the NTTP variadic list way, for compiler memory usage, is that
// the a type using the string as a parameter has a symbol size which
// is proportional to the number of chars in the string.
//
// However, NTTP parameters are pretty large in terms of memory footprint
// of the compiler and they do tax the compiler's CPU usage a lot more.
// As such, compile time strings of a "reasonable" size are probably the
// best we can hope for.
const std::size_t maxSize= 128;
}
inline namespace exports
{
struct ConstexprString;
inline namespace literals
{
consteval ConstexprString operator ""_cs( const char *s, std::size_t len );
}
}
struct exports::ConstexprString
{
private:
class BadConstantStringAllocationError
: public std::bad_alloc
{
public:
const char *
what() const noexcept final
{
return "Failure to allocate enough space for a a compile-time string.";
}
};
// Pretend that these are private, despite the fat that they are public.
// They have to be public, to work correctly with `template` parameters.
public:
std::array< char, C::maxSize > storage= {};// Always null terminated
std::size_t length= 0;
friend consteval ConstexprString literals::operator ""_cs( const char *, std::size_t );
public:
constexpr ConstexprString()= default;
constexpr
ConstexprString( const char *const s, std::size_t len )
{
if( len >= C::maxSize ) throw BadConstantStringAllocationError{};
std::copy_n( s, len, storage.begin() );
length= len;
}
template< std::size_t N >
constexpr
ConstexprString( const char (&s)[ N ] ) : ConstexprString( s, N ) {}
constexpr bool empty() const noexcept { return length == 0; }
constexpr std::size_t size() const noexcept { return length; }
constexpr auto begin() const noexcept { return storage.begin(); }
constexpr auto end() const noexcept { return storage.begin() + length; }
constexpr const char *c_str() const noexcept { return &storage[ 0 ]; }
constexpr const char *data() const noexcept { return &storage[ 0 ]; }
constexpr char *data() noexcept { return &storage[ 0 ]; }
friend constexpr ConstexprString
operator + ( const ConstexprString &lhs, const ConstexprString &rhs )
{
ConstexprString rv;
rv.length= lhs.size() + rhs.size();
if( rv.length >= C::maxSize ) throw BadConstantStringAllocationError{};
using std::begin, std::end;
const auto next= std::copy( begin( lhs ), end( lhs ), begin( rv.storage ) );
std::copy( begin( rhs ), end( rhs ), next );
return rv;
}
// The C++20 rules that build more operators upon these operators are fine:
friend constexpr bool
operator < ( const ConstexprString &lhs, const ConstexprString &rhs ) noexcept
{
using std::begin, std::end;
return std::lexicographical_compare( begin( lhs ), end( lhs ), begin( rhs ), end( rhs ) );
}
friend constexpr bool
operator == ( const ConstexprString &lhs, const ConstexprString &rhs ) noexcept
{
using std::begin, std::end;
return lhs.size() == rhs.size() and std::equal( begin( lhs ), end( lhs ), begin( rhs ) );
}
friend std::ostream &
operator << ( std::ostream &os, const ConstexprString &rhs )
{
return os << rhs.c_str();
}
// Total order is not helpful, here.
void operator<=>( ConstexprString )= delete;
};
consteval ConstexprString
exports::literals::operator ""_cs( const char *const s, const std::size_t len )
{
return ConstexprString( s, len );
}
}
namespace Alepha::Hydrogen::inline exports::inline ConstexprString_m
{
using namespace detail::ConstexprString_m::exports;
}
namespace Alepha::Hydrogen::inline exports::inline literals::inline constexpr_string_literals
{
using namespace ConstexprString_m::literals;
}