Cleanup constexpr namespace and some metaprogramming junk
This commit is contained in:
parent
c99abad226
commit
c622eb7323
@ -29,7 +29,7 @@ if(ENABLE_PROFILING)
|
||||
target_link_options(rexy PRIVATE -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls)
|
||||
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_PUBLIC_HEADERS "include/rexy/traits.hpp" "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")
|
||||
target_compile_options(rexy PRIVATE -Wall -Wextra -pedantic -std=c++17)
|
||||
|
||||
install(TARGETS rexy
|
||||
|
||||
@ -30,15 +30,15 @@ namespace rexy::cx{
|
||||
auto value = *pivot;
|
||||
|
||||
//move pivot value all the way to the right side to preserve it
|
||||
swap(*pivot, *right);
|
||||
cx::swap(*pivot, *right);
|
||||
for(auto it = left;it != right;++it){
|
||||
if(cmp(*it, value)){
|
||||
swap(*left, *it);
|
||||
cx::swap(*left, *it);
|
||||
++left;
|
||||
}
|
||||
}
|
||||
//move pivot value back to proper position
|
||||
swap(*left, *right);
|
||||
cx::swap(*left, *right);
|
||||
return left;
|
||||
}
|
||||
template<class Iter, class Compare>
|
||||
|
||||
@ -25,13 +25,18 @@
|
||||
#include "hash.hpp"
|
||||
|
||||
#include <climits> //CHAR_BIT
|
||||
#include <cstddef> //size_t, ptrdiff_t
|
||||
#include <utility> //pair
|
||||
#include <type_traits> //decay
|
||||
#include <initializer_list>
|
||||
|
||||
namespace rexy::cx{
|
||||
|
||||
template<class Key, class Value>
|
||||
struct element
|
||||
{
|
||||
struct element{
|
||||
using key_type = Key;
|
||||
using value_type = Value;
|
||||
|
||||
Key key;
|
||||
Value value;
|
||||
};
|
||||
@ -40,24 +45,42 @@ namespace rexy::cx{
|
||||
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;
|
||||
using key_type = Key;
|
||||
using mapped_type = Value;
|
||||
using value_type = element<Key,Value>;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using hasher = Hash;
|
||||
using reference = mapped_type&;
|
||||
using const_reference = const mapped_type&;
|
||||
using pointer = mapped_type*;
|
||||
using const_pointer = const mapped_type*;
|
||||
|
||||
static constexpr size_type single_bucket_bit = size_type{1} << ((sizeof(size_type)*CHAR_BIT) - 1);
|
||||
static constexpr size_type 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
|
||||
array<mapped_type,N> m_values; //perfect hash table
|
||||
array<size_type,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;
|
||||
constexpr hashmap(const value_type(&elements)[N]);
|
||||
|
||||
//no key checks. give a correct key or get a random answer :)
|
||||
template<class U, class UHash = hash<std::decay_t<U>>>
|
||||
constexpr reference operator[](U&& u);
|
||||
template<class U, class UHash = hash<std::decay_t<U>>>
|
||||
constexpr const_reference operator[](U&& u)const;
|
||||
};
|
||||
|
||||
template<class Key, class Value, size_t N, class Hash>
|
||||
constexpr hashmap<Key,Value,N,Hash>::hashmap(const value_type(&elements)[N]){
|
||||
array<vector<value_type,N>,N> buckets;
|
||||
array<bool,N> slots_used;
|
||||
size_t current_bucket = 0;
|
||||
size_type current_bucket = 0;
|
||||
|
||||
//place all keys into buckets
|
||||
for(auto& element : elements){
|
||||
@ -77,11 +100,11 @@ namespace rexy::cx{
|
||||
break;
|
||||
|
||||
array<bool,N> pass_slots_used;
|
||||
vector<size_t,N> pass_slots;
|
||||
size_t d = 1;
|
||||
vector<size_type,N> pass_slots;
|
||||
size_type d = 1;
|
||||
|
||||
for(size_t i = 0;i < bucket.size();){
|
||||
size_t slot = Hash{}(bucket[i].key, d) % max_size;
|
||||
for(size_type i = 0;i < bucket.size();){
|
||||
size_type 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;
|
||||
@ -99,14 +122,14 @@ namespace rexy::cx{
|
||||
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){
|
||||
for(size_type 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;
|
||||
size_type next_free_slot = 0;
|
||||
|
||||
for(;current_bucket < buckets.size();++current_bucket){
|
||||
auto& bucket = buckets[current_bucket];
|
||||
@ -121,22 +144,27 @@ namespace rexy::cx{
|
||||
}
|
||||
|
||||
//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];
|
||||
template<class Key, class Value, size_t N, class Hash>
|
||||
template<class U, class UHash>
|
||||
constexpr auto hashmap<Key,Value,N,Hash>::operator[](U&& key) -> reference{
|
||||
auto d = m_g[UHash{}(std::forward<U>(key)) % max_size];
|
||||
if(d & single_bucket_bit)
|
||||
return m_values[d & ~single_bucket_bit];
|
||||
return m_values[Hash{}(key, d) % max_size];
|
||||
return m_values[UHash{}(std::forward<U>(key), d) % max_size];
|
||||
}
|
||||
constexpr const value_type& operator[](const Key& key)const{
|
||||
size_t d = m_g[Hash{}(key) % max_size];
|
||||
template<class Key, class Value, size_t N, class Hash>
|
||||
template<class U, class UHash>
|
||||
constexpr auto hashmap<Key,Value,N,Hash>::operator[](U&& key)const -> const_reference{
|
||||
auto d = m_g[UHash{}(std::forward<U>(key)) % max_size];
|
||||
if(d & single_bucket_bit)
|
||||
return m_values[d & ~single_bucket_bit];
|
||||
return m_values[Hash{}(key, d) % max_size];
|
||||
return m_values[UHash{}(std::forward<U>(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]){
|
||||
constexpr auto make_hashmap(const typename hashmap<Key,Value,N,Hash>::value_type(&list)[N]){
|
||||
return hashmap<Key,Value,N,Hash>(list);
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
#include "steal.hpp"
|
||||
#include "cx/utility.hpp"
|
||||
#include "traits.hpp"
|
||||
|
||||
namespace rexy{
|
||||
|
||||
@ -166,36 +167,36 @@ namespace rexy{
|
||||
|
||||
|
||||
namespace detail{
|
||||
std::true_type is_string_helper(string_expr*);
|
||||
std::false_type is_string_helper(...);
|
||||
template<class T>
|
||||
struct is_string{
|
||||
static constexpr bool value = std::is_same<std::true_type,decltype(is_string_helper(std::declval<typename std::decay<T>::type*>()))>::value;
|
||||
static constexpr bool value = rexy::is_type<T,string_expr>::value;
|
||||
};
|
||||
std::true_type is_string_base(string_base*);
|
||||
std::false_type is_string_base(...);
|
||||
template<class T>
|
||||
struct is_concrete_string{
|
||||
static constexpr bool value = std::is_same<std::true_type,decltype(is_string_base(std::declval<typename std::decay<T>::type*>()))>::value;
|
||||
static constexpr bool value = rexy::is_type<T,string_base>::value;
|
||||
};
|
||||
|
||||
template<class... Ts>
|
||||
using enable_if_string = std::enable_if_t<(is_string<Ts>::value && ...),int>;
|
||||
template<class... Ts>
|
||||
using enable_if_concrete_string = std::enable_if_t<(is_concrete_string<Ts>::value && ...),int>;
|
||||
template<class... Ts>
|
||||
using enable_if_expr_string = std::enable_if_t<(rexy::is_template_type<Ts,string_cat_expr>::value && ...),int>;
|
||||
|
||||
template<class Targ>
|
||||
struct appender
|
||||
struct string_appender
|
||||
{
|
||||
private:
|
||||
Targ& m_targ;
|
||||
public:
|
||||
appender(Targ& t);
|
||||
constexpr string_appender(Targ& t);
|
||||
template<class L, class R>
|
||||
void operator()(const string_cat_expr<L,R>& str);
|
||||
void operator()(const string_base& str);
|
||||
constexpr void operator()(const string_cat_expr<L,R>& str);
|
||||
template<class Str, std::enable_if_t<!rexy::is_template_type<Str,string_cat_expr>::value,int> = 0>
|
||||
constexpr void operator()(Str&& str);
|
||||
};
|
||||
} //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() && !cx::strcmp(left.get(), right.get());
|
||||
|
||||
@ -219,7 +219,7 @@ namespace rexy{
|
||||
string_cat_expr<Left,Right>::operator string_intermediary<Alloc>(void){
|
||||
size_t len = length();
|
||||
string_intermediary<Alloc> ret(len);
|
||||
detail::appender<string_intermediary<Alloc>> append(ret);
|
||||
detail::string_appender<string_intermediary<Alloc>> append(ret);
|
||||
append(*this);
|
||||
return ret;
|
||||
}
|
||||
@ -259,15 +259,16 @@ namespace rexy{
|
||||
|
||||
namespace detail{
|
||||
template<class Targ>
|
||||
appender<Targ>::appender(Targ& t): m_targ(t){}
|
||||
constexpr string_appender<Targ>::string_appender(Targ& t): m_targ(t){}
|
||||
template<class Targ>
|
||||
template<class L, class R>
|
||||
void appender<Targ>::operator()(const string_cat_expr<L,R>& str){
|
||||
constexpr void string_appender<Targ>::operator()(const string_cat_expr<L,R>& str){
|
||||
(*this)(str.left());
|
||||
(*this)(str.right());
|
||||
}
|
||||
template<class Targ>
|
||||
void appender<Targ>::operator()(const string_base& str){
|
||||
template<class Str, std::enable_if_t<!rexy::is_template_type<Str,string_cat_expr>::value,int>>
|
||||
constexpr void string_appender<Targ>::operator()(Str&& str){
|
||||
m_targ.append(str.get(), str.length());
|
||||
}
|
||||
}
|
||||
|
||||
29
include/rexy/traits.hpp
Normal file
29
include/rexy/traits.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef REXY_TRAITS_HPP
|
||||
#define REXY_TRAITS_HPP
|
||||
|
||||
#include <type_traits> //is_same, decay, integral_constant, declval
|
||||
|
||||
namespace rexy{
|
||||
|
||||
template<class T, class U>
|
||||
struct is_type{
|
||||
static std::true_type check(U*);
|
||||
static std::false_type check(...);
|
||||
|
||||
static constexpr bool value = std::is_same<std::true_type,decltype(check(std::declval<std::decay_t<T>*>()))>::value;
|
||||
};
|
||||
template<class T, template<class...> class U>
|
||||
struct is_template_type_helper{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
template<template<class...> class U, class... Args>
|
||||
struct is_template_type_helper<U<Args...>,U>{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template<class T, template<class...> class U>
|
||||
struct is_template_type : public is_template_type_helper<std::decay_t<T>,U>{};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user