323 lines
9.5 KiB
C++
323 lines
9.5 KiB
C++
/*
|
|
* Copyright (c) 2023, Alibaba Group Holding Limited;
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* Author's Email: metabeyond@outlook.com
|
|
* Author's Github: https://github.com/refvalue/
|
|
* Description: this source file contains an implementation of a compile-time
|
|
* meta-string that can be utilized as a non-type parameter of a template.
|
|
*/
|
|
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cstddef>
|
|
#if __has_include(<span>)
|
|
#include <compare>
|
|
#include <concepts>
|
|
#include <span>
|
|
#endif
|
|
#include <string_view>
|
|
#include <utility>
|
|
|
|
namespace refvalue {
|
|
template <std::size_t N>
|
|
struct meta_string {
|
|
std::array<char, N + 1> elements_;
|
|
|
|
constexpr meta_string() noexcept : elements_{} {}
|
|
|
|
constexpr meta_string(const char (&data)[N + 1]) noexcept {
|
|
for (size_t i = 0; i < N + 1; i++) elements_[i] = data[i];
|
|
}
|
|
|
|
#if __has_include(<span>)
|
|
template <std::size_t... Ns>
|
|
constexpr meta_string(std::span<const char, Ns>... data) noexcept
|
|
: elements_{} {
|
|
auto iter = elements_.begin();
|
|
|
|
((iter = std::copy(data.begin(), data.end(), iter)), ...);
|
|
}
|
|
#endif
|
|
|
|
template <std::size_t... Ns>
|
|
constexpr meta_string(const meta_string<Ns>&... data) noexcept : elements_{} {
|
|
auto iter = elements_.begin();
|
|
|
|
((iter = std::copy(data.begin(), data.end(), iter)), ...);
|
|
}
|
|
|
|
#if __has_include(<span>)
|
|
template <std::same_as<char>... Ts>
|
|
constexpr meta_string(Ts... chars) noexcept requires(sizeof...(Ts) == N)
|
|
: elements_{chars...} {}
|
|
#endif
|
|
|
|
constexpr char& operator[](std::size_t index) noexcept {
|
|
return elements_[index];
|
|
}
|
|
|
|
constexpr const char& operator[](std::size_t index) const noexcept {
|
|
return elements_[index];
|
|
}
|
|
|
|
constexpr operator std::string_view() const noexcept {
|
|
return std::string_view{elements_.data(), size()};
|
|
}
|
|
|
|
constexpr bool empty() const noexcept { return size() == 0; }
|
|
|
|
constexpr std::size_t size() const noexcept { return N; }
|
|
|
|
constexpr char& front() noexcept { return elements_.front(); }
|
|
|
|
constexpr const char& front() const noexcept { return elements_.front(); }
|
|
|
|
constexpr char& back() noexcept { return elements_[size() - 1]; }
|
|
|
|
constexpr const char& back() const noexcept { return elements_[size() - 1]; }
|
|
|
|
constexpr auto begin() noexcept { return elements_.begin(); }
|
|
|
|
constexpr auto begin() const noexcept { return elements_.begin(); }
|
|
|
|
constexpr auto end() noexcept { return elements_.begin() + size(); }
|
|
|
|
constexpr auto end() const noexcept { return elements_.begin() + size(); }
|
|
|
|
constexpr char* data() noexcept { return elements_.data(); }
|
|
|
|
constexpr const char* data() const noexcept { return elements_.data(); };
|
|
|
|
constexpr const char* c_str() const noexcept { return elements_.data(); }
|
|
|
|
constexpr bool contains(char c) const noexcept {
|
|
return std::find(begin(), end(), c) != end();
|
|
}
|
|
|
|
constexpr bool contains(std::string_view str) const noexcept {
|
|
return str.size() <= size()
|
|
? std::search(begin(), end(), str.begin(), str.end()) != end()
|
|
: false;
|
|
}
|
|
|
|
static constexpr size_t substr_len(size_t pos, size_t count) {
|
|
if (pos >= N) {
|
|
return 0;
|
|
}
|
|
else if (count == std::string_view::npos || pos + count > N) {
|
|
return N - pos;
|
|
}
|
|
else {
|
|
return count;
|
|
}
|
|
}
|
|
|
|
template <size_t pos, size_t count = std::string_view::npos>
|
|
constexpr meta_string<substr_len(pos, count)> substr() const noexcept {
|
|
constexpr size_t n = substr_len(pos, count);
|
|
|
|
meta_string<n> result;
|
|
for (std::size_t i = 0; i < n; ++i) {
|
|
result[i] = elements_[pos + i];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
constexpr size_t rfind(char c) const noexcept {
|
|
return std::string_view(*this).rfind(c);
|
|
}
|
|
|
|
constexpr size_t find(char c) const noexcept {
|
|
return std::string_view(*this).find(c);
|
|
}
|
|
};
|
|
|
|
template <std::size_t N>
|
|
meta_string(const char (&)[N]) -> meta_string<N - 1>;
|
|
|
|
#if __has_include(<span>)
|
|
template <std::size_t... Ns>
|
|
meta_string(std::span<const char, Ns>...) -> meta_string<(Ns + ...)>;
|
|
#endif
|
|
|
|
template <std::size_t... Ns>
|
|
meta_string(const meta_string<Ns>&...) -> meta_string<(Ns + ...)>;
|
|
|
|
#if __has_include(<span>)
|
|
template <std::same_as<char>... Ts>
|
|
meta_string(Ts...) -> meta_string<sizeof...(Ts)>;
|
|
#endif
|
|
|
|
#if __has_include(<span>)
|
|
template <std::size_t M, std::size_t N>
|
|
constexpr auto operator<=>(const meta_string<M>& left,
|
|
const meta_string<N>& right) noexcept {
|
|
return static_cast<std::string_view>(left).compare(
|
|
static_cast<std::string_view>(right)) <=> 0;
|
|
}
|
|
#endif
|
|
|
|
template <std::size_t M, std::size_t N>
|
|
constexpr bool operator==(const meta_string<M>& left,
|
|
const meta_string<N>& right) noexcept {
|
|
return static_cast<std::string_view>(left) ==
|
|
static_cast<std::string_view>(right);
|
|
}
|
|
|
|
template <std::size_t M, std::size_t N>
|
|
constexpr bool operator==(const meta_string<M>& left,
|
|
const char (&right)[N]) noexcept {
|
|
return static_cast<std::string_view>(left) ==
|
|
static_cast<std::string_view>(meta_string{right});
|
|
}
|
|
|
|
template <std::size_t M, std::size_t N>
|
|
constexpr auto operator+(const meta_string<M>& left,
|
|
const meta_string<N>& right) noexcept {
|
|
return meta_string{left, right};
|
|
}
|
|
|
|
template <std::size_t M, std::size_t N>
|
|
constexpr auto operator+(const meta_string<M>& left,
|
|
const char (&right)[N]) noexcept {
|
|
meta_string<M + N - 1> s;
|
|
for (size_t i = 0; i < M; ++i) s[i] = left[i];
|
|
for (size_t i = 0; i < N; ++i) s[M + i] = right[i];
|
|
return s;
|
|
}
|
|
|
|
template <std::size_t M, std::size_t N>
|
|
constexpr auto operator+(const char (&left)[M],
|
|
const meta_string<N>& right) noexcept {
|
|
meta_string<M + N - 1> s;
|
|
for (size_t i = 0; i < M - 1; ++i) s[i] = left[i];
|
|
for (size_t i = 0; i < N; ++i) s[M + i - 1] = right[i];
|
|
return s;
|
|
}
|
|
|
|
#if __has_include(<span>)
|
|
template <meta_string S, meta_string Delim>
|
|
struct split_of {
|
|
static constexpr auto value = [] {
|
|
constexpr std::string_view view{S};
|
|
constexpr auto group_count = std::count_if(S.begin(), S.end(),
|
|
[](char c) {
|
|
return Delim.contains(c);
|
|
}) +
|
|
1;
|
|
std::array<std::string_view, group_count> result{};
|
|
|
|
auto iter = result.begin();
|
|
|
|
for (std::size_t start_index = 0, end_index = view.find_first_of(Delim);;
|
|
start_index = end_index + 1,
|
|
end_index = view.find_first_of(Delim, start_index)) {
|
|
*(iter++) = view.substr(start_index, end_index - start_index);
|
|
|
|
if (end_index == std::string_view::npos) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}();
|
|
};
|
|
|
|
template <meta_string S, meta_string Delim>
|
|
inline constexpr auto&& split_of_v = split_of<S, Delim>::value;
|
|
|
|
template <meta_string S, meta_string Delim>
|
|
struct split {
|
|
static constexpr std::string_view view{S};
|
|
static constexpr auto value = [] {
|
|
constexpr auto group_count = [] {
|
|
std::size_t count{};
|
|
std::size_t index{};
|
|
|
|
while ((index = view.find(Delim, index)) != std::string_view::npos) {
|
|
count++;
|
|
index += Delim.size();
|
|
}
|
|
|
|
return count + 1;
|
|
}();
|
|
std::array<std::string_view, group_count> result{};
|
|
|
|
auto iter = result.begin();
|
|
|
|
for (std::size_t start_index = 0, end_index = view.find(Delim);;
|
|
start_index = end_index + Delim.size(),
|
|
end_index = view.find(Delim, start_index)) {
|
|
*(iter++) = view.substr(start_index, end_index - start_index);
|
|
|
|
if (end_index == std::string_view::npos) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}();
|
|
};
|
|
|
|
template <meta_string S, meta_string Delim>
|
|
inline constexpr auto&& split_v = split<S, Delim>::value;
|
|
|
|
template <meta_string S, char C>
|
|
struct remove_char {
|
|
static constexpr auto value = [] {
|
|
struct removal_metadata {
|
|
decltype(S) result;
|
|
std::size_t actual_size;
|
|
};
|
|
|
|
constexpr auto metadata = [] {
|
|
auto result = S;
|
|
auto removal_end = std::remove(result.begin(), result.end(), C);
|
|
|
|
return removal_metadata{
|
|
.result{std::move(result)},
|
|
.actual_size{static_cast<std::size_t>(removal_end - result.begin())}};
|
|
}();
|
|
|
|
meta_string<metadata.actual_size> result;
|
|
|
|
std::copy(metadata.result.begin(),
|
|
metadata.result.begin() + metadata.actual_size, result.begin());
|
|
|
|
return result;
|
|
}();
|
|
};
|
|
|
|
template <meta_string S, char C>
|
|
inline constexpr auto&& remove_char_v = remove_char<S, C>::value;
|
|
|
|
template <meta_string S, meta_string Removal>
|
|
struct remove {
|
|
static constexpr auto groups = split_v<S, Removal>;
|
|
static constexpr auto value = [] {
|
|
return []<std::size_t... Is>(std::index_sequence<Is...>) {
|
|
return meta_string{std::span<const char, groups[Is].size()>{
|
|
groups[Is].data(), groups[Is].size()}...};
|
|
}
|
|
(std::make_index_sequence<groups.size()>{});
|
|
}();
|
|
};
|
|
|
|
template <meta_string S, meta_string Removal>
|
|
inline constexpr auto&& remove_v = remove<S, Removal>::value;
|
|
#endif
|
|
} // namespace refvalue
|