From 28c8caae0ad546c00d0cdfecfe3942ca53611601 Mon Sep 17 00:00:00 2001 From: rexy712 Date: Sat, 19 Sep 2020 09:44:05 -0700 Subject: [PATCH] Add string searching with default option of two-way algorithm or user specified algorithm. Rearrange file structure to hopefully make things not seem arbitrarily placed in the cx subfolder --- CMakeLists.txt | 2 +- include/rexy/algorithm.hpp | 109 ++++++++++++++++++ include/rexy/{cx => }/basic_string_hash.hpp | 8 +- include/rexy/binary_base.hpp | 2 +- include/rexy/binary_base.tpp | 22 ++-- include/rexy/cx/algorithm.hpp | 65 ----------- include/rexy/cx/array.hpp | 8 +- include/rexy/cx/cx_string_hash.hpp | 2 +- .../rexy/cx/detail/bool_specialize_base.hpp | 2 +- include/rexy/cx/hashmap.hpp | 8 +- include/rexy/cx/string.hpp | 8 +- include/rexy/cx/vector.hpp | 22 ++-- include/rexy/detail/algorithm.hpp | 86 ++++++++++++++ include/rexy/filerd.hpp | 6 +- include/rexy/{cx => }/hash.hpp | 6 +- include/rexy/{cx => }/static_string_hash.hpp | 8 +- include/rexy/string_base.hpp | 22 +++- include/rexy/string_base.tpp | 61 ++++++++-- include/rexy/{cx => }/string_hash.hpp | 6 +- include/rexy/{cx => }/utility.hpp | 14 +-- src/ensure.cpp | 8 +- tests/basic_string.cpp | 9 ++ 22 files changed, 337 insertions(+), 147 deletions(-) create mode 100644 include/rexy/algorithm.hpp rename include/rexy/{cx => }/basic_string_hash.hpp (87%) delete mode 100644 include/rexy/cx/algorithm.hpp create mode 100644 include/rexy/detail/algorithm.hpp rename include/rexy/{cx => }/hash.hpp (95%) rename include/rexy/{cx => }/static_string_hash.hpp (87%) rename include/rexy/{cx => }/string_hash.hpp (93%) rename include/rexy/{cx => }/utility.hpp (92%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 01f4855..9da17f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ if(BUILD_TESTS) add_subdirectory(tests) endif() -set(LIBREXY_PUBLIC_HEADERS "include/rexy/traits.hpp" "include/rexy/steal.hpp" "include/rexy/binary.hpp" "include/rexy/expression.hpp" "include/rexy/binary_base.hpp" "include/rexy/binary_base.tpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/filerd.hpp" "include/rexy/string_base.tpp" "include/rexy/allocator.hpp") +set(LIBREXY_PUBLIC_HEADERS "include/rexy/algorithm.hpp" "include/rexy/utility.hpp" "include/rexy/basic_string_hash.hpp" "include/rexy/hash.hpp" "include/rexy/static_string_hash.hpp" "include/rexy/string_hash.hpp" "include/rexy/traits.hpp" "include/rexy/steal.hpp" "include/rexy/binary.hpp" "include/rexy/expression.hpp" "include/rexy/binary_base.hpp" "include/rexy/binary_base.tpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/filerd.hpp" "include/rexy/string_base.tpp" "include/rexy/allocator.hpp") target_compile_options(rexy PRIVATE -Wall -Wextra -pedantic -std=c++17) install(TARGETS rexy diff --git a/include/rexy/algorithm.hpp b/include/rexy/algorithm.hpp new file mode 100644 index 0000000..6a52132 --- /dev/null +++ b/include/rexy/algorithm.hpp @@ -0,0 +1,109 @@ +/** + This file is a part of rexy's general purpose library + Copyright (C) 2020 rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +#ifndef REXY_ALGORITHM_HPP +#define REXY_ALGORITHM_HPP + +#include "utility.hpp" //swap +#include //SIZE_MAX +#include "detail/algorithm.hpp" +#include //size_t + +#include + +namespace rexy{ + + template + constexpr void quicksort(Iter left, Iter right, const Compare& cmp) + noexcept(noexcept(detail::qs_partition(left, right, cmp))) + { + while(left < right){ + auto real_right = right-1; + auto pivot = detail::qs_partition(left, real_right, cmp); + quicksort(left, pivot, cmp); + left = ++pivot; + } + } + + template + constexpr HIter two_way_search(const HIter& hstart, const HIter& hend, const NIter& nstart, const NIter& nend){ + size_t j = 0; + size_t i = 0; + size_t nlen = nend - nstart; + size_t hlen = hend - hstart; + auto [max_suffix, period] = detail::critical_factorization(nstart, nend); + + if(detail::iter_compare(nstart, nstart + period, max_suffix)){ + size_t memory = SIZE_MAX; + while(j <= hlen - nlen){ + i = max(max_suffix, memory) + 1; + //right side + while(i < nlen && nstart[i] == hstart[i + j]){ + ++i; + } + if(i >= nlen){ + i = max_suffix; + //left side + while(i > memory && nstart[i] == hstart[i + j]){ + --i; + } + if(i <= memory){ + return hstart + j; //? + } + j += period; + memory = nlen - period - 1; + }else{ + j += (i - max_suffix); + memory = SIZE_MAX; + } + } + }else{ + period = max(max_suffix + 1, nlen - max_suffix - 1) + 1; + j = 0; + while(j <= hlen - nlen){ + i = max_suffix + 1; + while(i < nlen && nstart[i] == hstart[i + j]){ + ++i; + } + if(i >= nlen){ + i = max_suffix; + while(i != SIZE_MAX && nstart[i] == hstart[i + j]){ + --i; + } + if(i == SIZE_MAX){ + return hstart + j; //? + } + j += period; + }else{ + j += (i - max_suffix); + } + } + } + return hend; + } + + struct two_way_searcher{ + template + constexpr HIter operator()(const HIter& hstart, const HIter& hend, const NIter& nstart, const NIter& nend)const{ + return two_way_search(hstart, hend, nstart, nend); + } + }; + +} + +#endif diff --git a/include/rexy/cx/basic_string_hash.hpp b/include/rexy/basic_string_hash.hpp similarity index 87% rename from include/rexy/cx/basic_string_hash.hpp rename to include/rexy/basic_string_hash.hpp index 70275ee..fecfba5 100644 --- a/include/rexy/cx/basic_string_hash.hpp +++ b/include/rexy/basic_string_hash.hpp @@ -16,13 +16,13 @@ along with this program. If not, see . */ -#ifndef REXY_CX_BASIC_STRING_HASH_HPP -#define REXY_CX_BASIC_STRING_HASH_HPP +#ifndef REXY_BASIC_STRING_HASH_HPP +#define REXY_BASIC_STRING_HASH_HPP #include "string_hash.hpp" -#include "../string.hpp" +#include "string.hpp" -namespace rexy::cx{ +namespace rexy{ template<> struct hash : public string_hash{}; diff --git a/include/rexy/binary_base.hpp b/include/rexy/binary_base.hpp index 323e967..3ccbefc 100644 --- a/include/rexy/binary_base.hpp +++ b/include/rexy/binary_base.hpp @@ -26,7 +26,7 @@ #include #include //reverse_iterator -#include "cx/utility.hpp" //max +#include "utility.hpp" //max #include "steal.hpp" #include "expression.hpp" #include "traits.hpp" diff --git a/include/rexy/binary_base.tpp b/include/rexy/binary_base.tpp index b228047..4b1648c 100644 --- a/include/rexy/binary_base.tpp +++ b/include/rexy/binary_base.tpp @@ -23,12 +23,10 @@ #include //move #include //memcpy #include -#include "cx/utility.hpp" //max +#include "utility.hpp" //max #include "steal.hpp" #include "detail/string_appender.hpp" -#include "cx/utility.hpp" //strlen - #define STOP_STRICT_ALIAS_WARNING(x) (x) namespace rexy{ @@ -42,7 +40,7 @@ namespace rexy{ constexpr binary_base::binary_base(const binary_base&)noexcept{} constexpr auto binary_base::release(void)noexcept -> pointer{ - return cx::exchange(m_data, nullptr); + return exchange(m_data, nullptr); } constexpr auto binary_base::size(void)const -> size_type{ @@ -109,7 +107,7 @@ namespace rexy{ constexpr basic_binary::basic_binary(void)noexcept{} template constexpr basic_binary::basic_binary(rexy::steal data)noexcept: - binary_base(data.value() ? cx::strlen(data.value()) : 0) + binary_base(data.value() ? strlen(data.value()) : 0) { m_data = data.value(); m_size = m_cap; @@ -132,7 +130,7 @@ namespace rexy{ template basic_binary::basic_binary(const_pointer data) noexcept(noexcept(this->allocate(0))): - basic_binary(data ? this->allocate(cx::strlen(data)) : nullptr, cx::strlen(data)) + basic_binary(data ? this->allocate(strlen(data)) : nullptr, strlen(data)) { if(data) memcpy(m_data, data, m_cap); @@ -163,7 +161,7 @@ namespace rexy{ } template constexpr basic_binary::basic_binary(basic_binary&& b)noexcept: - binary_base(cx::exchange(b.m_data, nullptr), b.m_size, b.m_cap){} + binary_base(exchange(b.m_data, nullptr), b.m_size, b.m_cap){} template basic_binary::basic_binary(const binary_base& b) noexcept(noexcept(this->allocate(0))): @@ -188,7 +186,7 @@ namespace rexy{ constexpr basic_binary& basic_binary::operator=(basic_binary&& b)noexcept{ m_size = b.m_size; m_cap = b.m_cap; - cx::swap(m_data, b.m_data); + swap(m_data, b.m_data); return *this; } template @@ -231,7 +229,7 @@ namespace rexy{ if(!tmp) return false; memcpy(STOP_STRICT_ALIAS_WARNING(tmp).m_data, m_data, m_size); - cx::swap(m_data, STOP_STRICT_ALIAS_WARNING(tmp).m_data); + swap(m_data, STOP_STRICT_ALIAS_WARNING(tmp).m_data); m_cap = STOP_STRICT_ALIAS_WARNING(tmp).m_cap; return true; } @@ -241,7 +239,7 @@ namespace rexy{ noexcept(this->deallocate(nullptr,0))) { if(m_size + len > m_cap) - resize(cx::max(m_cap*2, m_size+len)); + resize(max(m_cap*2, m_size+len)); memcpy(m_data+m_size, data, len); m_size += len; } @@ -263,7 +261,7 @@ namespace rexy{ constexpr static_binary::static_binary(const_pointer str, size_type len)noexcept: binary_base(const_cast(str), len, len){} constexpr static_binary::static_binary(const_pointer str)noexcept: - static_binary(str, cx::strlen(str)){} + static_binary(str, strlen(str)){} constexpr static_binary::static_binary(const static_binary& s)noexcept: static_binary(s.get(), s.size()){} constexpr static_binary::static_binary(static_binary&& s)noexcept: @@ -271,7 +269,7 @@ namespace rexy{ constexpr static_binary& static_binary::operator=(const_pointer str)noexcept{ m_data = const_cast(str); - m_size = cx::strlen(str); + m_size = strlen(str); m_cap = m_size; return *this; } diff --git a/include/rexy/cx/algorithm.hpp b/include/rexy/cx/algorithm.hpp deleted file mode 100644 index 89bf4a6..0000000 --- a/include/rexy/cx/algorithm.hpp +++ /dev/null @@ -1,65 +0,0 @@ -/** - This file is a part of rexy's general purpose library - Copyright (C) 2020 rexy712 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -#ifndef REXY_CX_ALGORITHM_HPP -#define REXY_CX_ALGORITHM_HPP - -#include "utility.hpp" //swap - -#include - -namespace rexy::cx{ - - namespace detail{ - template - constexpr Iter qs_partition(Iter left, Iter right, const Compare& cmp) - noexcept(std::is_nothrow_invocable::value && - noexcept(cx::swap(*left,*right))) - { - auto range = right - left; - auto pivot = left + (range / 2); - auto value = *pivot; - - //move pivot value all the way to the right side to preserve it - cx::swap(*pivot, *right); - for(auto it = left;it != right;++it){ - if(cmp(*it, value)){ - cx::swap(*left, *it); - ++left; - } - } - //move pivot value back to proper position - cx::swap(*left, *right); - return left; - } - } - template - constexpr void quicksort(Iter left, Iter right, const Compare& cmp) - noexcept(noexcept(cx::detail::qs_partition(left, right, cmp))) - { - while(left < right){ - auto real_right = right-1; - auto pivot = detail::qs_partition(left, real_right, cmp); - quicksort(left, pivot, cmp); - left = ++pivot; - } - } - -} - -#endif diff --git a/include/rexy/cx/array.hpp b/include/rexy/cx/array.hpp index 1f30c59..a821454 100644 --- a/include/rexy/cx/array.hpp +++ b/include/rexy/cx/array.hpp @@ -20,7 +20,7 @@ #define REXY_CX_ARRAY_HPP #include //size_t -#include "utility.hpp" //swap +#include "../utility.hpp" //swap #include "detail/bool_specialize_base.hpp" #include @@ -117,10 +117,10 @@ namespace rexy::cx{ } } constexpr void swap(array& other) - noexcept(noexcept(cx::swap(m_elements[0], other.m_elements[0]))) + noexcept(noexcept(swap(m_elements[0], other.m_elements[0]))) { for(size_type i = 0;i < max_size();++i){ - cx::swap(m_elements[i], other.m_elements[i]); + swap(m_elements[i], other.m_elements[i]); } } }; @@ -216,7 +216,7 @@ namespace rexy::cx{ } constexpr void swap(array& other)noexcept{ for(size_type i = 0;i < arr_size;++i){ - cx::swap(m_elements[i], other.m_elements[i]); + swap(m_elements[i], other.m_elements[i]); } } }; diff --git a/include/rexy/cx/cx_string_hash.hpp b/include/rexy/cx/cx_string_hash.hpp index 4ae612d..2f1b410 100644 --- a/include/rexy/cx/cx_string_hash.hpp +++ b/include/rexy/cx/cx_string_hash.hpp @@ -19,7 +19,7 @@ #ifndef REXY_CX_CX_STRING_HASH_HPP #define REXY_CX_CX_STRING_HASH_HPP -#include "string_hash.hpp" +#include "../string_hash.hpp" #include "string.hpp" namespace rexy::cx{ diff --git a/include/rexy/cx/detail/bool_specialize_base.hpp b/include/rexy/cx/detail/bool_specialize_base.hpp index e599fa7..f3463e4 100644 --- a/include/rexy/cx/detail/bool_specialize_base.hpp +++ b/include/rexy/cx/detail/bool_specialize_base.hpp @@ -22,7 +22,7 @@ #include //size_t #include //move, forward, pair #include //CHAR_BIT -#include "../utility.hpp" //swap +#include "../../utility.hpp" //swap namespace rexy::cx::detail{ diff --git a/include/rexy/cx/hashmap.hpp b/include/rexy/cx/hashmap.hpp index e3ace57..a193359 100644 --- a/include/rexy/cx/hashmap.hpp +++ b/include/rexy/cx/hashmap.hpp @@ -21,8 +21,8 @@ #include "vector.hpp" #include "array.hpp" -#include "algorithm.hpp" -#include "hash.hpp" +#include "../algorithm.hpp" +#include "../hash.hpp" #include //CHAR_BIT #include //size_t, ptrdiff_t @@ -103,7 +103,7 @@ namespace rexy::cx{ } //sort the buckets based on size, largest first - cx::quicksort(buckets.begin(), buckets.end(), [](auto&& left, auto&& right) -> bool{ + quicksort(buckets.begin(), buckets.end(), [](auto&& left, auto&& right) -> bool{ return left.size() > right.size(); }); @@ -199,7 +199,7 @@ namespace rexy::cx{ } #ifdef REXY_STRING_BASE_HPP -#include "string_hash.hpp" +#include "../string_hash.hpp" #endif #endif diff --git a/include/rexy/cx/string.hpp b/include/rexy/cx/string.hpp index 700b886..2456759 100644 --- a/include/rexy/cx/string.hpp +++ b/include/rexy/cx/string.hpp @@ -25,7 +25,7 @@ namespace rexy::cx{ } #include "../string_base.hpp" -#include "utility.hpp" +#include "../utility.hpp" #include #include //ptrdiff_t @@ -67,7 +67,7 @@ namespace rexy::cx{ } } constexpr string(const_pointer data)noexcept: - m_length(cx::strlen(data)) + m_length(strlen(data)) { for(size_type i = 0;i < m_length;++i){ m_data[i] = data[i]; @@ -101,7 +101,7 @@ namespace rexy::cx{ ~string(void)noexcept = default; constexpr string& operator=(const_pointer c)noexcept{ - m_length = cx::strlen(c); + m_length = strlen(c); for(size_type i = 0;i < m_length;++i){ m_data[i] = c[i]; } @@ -160,7 +160,7 @@ namespace rexy::cx{ } } constexpr void append(const_pointer data)noexcept{ - append(data, cx::strlen(data)); + append(data, strlen(data)); } constexpr void append(const string& s)noexcept{ append(s.get(), s.length()); diff --git a/include/rexy/cx/vector.hpp b/include/rexy/cx/vector.hpp index 154df41..e68db10 100644 --- a/include/rexy/cx/vector.hpp +++ b/include/rexy/cx/vector.hpp @@ -23,7 +23,7 @@ #include //move, forward #include "detail/bool_specialize_base.hpp" -#include "utility.hpp" //swap +#include "../utility.hpp" //swap #include @@ -60,7 +60,7 @@ namespace rexy::cx{ for(size_type i = 0;i < min(count, max_elements);++i){ m_elements[i] = value; } - m_size = cx::min(count, max_elements); + m_size = min(count, max_elements); } ~vector(void)noexcept = default; @@ -230,16 +230,16 @@ namespace rexy::cx{ } } constexpr void swap(vector& other) - noexcept(noexcept(cx::swap(m_elements[0], other.m_elements[0]))) + noexcept(noexcept(swap(m_elements[0], other.m_elements[0]))) { size_type i = 0; for(;i < m_size;++i){ - cx::swap(m_elements[i], other.m_elements[i]); + swap(m_elements[i], other.m_elements[i]); } for(;i < other.m_size;++i){ - cx::swap(m_elements[i], other.m_elements[i]); + swap(m_elements[i], other.m_elements[i]); } - cx::swap(m_size, other.m_size); + swap(m_size, other.m_size); } }; @@ -280,7 +280,7 @@ namespace rexy::cx{ for(size_type j = 0;j < bits_count;++j){ m_elements[i][j] = value; } - m_size = cx::min(count, max_elements); + m_size = min(count, max_elements); } ~vector(void)noexcept = default; @@ -422,7 +422,7 @@ namespace rexy::cx{ } constexpr void resize(size_type count, const value_type& value)noexcept{ if(count > m_size){ - auto actual_count = cx::min(count, max_size()); + auto actual_count = min(count, max_size()); auto num = actual_count - m_size; auto it = end(); for(size_type i = 0;i < num;++i){ @@ -446,12 +446,12 @@ namespace rexy::cx{ ++other_byte_count; size_type i = 0; for(;i < byte_count;++i){ - cx::swap(m_elements[i], other.m_elements[i]); + swap(m_elements[i], other.m_elements[i]); } for(;i < other_byte_count;++i){ - cx::swap(m_elements[i], other.m_elements[i]); + swap(m_elements[i], other.m_elements[i]); } - cx::swap(m_size, other.m_size); + swap(m_size, other.m_size); } }; diff --git a/include/rexy/detail/algorithm.hpp b/include/rexy/detail/algorithm.hpp new file mode 100644 index 0000000..2f5a10c --- /dev/null +++ b/include/rexy/detail/algorithm.hpp @@ -0,0 +1,86 @@ +#ifndef REXY_DETAIL_ALGORITHM_HPP +#define REXY_DETAIL_ALGORITHM_HPP + +#include "../utility.hpp" //swap + +#include //nothrow_invocable +#include //less, greater +#include //pair +#include //iterator_traits +#include //size_t + +namespace rexy::detail{ + + template + constexpr Iter qs_partition(Iter left, Iter right, const Compare& cmp) + noexcept(std::is_nothrow_invocable::value && + noexcept(swap(*left,*right))) + { + auto range = right - left; + auto pivot = left + (range / 2); + auto value = *pivot; + + //move pivot value all the way to the right side to preserve it + swap(*pivot, *right); + for(auto it = left;it != right;++it){ + if(cmp(*it, value)){ + swap(*left, *it); + ++left; + } + } + //move pivot value back to proper position + swap(*left, *right); + return left; + } + template + constexpr std::pair max_suffix(const Iter& needle, size_t nlen, const Op& op = Op()){ + using value_type = typename std::iterator_traits::value_type; + size_t max_suffix = -1; + size_t j = 0; + size_t k = 1; + size_t period = 1; + value_type a; + value_type b; + + while(j + k < nlen){ + a = needle[j + k]; + b = needle[max_suffix + k]; + if(op(a, b)){ + j += k; + k = 1; + period = j - max_suffix; + }else if(a == b){ + if(k != period){ + ++k; + }else{ + j += period; + k = 1; + } + }else{ + max_suffix = j++; + k = period = 1; + } + } + return {max_suffix, period}; + } + template + constexpr std::pair critical_factorization(const Iter& nstart, const Iter& nend){ + auto msuffix = max_suffix(nstart, nend - nstart, std::less{}); + auto msuffix_rev = max_suffix(nstart, nend - nstart, std::greater{}); + if(msuffix.first < msuffix_rev.first){ + return msuffix_rev; + } + return msuffix; + } + template + constexpr bool iter_compare(const Iter& left, const Iter& right, size_t length){ + for(size_t i = 0;i < length;++i){ + if(left[i] != right[i]) + return false; + } + return true; + } + +} + +#endif diff --git a/include/rexy/filerd.hpp b/include/rexy/filerd.hpp index be85cb0..99f874e 100644 --- a/include/rexy/filerd.hpp +++ b/include/rexy/filerd.hpp @@ -24,7 +24,7 @@ #include "string.hpp" #include "binary.hpp" -#include "cx/utility.hpp" +#include "utility.hpp" #include namespace rexy{ @@ -40,11 +40,11 @@ namespace rexy{ filerd(const char* f, const char* mode = "r")noexcept; filerd(const filerd&) = delete; constexpr filerd(filerd&& f)noexcept: - m_fp(cx::exchange(f.m_fp, nullptr)){} + m_fp(exchange(f.m_fp, nullptr)){} ~filerd(void)noexcept; filerd& operator=(const filerd&) = delete; constexpr filerd& operator=(filerd&& f)noexcept{ - cx::swap(m_fp, f.m_fp); + swap(m_fp, f.m_fp); return *this; } diff --git a/include/rexy/cx/hash.hpp b/include/rexy/hash.hpp similarity index 95% rename from include/rexy/cx/hash.hpp rename to include/rexy/hash.hpp index 2a0d8d9..6b92a06 100644 --- a/include/rexy/cx/hash.hpp +++ b/include/rexy/hash.hpp @@ -16,12 +16,12 @@ along with this program. If not, see . */ -#ifndef REXY_CX_HASH_HPP -#define REXY_CX_HASH_HPP +#ifndef REXY_HASH_HPP +#define REXY_HASH_HPP #include //CHAR_BIT -namespace rexy::cx{ +namespace rexy{ template struct hash{ diff --git a/include/rexy/cx/static_string_hash.hpp b/include/rexy/static_string_hash.hpp similarity index 87% rename from include/rexy/cx/static_string_hash.hpp rename to include/rexy/static_string_hash.hpp index 983deea..b62e9af 100644 --- a/include/rexy/cx/static_string_hash.hpp +++ b/include/rexy/static_string_hash.hpp @@ -16,13 +16,13 @@ along with this program. If not, see . */ -#ifndef REXY_CX_STATIC_STRING_HASH_HPP -#define REXY_CX_STATIC_STRING_HASH_HPP +#ifndef REXY_STATIC_STRING_HASH_HPP +#define REXY_STATIC_STRING_HASH_HPP #include "string_hash.hpp" -#include "../string_base.hpp" +#include "string_base.hpp" -namespace rexy::cx{ +namespace rexy{ template struct hash> : public string_hash>{}; diff --git a/include/rexy/string_base.hpp b/include/rexy/string_base.hpp index 66c96a6..d3f655e 100644 --- a/include/rexy/string_base.hpp +++ b/include/rexy/string_base.hpp @@ -27,7 +27,7 @@ #include //reverse_iterator #include "steal.hpp" -#include "cx/utility.hpp" +#include "utility.hpp" #include "traits.hpp" #include "expression.hpp" #include "detail/string_appender.hpp" @@ -200,8 +200,18 @@ namespace rexy{ constexpr reference operator[](size_type i)noexcept{return get_pointer()[i];} constexpr const_reference operator[](size_type i)const noexcept{return get_pointer()[i];} - //constexpr bool search(const string_base& s)const; - //constexpr bool search(const_pointer c)const; + constexpr const_iterator search(const string_base& s)const; + constexpr const_iterator search(const_pointer c)const; + constexpr iterator search(const string_base& s); + constexpr iterator search(const_pointer c); + template + constexpr const_iterator search(const string_base& s, const Searcher& searcher)const; + template + constexpr const_iterator search(const_pointer c, const Searcher& searcher)const; + template + constexpr iterator search(const string_base& s, const Searcher& searcher); + template + constexpr iterator search(const_pointer c, const Searcher& searcher); constexpr bool compare(const string_base& s)const{return *this == s;} constexpr bool compare(const_pointer c)const{return *this == c;} @@ -391,11 +401,11 @@ namespace rexy{ template = 0> constexpr bool operator==(Str1&& left, Str2&& right)noexcept{ - return left.valid() && right.valid() && left.length() == right.length() && !cx::strcmp(left.get(), right.get()); + return left.valid() && right.valid() && left.length() == right.length() && !strcmp(left.get(), right.get()); } template = 0> constexpr bool operator==(Str&& left, typename std::decay_t::const_pointer right)noexcept{ - return left.valid() && right && !cx::strcmp(left.get(), right); + return left.valid() && right && !strcmp(left.get(), right); } template = 0> constexpr bool operator!=(Str1&& left, Str2&& right)noexcept{ @@ -463,7 +473,7 @@ namespace{ #include "detail/binary_string_conv.hpp" #endif #ifdef REXY_CX_HASH_HPP -#include "cx/static_string_hash.hpp" +#include "static_string_hash.hpp" #endif #endif diff --git a/include/rexy/string_base.tpp b/include/rexy/string_base.tpp index 522ec81..6bebc0d 100644 --- a/include/rexy/string_base.tpp +++ b/include/rexy/string_base.tpp @@ -23,13 +23,56 @@ #include //memcpy #include //strlen, strcpy -#include "cx/utility.hpp" //max +#include "utility.hpp" //max #include "detail/string_appender.hpp" +#include "algorithm.hpp" #define STOP_STRICT_ALIAS_WARNING(x) (x) namespace rexy{ + template + constexpr auto string_base::search(const string_base& s)const -> const_iterator{ + return two_way_search(cbegin(), cend(), s.begin(), s.end()); + } + template + constexpr auto string_base::search(const_pointer c)const -> const_iterator{ + const auto len = strlen(c); + return two_way_search(cbegin(), cend(), c, c + len); + } + template + constexpr auto string_base::search(const string_base& s) -> iterator{ + return two_way_search(begin(), end(), s.begin(), s.end()); + } + template + constexpr auto string_base::search(const_pointer c) -> iterator{ + const auto len = strlen(c); + return two_way_search(begin(), end(), c, c + len); + } + template + template + constexpr auto string_base::search(const string_base& s, const Searcher& searcher)const -> const_iterator{ + return searcher(cbegin(), cend(), s.begin(), s.end()); + } + template + template + constexpr auto string_base::search(const_pointer c, const Searcher& searcher)const -> const_iterator{ + const auto len = strlen(c); + return searcher(cbegin(), cend(), c, c + len); + } + template + template + constexpr auto string_base::search(const string_base& s, const Searcher& searcher) -> iterator{ + return searcher(begin(), end(), s.begin(), s.end()); + } + template + template + constexpr auto string_base::search(const_pointer c, const Searcher& searcher) -> iterator{ + const auto len = strlen(c); + return searcher(begin(), end(), c, c + len); + } + + //allocate string if longer than small string capacity, copy otherwise template void basic_string::_copy_construct_string(const_pointer data, size_type len, size_type cap) @@ -58,7 +101,7 @@ namespace rexy{ constexpr basic_string::basic_string(void)noexcept{} template constexpr basic_string::basic_string(rexy::steal data)noexcept: - basic_string(data.value(), data.value() ? cx::strlen(data.value()) : 0){} + basic_string(data.value(), data.value() ? strlen(data.value()) : 0){} template constexpr basic_string::basic_string(rexy::steal data, size_type len)noexcept: string_base(data.value(), len, len){} @@ -78,7 +121,7 @@ namespace rexy{ template basic_string::basic_string(const_pointer data) noexcept(noexcept(this->allocate(0))): - basic_string(data, data ? cx::strlen(data) : 0){} + basic_string(data, data ? strlen(data) : 0){} template basic_string::basic_string(size_type cap) noexcept(noexcept(this->allocate(0))): @@ -149,7 +192,7 @@ namespace rexy{ noexcept(noexcept(this->allocate(0)) && noexcept(this->deallocate(nullptr,0))) { - return _copy_string(c, cx::strlen(c)); + return _copy_string(c, strlen(c)); } //Replace managed pointer. Frees existing value @@ -157,7 +200,7 @@ namespace rexy{ void basic_string::reset(pointer val) noexcept(noexcept(this->deallocate(nullptr,0))) { - reset(val, val ? cx::strlen(val) : 0); + reset(val, val ? strlen(val) : 0); } template void basic_string::reset(pointer val, size_type len) @@ -195,7 +238,7 @@ namespace rexy{ this->set_length(mylen+len); raw[mylen+len] = 0; }else{ - auto newsize = cx::max(mylen+len, mycap*2); + auto newsize = max(mylen+len, mycap*2); basic_string tmp(newsize); tmp.append(raw, mylen); tmp.append(data, len); @@ -208,7 +251,7 @@ namespace rexy{ noexcept(this->deallocate(nullptr,0))) { if(data) - append(data, cx::strlen(data)); + append(data, strlen(data)); } template @@ -304,10 +347,10 @@ namespace rexy{ } template constexpr static_string::static_string(const_pointer c)noexcept: - static_string(c, cx::strlen(c)){} + static_string(c, strlen(c)){} template constexpr static_string& static_string::operator=(const_pointer c)noexcept{ - size_type len = cx::strlen(c); + size_type len = strlen(c); this->set_long_ptr(const_cast(c)); this->set_long_length(len); this->set_long_capacity(len); diff --git a/include/rexy/cx/string_hash.hpp b/include/rexy/string_hash.hpp similarity index 93% rename from include/rexy/cx/string_hash.hpp rename to include/rexy/string_hash.hpp index de1a1e0..b57383c 100644 --- a/include/rexy/cx/string_hash.hpp +++ b/include/rexy/string_hash.hpp @@ -16,12 +16,12 @@ along with this program. If not, see . */ -#ifndef REXY_CX_STRING_HASH_HPP -#define REXY_CX_STRING_HASH_HPP +#ifndef REXY_STRING_HASH_HPP +#define REXY_STRING_HASH_HPP #include "hash.hpp" -namespace rexy::cx{ +namespace rexy{ //jenkns one at a time hash template diff --git a/include/rexy/cx/utility.hpp b/include/rexy/utility.hpp similarity index 92% rename from include/rexy/cx/utility.hpp rename to include/rexy/utility.hpp index ac366da..267f4fb 100644 --- a/include/rexy/cx/utility.hpp +++ b/include/rexy/utility.hpp @@ -16,13 +16,13 @@ along with this program. If not, see . */ -#ifndef REXY_CX_UTILITY_HPP -#define REXY_CX_UTILITY_HPP +#ifndef REXY_UTILITY_HPP +#define REXY_UTILITY_HPP #include //forward, move #include -namespace rexy::cx{ +namespace rexy{ namespace{ template @@ -36,18 +36,18 @@ namespace rexy::cx{ } template constexpr Iter2 swap_ranges(Iter1 start1, Iter1 end1, Iter2 start2) - noexcept(noexcept(cx::swap(*start1, *start2))) + noexcept(noexcept(swap(*start1, *start2))) { while(start1 != end1){ - cx::swap(start1++, start2++); + swap(start1++, start2++); } return start2; } template constexpr void swap(T (&l)[N], T (&r)[N]) - noexcept(noexcept(cx::swap(*l, *r))) + noexcept(noexcept(swap(*l, *r))) { - cx::swap_ranges(l, l+N, r); + swap_ranges(l, l+N, r); } template diff --git a/src/ensure.cpp b/src/ensure.cpp index fb21de5..59aa387 100644 --- a/src/ensure.cpp +++ b/src/ensure.cpp @@ -15,13 +15,13 @@ #include "rexy/allocator.hpp" #include "rexy/detail/string_appender.hpp" -#include "rexy/cx/algorithm.hpp" +#include "rexy/algorithm.hpp" #include "rexy/cx/array.hpp" -#include "rexy/cx/hash.hpp" +#include "rexy/hash.hpp" #include "rexy/cx/hashmap.hpp" -#include "rexy/cx/string_hash.hpp" +#include "rexy/string_hash.hpp" #include "rexy/cx/string.hpp" -#include "rexy/cx/utility.hpp" +#include "rexy/utility.hpp" #include "rexy/cx/vector.hpp" #include "rexy/cx/detail/bool_specialize_base.hpp" diff --git a/tests/basic_string.cpp b/tests/basic_string.cpp index 150655f..21c821d 100644 --- a/tests/basic_string.cpp +++ b/tests/basic_string.cpp @@ -243,6 +243,14 @@ void check_substring(){ if(strcmp(test2.get(), "is") || test2.length() != 2) error("substring operation should have resulted in 'is'\n"); } +void check_string_search(){ + rexy::string test1 = "this is a test string"; + rexy::string test2 = "string"; + auto res = test1.search(test2); + if(test1 + 15 != res){ + error("string search operation did not result in a correct result"); + } +} int main(){ check_empty_construction(); @@ -253,4 +261,5 @@ int main(){ check_short_append(); check_long_append(); check_substring(); + check_string_search(); }