Make allocator and string_base compat easier to read and remove unneccessary concepts subdirectory
This commit is contained in:
parent
5a6d7023ac
commit
7f47a4cbf8
@ -19,143 +19,12 @@
|
|||||||
#ifndef REXY_DEFAULT_ALLOCATOR_HPP
|
#ifndef REXY_DEFAULT_ALLOCATOR_HPP
|
||||||
#define REXY_DEFAULT_ALLOCATOR_HPP
|
#define REXY_DEFAULT_ALLOCATOR_HPP
|
||||||
|
|
||||||
#include <cstddef> //ptrdiff_t, size_t
|
#include "compat/allocator.hpp"
|
||||||
#include <type_traits> //true_type, false_type
|
|
||||||
#include <new>
|
|
||||||
#include <limits> //numeric_limits
|
|
||||||
|
|
||||||
#if __cplusplus >= 202002L
|
|
||||||
#include <memory> //allocator
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cpp_concepts
|
|
||||||
#include "concepts/allocator.hpp"
|
|
||||||
#define REXY_ALLOCATOR_CONCEPT Allocator
|
|
||||||
#else
|
|
||||||
#define REXY_ALLOCATOR_CONCEPT class
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "rexy.hpp"
|
|
||||||
#include "compat/standard.hpp"
|
|
||||||
#include "compat/if_consteval.hpp"
|
|
||||||
|
|
||||||
#include <type_traits> //declval
|
#include <type_traits> //declval
|
||||||
|
|
||||||
namespace rexy{
|
namespace rexy{
|
||||||
|
|
||||||
template<class T>
|
|
||||||
struct allocator
|
|
||||||
{
|
|
||||||
using pointer = T*;
|
|
||||||
using const_pointer = const T*;
|
|
||||||
using void_pointer = void*;
|
|
||||||
using const_void_pointer = const void*;
|
|
||||||
using value_type = T;
|
|
||||||
using size_type = std::size_t;
|
|
||||||
using difference_type = ptrdiff_t;
|
|
||||||
using is_always_equal = std::true_type;
|
|
||||||
using propagate_on_container_copy_assignment = std::false_type;
|
|
||||||
using propagate_on_container_move_assignment = std::false_type;
|
|
||||||
using propagate_on_container_swap = std::false_type;
|
|
||||||
|
|
||||||
template<class U>
|
|
||||||
struct rebind{
|
|
||||||
using other = allocator<U>;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
constexpr bool has_overflow(size_type n)const{
|
|
||||||
return n > max_size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
REXY_CPP20_CONSTEXPR allocator(void) = default;
|
|
||||||
REXY_CPP20_CONSTEXPR allocator(const allocator&) = default;
|
|
||||||
REXY_CPP20_CONSTEXPR allocator(allocator&&) = default;
|
|
||||||
template<class U>
|
|
||||||
constexpr allocator(const allocator<U>&)noexcept{}
|
|
||||||
REXY_CPP20_CONSTEXPR ~allocator(void) = default;
|
|
||||||
|
|
||||||
//'::operator new' is never a constexpr call as of C++23. However, 'std::allocator::allocate' *is* transiently constexpr as of C++20,
|
|
||||||
//even though it directly calls '::operator new' as is stated in the standard. Therefore, when evaluating this call with support for
|
|
||||||
//'if consteval', we can use the 'std::allocator::allocate' constexpr-ness when this is in a constant evaluation context.
|
|
||||||
#if __cplusplus >= 202002L
|
|
||||||
REXY_CPP20_CONSTEXPR pointer allocate(size_type n){
|
|
||||||
size_type bytes = has_overflow(n) ? std::numeric_limits<size_type>::max() : n*sizeof(T);
|
|
||||||
|
|
||||||
REXY_if_consteval{
|
|
||||||
std::allocator<value_type> a;
|
|
||||||
const size_type num_items = n / sizeof(value_type);
|
|
||||||
return a.allocate(num_items);
|
|
||||||
}else{
|
|
||||||
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
|
|
||||||
return reinterpret_cast<pointer>(::operator new(bytes));
|
|
||||||
}else{
|
|
||||||
return reinterpret_cast<pointer>(::operator new(bytes, static_cast<std::align_val_t>(alignof(T))));
|
|
||||||
}
|
|
||||||
} //if consteval
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
REXY_CPP20_CONSTEXPR void deallocate(pointer p, size_type n){
|
|
||||||
REXY_if_consteval{
|
|
||||||
std::allocator<value_type> a;
|
|
||||||
const size_type num_items = n / sizeof(value_type);
|
|
||||||
return a.deallocate(p, num_items);
|
|
||||||
}else{
|
|
||||||
|
|
||||||
#if !defined(__cpp_sized_deallocation)
|
|
||||||
//clang does not enable ::operator delete(void* ptr, std::size_t sz) by default for some reason
|
|
||||||
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
|
|
||||||
::operator delete(p);
|
|
||||||
}else{
|
|
||||||
::operator delete(p, static_cast<std::align_val_t>(alignof(T)));
|
|
||||||
}
|
|
||||||
#else //__cpp_sized_deallocation
|
|
||||||
size_type bytes = has_overflow(n) ? std::numeric_limits<size_type>::max() : n*sizeof(T);
|
|
||||||
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
|
|
||||||
::operator delete(p, bytes);
|
|
||||||
}else{
|
|
||||||
::operator delete(p, bytes, static_cast<std::align_val_t>(alignof(T)));
|
|
||||||
}
|
|
||||||
#endif //__cpp_sized_deallocation
|
|
||||||
|
|
||||||
} //if consteval
|
|
||||||
|
|
||||||
}
|
|
||||||
#else //__cplusplus
|
|
||||||
REXY_CPP20_CONSTEXPR pointer allocate(size_type n){
|
|
||||||
size_type bytes = has_overflow(n) ? std::numeric_limits<size_type>::max() : n*sizeof(T);
|
|
||||||
|
|
||||||
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
|
|
||||||
return reinterpret_cast<pointer>(::operator new(bytes));
|
|
||||||
}else{
|
|
||||||
return reinterpret_cast<pointer>(::operator new(bytes, static_cast<std::align_val_t>(alignof(T))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
REXY_CPP20_CONSTEXPR void deallocate(pointer p, size_type n){
|
|
||||||
#if !defined(__cpp_sized_deallocation)
|
|
||||||
//clang does not enable ::operator delete(void* ptr, std::size_t sz) by default for some reason
|
|
||||||
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
|
|
||||||
::operator delete(p);
|
|
||||||
}else{
|
|
||||||
::operator delete(p, static_cast<std::align_val_t>(alignof(T)));
|
|
||||||
}
|
|
||||||
#else //__cpp_sized_deallocation
|
|
||||||
size_type bytes = has_overflow(n) ? std::numeric_limits<size_type>::max() : n*sizeof(T);
|
|
||||||
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
|
|
||||||
::operator delete(p, bytes);
|
|
||||||
}else{
|
|
||||||
::operator delete(p, bytes, static_cast<std::align_val_t>(alignof(T)));
|
|
||||||
}
|
|
||||||
#endif //__cpp_sized_deallocation
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //__cplusplus
|
|
||||||
constexpr size_type max_size(void)const{
|
|
||||||
return std::numeric_limits<size_type>::max()/sizeof(T);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<class T, class U>
|
template<class T, class U>
|
||||||
constexpr bool operator==(const allocator<T>&, const allocator<U>&){
|
constexpr bool operator==(const allocator<T>&, const allocator<U>&){
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -16,23 +16,8 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef REXY_CONCEPTS_ALLOCATOR_HPP
|
#if __cplusplus >= 202002L
|
||||||
#define REXY_CONCEPTS_ALLOCATOR_HPP
|
#include "cpp20/allocator.hpp"
|
||||||
|
#else
|
||||||
#include <concepts> //convertible_to
|
#include "cpp17/allocator.hpp"
|
||||||
|
|
||||||
namespace rexy{
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
concept Allocator = requires(T a, typename T::size_type sz, typename T::pointer pa){
|
|
||||||
typename T::value_type;
|
|
||||||
typename T::size_type;
|
|
||||||
typename T::pointer;
|
|
||||||
typename T::const_pointer;
|
|
||||||
{a.allocate(sz)} -> std::convertible_to<typename T::pointer>;
|
|
||||||
{a.deallocate(pa, sz)};
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
100
include/rexy/compat/cpp17/allocator.hpp
Normal file
100
include/rexy/compat/cpp17/allocator.hpp
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/**
|
||||||
|
This file is a part of rexy's general purpose library
|
||||||
|
Copyright (C) 2022 rexy712
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef REXY_COMPAT_CPP17_DEFAULT_ALLOCATOR_HPP
|
||||||
|
#define REXY_COMPAT_CPP17_DEFAULT_ALLOCATOR_HPP
|
||||||
|
|
||||||
|
#include <cstddef> //ptrdiff_t, size_t
|
||||||
|
#include <type_traits> //true_type, false_type
|
||||||
|
#include <new>
|
||||||
|
#include <limits> //numeric_limits
|
||||||
|
|
||||||
|
#include "../../rexy.hpp"
|
||||||
|
|
||||||
|
#define REXY_ALLOCATOR_CONCEPT class
|
||||||
|
|
||||||
|
namespace rexy{
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct allocator
|
||||||
|
{
|
||||||
|
using pointer = T*;
|
||||||
|
using const_pointer = const T*;
|
||||||
|
using void_pointer = void*;
|
||||||
|
using const_void_pointer = const void*;
|
||||||
|
using value_type = T;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using difference_type = ptrdiff_t;
|
||||||
|
using is_always_equal = std::true_type;
|
||||||
|
using propagate_on_container_copy_assignment = std::false_type;
|
||||||
|
using propagate_on_container_move_assignment = std::false_type;
|
||||||
|
using propagate_on_container_swap = std::false_type;
|
||||||
|
|
||||||
|
template<class U>
|
||||||
|
struct rebind{
|
||||||
|
using other = allocator<U>;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
constexpr bool has_overflow(size_type n)const{
|
||||||
|
return n > max_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
allocator(void) = default;
|
||||||
|
allocator(const allocator&) = default;
|
||||||
|
allocator(allocator&&) = default;
|
||||||
|
template<class U>
|
||||||
|
constexpr allocator(const allocator<U>&)noexcept{}
|
||||||
|
~allocator(void) = default;
|
||||||
|
|
||||||
|
pointer allocate(size_type n){
|
||||||
|
size_type bytes = has_overflow(n) ? std::numeric_limits<size_type>::max() : n*sizeof(T);
|
||||||
|
|
||||||
|
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
|
||||||
|
return reinterpret_cast<pointer>(::operator new(bytes));
|
||||||
|
}else{
|
||||||
|
return reinterpret_cast<pointer>(::operator new(bytes, static_cast<std::align_val_t>(alignof(T))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void deallocate(pointer p, size_type n){
|
||||||
|
#if !defined(__cpp_sized_deallocation)
|
||||||
|
//clang does not enable ::operator delete(void* ptr, std::size_t sz) by default for some reason
|
||||||
|
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
|
||||||
|
::operator delete(p);
|
||||||
|
}else{
|
||||||
|
::operator delete(p, static_cast<std::align_val_t>(alignof(T)));
|
||||||
|
}
|
||||||
|
#else //__cpp_sized_deallocation
|
||||||
|
size_type bytes = has_overflow(n) ? std::numeric_limits<size_type>::max() : n*sizeof(T);
|
||||||
|
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
|
||||||
|
::operator delete(p, bytes);
|
||||||
|
}else{
|
||||||
|
::operator delete(p, bytes, static_cast<std::align_val_t>(alignof(T)));
|
||||||
|
}
|
||||||
|
#endif //__cpp_sized_deallocation
|
||||||
|
|
||||||
|
}
|
||||||
|
constexpr size_type max_size(void)const{
|
||||||
|
return std::numeric_limits<size_type>::max()/sizeof(T);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -25,9 +25,17 @@
|
|||||||
#include <type_traits> //{false,true}_type, declval, enable_if, remove_reference, decay
|
#include <type_traits> //{false,true}_type, declval, enable_if, remove_reference, decay
|
||||||
|
|
||||||
#include "../../utility.hpp" //strlen, strncmp
|
#include "../../utility.hpp" //strlen, strncmp
|
||||||
|
#include "../../traits.hpp"
|
||||||
|
|
||||||
namespace rexy{
|
namespace rexy{
|
||||||
|
|
||||||
|
template<class Left, class Right>
|
||||||
|
class string_cat_expr;
|
||||||
|
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
|
||||||
|
class basic_string;
|
||||||
|
template<class Char>
|
||||||
|
class basic_string_view;
|
||||||
|
|
||||||
#define REXY_HAS_MEMFUN_WITH_RET(type, ret, fun, ...) \
|
#define REXY_HAS_MEMFUN_WITH_RET(type, ret, fun, ...) \
|
||||||
template<class T> \
|
template<class T> \
|
||||||
struct has_##fun##_f{ \
|
struct has_##fun##_f{ \
|
||||||
@ -62,9 +70,35 @@ namespace rexy{
|
|||||||
#undef REXY_HAS_MEMFUN_WITH_RET
|
#undef REXY_HAS_MEMFUN_WITH_RET
|
||||||
#undef REXY_HAS_MEMOP_WITH_RET
|
#undef REXY_HAS_MEMOP_WITH_RET
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct is_basic_string{
|
||||||
|
template<class Char, class Alloc>
|
||||||
|
static std::true_type check(const basic_string<Char,Alloc>*);
|
||||||
|
static std::false_type check(...);
|
||||||
|
|
||||||
|
static constexpr bool value = decltype(check(std::declval<rexy::remove_cvref_t<T>*>()))::value;
|
||||||
|
};
|
||||||
|
template<class T>
|
||||||
|
struct is_basic_string_view{
|
||||||
|
template<class Char>
|
||||||
|
static std::true_type check(const basic_string_view<Char>*);
|
||||||
|
static std::false_type check(...);
|
||||||
|
|
||||||
|
static constexpr bool value = decltype(check(std::declval<rexy::remove_cvref_t<T>*>()))::value;
|
||||||
|
};
|
||||||
|
template<class T>
|
||||||
|
struct is_basic_string_expr{
|
||||||
|
template<class Left, class Right>
|
||||||
|
static std::true_type check(const string_cat_expr<Left,Right>*);
|
||||||
|
static std::false_type check(...);
|
||||||
|
|
||||||
|
static constexpr bool value = decltype(check(std::declval<rexy::remove_cvref_t<T>*>()))::value;
|
||||||
|
};
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
struct is_string{
|
struct is_string{
|
||||||
static constexpr bool value = has_length_f_v<T> && has_c_str_f_v<T> && has_indexop_f_v<T> && has_begin_f_v<T> && has_end_f_v<T>;
|
static constexpr bool value = (is_basic_string<T>::value || is_basic_string_view<T>::value) &&
|
||||||
|
(has_length_f_v<T> && has_c_str_f_v<T> && has_indexop_f_v<T> && has_begin_f_v<T> && has_end_f_v<T>);
|
||||||
};
|
};
|
||||||
template<class T>
|
template<class T>
|
||||||
static constexpr bool is_string_v = is_string<T>::value;
|
static constexpr bool is_string_v = is_string<T>::value;
|
||||||
@ -77,7 +111,7 @@ namespace rexy{
|
|||||||
static constexpr bool are_strings_v = are_strings<Ts...>::value;
|
static constexpr bool are_strings_v = are_strings<Ts...>::value;
|
||||||
template<class T>
|
template<class T>
|
||||||
struct is_string_expr{
|
struct is_string_expr{
|
||||||
static constexpr bool value = rexy::is_template_type<T,string_cat_expr>::value;
|
static constexpr bool value = is_basic_string_expr<T>::value;
|
||||||
};
|
};
|
||||||
template<class T>
|
template<class T>
|
||||||
static constexpr bool is_string_expr_v = is_string_expr<T>::value;
|
static constexpr bool is_string_expr_v = is_string_expr<T>::value;
|
||||||
|
|||||||
139
include/rexy/compat/cpp20/allocator.hpp
Normal file
139
include/rexy/compat/cpp20/allocator.hpp
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
/**
|
||||||
|
This file is a part of rexy's general purpose library
|
||||||
|
Copyright (C) 2022 rexy712
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef REXY_COMPAT_CPP20_DEFAULT_ALLOCATOR_HPP
|
||||||
|
#define REXY_COMPAT_CPP20_DEFAULT_ALLOCATOR_HPP
|
||||||
|
|
||||||
|
#include <cstddef> //ptrdiff_t, size_t
|
||||||
|
#include <type_traits> //true_type, false_type
|
||||||
|
#include <new>
|
||||||
|
#include <limits> //numeric_limits
|
||||||
|
#include <memory> //allocator
|
||||||
|
|
||||||
|
#ifdef __cpp_concepts
|
||||||
|
|
||||||
|
#include <concepts> //convertible_to
|
||||||
|
template<class T>
|
||||||
|
concept Allocator = requires(T a, typename T::size_type sz, typename T::pointer pa){
|
||||||
|
typename T::value_type;
|
||||||
|
typename T::size_type;
|
||||||
|
typename T::pointer;
|
||||||
|
typename T::const_pointer;
|
||||||
|
{a.allocate(sz)} -> std::convertible_to<typename T::pointer>;
|
||||||
|
{a.deallocate(pa, sz)};
|
||||||
|
};
|
||||||
|
#define REXY_ALLOCATOR_CONCEPT Allocator
|
||||||
|
|
||||||
|
#else //__cpp_concepts
|
||||||
|
|
||||||
|
#define REXY_ALLOCATOR_CONCEPT class
|
||||||
|
|
||||||
|
#endif // __cpp_concepts
|
||||||
|
|
||||||
|
#include "../../rexy.hpp"
|
||||||
|
#include "../if_consteval.hpp"
|
||||||
|
|
||||||
|
namespace rexy{
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct allocator
|
||||||
|
{
|
||||||
|
using pointer = T*;
|
||||||
|
using const_pointer = const T*;
|
||||||
|
using void_pointer = void*;
|
||||||
|
using const_void_pointer = const void*;
|
||||||
|
using value_type = T;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using is_always_equal = std::true_type;
|
||||||
|
using propagate_on_container_copy_assignment = std::false_type;
|
||||||
|
using propagate_on_container_move_assignment = std::false_type;
|
||||||
|
using propagate_on_container_swap = std::false_type;
|
||||||
|
|
||||||
|
template<class U>
|
||||||
|
struct rebind{
|
||||||
|
using other = allocator<U>;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
constexpr bool has_overflow(size_type n)const{
|
||||||
|
return n > max_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr allocator(void) = default;
|
||||||
|
constexpr allocator(const allocator&) = default;
|
||||||
|
constexpr allocator(allocator&&) = default;
|
||||||
|
template<class U>
|
||||||
|
constexpr allocator(const allocator<U>&)noexcept{}
|
||||||
|
constexpr ~allocator(void) = default;
|
||||||
|
|
||||||
|
//'::operator new' is never a constexpr call as of C++23. However, 'std::allocator::allocate' *is* transiently constexpr as of C++20,
|
||||||
|
//even though it directly calls '::operator new' as is stated in the standard. Therefore, when evaluating this call with support for
|
||||||
|
//'if consteval', we can use the 'std::allocator::allocate' constexpr-ness when this is in a constant evaluation context.
|
||||||
|
constexpr pointer allocate(size_type n){
|
||||||
|
size_type bytes = has_overflow(n) ? std::numeric_limits<size_type>::max() : n*sizeof(T);
|
||||||
|
|
||||||
|
REXY_if_consteval{
|
||||||
|
std::allocator<value_type> a;
|
||||||
|
const size_type num_items = n / sizeof(value_type);
|
||||||
|
return a.allocate(num_items);
|
||||||
|
}else{
|
||||||
|
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
|
||||||
|
return reinterpret_cast<pointer>(::operator new(bytes));
|
||||||
|
}else{
|
||||||
|
return reinterpret_cast<pointer>(::operator new(bytes, static_cast<std::align_val_t>(alignof(T))));
|
||||||
|
}
|
||||||
|
} //if consteval
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
constexpr void deallocate(pointer p, size_type n){
|
||||||
|
REXY_if_consteval{
|
||||||
|
std::allocator<value_type> a;
|
||||||
|
const size_type num_items = n / sizeof(value_type);
|
||||||
|
return a.deallocate(p, num_items);
|
||||||
|
}else{
|
||||||
|
|
||||||
|
#if !defined(__cpp_sized_deallocation)
|
||||||
|
//clang does not enable ::operator delete(void* ptr, std::size_t sz) by default for some reason
|
||||||
|
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
|
||||||
|
::operator delete(p);
|
||||||
|
}else{
|
||||||
|
::operator delete(p, static_cast<std::align_val_t>(alignof(T)));
|
||||||
|
}
|
||||||
|
#else //__cpp_sized_deallocation
|
||||||
|
size_type bytes = has_overflow(n) ? std::numeric_limits<size_type>::max() : n*sizeof(T);
|
||||||
|
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
|
||||||
|
::operator delete(p, bytes);
|
||||||
|
}else{
|
||||||
|
::operator delete(p, bytes, static_cast<std::align_val_t>(alignof(T)));
|
||||||
|
}
|
||||||
|
#endif //__cpp_sized_deallocation
|
||||||
|
|
||||||
|
} //if consteval
|
||||||
|
|
||||||
|
}
|
||||||
|
constexpr size_type max_size(void)const{
|
||||||
|
return std::numeric_limits<size_type>::max()/sizeof(T);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -24,11 +24,71 @@
|
|||||||
#include <utility> //forward
|
#include <utility> //forward
|
||||||
#include <type_traits> //decay, is_nothrow_assignable
|
#include <type_traits> //decay, is_nothrow_assignable
|
||||||
|
|
||||||
#include "../../concepts/string.hpp"
|
|
||||||
#include "../../utility.hpp" //strlen, strncmp
|
#include "../../utility.hpp" //strlen, strncmp
|
||||||
|
|
||||||
namespace rexy{
|
namespace rexy{
|
||||||
|
|
||||||
|
template<class Left, class Right>
|
||||||
|
class string_cat_expr;
|
||||||
|
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
|
||||||
|
class basic_string;
|
||||||
|
template<class Char>
|
||||||
|
class basic_string_view;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct is_basic_string{
|
||||||
|
template<class Char, class Alloc>
|
||||||
|
static std::true_type check(const basic_string<Char,Alloc>*);
|
||||||
|
static std::false_type check(...);
|
||||||
|
|
||||||
|
static constexpr bool value = decltype(check(std::declval<std::remove_cvref_t<T>*>()))::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct is_basic_string_view{
|
||||||
|
template<class Char>
|
||||||
|
static std::true_type check(const basic_string_view<Char>*);
|
||||||
|
static std::false_type check(...);
|
||||||
|
|
||||||
|
static constexpr bool value = decltype(check(std::declval<std::remove_cvref_t<T>*>()))::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct is_basic_string_expr{
|
||||||
|
template<class Left, class Right>
|
||||||
|
static std::true_type check(const string_cat_expr<Left,Right>*);
|
||||||
|
static std::false_type check(...);
|
||||||
|
|
||||||
|
static constexpr bool value = decltype(check(std::declval<std::remove_cvref_t<T>*>()))::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
concept BasicString = requires(const T& a){
|
||||||
|
requires(is_basic_string<T>::value || is_basic_string_view<T>::value);
|
||||||
|
{std::as_const(a).length()} -> std::convertible_to<typename std::decay_t<T>::size_type>;
|
||||||
|
{std::as_const(a).c_str()} -> std::convertible_to<typename std::decay_t<T>::const_pointer>;
|
||||||
|
{std::as_const(a)[0]} -> std::convertible_to<typename std::decay_t<T>::const_reference>;
|
||||||
|
{std::as_const(a).begin()} -> std::convertible_to<typename std::decay_t<T>::const_iterator>;
|
||||||
|
{std::as_const(a).end()} -> std::convertible_to<typename std::decay_t<T>::const_iterator>;
|
||||||
|
};
|
||||||
|
template<class T>
|
||||||
|
concept StringExpr = is_basic_string_expr<T>::value;
|
||||||
|
template<class T>
|
||||||
|
concept String = BasicString<T> || StringExpr<T>;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct is_string{
|
||||||
|
static constexpr bool value = BasicString<T>;
|
||||||
|
};
|
||||||
|
template<class T>
|
||||||
|
static constexpr bool is_string_v = is_string<T>::value;
|
||||||
|
template<class T>
|
||||||
|
struct is_string_expr{
|
||||||
|
static constexpr bool value = StringExpr<T>;
|
||||||
|
};
|
||||||
|
template<class T>
|
||||||
|
static constexpr bool is_string_expr_v = is_string_expr<T>::value;
|
||||||
|
|
||||||
//Compare
|
//Compare
|
||||||
template<BasicString Str1, BasicString Str2>
|
template<BasicString Str1, BasicString Str2>
|
||||||
constexpr bool operator==(Str1&& left, Str2&& right){
|
constexpr bool operator==(Str1&& left, Str2&& right){
|
||||||
|
|||||||
@ -1,105 +0,0 @@
|
|||||||
/**
|
|
||||||
This file is a part of rexy's general purpose library
|
|
||||||
Copyright (C) 2022 rexy712
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU 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 General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef REXY_CONCEPTS_STRING_HPP
|
|
||||||
#define REXY_CONCEPTS_STRING_HPP
|
|
||||||
|
|
||||||
#include <type_traits> //decay
|
|
||||||
#include <concepts> //convertible_to
|
|
||||||
#include <utility> //as_const
|
|
||||||
|
|
||||||
#include "../traits.hpp"
|
|
||||||
|
|
||||||
namespace rexy{
|
|
||||||
|
|
||||||
template<class Left, class Right>
|
|
||||||
class string_cat_expr;
|
|
||||||
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
|
|
||||||
class basic_string;
|
|
||||||
template<class Char>
|
|
||||||
class basic_string_view;
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
struct is_basic_string{
|
|
||||||
template<class Char, class Alloc>
|
|
||||||
static std::true_type check(const basic_string<Char,Alloc>*);
|
|
||||||
static std::false_type check(...);
|
|
||||||
|
|
||||||
static constexpr bool value = decltype(check(std::declval<std::remove_cvref_t<T>*>()))::value;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
struct is_basic_string_view{
|
|
||||||
template<class Char>
|
|
||||||
static std::true_type check(const basic_string_view<Char>*);
|
|
||||||
static std::false_type check(...);
|
|
||||||
|
|
||||||
static constexpr bool value = decltype(check(std::declval<std::remove_cvref_t<T>*>()))::value;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
struct is_basic_string_expr{
|
|
||||||
template<class Left, class Right>
|
|
||||||
static std::true_type check(const string_cat_expr<Left,Right>*);
|
|
||||||
static std::false_type check(...);
|
|
||||||
|
|
||||||
static constexpr bool value = decltype(check(std::declval<std::remove_cvref_t<T>*>()))::value;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
concept BasicString = requires(const T& a){
|
|
||||||
requires(is_basic_string<T>::value || is_basic_string_view<T>::value);
|
|
||||||
{std::as_const(a).length()} -> std::convertible_to<typename std::decay_t<T>::size_type>;
|
|
||||||
{std::as_const(a).c_str()} -> std::convertible_to<typename std::decay_t<T>::const_pointer>;
|
|
||||||
{std::as_const(a)[0]} -> std::convertible_to<typename std::decay_t<T>::const_reference>;
|
|
||||||
{std::as_const(a).begin()} -> std::convertible_to<typename std::decay_t<T>::const_iterator>;
|
|
||||||
{std::as_const(a).end()} -> std::convertible_to<typename std::decay_t<T>::const_iterator>;
|
|
||||||
};
|
|
||||||
template<class T>
|
|
||||||
concept StringExpr = is_basic_string_expr<T>::value;
|
|
||||||
template<class T>
|
|
||||||
concept String = BasicString<T> || StringExpr<T>;
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
struct is_string{
|
|
||||||
static constexpr bool value = BasicString<T>;
|
|
||||||
};
|
|
||||||
template<class T>
|
|
||||||
static constexpr bool is_string_v = is_string<T>::value;
|
|
||||||
template<class... Ts>
|
|
||||||
struct are_strings{
|
|
||||||
static constexpr bool value = (BasicString<Ts> && ...);
|
|
||||||
};
|
|
||||||
template<class... Ts>
|
|
||||||
static constexpr bool are_strings_v = are_strings<Ts...>::value;
|
|
||||||
template<class T>
|
|
||||||
struct is_string_expr{
|
|
||||||
static constexpr bool value = StringExpr<T>;
|
|
||||||
};
|
|
||||||
template<class T>
|
|
||||||
static constexpr bool is_string_expr_v = is_string_expr<T>::value;
|
|
||||||
template<class... Ts>
|
|
||||||
struct are_string_expr{
|
|
||||||
static constexpr bool value = (StringExpr<Ts> && ...);
|
|
||||||
};
|
|
||||||
template<class... Ts>
|
|
||||||
static constexpr bool are_string_expr_v = are_string_expr<Ts...>::value;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
Loading…
x
Reference in New Issue
Block a user