1#ifndef NEFORCE_CORE_STRING_CHAR_TRAITS_HPP__
2#define NEFORCE_CORE_STRING_CHAR_TRAITS_HPP__
16NEFORCE_BEGIN_NAMESPACE__
33template <
typename CharT,
typename IntT>
39 "int_type must be able to represent all char_type values plus EOF");
121 NEFORCE_NODISCARD
static constexpr bool eq(
const char_type lhs,
const char_type rhs)
noexcept {
return lhs == rhs; }
129 NEFORCE_NODISCARD
static constexpr bool lt(
const char_type lhs,
const char_type rhs)
noexcept {
return lhs < rhs; }
137 return rsc ==
eof() ?
static_cast<int_type>(0) : rsc;
155template <
typename CharT,
typename IntT>
157 static_assert(
sizeof(CharT) ==
sizeof(
byte_t),
"size of CharT must be the same as byte type");
183 const size_t n)
noexcept {
226template <
typename CharT>
237#ifdef NEFORCE_STANDARD_20
256template <
typename Traits>
263template <
typename Traits>
269template <
typename Traits>
273template <
typename Traits>
286template <
typename CharT,
typename =
void>
287class __string_bitmap {
289 constexpr bool mark(
const CharT* ,
const CharT* )
const noexcept {
return false; }
290 constexpr bool match(
const CharT )
const noexcept {
return false; }
297template <
typename CharT>
298class __string_bitmap<CharT, enable_if_t<is_character_v<CharT> &&
sizeof(CharT) == 1>> {
300 bool matches_[numeric_traits<byte_t>::max() + 1] = {};
306 constexpr __string_bitmap() =
default;
314 constexpr bool mark(
const CharT* first,
const CharT*
const last)
noexcept {
315 for (; first != last; ++first) {
316 matches_[
static_cast<byte_t>(*first)] =
true;
326 constexpr bool match(
const CharT chr)
const noexcept {
return matches_[
static_cast<byte_t>(chr)]; }
339template <
typename Traits>
340constexpr size_t char_traits_find_bmh(
const char_traits_ptr_t<Traits> dest,
const size_t dest_size,
const size_t start,
341 const char_traits_ptr_t<Traits> rsc,
const size_t rsc_size)
noexcept {
343 return _NEFORCE char_traits_find_char<Traits>(dest, dest_size, start, rsc[0]);
346 size_t skip[256] = {};
347 for (
auto& s: skip) {
350 for (
size_t i = 0; i + 1 < rsc_size; ++i) {
351 skip[
static_cast<byte_t>(rsc[i])] = rsc_size - 1 - i;
354 const auto last = rsc[rsc_size - 1];
356 const size_t limit = dest_size - rsc_size;
359 if (Traits::eq(dest[i + rsc_size - 1], last)) {
360 if (Traits::compare(dest + i, rsc, rsc_size) == 0) {
364 i += skip[
static_cast<byte_t>(dest[i + rsc_size - 1])];
366 return static_cast<size_t>(-1);
381template <
typename Traits>
382constexpr size_t char_traits_rfind_bmh(
const char_traits_ptr_t<Traits> dest,
const size_t dest_size,
const size_t start,
383 const char_traits_ptr_t<Traits> rsc,
const size_t rsc_size)
noexcept {
385 return _NEFORCE char_traits_rfind_char<Traits>(dest, dest_size, start, rsc[0]);
388 size_t skip[256] = {};
389 for (
auto& s: skip) {
392 for (
size_t i = 0; i + 1 < rsc_size; ++i) {
393 skip[
static_cast<byte_t>(rsc[i])] = rsc_size - 1 - i;
396 const auto last = rsc[rsc_size - 1];
397 auto last_found =
static_cast<size_t>(-1);
398 const size_t limit = _NEFORCE
min(start, dest_size - rsc_size);
402 if (Traits::eq(dest[i + rsc_size - 1], last)) {
403 if (Traits::compare(dest + i, rsc, rsc_size) == 0) {
409 i += skip[
static_cast<byte_t>(dest[i + rsc_size - 1])];
415template <
typename Traits>
416constexpr size_t char_traits_find_naive(
const char_traits_ptr_t<Traits> dest,
const size_t dest_size,
417 const size_t start,
const char_traits_ptr_t<Traits> rsc,
418 const size_t rsc_size)
noexcept {
419 const auto may_match_end = dest + (dest_size - rsc_size) + 1;
420 for (
auto if_match = dest + start;; ++if_match) {
421 if_match = Traits::find(if_match,
static_cast<size_t>(may_match_end - if_match), *rsc);
423 return static_cast<size_t>(-1);
426 if (Traits::compare(if_match, rsc, rsc_size) == 0) {
427 return static_cast<size_t>(if_match - dest);
432template <
typename Traits>
433constexpr enable_if_t<
sizeof(
typename Traits::char_type) == 1,
size_t>
434char_traits_find_dispatch(
const char_traits_ptr_t<Traits> dest,
const size_t dest_size,
const size_t start,
435 const char_traits_ptr_t<Traits> rsc,
const size_t rsc_size)
noexcept {
436 return inner::char_traits_find_bmh<Traits>(dest, dest_size, start, rsc, rsc_size);
439template <
typename Traits>
440constexpr enable_if_t<(
sizeof(
typename Traits::char_type) != 1),
size_t>
441char_traits_find_dispatch(
const char_traits_ptr_t<Traits> dest,
const size_t dest_size,
const size_t start,
442 const char_traits_ptr_t<Traits> rsc,
const size_t rsc_size)
noexcept {
443 return inner::char_traits_find_naive<Traits>(dest, dest_size, start, rsc, rsc_size);
446template <
typename Traits>
447constexpr size_t char_traits_rfind_naive(
const char_traits_ptr_t<Traits> dest,
const size_t dest_size,
448 const size_t start,
const char_traits_ptr_t<Traits> rsc,
449 const size_t rsc_size)
noexcept {
450 if (rsc_size <= dest_size) {
451 for (
auto if_match = dest + _NEFORCE
min(start, dest_size - rsc_size);; --if_match) {
452 if (Traits::eq(*if_match, *rsc) && Traits::compare(if_match, rsc, rsc_size) == 0) {
453 return static_cast<size_t>(if_match - dest);
456 if (if_match == dest) {
461 return static_cast<size_t>(-1);
464template <
typename Traits>
465constexpr enable_if_t<
sizeof(
typename Traits::char_type) == 1,
size_t>
466char_traits_rfind_dispatch(
const char_traits_ptr_t<Traits> dest,
const size_t dest_size,
const size_t start,
467 const char_traits_ptr_t<Traits> rsc,
const size_t rsc_size)
noexcept {
468 return inner::char_traits_rfind_bmh<Traits>(dest, dest_size, start, rsc, rsc_size);
471template <
typename Traits>
472constexpr enable_if_t<(
sizeof(
typename Traits::char_type) != 1),
size_t>
473char_traits_rfind_dispatch(
const char_traits_ptr_t<Traits> dest,
const size_t dest_size,
const size_t start,
474 const char_traits_ptr_t<Traits> rsc,
const size_t rsc_size)
noexcept {
475 return inner::char_traits_rfind_naive<Traits>(dest, dest_size, start, rsc, rsc_size);
490template <
typename Traits>
493 if (lh_size != rh_size) {
500 return Traits::compare(lhs, rhs, lh_size) == 0;
512template <
typename Traits>
515 const int state = Traits::compare(lhs, rhs, _NEFORCE
min(lh_size, rh_size));
520 if (lh_size < rh_size) {
523 if (lh_size > rh_size) {
539template <
typename Traits>
542 if (rsc_size > dest_size || start > dest_size - rsc_size) {
543 return static_cast<size_t>(-1);
549 return inner::char_traits_find_dispatch<Traits>(dest, dest_size, start, rsc, rsc_size);
561template <
typename Traits>
564 if (start < dest_size) {
565 const auto found = Traits::find(dest + start, dest_size - start, chr);
567 return static_cast<size_t>(found - dest);
570 return static_cast<size_t>(-1);
583template <
typename Traits>
587 return _NEFORCE
min(start, dest_size);
589 if (rsc_size > dest_size) {
590 return static_cast<size_t>(-1);
593 return inner::char_traits_rfind_dispatch<Traits>(dest, dest_size, start, rsc, rsc_size);
605template <
typename Traits>
608 if (dest_size != 0) {
609 for (
auto if_match = dest + _NEFORCE
min(start, dest_size - 1);; --if_match) {
610 if (Traits::eq(*if_match, chr)) {
611 return static_cast<size_t>(if_match - dest);
614 if (if_match == dest) {
619 return static_cast<size_t>(-1);
632template <
typename Traits, enable_if_t<
633#ifdef NEFORCE_STANDARD_17
634 is_specialization_v<Traits, char_traits>
636 is_specialization_v<Traits, char_traits>()
642 const size_t rsc_size)
noexcept {
643 if (rsc_size != 0 && start < dest_size) {
644 inner::__string_bitmap<char_traits_char_t<Traits>> match;
645 if (!match.mark(rsc, rsc + rsc_size)) {
648 const auto end = dest + dest_size;
649 for (
auto if_match = dest + start; if_match <
end; ++if_match) {
650 if (match.match(*if_match)) {
651 return static_cast<size_t>(if_match - dest);
655 return static_cast<size_t>(-1);
668template <
typename Traits, enable_if_t<
669#ifdef NEFORCE_STANDARD_17
670 !is_specialization_v<Traits, char_traits>
672 !is_specialization_v<Traits, char_traits>()
678 const size_t rsc_size)
noexcept {
679 if (rsc_size != 0 && start < dest_size) {
680 const auto end = dest + dest_size;
681 for (
auto if_match = dest + start; if_match <
end; ++if_match) {
682 if (Traits::find(rsc, rsc_size, *if_match)) {
683 return static_cast<size_t>(if_match - dest);
687 return static_cast<size_t>(-1);
700template <
typename Traits, enable_if_t<
701#ifdef NEFORCE_STANDARD_17
702 is_specialization_v<Traits, char_traits>
704 is_specialization_v<Traits, char_traits>()
710 const size_t rsc_size)
noexcept {
711 if (rsc_size != 0 && dest_size != 0) {
712 inner::__string_bitmap<char_traits_char_t<Traits>> match;
713 if (!match.mark(rsc, rsc + rsc_size)) {
717 for (
auto if_match = dest + _NEFORCE
min(start, dest_size - 1);; --if_match) {
718 if (match.match(*if_match)) {
719 return static_cast<size_t>(if_match - dest);
722 if (if_match == dest) {
727 return static_cast<size_t>(-1);
740template <
typename Traits, enable_if_t<
741#ifdef NEFORCE_STANDARD_17
742 !is_specialization_v<Traits, char_traits>
744 !is_specialization_v<Traits, char_traits>()
750 const size_t rsc_size)
noexcept {
751 if (rsc_size != 0 && dest_size != 0) {
752 for (
auto if_match = dest + _NEFORCE
min(start, dest_size - 1);; --if_match) {
753 if (Traits::find(rsc, rsc_size, *if_match)) {
754 return static_cast<size_t>(if_match - dest);
757 if (if_match == dest) {
762 return static_cast<size_t>(-1);
775template <
typename Traits, enable_if_t<
776#ifdef NEFORCE_STANDARD_17
777 is_specialization_v<Traits, char_traits>
779 is_specialization_v<Traits, char_traits>()
785 const size_t rsc_size)
noexcept {
786 if (start < dest_size) {
787 inner::__string_bitmap<char_traits_char_t<Traits>> match;
788 if (!match.mark(rsc, rsc + rsc_size)) {
792 const auto end = dest + dest_size;
793 for (
auto if_match = dest + start; if_match <
end; ++if_match) {
794 if (!match.match(*if_match)) {
795 return static_cast<size_t>(if_match - dest);
799 return static_cast<size_t>(-1);
812template <
typename Traits, enable_if_t<
813#ifdef NEFORCE_STANDARD_17
814 !is_specialization_v<Traits, char_traits>
816 !is_specialization_v<Traits, char_traits>()
822 const size_t rsc_size)
noexcept {
823 if (start < dest_size) {
824 const auto end = dest + dest_size;
825 for (
auto if_match = dest + start; if_match <
end; ++if_match) {
826 if (!Traits::find(rsc, rsc_size, *if_match)) {
827 return static_cast<size_t>(if_match - dest);
831 return static_cast<size_t>(-1);
843template <
typename Traits>
846 if (start < dest_size) {
847 const auto end = dest + dest_size;
848 for (
auto if_match = dest + start; if_match <
end; ++if_match) {
849 if (!Traits::eq(*if_match, chr)) {
850 return static_cast<size_t>(if_match - dest);
854 return static_cast<size_t>(-1);
867template <
typename Traits, enable_if_t<
868#ifdef NEFORCE_STANDARD_17
869 is_specialization_v<Traits, char_traits>
871 is_specialization_v<Traits, char_traits>()
877 const size_t rsc_size)
noexcept {
878 if (dest_size != 0) {
879 inner::__string_bitmap<char_traits_char_t<Traits>> match;
880 if (!match.mark(rsc, rsc + rsc_size)) {
884 for (
auto if_match = dest + _NEFORCE
min(start, dest_size - 1);; --if_match) {
885 if (!match.match(*if_match)) {
886 return static_cast<size_t>(if_match - dest);
889 if (if_match == dest) {
894 return static_cast<size_t>(-1);
907template <
typename Traits, enable_if_t<
908#ifdef NEFORCE_STANDARD_17
909 !is_specialization_v<Traits, char_traits>
911 !is_specialization_v<Traits, char_traits>()
917 const size_t rsc_size)
noexcept {
918 if (dest_size != 0) {
919 for (
auto if_match = dest + _NEFORCE
min(start, dest_size - 1);; --if_match) {
920 if (!Traits::find(rsc, rsc_size, *if_match)) {
921 return static_cast<size_t>(if_match - dest);
924 if (if_match == dest) {
929 return static_cast<size_t>(-1);
941template <
typename Traits>
944 if (dest_size != 0) {
945 for (
auto if_match = dest + _NEFORCE
min(start, dest_size - 1);; --if_match) {
946 if (!Traits::eq(*if_match, chr)) {
947 return static_cast<size_t>(if_match - dest);
950 if (if_match == dest) {
955 return static_cast<size_t>(-1);
967template <
typename Traits>
969 const size_t start,
const charset& cs)
noexcept {
970 if (start < dest_size) {
971 const auto end = dest + dest_size;
972 for (
auto if_match = dest + start; if_match <
end; ++if_match) {
973 if (cs.contains(*if_match)) {
974 return static_cast<size_t>(if_match - dest);
978 return static_cast<size_t>(-1);
990template <
typename Traits>
992 const size_t start,
const charset& cs)
noexcept {
993 if (dest_size != 0) {
994 for (
auto if_match = dest + _NEFORCE
min(start, dest_size - 1);; --if_match) {
995 if (cs.contains(*if_match)) {
996 return static_cast<size_t>(if_match - dest);
998 if (if_match == dest) {
1003 return static_cast<size_t>(-1);
1015template <
typename Traits>
1017 const size_t start,
const charset& cs)
noexcept {
1018 if (start < dest_size) {
1019 const auto end = dest + dest_size;
1020 for (
auto if_match = dest + start; if_match <
end; ++if_match) {
1021 if (!cs.contains(*if_match)) {
1022 return static_cast<size_t>(if_match - dest);
1026 return static_cast<size_t>(-1);
1038template <
typename Traits>
1040 const size_t start,
const charset& cs)
noexcept {
1041 if (dest_size != 0) {
1042 for (
auto if_match = dest + _NEFORCE
min(start, dest_size - 1);; --if_match) {
1043 if (!cs.contains(*if_match)) {
1044 return static_cast<size_t>(if_match - dest);
1046 if (if_match == dest) {
1051 return static_cast<size_t>(-1);
1056#define __NEFORCE_BUILD_CHAR_PTR_HASH(OPT) \
1058 struct hash<OPT*> { \
1059 NEFORCE_NODISCARD constexpr size_t operator()(const OPT* str) const noexcept { \
1060 return XXH64(str, char_traits<OPT>::length(str) * sizeof(OPT)); \
1064 struct hash<const OPT*> { \
1065 NEFORCE_NODISCARD constexpr size_t operator()(const OPT* str) const noexcept { \
1066 return XXH64(str, char_traits<OPT>::length(str) * sizeof(OPT)); \
1069 template <size_t N> \
1070 struct hash<OPT[N]> { \
1071 NEFORCE_NODISCARD constexpr size_t operator()(const OPT (&str)[N]) const noexcept { \
1072 return XXH64(str, (N - 1) * sizeof(OPT)); \
1075 template <size_t N> \
1076 struct hash<const OPT[N]> { \
1077 NEFORCE_NODISCARD constexpr size_t operator()(const OPT (&str)[N]) const noexcept { \
1078 return XXH64(str, (N - 1) * sizeof(OPT)); \
1083#undef __NEFORCE_BUILD_CHAR_PTR_HASH
1085NEFORCE_END_NAMESPACE__
constexpr size_t char_traits_rfind(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_ptr_t< Traits > rsc, const size_t rsc_size) noexcept
从后向前查找子序列
constexpr size_t char_traits_find_not_char(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_char_t< Traits > chr) noexcept
查找第一个不等于指定字符的位置
constexpr int char_traits_compare(const char_traits_ptr_t< Traits > lhs, const size_t lh_size, const char_traits_ptr_t< Traits > rhs, const size_t rh_size) noexcept
比较两个字符序列(三路比较)
constexpr size_t char_traits_find_char(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_char_t< Traits > chr) noexcept
在字符序列中查找单个字符
constexpr size_t char_traits_find_first_not_of(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_ptr_t< Traits > rsc, const size_t rsc_size) noexcept
查找第一个不在给定集合中的字符(char_traits特化版本)
constexpr size_t char_traits_find(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_ptr_t< Traits > rsc, const size_t rsc_size) noexcept
在字符序列中查找子序列
constexpr size_t char_traits_find_last_not_of(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_ptr_t< Traits > rsc, const size_t rsc_size) noexcept
查找最后一个不在给定集合中的字符(char_traits特化版本)
constexpr bool char_traits_equal(const char_traits_ptr_t< Traits > lhs, const size_t lh_size, const char_traits_ptr_t< Traits > rhs, const size_t rh_size) noexcept
比较两个字符序列是否相等
constexpr size_t char_traits_find_first_of(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_ptr_t< Traits > rsc, const size_t rsc_size) noexcept
查找第一个出现在给定集合中的字符(char_traits特化版本)
constexpr size_t char_traits_find_last_of(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_ptr_t< Traits > rsc, const size_t rsc_size) noexcept
查找最后一个出现在给定集合中的字符(char_traits特化版本)
typename Traits::char_type char_traits_char_t
获取字符特征中的字符类型
constexpr size_t char_traits_rfind_not_char(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_char_t< Traits > chr) noexcept
查找最后一个不等于指定字符的位置
constexpr size_t char_traits_rfind_char(const char_traits_ptr_t< Traits > dest, const size_t dest_size, const size_t start, const char_traits_char_t< Traits > chr) noexcept
从后向前查找单个字符
const typename Traits::char_type * char_traits_ptr_t
获取字符特征中的字符指针类型
constexpr const T & min(const T &a, const T &b, Compare comp) noexcept(noexcept(comp(b, a)))
返回两个值中的较小者
unsigned char byte_t
字节类型,定义为无符号字符
constexpr iter_difference_t< Iterator > count(Iterator first, Iterator last, const T &value)
统计范围内等于指定值的元素数量
constexpr const void * memory_find(const void *dest, const byte_t value, size_t count) noexcept
在内存中搜索特定字节
constexpr void * memory_copy(void *__restrict dest, const void *__restrict src, size_t count) noexcept
从源内存复制到目标内存
constexpr int memory_compare(const void *lhs, const void *rhs, size_t count) noexcept
比较两个内存区域的内容
constexpr void * memory_set(void *dest, const byte_t value, size_t count) noexcept
使用指定字节填充内存区域
constexpr void * memory_move(void *dest, const void *src, size_t count) noexcept
从源内存移动数据到目标内存
constexpr const CharT * string_find(const CharT *str, const CharT chr) noexcept
查找字符在字符串中首次出现的位置
constexpr int string_compare(const CharT *dest, const CharT *src) noexcept
比较两个字符串
constexpr CharT * string_set(CharT *str, const CharT value) noexcept
将字符串中的所有字符设置为指定值
constexpr size_t string_length(const CharT *str) noexcept
计算字符串长度
constexpr decltype(auto) end(Container &cont) noexcept(noexcept(cont.end()))
获取容器的结束迭代器
#define NEFORCE_MACRO_RANGE_CHARS(MAC)
所有字符类型列表宏
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名
static constexpr char_type * assign(char_type *const str, const size_t count, const char_type chr) noexcept
将字符序列中的每个字符设置为指定值
static constexpr const char_type * find(const char_type *str, const size_t count, const char_type target) noexcept
在字符序列中查找指定字符
static constexpr bool lt(const char_type lhs, const char_type rhs) noexcept
小于比较
static constexpr int_type not_eof(const int_type rsc) noexcept
如果不是EOF则返回原值,否则返回0
static constexpr int compare(const char_type *lhs, const char_type *rhs, size_t count) noexcept
比较两个字符序列
static constexpr char_type * move(char_type *dest, const char_type *srcs, const size_t count) noexcept
移动字符序列
static constexpr size_t length(const char_type *str) noexcept
计算字符串长度
static constexpr char_type * copy(char_type *dest, const char_type *srcs, const size_t count) noexcept
复制字符序列
static constexpr int_type eof() noexcept
返回EOF值
static constexpr bool eq(const char_type lhs, const char_type rhs) noexcept
相等比较
static constexpr void assign(char_type &lhs, const char_type rhs) noexcept
赋值单个字符
static constexpr char_type * assign(char_type *str, size_t n, const char_type chr) noexcept
将字符序列中的每个字符设置为指定值(内存优化版本)
static constexpr int compare(const char_type *lhs, const char_type *rhs, const size_t n) noexcept
比较两个字符序列(内存优化版本)
static constexpr const char_type * find(const char_type *str, const size_t n, const char_type chr) noexcept
在字符序列中查找指定字符(内存优化版本)
static constexpr void assign(char_type &lhs, const char_type &rhs) noexcept
赋值单个字符