From 1acce4c5882abe3f18e3921ef64b366aa78cfa10 Mon Sep 17 00:00:00 2001 From: rexy712 Date: Wed, 8 Jun 2022 19:21:49 -0700 Subject: [PATCH] Add is_nothrow_allocator type trait --- include/rexy/allocator.hpp | 9 +++++ include/rexy/detail/hasallocator.hpp | 18 ++++----- include/rexy/string_base.hpp | 59 ++++++++++++---------------- include/rexy/string_base.tpp | 58 +++++++++++---------------- 4 files changed, 67 insertions(+), 77 deletions(-) diff --git a/include/rexy/allocator.hpp b/include/rexy/allocator.hpp index 2bfda3b..3272898 100644 --- a/include/rexy/allocator.hpp +++ b/include/rexy/allocator.hpp @@ -38,6 +38,8 @@ #include "rexy.hpp" #include "compat/standard.hpp" +#include //declval + namespace rexy{ template @@ -170,6 +172,13 @@ namespace rexy{ return false; } + template + struct is_nothrow_allocator{ + static constexpr bool value = noexcept(std::declval().allocate(0)) && noexcept(std::declval().deallocate(nullptr, 0)); + }; + template + static constexpr bool is_nothrow_allocator_v = is_nothrow_allocator::value; + } #endif diff --git a/include/rexy/detail/hasallocator.hpp b/include/rexy/detail/hasallocator.hpp index 34a7731..9182496 100644 --- a/include/rexy/detail/hasallocator.hpp +++ b/include/rexy/detail/hasallocator.hpp @@ -31,17 +31,17 @@ namespace rexy::detail{ { Alloc m_alloc; - REXY_CPP20_CONSTEXPR auto allocate(typename Alloc::size_type bytes)noexcept(noexcept(m_alloc.allocate(0))){ + REXY_CPP20_CONSTEXPR auto allocate(typename Alloc::size_type bytes)noexcept(is_nothrow_allocator_v){ return m_alloc.allocate(bytes); } - REXY_CPP20_CONSTEXPR void deallocate(typename Alloc::pointer p, typename Alloc::size_type bytes)noexcept(noexcept(m_alloc.deallocate(nullptr,0))){ + REXY_CPP20_CONSTEXPR void deallocate(typename Alloc::pointer p, typename Alloc::size_type bytes)noexcept(is_nothrow_allocator_v){ m_alloc.deallocate(p, bytes); } - Alloc& allocator(void){ + constexpr Alloc& allocator(void){ return m_alloc; } - const Alloc& allocator(void)const{ + constexpr const Alloc& allocator(void)const{ return m_alloc; } }; @@ -52,21 +52,21 @@ namespace rexy::detail{ [[no_unique_address]] Alloc m_alloc; - REXY_CPP20_CONSTEXPR auto allocate(typename Alloc::size_type bytes)noexcept(noexcept(m_alloc.allocate(0))){ + REXY_CPP20_CONSTEXPR auto allocate(typename Alloc::size_type bytes)noexcept(is_nothrow_allocator_v){ return m_alloc.allocate(bytes); } - REXY_CPP20_CONSTEXPR void deallocate(typename Alloc::pointer p, typename Alloc::size_type bytes)noexcept(noexcept(m_alloc.deallocate(nullptr,0))){ + REXY_CPP20_CONSTEXPR void deallocate(typename Alloc::pointer p, typename Alloc::size_type bytes)noexcept(is_nothrow_allocator_v){ m_alloc.deallocate(p, bytes); } - Alloc& allocator(void){ + constexpr Alloc& allocator(void){ return m_alloc; } - const Alloc& allocator(void)const{ + constexpr const Alloc& allocator(void)const{ return m_alloc; } }; -#endif +#endif //no_unique_address } #endif diff --git a/include/rexy/string_base.hpp b/include/rexy/string_base.hpp index 5306d77..6b13a1a 100644 --- a/include/rexy/string_base.hpp +++ b/include/rexy/string_base.hpp @@ -33,6 +33,7 @@ #include "expression.hpp" #include "detail/string_appender.hpp" #include "detail/hasallocator.hpp" +#include "allocator.hpp" #include "rexy.hpp" #include "compat/standard.hpp" @@ -260,74 +261,64 @@ namespace rexy{ private: REXY_CPP20_CONSTEXPR void _copy_construct_string(const_pointer data, size_type len, size_type cap) - noexcept(noexcept(this->allocate(0))); + noexcept(is_nothrow_allocator_v); REXY_CPP20_CONSTEXPR basic_string& _copy_string(const_pointer s, size_type len) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))); + noexcept(is_nothrow_allocator_v); public: constexpr basic_string(void)noexcept; constexpr basic_string(rexy::steal data, size_type len)noexcept; constexpr basic_string(rexy::steal data, size_type len, size_type cap)noexcept; constexpr basic_string(rexy::steal data)noexcept; - REXY_CPP20_CONSTEXPR basic_string(const_pointer data, size_type len)noexcept(noexcept(this->allocate(0))); - REXY_CPP20_CONSTEXPR basic_string(const_pointer data, size_type len, size_type cap)noexcept(noexcept(this->allocate(0))); - REXY_CPP20_CONSTEXPR basic_string(const_pointer data)noexcept(noexcept(this->allocate(0))); - REXY_CPP20_CONSTEXPR explicit basic_string(size_type len)noexcept(noexcept(this->allocate(0))); - REXY_CPP20_CONSTEXPR basic_string(size_type len, size_type cap)noexcept(noexcept(this->allocate(0))); + REXY_CPP20_CONSTEXPR basic_string(const_pointer data, size_type len)noexcept(is_nothrow_allocator_v); + REXY_CPP20_CONSTEXPR basic_string(const_pointer data, size_type len, size_type cap)noexcept(is_nothrow_allocator_v); + REXY_CPP20_CONSTEXPR basic_string(const_pointer data)noexcept(is_nothrow_allocator_v); + REXY_CPP20_CONSTEXPR explicit basic_string(size_type len)noexcept(is_nothrow_allocator_v); + REXY_CPP20_CONSTEXPR basic_string(size_type len, size_type cap)noexcept(is_nothrow_allocator_v); template - REXY_CPP20_CONSTEXPR basic_string(InputIt start, InputIt fin)noexcept(noexcept(this->allocate(0))); - REXY_CPP20_CONSTEXPR basic_string(const basic_string_view& sv)noexcept(noexcept(this->allocate(0))); + REXY_CPP20_CONSTEXPR basic_string(InputIt start, InputIt fin)noexcept(is_nothrow_allocator_v); + REXY_CPP20_CONSTEXPR basic_string(const basic_string_view& sv)noexcept(is_nothrow_allocator_v); //normal copy and move ctors - REXY_CPP20_CONSTEXPR basic_string(const basic_string& b)noexcept(noexcept(this->allocate(0))); + REXY_CPP20_CONSTEXPR basic_string(const basic_string& b)noexcept(is_nothrow_allocator_v); constexpr basic_string(basic_string&& s)noexcept; - REXY_CPP20_CONSTEXPR basic_string(const string_base&)noexcept(noexcept(this->allocate(0))); + REXY_CPP20_CONSTEXPR basic_string(const string_base&)noexcept(is_nothrow_allocator_v); //dtor - REXY_CPP20_CONSTEXPR ~basic_string(void)noexcept(noexcept(this->deallocate(nullptr, 0))); + REXY_CPP20_CONSTEXPR ~basic_string(void)noexcept(is_nothrow_allocator_v); REXY_CPP20_CONSTEXPR basic_string& operator=(const basic_string& s) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))); + noexcept(is_nothrow_allocator_v); constexpr basic_string& operator=(basic_string&& s)noexcept; REXY_CPP20_CONSTEXPR basic_string& operator=(const string_base& s) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))); + noexcept(is_nothrow_allocator_v); REXY_CPP20_CONSTEXPR basic_string& operator=(const basic_string_view& sv) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))); + noexcept(is_nothrow_allocator_v); //Copy from c string REXY_CPP20_CONSTEXPR basic_string& operator=(const_pointer c) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))); + noexcept(is_nothrow_allocator_v); //Replace managed pointer. Frees existing value - REXY_CPP20_CONSTEXPR void reset(pointer val = nullptr)noexcept(noexcept(this->deallocate(nullptr,0))); - REXY_CPP20_CONSTEXPR void reset(pointer val, size_type len)noexcept(noexcept(this->deallocate(nullptr,0))); + REXY_CPP20_CONSTEXPR void reset(pointer val = nullptr)noexcept(is_nothrow_allocator_v); + REXY_CPP20_CONSTEXPR void reset(pointer val, size_type len)noexcept(is_nothrow_allocator_v); REXY_CPP20_CONSTEXPR bool resize(size_type newsize) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))); + noexcept(is_nothrow_allocator_v); REXY_CPP20_CONSTEXPR void push_back(value_type data) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))); + noexcept(is_nothrow_allocator_v); REXY_CPP20_CONSTEXPR void append(const_pointer data, size_type len) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))); + noexcept(is_nothrow_allocator_v); REXY_CPP20_CONSTEXPR void append(const_pointer data) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))); + noexcept(is_nothrow_allocator_v); template REXY_CPP20_CONSTEXPR void append(InputIt start, InputIt fin) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))); + noexcept(is_nothrow_allocator_v); template REXY_CPP20_CONSTEXPR basic_string substring(size_type start, size_type end)const; - REXY_CPP20_CONSTEXPR pointer release(void)noexcept(noexcept(this->allocate(0))); + REXY_CPP20_CONSTEXPR pointer release(void)noexcept(is_nothrow_allocator_v); using detail::hasallocator::allocator; constexpr basic_string_view create_view(void)const noexcept; diff --git a/include/rexy/string_base.tpp b/include/rexy/string_base.tpp index a6c6bc0..8d228e0 100644 --- a/include/rexy/string_base.tpp +++ b/include/rexy/string_base.tpp @@ -82,7 +82,7 @@ namespace rexy{ //allocate string if longer than small string capacity, copy otherwise template REXY_CPP20_CONSTEXPR void basic_string::_copy_construct_string(const_pointer data, size_type len, size_type cap) - noexcept(noexcept(this->allocate(0))) + noexcept(is_nothrow_allocator_v) { if(cap > this->get_short_capacity()){ this->set_islong_flag(true); @@ -116,31 +116,31 @@ namespace rexy{ string_base(data.value(), len, cap){} template REXY_CPP20_CONSTEXPR basic_string::basic_string(const_pointer data, size_type len, size_type cap) - noexcept(noexcept(this->allocate(0))) + noexcept(is_nothrow_allocator_v) { _copy_construct_string(data, len, cap); } template REXY_CPP20_CONSTEXPR basic_string::basic_string(const_pointer data, size_type len) - noexcept(noexcept(this->allocate(0))): + noexcept(is_nothrow_allocator_v): basic_string(data, len, len){} template REXY_CPP20_CONSTEXPR basic_string::basic_string(const_pointer data) - noexcept(noexcept(this->allocate(0))): + noexcept(is_nothrow_allocator_v): basic_string(data, data ? strlen(data) : 0){} template REXY_CPP20_CONSTEXPR basic_string::basic_string(size_type cap) - noexcept(noexcept(this->allocate(0))): + noexcept(is_nothrow_allocator_v): basic_string(size_type{0}, cap){} template REXY_CPP20_CONSTEXPR basic_string::basic_string(size_type len, size_type cap) - noexcept(noexcept(this->allocate(0))) + noexcept(is_nothrow_allocator_v) { _copy_construct_string(nullptr, len, cap); } template REXY_CPP20_CONSTEXPR basic_string::basic_string(const basic_string_view& sv) - noexcept(noexcept(this->allocate(0))) + noexcept(is_nothrow_allocator_v) { _copy_construct_string(sv.c_str(), sv.length(), sv.length()); } @@ -148,7 +148,7 @@ namespace rexy{ template template REXY_CPP20_CONSTEXPR basic_string::basic_string(InputIt start, InputIt fin) - noexcept(noexcept(this->allocate(0))): + noexcept(is_nothrow_allocator_v): basic_string(nullptr, size_type{fin - start}) { auto raw = this->get_pointer(); @@ -161,7 +161,7 @@ namespace rexy{ //normal copy and move ctors template REXY_CPP20_CONSTEXPR basic_string::basic_string(const basic_string& b) - noexcept(noexcept(this->allocate(0))): + noexcept(is_nothrow_allocator_v): detail::hasallocator(b) { _copy_construct_string(b.get(), b.length(), b.capacity()); @@ -172,7 +172,7 @@ namespace rexy{ string_base(std::move(s)){} template REXY_CPP20_CONSTEXPR basic_string::basic_string(const string_base& b) - noexcept(noexcept(this->allocate(0))) + noexcept(is_nothrow_allocator_v) { _copy_construct_string(b.get(), b.length(), b.capacity()); } @@ -180,7 +180,7 @@ namespace rexy{ //dtor template REXY_CPP20_CONSTEXPR basic_string::~basic_string(void) - noexcept(noexcept(this->deallocate(nullptr, 0))) + noexcept(is_nothrow_allocator_v) { if(this->islong()){ this->deallocate(this->get_pointer(), sizeof(value_type)*(this->get_long_capacity()+1)); @@ -189,8 +189,7 @@ namespace rexy{ template REXY_CPP20_CONSTEXPR basic_string& basic_string::operator=(const basic_string& s) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr, 0))) + noexcept(is_nothrow_allocator_v) { if(s.length() < this->capacity()){ memcpy(this->get_pointer(), s.get_pointer(), sizeof(value_type)*(s.length()+1)); @@ -207,24 +206,21 @@ namespace rexy{ } template REXY_CPP20_CONSTEXPR basic_string& basic_string::operator=(const string_base& s) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))) + noexcept(is_nothrow_allocator_v) { return (*this = basic_string(s)); } //Copy from c string template REXY_CPP20_CONSTEXPR basic_string& basic_string::operator=(const basic_string_view& sv) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))) + noexcept(is_nothrow_allocator_v) { return _copy_string(sv.c_str(), sv.length()); } template REXY_CPP20_CONSTEXPR basic_string& basic_string::operator=(const_pointer c) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))) + noexcept(is_nothrow_allocator_v) { return _copy_string(c, strlen(c)); } @@ -232,13 +228,13 @@ namespace rexy{ //Replace managed pointer. Frees existing value template REXY_CPP20_CONSTEXPR void basic_string::reset(pointer val) - noexcept(noexcept(this->deallocate(nullptr,0))) + noexcept(is_nothrow_allocator_v) { reset(val, val ? strlen(val) : 0); } template REXY_CPP20_CONSTEXPR void basic_string::reset(pointer val, size_type len) - noexcept(noexcept(this->deallocate(nullptr,0))) + noexcept(is_nothrow_allocator_v) { if(this->islong()) this->deallocate(this->get_long_ptr(),sizeof(value_type)*(this->get_long_capacity()+1)); @@ -249,8 +245,7 @@ namespace rexy{ } template REXY_CPP20_CONSTEXPR bool basic_string::resize(size_type newsize) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))) + noexcept(is_nothrow_allocator_v) { if(newsize < this->capacity()) return false; @@ -261,16 +256,14 @@ namespace rexy{ template REXY_CPP20_CONSTEXPR void basic_string::push_back(value_type data) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))) + noexcept(is_nothrow_allocator_v) { append(&data, 1); } template REXY_CPP20_CONSTEXPR void basic_string::append(const_pointer data, size_type len) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))) + noexcept(is_nothrow_allocator_v) { size_type mylen = this->length(); size_type mycap = this->capacity(); @@ -290,8 +283,7 @@ namespace rexy{ } template REXY_CPP20_CONSTEXPR void basic_string::append(const_pointer data) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))) + noexcept(is_nothrow_allocator_v) { if(data) append(data, strlen(data)); @@ -299,8 +291,7 @@ namespace rexy{ template template REXY_CPP20_CONSTEXPR void basic_string::append(InputIt start, InputIt fin) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))) + noexcept(is_nothrow_allocator_v) { size_type append_len = fin - start; @@ -334,7 +325,7 @@ namespace rexy{ return tmp; } template - REXY_CPP20_CONSTEXPR auto basic_string::release(void)noexcept(noexcept(this->allocate(0))) -> pointer{ + REXY_CPP20_CONSTEXPR auto basic_string::release(void)noexcept(is_nothrow_allocator_v) -> pointer{ if(this->islong()){ pointer raw = this->get_long_ptr(); this->set_islong_flag(false); @@ -363,8 +354,7 @@ namespace rexy{ template REXY_CPP20_CONSTEXPR basic_string& basic_string::_copy_string(const_pointer s, size_type len) - noexcept(noexcept(this->allocate(0)) && - noexcept(this->deallocate(nullptr,0))) + noexcept(is_nothrow_allocator_v) { if(!s || !len) return (*this = basic_string(rexy::steal(nullptr), 0, 0));