blob: cb03ee72fe494a44096e708ed6a492ccda27308a [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_INTERNAL_CONST_STRING_H_
#define SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_INTERNAL_CONST_STRING_H_
#include <array>
#include <functional>
#include <string_view>
#include <type_traits>
namespace elfldltl::internal {
// This is a poor programmer's constexpr std::string (which C++ 20 has).
// It provides the barest subset of std::string functionality in constexpr:
// * Copy-constructible, constructible from string literals
// * Convertible to std::string_view, has those common methods
// * Has c_str() method with NUL terminator guarantee
// * Has operator+ that takes other ConstString types or string literals
// So essentially it acts as an immutable std::string that can be used in
// simple functional style.
template <size_t Len>
class ConstString {
public:
template <size_t N>
using ConstStringRef = const char (&)[N];
using Literal = ConstStringRef<Len + 1>;
constexpr ConstString(Literal other) { Appender{str_.data()}(other); }
template <size_t... N>
explicit constexpr ConstString(ConstStringRef<N>... literals) {
static_assert(((N - 1) + ...) == Len);
Appender append{str_.data()};
(append(literals), ...);
}
template <size_t... OtherLen>
explicit constexpr ConstString(const ConstString<OtherLen>&... other) {
static_assert((OtherLen + ...) == Len);
Appender append{str_.data()};
(append(other), ...);
}
constexpr const char* data() const { return str_.data(); }
constexpr size_t size() const { return Len; }
constexpr size_t empty() const { return size() == 0; }
constexpr const char* c_str() const { return str_.data(); }
constexpr const char* begin() const { return data(); }
constexpr const char* end() const { return data() + size(); }
constexpr operator std::string_view() const { return {data(), size()}; }
template <size_t OtherLen>
constexpr auto operator+(const ConstString<OtherLen>& other) const {
return ConstString<Len + OtherLen>(*this, other);
}
template <size_t OtherLenWithTerminator>
constexpr auto operator+(const char (&other)[OtherLenWithTerminator]) const {
return *this + ConstString<OtherLenWithTerminator - 1>(other);
}
private:
struct Appender {
template <size_t OtherLen>
constexpr void operator()(const ConstString<OtherLen>& str) {
for (char c : str) {
*p_++ = c;
}
}
constexpr void operator()(std::string_view str) {
for (char c : str) {
*p_++ = c;
}
}
char* p_ = nullptr;
};
std::array<char, Len + 1> str_{};
};
template <size_t Len>
ConstString(ConstString<Len> other) -> ConstString<Len>;
template <size_t LiteralLen>
ConstString(const char (&literal)[LiteralLen]) -> ConstString<LiteralLen - 1>;
} // namespace elfldltl::internal
#endif // SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_INTERNAL_CONST_STRING_H_