Add compile time vector, array, and hashmap
This commit is contained in:
parent
d415af2bdd
commit
c99abad226
@ -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"
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
#include <utility> //move
|
||||
#include <cstring> //memcpy
|
||||
#include <type_traits>
|
||||
#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;
|
||||
}
|
||||
|
||||
56
include/rexy/cx/algorithm.hpp
Normal file
56
include/rexy/cx/algorithm.hpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef REXY_CX_ALGORITHM_HPP
|
||||
#define REXY_CX_ALGORITHM_HPP
|
||||
|
||||
#include "utility.hpp" //swap
|
||||
|
||||
namespace rexy::cx{
|
||||
|
||||
template<class Iter, class Compare>
|
||||
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<class Iter, class Compare>
|
||||
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
|
||||
126
include/rexy/cx/array.hpp
Normal file
126
include/rexy/cx/array.hpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef REXY_CX_ARRAY_HPP
|
||||
#define REXY_CX_ARRAY_HPP
|
||||
|
||||
#include <cstddef> //size_t
|
||||
#include "utility.hpp" //swap
|
||||
|
||||
namespace rexy::cx{
|
||||
|
||||
template<class T, size_t N>
|
||||
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<class T, class... Us>
|
||||
array(T, Us...) -> array<T, 1 + sizeof...(Us)>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
42
include/rexy/cx/hash.hpp
Normal file
42
include/rexy/cx/hash.hpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef REXY_CX_HASH_HPP
|
||||
#define REXY_CX_HASH_HPP
|
||||
|
||||
#include <climits> //CHAR_BIT
|
||||
|
||||
namespace rexy::cx{
|
||||
|
||||
template<class T>
|
||||
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<size_t>(t);
|
||||
size_t hash = 5381 + salt; //magic hash number
|
||||
for(size_t i = 0;i < bytes;++i){
|
||||
unsigned char c = static_cast<unsigned char>(val >> (i * CHAR_BIT));
|
||||
hash = ((hash << 5) + hash) ^ c;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
148
include/rexy/cx/hashmap.hpp
Normal file
148
include/rexy/cx/hashmap.hpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef REXY_CX_HASHMAP_HPP
|
||||
#define REXY_CX_HASHMAP_HPP
|
||||
|
||||
#include "vector.hpp"
|
||||
#include "array.hpp"
|
||||
#include "algorithm.hpp"
|
||||
#include "hash.hpp"
|
||||
|
||||
#include <climits> //CHAR_BIT
|
||||
#include <initializer_list>
|
||||
|
||||
namespace rexy::cx{
|
||||
|
||||
template<class Key, class Value>
|
||||
struct element
|
||||
{
|
||||
Key key;
|
||||
Value value;
|
||||
};
|
||||
|
||||
template<class Key, class Value, size_t N, class Hash = hash<Key>>
|
||||
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<Value,N> m_values; //perfect hash table
|
||||
array<size_t,N> m_g; //'salt' values for indexing into the perfect hash table
|
||||
|
||||
public:
|
||||
constexpr hashmap(const element<Key,Value>(&elements)[N]){
|
||||
array<vector<element<Key,Value>,N>,N> buckets;
|
||||
array<bool,N> 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<bool,N> pass_slots_used;
|
||||
vector<size_t,N> 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<class Key, class Value, size_t N, class Hash = hash<Key>>
|
||||
constexpr auto make_hashmap(const element<Key,Value>(&list)[N]){
|
||||
return hashmap<Key,Value,N,Hash>(list);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef REXY_STRING_BASE_HPP
|
||||
#include "string_hash.hpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
40
include/rexy/cx/string_hash.hpp
Normal file
40
include/rexy/cx/string_hash.hpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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<rexy::static_string>{
|
||||
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
|
||||
70
include/rexy/cx/utility.hpp
Normal file
70
include/rexy/cx/utility.hpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef REXY_CX_UTILITY_HPP
|
||||
#define REXY_CX_UTILITY_HPP
|
||||
|
||||
#include <utility> //forward, move
|
||||
|
||||
namespace rexy::cx{
|
||||
|
||||
namespace{
|
||||
template<class T>
|
||||
constexpr void swap(T& l, T& r){
|
||||
T tmp = l;
|
||||
l = r;
|
||||
r = tmp;
|
||||
}
|
||||
template<class T, class U = T>
|
||||
constexpr T exchange(T& l, U&& r){
|
||||
T old = std::move(l);
|
||||
l = std::forward<U>(r);
|
||||
return old;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
constexpr const T& min(const T& l, const T& r){
|
||||
return l < r ? l : r;
|
||||
}
|
||||
template<class T, class Compare>
|
||||
constexpr const T& min(const T& l, const T& r, Compare cmp){
|
||||
return cmp(l, r) ? l : r;
|
||||
}
|
||||
template<class T>
|
||||
constexpr const T& max(const T& l, const T& r){
|
||||
return l > r ? l : r;
|
||||
}
|
||||
template<class T, class Compare>
|
||||
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<uchar>(*l)) - (static_cast<uchar>(*r));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
213
include/rexy/cx/vector.hpp
Normal file
213
include/rexy/cx/vector.hpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef REXY_CX_VECTOR_HPP
|
||||
#define REXY_CX_VECTOR_HPP
|
||||
|
||||
#include <cstddef> //size_t
|
||||
#include <utility> //move, forward
|
||||
|
||||
#include "utility.hpp" //swap
|
||||
|
||||
namespace rexy::cx{
|
||||
|
||||
template<class T, size_t N>
|
||||
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<class... Args>
|
||||
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>(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<class... Args>
|
||||
constexpr iterator emplace_back(Args&&... args){
|
||||
m_elements[m_size++] = T{std::forward<Args>(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
|
||||
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef REXY_DETAIL_UTIL_HPP
|
||||
#define REXY_DETAIL_UTIL_HPP
|
||||
|
||||
#include <cstddef> //size_t
|
||||
|
||||
namespace rexy::detail{
|
||||
namespace{
|
||||
//including <algorithm> causes long compile times. so just make my own max instead
|
||||
template<class T>
|
||||
constexpr const T& max(const T& a, const T& b){
|
||||
return (a < b) ? b : a;
|
||||
}
|
||||
template<class T>
|
||||
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 <utility>
|
||||
#define rexy_cx_swap(...) std::swap(__VA_ARGS__)
|
||||
#define rexy_cx_exchange(...) std::exchange(__VA_ARGS__)
|
||||
#else
|
||||
#include <type_traits>
|
||||
namespace rexy::detail{
|
||||
namespace{
|
||||
template<class T>
|
||||
constexpr void cx_swap(T& a, T& b)noexcept(std::is_nothrow_move_constructible<T>::value &&
|
||||
std::is_nothrow_move_assignable<T>::value)
|
||||
{
|
||||
T tmp = std::move(a);
|
||||
a = std::move(b);
|
||||
b = std::move(tmp);
|
||||
}
|
||||
template<class T, class U = T>
|
||||
constexpr T cx_exchange(T& t, U&& u){
|
||||
T old = std::move(t);
|
||||
t = std::forward<U>(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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
#include <cstdlib> //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<class Str1, class Str2, detail::enable_if_concrete_string<Str1,Str2> = 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<class Str1, class Str2, detail::enable_if_concrete_string<Str1,Str2> = 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
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
#include <cstdlib> //memcpy
|
||||
#include <cstring> //strlen, strcpy
|
||||
|
||||
#include "detail/util.hpp" //max
|
||||
#include "cx/utility.hpp" //max
|
||||
|
||||
namespace rexy{
|
||||
|
||||
@ -58,7 +58,7 @@ namespace rexy{
|
||||
}
|
||||
template<class Allocator>
|
||||
constexpr string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> 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<char*>(b.m_length ? Allocator::copy(b.m_data, b.m_length+1) : nullptr), b.m_length, b.m_cap){}
|
||||
template<class Allocator>
|
||||
constexpr string_intermediary<Allocator>::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<class Allocator>
|
||||
string_intermediary<Allocator>::string_intermediary(const string_base& b):
|
||||
@ -106,7 +106,7 @@ namespace rexy{
|
||||
}
|
||||
template<class Allocator>
|
||||
constexpr string_intermediary<Allocator>& string_intermediary<Allocator>::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<char*>(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<char*>(c), detail::cx_strlen(c)){}
|
||||
static_string(const_cast<char*>(c), cx::strlen(c)){}
|
||||
constexpr static_string& static_string::operator=(const char* c){
|
||||
m_data = const_cast<char*>(c);
|
||||
m_length = detail::cx_strlen(c);
|
||||
m_length = cx::strlen(c);
|
||||
return *this;
|
||||
}
|
||||
constexpr static_string& static_string::operator=(static_string&& s){
|
||||
|
||||
@ -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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user