From c99abad22631b5ce5481c07cff88986bc1ef35aa Mon Sep 17 00:00:00 2001 From: rexy712 Date: Fri, 1 May 2020 23:49:25 -0700 Subject: [PATCH] Add compile time vector, array, and hashmap --- CMakeLists.txt | 4 +- include/rexy/binary.hpp | 4 +- include/rexy/cx/algorithm.hpp | 56 +++++++++ include/rexy/cx/array.hpp | 126 +++++++++++++++++++ include/rexy/cx/hash.hpp | 42 +++++++ include/rexy/cx/hashmap.hpp | 148 ++++++++++++++++++++++ include/rexy/cx/string_hash.hpp | 40 ++++++ include/rexy/cx/utility.hpp | 70 +++++++++++ include/rexy/cx/vector.hpp | 213 ++++++++++++++++++++++++++++++++ include/rexy/detail/util.hpp | 78 ------------ include/rexy/filerd.hpp | 5 +- include/rexy/string_base.hpp | 10 +- include/rexy/string_base.tpp | 16 +-- src/ensure.cpp | 8 ++ 14 files changed, 725 insertions(+), 95 deletions(-) create mode 100644 include/rexy/cx/algorithm.hpp create mode 100644 include/rexy/cx/array.hpp create mode 100644 include/rexy/cx/hash.hpp create mode 100644 include/rexy/cx/hashmap.hpp create mode 100644 include/rexy/cx/string_hash.hpp create mode 100644 include/rexy/cx/utility.hpp create mode 100644 include/rexy/cx/vector.hpp delete mode 100644 include/rexy/detail/util.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bfdce9d..9af74e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,6 @@ if(ENABLE_PROFILING) endif() set(LIBREXY_PUBLIC_HEADERS "include/rexy/steal.hpp" "include/rexy/binary.hpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/filerd.hpp" "include/rexy/string_base.tpp") -set(LIBREXY_DETAIL_HEADERS "include/rexy/detail/binary_string_conv.hpp" "include/rexy/detail/default_allocator.hpp" "include/rexy/detail/util.hpp") target_compile_options(rexy PRIVATE -Wall -Wextra -pedantic -std=c++17) install(TARGETS rexy @@ -41,7 +40,8 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pc/librexy.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" ) install(FILES ${LIBREXY_PUBLIC_HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy/") -install(FILES ${LIBREXY_DETAIL_HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy/detail/") +install(DIRECTORY "include/rexy/detail" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy") +install(DIRECTORY "include/rexy/cx" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy") configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/pc/librexy.pc.cmake.in" diff --git a/include/rexy/binary.hpp b/include/rexy/binary.hpp index 7eaf20b..df6a276 100644 --- a/include/rexy/binary.hpp +++ b/include/rexy/binary.hpp @@ -23,7 +23,7 @@ #include //move #include //memcpy #include -#include "detail/util.hpp" //max +#include "cx/utility.hpp" //max #include "detail/default_allocator.hpp" #include "steal.hpp" @@ -130,7 +130,7 @@ namespace rexy{ } void append(const char* data, size_t len){ if(m_size + len > m_cap) - resize(detail::max(m_cap*2, m_size+len)); + resize(cx::max(m_cap*2, m_size+len)); memcpy(m_data+m_size, data, len); m_size += len; } diff --git a/include/rexy/cx/algorithm.hpp b/include/rexy/cx/algorithm.hpp new file mode 100644 index 0000000..1855ef6 --- /dev/null +++ b/include/rexy/cx/algorithm.hpp @@ -0,0 +1,56 @@ +/** + 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 + +namespace rexy::cx{ + + template + constexpr Iter qs_partition(Iter left, Iter right, const Compare& cmp){ + 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 void quicksort(Iter left, Iter right, const Compare& cmp){ + while(left < right){ + auto real_right = right-1; + auto pivot = 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 new file mode 100644 index 0000000..f0042a0 --- /dev/null +++ b/include/rexy/cx/array.hpp @@ -0,0 +1,126 @@ +/** + 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_ARRAY_HPP +#define REXY_CX_ARRAY_HPP + +#include //size_t +#include "utility.hpp" //swap + +namespace rexy::cx{ + + template + class array + { + public: + using value_type = T; + using size_type = size_t; + using difference_type = ptrdiff_t; + using reference = T&; + using const_reference = const T&; + using pointer = T*; + using const_pointer = const T*; + using iterator = T*; + using const_iterator = const T*; + + static constexpr size_type max_elements = N; + + private: + T m_elements[N] = {}; + + public: + constexpr reference at(size_type pos){ + return m_elements[pos]; + } + constexpr const_reference at(size_type pos)const{ + return m_elements[pos]; + } + constexpr reference operator[](size_type pos){ + return m_elements[pos]; + } + constexpr const_reference operator[](size_type pos)const{ + return m_elements[pos]; + } + constexpr reference front(void){ + return m_elements[0]; + } + constexpr const_reference front(void)const{ + return m_elements[0]; + } + constexpr reference back(void){ + return m_elements[max_elements-1]; + } + constexpr const_reference back(void)const{ + return m_elements[max_elements-1]; + } + constexpr pointer data(void){ + return m_elements; + } + constexpr const_pointer data(void)const{ + return m_elements; + } + + constexpr iterator begin(void){ + return m_elements; + } + constexpr const_iterator begin(void)const{ + return m_elements; + } + constexpr const_iterator cbegin(void)const{ + return m_elements; + } + constexpr iterator end(void){ + return m_elements+max_elements; + } + constexpr const_iterator end(void)const{ + return m_elements+max_elements; + } + constexpr const_iterator cend(void)const{ + return m_elements+max_elements; + } + constexpr bool empty(void)const{ + if constexpr(max_elements == 0){ + return true; + }else{ + return false; + } + } + constexpr size_type size(void)const{ + return max_elements; + } + constexpr size_type max_size(void)const{ + return max_elements; + } + constexpr void fill(const T& value){ + for(auto it = begin();it != end();++it){ + *it = value; + } + } + constexpr void swap(array& other){ + for(size_type i = 0;i < max_size();++i){ + swap(m_elements[i], other.m_elements[i]); + } + } + }; + + template + array(T, Us...) -> array; + +} + +#endif diff --git a/include/rexy/cx/hash.hpp b/include/rexy/cx/hash.hpp new file mode 100644 index 0000000..f2fd188 --- /dev/null +++ b/include/rexy/cx/hash.hpp @@ -0,0 +1,42 @@ +/** + 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_HASH_HPP +#define REXY_CX_HASH_HPP + +#include //CHAR_BIT + +namespace rexy::cx{ + + template + struct hash{ + constexpr size_t operator()(const T& t, size_t salt = 0){ + constexpr size_t bytes = sizeof(size_t); + size_t val = static_cast(t); + size_t hash = 5381 + salt; //magic hash number + for(size_t i = 0;i < bytes;++i){ + unsigned char c = static_cast(val >> (i * CHAR_BIT)); + hash = ((hash << 5) + hash) ^ c; + } + return hash; + } + }; + +} + +#endif diff --git a/include/rexy/cx/hashmap.hpp b/include/rexy/cx/hashmap.hpp new file mode 100644 index 0000000..899b49f --- /dev/null +++ b/include/rexy/cx/hashmap.hpp @@ -0,0 +1,148 @@ +/** + 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_HASHMAP_HPP +#define REXY_CX_HASHMAP_HPP + +#include "vector.hpp" +#include "array.hpp" +#include "algorithm.hpp" +#include "hash.hpp" + +#include //CHAR_BIT +#include + +namespace rexy::cx{ + + template + struct element + { + Key key; + Value value; + }; + + template> + class hashmap + { + public: + static constexpr size_t single_bucket_bit = size_t{1} << ((sizeof(size_t)*CHAR_BIT) - 1); + static constexpr size_t max_size = N; + + static_assert((max_size & single_bucket_bit) == 0); + + using key_type = Key; + using value_type = Value; + using hash_type = Hash; + + private: + array m_values; //perfect hash table + array m_g; //'salt' values for indexing into the perfect hash table + + public: + constexpr hashmap(const element(&elements)[N]){ + array,N>,N> buckets; + array slots_used; + size_t current_bucket = 0; + + //place all keys into buckets + for(auto& element : elements){ + buckets[Hash{}(element.key) % max_size].push_back(element); + } + + //sort the buckets based on size, largest first + quicksort(buckets.begin(), buckets.end(), [](auto&& left, auto&& right) -> bool{ + return left.size() > right.size(); + }); + + //for each bucket, try different values of 'd' to try to find a hash that doesn't collide + for(current_bucket = 0;current_bucket < buckets.size();++current_bucket){ + auto& bucket = buckets[current_bucket]; + //only handle buckets containing collisions + if(bucket.size() <= 1) + break; + + array pass_slots_used; + vector pass_slots; + size_t d = 1; + + for(size_t i = 0;i < bucket.size();){ + size_t slot = Hash{}(bucket[i].key, d) % max_size; + if(pass_slots_used[slot] || slots_used[slot]){ + //slot already in use, try another value for 'd' + ++d; + i = 0; + pass_slots_used.fill(false); + pass_slots.clear(); + }else{ + //slot is good to go + pass_slots_used[slot] = true; + pass_slots.push_back(slot); + ++i; + } + } + //store the successful value of 'd' at index of the first hash for this bucket + m_g[Hash{}(bucket[0].key) % max_size] = d; + + //take the value from the temporary bucket into the permanent slot + for(size_t i = 0;i < bucket.size();++i){ + m_values[pass_slots[i]] = std::move(bucket[i].value); + slots_used[pass_slots[i]] = true; + } + } + + //Handle remaining single value buckets + size_t next_free_slot = 0; + + for(;current_bucket < buckets.size();++current_bucket){ + auto& bucket = buckets[current_bucket]; + if(bucket.size() == 0) + break; + for(;slots_used[next_free_slot];++next_free_slot); + + m_g[Hash{}(bucket[0].key) % max_size] = (next_free_slot | single_bucket_bit); + m_values[next_free_slot] = std::move(bucket[0].value); + slots_used[next_free_slot] = true; + } + } + + //no key checks. give a correct key or get a random answer :) + constexpr value_type& operator[](const Key& key){ + size_t d = m_g[Hash{}(key) % max_size]; + if(d & single_bucket_bit) + return m_values[d & ~single_bucket_bit]; + return m_values[Hash{}(key, d) % max_size]; + } + constexpr const value_type& operator[](const Key& key)const{ + size_t d = m_g[Hash{}(key) % max_size]; + if(d & single_bucket_bit) + return m_values[d & ~single_bucket_bit]; + return m_values[Hash{}(key, d) % max_size]; + } + }; + + template> + constexpr auto make_hashmap(const element(&list)[N]){ + return hashmap(list); + } +} + +#ifdef REXY_STRING_BASE_HPP +#include "string_hash.hpp" +#endif + +#endif diff --git a/include/rexy/cx/string_hash.hpp b/include/rexy/cx/string_hash.hpp new file mode 100644 index 0000000..6c13386 --- /dev/null +++ b/include/rexy/cx/string_hash.hpp @@ -0,0 +1,40 @@ +/** + 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_STRING_HASH_HPP +#define REXY_CX_STRING_HASH_HPP + +#include "hash.hpp" +#include "../string_base.hpp" + +namespace rexy::cx{ + + template<> + struct hash{ + constexpr size_t operator()(const rexy::static_string& t, size_t salt = 0){ + size_t hash = 5381 + salt; + for(size_t i = 0;i < t.length();++i){ + hash = ((hash << 5) + hash) ^ t[i]; + } + return hash; + } + }; + +} + +#endif diff --git a/include/rexy/cx/utility.hpp b/include/rexy/cx/utility.hpp new file mode 100644 index 0000000..9b31ebf --- /dev/null +++ b/include/rexy/cx/utility.hpp @@ -0,0 +1,70 @@ +/** + 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_UTILITY_HPP +#define REXY_CX_UTILITY_HPP + +#include //forward, move + +namespace rexy::cx{ + + namespace{ + template + constexpr void swap(T& l, T& r){ + T tmp = l; + l = r; + r = tmp; + } + template + constexpr T exchange(T& l, U&& r){ + T old = std::move(l); + l = std::forward(r); + return old; + } + + template + constexpr const T& min(const T& l, const T& r){ + return l < r ? l : r; + } + template + constexpr const T& min(const T& l, const T& r, Compare cmp){ + return cmp(l, r) ? l : r; + } + template + constexpr const T& max(const T& l, const T& r){ + return l > r ? l : r; + } + template + constexpr const T& max(const T& l, const T& r, Compare cmp){ + return cmp(l, r) ? l : r; + } + constexpr size_t strlen(const char* c){ + size_t i = 0; + for(;c[i];++i); + return i; + } + constexpr int strcmp(const char* l, const char* r){ + using uchar = unsigned char; + for(;*l == *r && *l;++l, ++r); + return (static_cast(*l)) - (static_cast(*r)); + } + } + +} + +#endif diff --git a/include/rexy/cx/vector.hpp b/include/rexy/cx/vector.hpp new file mode 100644 index 0000000..55eaab5 --- /dev/null +++ b/include/rexy/cx/vector.hpp @@ -0,0 +1,213 @@ +/** + 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_VECTOR_HPP +#define REXY_CX_VECTOR_HPP + +#include //size_t +#include //move, forward + +#include "utility.hpp" //swap + +namespace rexy::cx{ + + template + class vector + { + public: + using value_type = T; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = T*; + using const_iterator = const T*; + using reference = T&; + using const_reference = const T&; + using pointer = T*; + using const_pointer = const T*; + + static constexpr size_type max_elements = N; + + private: + T m_elements[N] = {}; + size_type m_size = 0; + + public: + constexpr vector(void) = default; + constexpr vector(const vector&) = default; + constexpr vector(vector&&) = default; + + constexpr vector(size_type count, const T& value){ + for(size_type i = 0;i < min(count, max_elements);++i){ + m_elements[i] = value; + } + } + + ~vector(void) = default; + + constexpr vector& operator=(const vector&) = default; + constexpr vector& operator=(vector&&) = default; + + constexpr reference at(size_type pos){ + return m_elements[pos]; + } + constexpr const_reference at(size_type pos)const{ + return m_elements[pos]; + } + constexpr reference operator[](size_type pos){ + return m_elements[pos]; + } + constexpr const_reference operator[](size_type pos)const{ + return m_elements[pos]; + } + constexpr reference front(void){ + return m_elements[0]; + } + constexpr const_reference front(void)const{ + return m_elements[0]; + } + constexpr reference back(void){ + return m_elements[m_size-1]; + } + constexpr const_reference back(void)const{ + return m_elements[m_size-1]; + } + constexpr const_pointer data(void)const{ + return m_elements; + } + constexpr iterator begin(void){ + return m_elements; + } + constexpr const_iterator begin(void)const{ + return m_elements; + } + constexpr const_iterator cbegin(void)const{ + return m_elements; + } + constexpr iterator end(void){ + return m_elements+max_elements; + } + constexpr const_iterator end(void)const{ + return m_elements+max_elements; + } + constexpr const_iterator cend(void)const{ + return m_elements+max_elements; + } + + constexpr bool empty(void)const{ + return m_size == 0; + } + constexpr size_type size(void)const{ + return m_size; + } + constexpr size_type max_size(void)const{ + return max_elements; + } + constexpr size_type capacity(void)const{ + return max_elements; + } + constexpr void clear(void){ + m_size = 0; + } + constexpr iterator insert(iterator pos, const T& value){ + auto start = pos; + auto it = pos; + ++pos; + for(;pos != end();++it,++pos){ + *pos = std::move(*it); + } + *start = value; + return start; + } + constexpr iterator insert(const_iterator pos, T&& value){ + auto start = pos; + auto it = pos; + ++pos; + for(;pos != end();++it,++pos){ + *pos = std::move(*it); + } + *start = std::move(value); + return start; + } + template + constexpr iterator emplace(const_iterator pos, Args&&... args){ + auto start = pos; + auto it = pos; + ++pos; + for(;pos != end();++it,++pos){ + *pos = std::move(*it); + } + *start = T{std::forward(args)...}; + return start; + } + constexpr iterator erase(const_iterator pos){ + auto start = pos; + auto it = pos; + ++pos; + for(;pos != end();++it,++pos){ + *it = std::move(*pos); + } + return start; + } + constexpr iterator push_back(const T& value){ + m_elements[m_size] = value; + return m_elements+(m_size++); + } + template + constexpr iterator emplace_back(Args&&... args){ + m_elements[m_size++] = T{std::forward(args)...}; + return m_elements+(m_size++); + } + constexpr void pop_back(void){ + --m_size; + } + constexpr void resize(size_type count){ + if(count <= max_size()) + m_size = count; + } + constexpr void resize(size_type count, const value_type& value){ + if(count > m_size){ + if(count <= max_size()){ + for(size_type i = m_size;i < count;++i){ + m_elements[i] = value; + } + } + }else{ + m_size = count; + } + } + constexpr void fill(const T& value){ + for(auto it = begin();it != end();++it){ + *it = value; + } + } + constexpr void swap(vector& other){ + size_type i = 0; + for(;i < m_size;++i){ + swap(m_elements[i], other.m_elements[i]); + } + for(;i < other.m_size;++i){ + swap(m_elements[i], other.m_elements[i]); + } + swap(m_size, other.m_size); + } + + }; + +} + +#endif diff --git a/include/rexy/detail/util.hpp b/include/rexy/detail/util.hpp deleted file mode 100644 index ab1aafe..0000000 --- a/include/rexy/detail/util.hpp +++ /dev/null @@ -1,78 +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_DETAIL_UTIL_HPP -#define REXY_DETAIL_UTIL_HPP - -#include //size_t - -namespace rexy::detail{ - namespace{ - //including causes long compile times. so just make my own max instead - template - constexpr const T& max(const T& a, const T& b){ - return (a < b) ? b : a; - } - template - constexpr const T& min(const T& a, const T& b){ - return (a > b) ? b : a; - } - - constexpr size_t cx_strlen(const char* c){ - size_t i = 0; - for(;c[i];++i); - return i; - } - constexpr int cx_strcmp(const char* l, const char* r){ - using uchar = unsigned char; - for(;*l == *r && *l;++l, ++r); - return (uchar{*l}) - (uchar{*r}); - } - } //anonymous namespace -} //namespace detail - -//std::swap and std::exchange aren't constexpr until c++20 -#if __cplusplus > 201703L - #include - #define rexy_cx_swap(...) std::swap(__VA_ARGS__) - #define rexy_cx_exchange(...) std::exchange(__VA_ARGS__) -#else - #include - namespace rexy::detail{ - namespace{ - template - constexpr void cx_swap(T& a, T& b)noexcept(std::is_nothrow_move_constructible::value && - std::is_nothrow_move_assignable::value) - { - T tmp = std::move(a); - a = std::move(b); - b = std::move(tmp); - } - template - constexpr T cx_exchange(T& t, U&& u){ - T old = std::move(t); - t = std::forward(u); - return old; - } - } - } //namespace detail - #define rexy_cx_swap(...) detail::cx_swap(__VA_ARGS__) - #define rexy_cx_exchange(...) detail::cx_exchange(__VA_ARGS__) -#endif - -#endif diff --git a/include/rexy/filerd.hpp b/include/rexy/filerd.hpp index dc547f6..21e7715 100644 --- a/include/rexy/filerd.hpp +++ b/include/rexy/filerd.hpp @@ -24,6 +24,7 @@ #include "string.hpp" #include "binary.hpp" +#include "cx/utility.hpp" namespace rexy{ @@ -38,11 +39,11 @@ namespace rexy{ filerd(const char* f, const char* mode = "r"); filerd(const filerd&) = delete; constexpr filerd(filerd&& f): - m_fp(rexy_cx_exchange(f.m_fp, nullptr)){} + m_fp(cx::exchange(f.m_fp, nullptr)){} ~filerd(void); filerd& operator=(const filerd&) = delete; constexpr filerd& operator=(filerd&& f){ - rexy_cx_swap(m_fp, f.m_fp); + cx::swap(m_fp, f.m_fp); return *this; } diff --git a/include/rexy/string_base.hpp b/include/rexy/string_base.hpp index 9eba175..58add75 100644 --- a/include/rexy/string_base.hpp +++ b/include/rexy/string_base.hpp @@ -24,7 +24,7 @@ #include //size_t #include "steal.hpp" -#include "detail/util.hpp" +#include "cx/utility.hpp" namespace rexy{ @@ -53,7 +53,7 @@ namespace rexy{ public: //Stop managing stored pointer. Does not free. - constexpr char* release(void){return rexy_cx_exchange(m_data, nullptr);} + constexpr char* release(void){return cx::exchange(m_data, nullptr);} //Length of string not including null terminator constexpr size_t length(void)const{return m_length;} @@ -198,7 +198,7 @@ namespace rexy{ } //namespace detail template = 0> constexpr bool operator==(Str1&& left, Str2&& right){ - return left.valid() && right.valid() && left.length() == right.length() && !detail::cx_strcmp(left.get(), right.get()); + return left.valid() && right.valid() && left.length() == right.length() && !cx::strcmp(left.get(), right.get()); } template = 0> constexpr bool operator!=(Str1&& left, Str2&& right){ @@ -241,4 +241,8 @@ namespace{ #include "detail/binary_string_conv.hpp" #endif +#ifdef REXY_CX_HASH_HPP +#include "cx/string_hash.hpp" +#endif + #endif diff --git a/include/rexy/string_base.tpp b/include/rexy/string_base.tpp index fc73aea..c1712f2 100644 --- a/include/rexy/string_base.tpp +++ b/include/rexy/string_base.tpp @@ -23,7 +23,7 @@ #include //memcpy #include //strlen, strcpy -#include "detail/util.hpp" //max +#include "cx/utility.hpp" //max namespace rexy{ @@ -58,7 +58,7 @@ namespace rexy{ } template constexpr string_intermediary::string_intermediary(rexy::steal data): - string_base(data.value() ? detail::cx_strlen(data.value()) : 0) + string_base(data.value() ? cx::strlen(data.value()) : 0) { m_data = data.value(); m_length = m_cap; @@ -82,7 +82,7 @@ namespace rexy{ string_base(reinterpret_cast(b.m_length ? Allocator::copy(b.m_data, b.m_length+1) : nullptr), b.m_length, b.m_cap){} template constexpr string_intermediary::string_intermediary(string_intermediary&& s): - string_base(rexy_cx_exchange(s.m_data, nullptr), s.m_length, s.m_cap){} + string_base(cx::exchange(s.m_data, nullptr), s.m_length, s.m_cap){} template string_intermediary::string_intermediary(const string_base& b): @@ -106,7 +106,7 @@ namespace rexy{ } template constexpr string_intermediary& string_intermediary::operator=(string_intermediary&& s){ - rexy_cx_swap(m_data, s.m_data); + cx::swap(m_data, s.m_data); m_length = s.m_length; m_cap = s.m_cap; return *this; @@ -156,7 +156,7 @@ namespace rexy{ m_length += len; m_data[m_length] = 0; }else{ - string_intermediary tmp(detail::max(m_length + len, m_cap*2)); + string_intermediary tmp(cx::max(m_length + len, m_cap*2)); if(m_data) memcpy(tmp.m_data, m_data, m_length); memcpy(tmp.m_data+m_length, data, len); @@ -187,7 +187,7 @@ namespace rexy{ strcpy(m_data, s); }else{ Allocator::free(m_data); - m_cap = detail::max(len, m_cap*2); + m_cap = cx::max(len, m_cap*2); m_data = reinterpret_cast(Allocator::copy(s, m_cap+1)); if(!m_data){ m_length = 0; @@ -245,10 +245,10 @@ namespace rexy{ return *this; } constexpr static_string::static_string(const char* c): - static_string(const_cast(c), detail::cx_strlen(c)){} + static_string(const_cast(c), cx::strlen(c)){} constexpr static_string& static_string::operator=(const char* c){ m_data = const_cast(c); - m_length = detail::cx_strlen(c); + m_length = cx::strlen(c); return *this; } constexpr static_string& static_string::operator=(static_string&& s){ diff --git a/src/ensure.cpp b/src/ensure.cpp index 3edf0c6..f81db15 100644 --- a/src/ensure.cpp +++ b/src/ensure.cpp @@ -3,3 +3,11 @@ #include "rexy/string.hpp" #include "rexy/binary.hpp" #include "rexy/filerd.hpp" +#include "rexy/steal.hpp" +#include "rexy/cx/algorithm.hpp" +#include "rexy/cx/utility.hpp" +#include "rexy/cx/vector.hpp" +#include "rexy/cx/array.hpp" +#include "rexy/cx/hashmap.hpp" +#include "rexy/cx/array.hpp" +#include "rexy/cx/vector.hpp"