diff --git a/include/rexy/binary.hpp b/include/rexy/binary.hpp index 8b9e406..4cb81f1 100644 --- a/include/rexy/binary.hpp +++ b/include/rexy/binary.hpp @@ -39,18 +39,14 @@ namespace rexy{ size_t m_cap = 0; public: protected: - constexpr binary_base(void) = default; - constexpr binary_base(char* data, size_t size): + constexpr binary_base(void)noexcept = default; + constexpr binary_base(char* data, size_t size)noexcept: m_data(data), m_cap(size){} - constexpr binary_base(char* data, size_t cap, size_t size): + constexpr binary_base(char* data, size_t cap, size_t size)noexcept: m_data(data), m_size(size), m_cap(cap){} template - binary_base(const binary_base& b): - m_data(Allocator::copy(b.m_data, b.m_cap)), - m_size(b.m_size), - m_cap(b.m_cap){} - binary_base(binary_base&&); - ~binary_base(void) = default; + binary_base(const binary_base& b)noexcept{} + ~binary_base(void)noexcept = default; public: char* release(void); @@ -71,64 +67,83 @@ namespace rexy{ public: using allocator_type = Allocator; public: - constexpr binary_data(void) = default; - [[deprecated]] binary_data(char* data, size_t size): + constexpr binary_data(void)noexcept = default; + [[deprecated]] binary_data(char* data, size_t size)noexcept: binary_base(data, size){} - binary_data(rexy::steal data, size_t size): - binary_base(data.value(), size){} - binary_data(const char* data, size_t size): - binary_base(reinterpret_cast(Allocator::copy(data, size)), size){} - [[deprecated]] binary_data(char* data, size_t cap, size_t size): + [[deprecated]] binary_data(char* data, size_t cap, size_t size)noexcept: binary_base(data, cap, size){} - binary_data(rexy::steal data, size_t cap, size_t size): + binary_data(const char* data, size_t size) + noexcept(noexcept(Allocator::copy(data, size))): + binary_base(reinterpret_cast(Allocator::copy(data, size)), size){} + constexpr binary_data(rexy::steal data, size_t size)noexcept: + binary_base(data.value(), size){} + constexpr binary_data(rexy::steal data, size_t cap, size_t size)noexcept: binary_base(data.value(), cap, size){} - binary_data(const char* data, size_t cap, size_t size): + binary_data(const char* data, size_t cap, size_t size) + noexcept(noexcept(Allocator::copy(data, size))): binary_base(reinterpret_cast(Allocator::copy(data, size)), cap, size){} - binary_data(size_t size): + binary_data(size_t size) + noexcept(noexcept(Allocator::allocate(size))): binary_base(reinterpret_cast(Allocator::allocate(size)), size){} - binary_data(const binary_data& b): - binary_base(b) + binary_data(const binary_data& b) + noexcept(noexcept(Allocator::copy(b.m_data, b.m_cap))): + binary_base(b.m_data, b.m_cap, b.m_size) { m_data = Allocator::copy(b.m_data, b.m_cap); } - binary_data(binary_data&& b): - binary_base(std::move(b)){} - ~binary_data(void){ + constexpr binary_data(binary_data&& b)noexcept: + binary_base(cx::exchange(b.m_data, nullptr), b.m_cap, b.m_size){} + ~binary_data(void) + noexcept(noexcept(Allocator::free(m_data))) + { Allocator::free(m_data); } - binary_data& operator=(const binary_data& b){ + binary_data& operator=(const binary_data& b) + noexcept(std::is_nothrow_copy_constructible>::value && + std::is_nothrow_move_assignable>::value) + { binary_data tmp(b); return (*this = std::move(tmp)); } - binary_data& operator=(binary_data&& b){ + constexpr binary_data& operator=(binary_data&& b) + noexcept(noexcept(cx::swap(m_data, b.m_data))) + { m_size = b.m_size; m_cap = b.m_cap; - std::swap(m_data, b.m_data); + cx::swap(m_data, b.m_data); return *this; } - void reset(void){ + void reset(void) + noexcept(noexcept(Allocator::free(m_data))) + { Allocator::free(m_data); m_data = nullptr; m_cap = m_size = 0; } - void reset(char* val, size_t cap, size_t size = 0){ + void reset(char* val, size_t cap, size_t size = 0) + noexcept(noexcept(Allocator::free(m_data))) + { Allocator::free(m_data); m_data = val; m_cap = cap; m_size = size; } - bool resize(size_t newsize){ + bool resize(size_t newsize) + noexcept(std::is_nothrow_constructible,size_t>::value) + { if(newsize < m_cap) return false; binary_data tmp(newsize); if(!tmp) return false; memcpy(STOP_STRICT_ALIAS_WARNING(tmp).m_data, m_data, m_size); - std::swap(m_data, STOP_STRICT_ALIAS_WARNING(tmp).m_data); + cx::swap(m_data, STOP_STRICT_ALIAS_WARNING(tmp).m_data); m_cap = STOP_STRICT_ALIAS_WARNING(tmp).m_cap; return true; } - void append(const char* data, size_t len){ + void append(const char* data, size_t len) + noexcept(noexcept(resize(len))) + { if(m_size + len > m_cap) resize(cx::max(m_cap*2, m_size+len)); memcpy(m_data+m_size, data, len); @@ -151,22 +166,26 @@ namespace rexy{ } template = 0> - bool operator==(Left&& l, Right&& r){ + bool operator==(Left&& l, Right&& r)noexcept{ return l && r && l.size() == r.size() && l.capacity() == r.capacity() && !memcmp(l.get(), r.get(), l.size()); } template = 0> - bool operator!=(Left&& l, Right&& r){ + bool operator!=(Left&& l, Right&& r)noexcept{ return !(std::forward(l) == std::forward(r)); } template - auto operator+(const rexy::binary_data& l, const rexy::binary_data& r){ + auto operator+(const rexy::binary_data& l, const rexy::binary_data& r) + noexcept(std::is_nothrow_constructible, size_t>::value) + { rexy::binary_data retval(l.size() + r.size()); memcpy(retval.get(), l.get(), l.size()); memcpy(retval.get()+l.size(), r.get(), r.size()); return retval; } template - decltype(auto) operator+=(rexy::binary_data& l, const rexy::binary_data& r){ + decltype(auto) operator+=(rexy::binary_data& l, const rexy::binary_data& r) + noexcept(noexcept(l.resize(0))) + { l.resize(l.size() + r.size()); memcpy(l.get()+l.size(), r.get(), r.size()); return l; diff --git a/include/rexy/cx/algorithm.hpp b/include/rexy/cx/algorithm.hpp index dc70fce..41e948b 100644 --- a/include/rexy/cx/algorithm.hpp +++ b/include/rexy/cx/algorithm.hpp @@ -21,10 +21,15 @@ #include "utility.hpp" //swap +#include + namespace rexy::cx{ template - constexpr Iter qs_partition(Iter left, Iter right, const Compare& cmp){ + constexpr Iter qs_partition(Iter left, Iter right, const Compare& cmp) + noexcept(std::is_nothrow_invocable::value && + noexcept(cx::swap(*left,*right))) + { auto range = right - left; auto pivot = left + (range / 2); auto value = *pivot; @@ -42,7 +47,9 @@ namespace rexy::cx{ return left; } template - constexpr void quicksort(Iter left, Iter right, const Compare& cmp){ + constexpr void quicksort(Iter left, Iter right, const Compare& cmp) + noexcept(noexcept(cx::qs_partition(left, right, cmp))) + { while(left < right){ auto real_right = right-1; auto pivot = qs_partition(left, real_right, cmp); diff --git a/include/rexy/cx/array.hpp b/include/rexy/cx/array.hpp index f0042a0..f8662c4 100644 --- a/include/rexy/cx/array.hpp +++ b/include/rexy/cx/array.hpp @@ -22,6 +22,8 @@ #include //size_t #include "utility.hpp" //swap +#include + namespace rexy::cx{ template @@ -44,76 +46,80 @@ namespace rexy::cx{ T m_elements[N] = {}; public: - constexpr reference at(size_type pos){ + constexpr reference at(size_type pos)noexcept{ return m_elements[pos]; } - constexpr const_reference at(size_type pos)const{ + constexpr const_reference at(size_type pos)const noexcept{ return m_elements[pos]; } - constexpr reference operator[](size_type pos){ + constexpr reference operator[](size_type pos)noexcept{ return m_elements[pos]; } - constexpr const_reference operator[](size_type pos)const{ + constexpr const_reference operator[](size_type pos)const noexcept{ return m_elements[pos]; } - constexpr reference front(void){ + constexpr reference front(void)noexcept{ return m_elements[0]; } - constexpr const_reference front(void)const{ + constexpr const_reference front(void)const noexcept{ return m_elements[0]; } - constexpr reference back(void){ + constexpr reference back(void)noexcept{ return m_elements[max_elements-1]; } - constexpr const_reference back(void)const{ + constexpr const_reference back(void)const noexcept{ return m_elements[max_elements-1]; } - constexpr pointer data(void){ + constexpr pointer data(void)noexcept{ return m_elements; } - constexpr const_pointer data(void)const{ + constexpr const_pointer data(void)const noexcept{ return m_elements; } - constexpr iterator begin(void){ + constexpr iterator begin(void)noexcept{ return m_elements; } - constexpr const_iterator begin(void)const{ + constexpr const_iterator begin(void)const noexcept{ return m_elements; } - constexpr const_iterator cbegin(void)const{ + constexpr const_iterator cbegin(void)const noexcept{ return m_elements; } - constexpr iterator end(void){ + constexpr iterator end(void)noexcept{ return m_elements+max_elements; } - constexpr const_iterator end(void)const{ + constexpr const_iterator end(void)const noexcept{ return m_elements+max_elements; } - constexpr const_iterator cend(void)const{ + constexpr const_iterator cend(void)const noexcept{ return m_elements+max_elements; } - constexpr bool empty(void)const{ + constexpr bool empty(void)const noexcept{ if constexpr(max_elements == 0){ return true; }else{ return false; } } - constexpr size_type size(void)const{ + constexpr size_type size(void)const noexcept{ return max_elements; } - constexpr size_type max_size(void)const{ + constexpr size_type max_size(void)const noexcept{ return max_elements; } - constexpr void fill(const T& value){ + constexpr void fill(const T& value) + noexcept(std::is_nothrow_copy_assignable::value) + { for(auto it = begin();it != end();++it){ *it = value; } } - constexpr void swap(array& other){ + constexpr void swap(array& other) + noexcept(noexcept(cx::swap(m_elements[0], other.m_elements[0]))) + { for(size_type i = 0;i < max_size();++i){ - swap(m_elements[i], other.m_elements[i]); + cx::swap(m_elements[i], other.m_elements[i]); } } }; diff --git a/include/rexy/cx/hash.hpp b/include/rexy/cx/hash.hpp index f2fd188..bc9b7c5 100644 --- a/include/rexy/cx/hash.hpp +++ b/include/rexy/cx/hash.hpp @@ -25,7 +25,7 @@ namespace rexy::cx{ template struct hash{ - constexpr size_t operator()(const T& t, size_t salt = 0){ + constexpr size_t operator()(const T& t, size_t salt = 0)const noexcept{ constexpr size_t bytes = sizeof(size_t); size_t val = static_cast(t); size_t hash = 5381 + salt; //magic hash number diff --git a/include/rexy/cx/hashmap.hpp b/include/rexy/cx/hashmap.hpp index fe1973d..7f2e971 100644 --- a/include/rexy/cx/hashmap.hpp +++ b/include/rexy/cx/hashmap.hpp @@ -73,9 +73,9 @@ namespace rexy::cx{ //no key checks. give a correct key or get a random answer :) template>> - constexpr reference operator[](U&& u); + constexpr reference operator[](U&& u)noexcept; template>> - constexpr const_reference operator[](U&& u)const; + constexpr const_reference operator[](U&& u)const noexcept; }; template @@ -90,7 +90,7 @@ namespace rexy::cx{ } //sort the buckets based on size, largest first - quicksort(buckets.begin(), buckets.end(), [](auto&& left, auto&& right) -> bool{ + cx::quicksort(buckets.begin(), buckets.end(), [](auto&& left, auto&& right) -> bool{ return left.size() > right.size(); }); @@ -148,7 +148,7 @@ namespace rexy::cx{ //no key checks. give a correct key or get a random answer :) template template - constexpr auto hashmap::operator[](U&& key) -> reference{ + constexpr auto hashmap::operator[](U&& key)noexcept -> reference{ auto d = m_g[UHash{}(std::forward(key)) % max_size]; if(d & single_bucket_bit) return m_values[d & ~single_bucket_bit]; @@ -156,7 +156,7 @@ namespace rexy::cx{ } template template - constexpr auto hashmap::operator[](U&& key)const -> const_reference{ + constexpr auto hashmap::operator[](U&& key)const noexcept -> const_reference{ auto d = m_g[UHash{}(std::forward(key)) % max_size]; if(d & single_bucket_bit) return m_values[d & ~single_bucket_bit]; diff --git a/include/rexy/cx/string.hpp b/include/rexy/cx/string.hpp index 86610e3..a7be24b 100644 --- a/include/rexy/cx/string.hpp +++ b/include/rexy/cx/string.hpp @@ -26,7 +26,7 @@ namespace rexy::cx{ #include "../string_base.hpp" #include "utility.hpp" - +#include //This is different from rexy::static_string in that this doesn't hold a pointer to a constant string array. //This holds a mutable array of data which can be modified during compile time. static_string is @@ -46,7 +46,7 @@ namespace rexy::cx{ public: constexpr string(void) = default; template - constexpr string(const char(&data)[M]): + constexpr string(const char(&data)[M])noexcept: m_length(M) { static_assert(M <= N); @@ -54,14 +54,14 @@ namespace rexy::cx{ m_data[i] = data[i]; } } - constexpr string(const char* data): + constexpr string(const char* data)noexcept: m_length(cx::strlen(data)) { for(size_t i = 0;i < m_length;++i){ m_data[i] = data[i]; } } - constexpr string(const char* data, size_t len): + constexpr string(const char* data, size_t len)noexcept: m_length(len) { for(size_t i = 0;i < m_length;++i){ @@ -69,7 +69,7 @@ namespace rexy::cx{ } } - constexpr string(const rexy::static_string& str): + constexpr string(const rexy::static_string& str)noexcept: m_length(str.length()) { for(size_t i = 0;i < m_length;++i){ @@ -77,56 +77,58 @@ namespace rexy::cx{ } } template - constexpr string(const rexy::string_cat_expr& expr){ + constexpr string(const rexy::string_cat_expr& expr) + noexcept(std::is_nothrow_invocable>, decltype(expr)>::value) + { rexy::detail::string_appender> append(*this); append(expr); } - constexpr string(const string&) = default; - constexpr string(string&&) = default; - ~string(void) = default; + constexpr string(const string&)noexcept = default; + constexpr string(string&&)noexcept = default; + ~string(void)noexcept = default; - constexpr string& operator=(const char* c){ + constexpr string& operator=(const char* c)noexcept{ m_length = cx::strlen(c); for(size_t i = 0;i < m_length;++i){ m_data[i] = c[i]; } return *this; } - constexpr string& operator=(const string&) = default; - constexpr string& operator=(string&&) = default; + constexpr string& operator=(const string&)noexcept = default; + constexpr string& operator=(string&&)noexcept = default; - constexpr size_t length(void)const{ + constexpr size_t length(void)const noexcept{ return m_length; } - constexpr size_t capacity(void)const{ + constexpr size_t capacity(void)const noexcept{ return max_size; } - constexpr char* get(void){ + constexpr char* get(void)noexcept{ return m_data; } - constexpr const char* get(void)const{ + constexpr const char* get(void)const noexcept{ return m_data; } - constexpr operator char*(void){ + constexpr operator char*(void)noexcept{ return m_data; } - constexpr operator const char*(void)const{ + constexpr operator const char*(void)const noexcept{ return m_data; } - constexpr bool valid(void)const{ + constexpr bool valid(void)const noexcept{ return m_length > 0; } - constexpr char& operator[](size_t i){ + constexpr char& operator[](size_t i)noexcept{ return m_data[i]; } - constexpr const char& operator[](size_t i)const{ + constexpr const char& operator[](size_t i)const noexcept{ return m_data[i]; } - constexpr bool resize(size_t i){ + constexpr bool resize(size_t i)noexcept{ if(i >= capacity()) return false; m_length = i; @@ -134,18 +136,18 @@ namespace rexy::cx{ return true; } - constexpr void append(const char* data, size_t len){ + constexpr void append(const char* data, size_t len)noexcept{ for(size_t i = 0;i < len;++i){ m_data[m_length++] = data[i]; } } - constexpr void append(const char* data){ + constexpr void append(const char* data)noexcept{ append(data, cx::strlen(data)); } - constexpr void append(const string& s){ + constexpr void append(const string& s)noexcept{ append(s.get(), s.length()); } - constexpr void append(const rexy::static_string& s){ + constexpr void append(const rexy::static_string& s)noexcept{ append(s.get(), s.length()); } }; @@ -166,15 +168,15 @@ namespace rexy::cx{ } template::value,int> = 0> - constexpr auto operator+(Str1&& l, Str2&& r){ + constexpr auto operator+(Str1&& l, Str2&& r)noexcept{ return string_cat_expr(std::forward(l), std::forward(r)); } template::value,int> = 0> - constexpr auto operator+(Str1&& l, const char* r){ + constexpr auto operator+(Str1&& l, const char* r)noexcept{ return string_cat_expr(std::forward(l), rexy::static_string(r)); } template::value,int> = 0> - constexpr auto operator+(const char* l, Str1&& r){ + constexpr auto operator+(const char* l, Str1&& r)noexcept{ return string_cat_expr(rexy::static_string(l), std::forward(r)); } } diff --git a/include/rexy/cx/string_hash.hpp b/include/rexy/cx/string_hash.hpp index c54be81..64757cf 100644 --- a/include/rexy/cx/string_hash.hpp +++ b/include/rexy/cx/string_hash.hpp @@ -28,7 +28,7 @@ namespace rexy::cx{ //jenkns one at a time hash template struct string_hash{ - constexpr size_t operator()(const Str& s, size_t salt = 0){ + constexpr size_t operator()(const Str& s, size_t salt = 0)const noexcept{ size_t hash = salt; for(size_t i = 0;i < s.length();++i){ hash += s[i]; diff --git a/include/rexy/cx/utility.hpp b/include/rexy/cx/utility.hpp index 9b31ebf..4074450 100644 --- a/include/rexy/cx/utility.hpp +++ b/include/rexy/cx/utility.hpp @@ -20,45 +20,55 @@ #define REXY_CX_UTILITY_HPP #include //forward, move +#include namespace rexy::cx{ namespace{ template - constexpr void swap(T& l, T& r){ + constexpr void swap(T& l, T& r) + noexcept(std::is_nothrow_copy_assignable::value) + { T tmp = l; l = r; r = tmp; } template - constexpr T exchange(T& l, U&& r){ + constexpr T exchange(T& l, U&& r) + noexcept(std::is_nothrow_assignable::value && + std::is_nothrow_move_assignable::value) + { T old = std::move(l); l = std::forward(r); return old; } template - constexpr const T& min(const T& l, const T& r){ + constexpr const T& min(const T& l, const T& r)noexcept{ return l < r ? l : r; } template - constexpr const T& min(const T& l, const T& r, Compare cmp){ + constexpr const T& min(const T& l, const T& r, Compare cmp) + noexcept(std::is_nothrow_invocable::value) + { return cmp(l, r) ? l : r; } template - constexpr const T& max(const T& l, const T& r){ + constexpr const T& max(const T& l, const T& r)noexcept{ return l > r ? l : r; } template - constexpr const T& max(const T& l, const T& r, Compare cmp){ + constexpr const T& max(const T& l, const T& r, Compare cmp) + noexcept(std::is_nothrow_invocable::value) + { return cmp(l, r) ? l : r; } - constexpr size_t strlen(const char* c){ + constexpr size_t strlen(const char* c)noexcept{ size_t i = 0; for(;c[i];++i); return i; } - constexpr int strcmp(const char* l, const char* r){ + constexpr int strcmp(const char* l, const char* r)noexcept{ using uchar = unsigned char; for(;*l == *r && *l;++l, ++r); return (static_cast(*l)) - (static_cast(*r)); diff --git a/include/rexy/cx/vector.hpp b/include/rexy/cx/vector.hpp index 55eaab5..71d760e 100644 --- a/include/rexy/cx/vector.hpp +++ b/include/rexy/cx/vector.hpp @@ -24,6 +24,8 @@ #include "utility.hpp" //swap +#include + namespace rexy::cx{ template @@ -47,83 +49,88 @@ namespace rexy::cx{ size_type m_size = 0; public: - constexpr vector(void) = default; - constexpr vector(const vector&) = default; - constexpr vector(vector&&) = default; + constexpr vector(void)noexcept(std::is_nothrow_default_constructible::value) = default; + constexpr vector(const vector&)noexcept(std::is_nothrow_copy_constructible::value) = default; + constexpr vector(vector&&)noexcept(std::is_nothrow_move_constructible::value) = default; - constexpr vector(size_type count, const T& value){ + constexpr vector(size_type count, const T& value) + noexcept(std::is_nothrow_copy_assignable::value) + { for(size_type i = 0;i < min(count, max_elements);++i){ m_elements[i] = value; } } - ~vector(void) = default; + ~vector(void)noexcept = default; - constexpr vector& operator=(const vector&) = default; - constexpr vector& operator=(vector&&) = default; + constexpr vector& operator=(const vector&)noexcept(std::is_nothrow_copy_assignable::value) = default; + constexpr vector& operator=(vector&&)noexcept(std::is_nothrow_move_assignable::value) = default; - constexpr reference at(size_type pos){ + constexpr reference at(size_type pos)noexcept{ return m_elements[pos]; } - constexpr const_reference at(size_type pos)const{ + constexpr const_reference at(size_type pos)const noexcept{ return m_elements[pos]; } - constexpr reference operator[](size_type pos){ + constexpr reference operator[](size_type pos)noexcept{ return m_elements[pos]; } - constexpr const_reference operator[](size_type pos)const{ + constexpr const_reference operator[](size_type pos)const noexcept{ return m_elements[pos]; } - constexpr reference front(void){ + constexpr reference front(void)noexcept{ return m_elements[0]; } - constexpr const_reference front(void)const{ + constexpr const_reference front(void)const noexcept{ return m_elements[0]; } - constexpr reference back(void){ + constexpr reference back(void)noexcept{ return m_elements[m_size-1]; } - constexpr const_reference back(void)const{ + constexpr const_reference back(void)const noexcept{ return m_elements[m_size-1]; } - constexpr const_pointer data(void)const{ + constexpr const_pointer data(void)const noexcept{ return m_elements; } - constexpr iterator begin(void){ + constexpr iterator begin(void)noexcept{ return m_elements; } - constexpr const_iterator begin(void)const{ + constexpr const_iterator begin(void)const noexcept{ return m_elements; } - constexpr const_iterator cbegin(void)const{ + constexpr const_iterator cbegin(void)const noexcept{ return m_elements; } - constexpr iterator end(void){ + constexpr iterator end(void)noexcept{ return m_elements+max_elements; } - constexpr const_iterator end(void)const{ + constexpr const_iterator end(void)const noexcept{ return m_elements+max_elements; } - constexpr const_iterator cend(void)const{ + constexpr const_iterator cend(void)const noexcept{ return m_elements+max_elements; } - constexpr bool empty(void)const{ + constexpr bool empty(void)const noexcept{ return m_size == 0; } - constexpr size_type size(void)const{ + constexpr size_type size(void)const noexcept{ return m_size; } - constexpr size_type max_size(void)const{ + constexpr size_type max_size(void)const noexcept{ return max_elements; } - constexpr size_type capacity(void)const{ + constexpr size_type capacity(void)const noexcept{ return max_elements; } - constexpr void clear(void){ + constexpr void clear(void)noexcept{ m_size = 0; } - constexpr iterator insert(iterator pos, const T& value){ + constexpr iterator insert(iterator pos, const T& value) + noexcept(std::is_nothrow_move_assignable::value && + std::is_nothrow_copy_assignable::value) + { auto start = pos; auto it = pos; ++pos; @@ -133,7 +140,9 @@ namespace rexy::cx{ *start = value; return start; } - constexpr iterator insert(const_iterator pos, T&& value){ + constexpr iterator insert(const_iterator pos, T&& value) + noexcept(std::is_nothrow_move_assignable::value) + { auto start = pos; auto it = pos; ++pos; @@ -144,7 +153,10 @@ namespace rexy::cx{ return start; } template - constexpr iterator emplace(const_iterator pos, Args&&... args){ + constexpr iterator emplace(const_iterator pos, Args&&... args) + noexcept(std::is_nothrow_move_assignable::value && + std::is_nothrow_constructible::value) + { auto start = pos; auto it = pos; ++pos; @@ -154,7 +166,9 @@ namespace rexy::cx{ *start = T{std::forward(args)...}; return start; } - constexpr iterator erase(const_iterator pos){ + constexpr iterator erase(const_iterator pos) + noexcept(std::is_nothrow_move_assignable::value) + { auto start = pos; auto it = pos; ++pos; @@ -163,23 +177,27 @@ namespace rexy::cx{ } return start; } - constexpr iterator push_back(const T& value){ + constexpr iterator push_back(const T& value) + noexcept(std::is_nothrow_copy_assignable::value) + { m_elements[m_size] = value; return m_elements+(m_size++); } template - constexpr iterator emplace_back(Args&&... args){ + constexpr iterator emplace_back(Args&&... args) + noexcept(std::is_nothrow_constructible::value) + { m_elements[m_size++] = T{std::forward(args)...}; return m_elements+(m_size++); } - constexpr void pop_back(void){ + constexpr void pop_back(void)noexcept{ --m_size; } - constexpr void resize(size_type count){ + constexpr void resize(size_type count)noexcept{ if(count <= max_size()) m_size = count; } - constexpr void resize(size_type count, const value_type& value){ + constexpr void resize(size_type count, const value_type& value)noexcept{ if(count > m_size){ if(count <= max_size()){ for(size_type i = m_size;i < count;++i){ @@ -190,20 +208,24 @@ namespace rexy::cx{ m_size = count; } } - constexpr void fill(const T& value){ + constexpr void fill(const T& value) + noexcept(std::is_nothrow_copy_assignable::value) + { for(auto it = begin();it != end();++it){ *it = value; } } - constexpr void swap(vector& other){ + constexpr void swap(vector& other) + noexcept(noexcept(cx::swap(m_elements[0], other.m_elements[0]))) + { size_type i = 0; for(;i < m_size;++i){ - swap(m_elements[i], other.m_elements[i]); + cx::swap(m_elements[i], other.m_elements[i]); } for(;i < other.m_size;++i){ - swap(m_elements[i], other.m_elements[i]); + cx::swap(m_elements[i], other.m_elements[i]); } - swap(m_size, other.m_size); + cx::swap(m_size, other.m_size); } }; diff --git a/include/rexy/detail/binary_string_conv.hpp b/include/rexy/detail/binary_string_conv.hpp index e4ec1cf..89c0146 100644 --- a/include/rexy/detail/binary_string_conv.hpp +++ b/include/rexy/detail/binary_string_conv.hpp @@ -25,44 +25,64 @@ namespace rexy{ template = 0> - auto binary_to_string(const binary_data& b){ + auto binary_to_string(const binary_data& b) + noexcept(std::is_nothrow_constructible::value) + { Str s(b.size()+1); memcpy(s.get(), b.get(), b.size()); s[b.size()] = 0; return s; } template = 0, std::enable_if_t,typename Str::allocator_type>::value,int> = 0> - auto binary_to_string(binary_data&& b){ + auto binary_to_string(binary_data&& b) + noexcept(std::is_nothrow_default_constructible::value && + noexcept(std::declval().reset(nullptr, 0)) && + noexcept(b.release())) + { Str s; s.reset(b.get(), b.size()); b.release(); return s; } template = 0> - auto string_to_binary(const string_base& s){ + auto string_to_binary(const string_base& s) + noexcept(std::is_nothrow_constructible::value && + noexcept(std::declval().append(nullptr, 0))) + { Bin b(s.length()+1); b.append(s.get(), s.length()+1); return b; } template = 0, std::enable_if_t,typename Bin::allocator_type>::value,int> = 0> - auto string_to_binary(string_intermediary&& s){ + auto string_to_binary(string_intermediary&& s) + noexcept(std::is_nothrow_default_constructible::value && + noexcept(std::declval().reset(nullptr, 0)) && + noexcept(s.release())) + { Bin b; b.reset(s.get(), s.length()+1); s.release(); return b; } template = 0, detail::enable_if_concrete_string = 0> - decltype(auto) operator+=(L& l, R&& r){ + decltype(auto) operator+=(L& l, R&& r) + noexcept(noexcept(l.append(nullptr, 0))) + { l.append(r.get(), r.length()+1); return l; } template = 0, detail::enable_if_string = 0, std::enable_if_t::value,int> = 0> - decltype(auto) operator+=(L& l, R&& r){ + decltype(auto) operator+=(L& l, R&& r) + noexcept(std::is_nothrow_constructible::value && + std::is_nothrow_assignable::value) + { rexy::string concrete = r; return (l = concrete); } template = 0, detail::enable_if_binary = 0> - decltype(auto) operator+=(L& l, R&& r){ + decltype(auto) operator+=(L& l, R&& r) + noexcept(noexcept(l.resize(0, 0))) + { l.resize(l.length(), r.size() + 1); memcpy(l.get()+l.length()+1, r.get(), r.size()); return l; diff --git a/include/rexy/filerd.hpp b/include/rexy/filerd.hpp index 21e7715..1ac83e9 100644 --- a/include/rexy/filerd.hpp +++ b/include/rexy/filerd.hpp @@ -25,6 +25,7 @@ #include "string.hpp" #include "binary.hpp" #include "cx/utility.hpp" +#include namespace rexy{ @@ -35,37 +36,37 @@ namespace rexy{ FILE* m_fp = nullptr; public: - constexpr filerd(void) = default; - filerd(const char* f, const char* mode = "r"); + constexpr filerd(void)noexcept = default; + filerd(const char* f, const char* mode = "r")noexcept; filerd(const filerd&) = delete; - constexpr filerd(filerd&& f): + constexpr filerd(filerd&& f)noexcept: m_fp(cx::exchange(f.m_fp, nullptr)){} - ~filerd(void); + ~filerd(void)noexcept; filerd& operator=(const filerd&) = delete; - constexpr filerd& operator=(filerd&& f){ + constexpr filerd& operator=(filerd&& f)noexcept{ cx::swap(m_fp, f.m_fp); return *this; } - void reset(FILE* fp = nullptr); - FILE* release(void); - size_t length(void); - size_t position(void)const; - void rewind(size_t pos = 0); + void reset(FILE* fp = nullptr)noexcept; + FILE* release(void)noexcept; + size_t length(void)noexcept; + size_t position(void)const noexcept; + void rewind(size_t pos = 0)noexcept; - operator FILE*(void); - operator const FILE*(void)const; - FILE* get(void); - const FILE* get(void)const; - operator bool(void)const; + operator FILE*(void)noexcept; + operator const FILE*(void)const noexcept; + FILE* get(void)noexcept; + const FILE* get(void)const noexcept; + operator bool(void)const noexcept; - size_t read(char* dest, size_t bytes); - rexy::string read(size_t bytes); - rexy::string readln(size_t max = 0); - rexy::binary read_bin(size_t bytes); + size_t read(char* dest, size_t bytes)noexcept; + rexy::string read(size_t bytes)noexcept; + rexy::string readln(size_t max = 0)noexcept; + rexy::binary read_bin(size_t bytes)noexcept(std::is_nothrow_constructible, size_t, size_t>::value); - size_t write(const char* c, size_t bytes); - size_t write(const rexy::string_base&); + size_t write(const char* c, size_t bytes)noexcept; + size_t write(const rexy::string_base&)noexcept; }; } diff --git a/include/rexy/steal.hpp b/include/rexy/steal.hpp index 69d0031..590fe55 100644 --- a/include/rexy/steal.hpp +++ b/include/rexy/steal.hpp @@ -21,6 +21,8 @@ #include //forward +#include + namespace rexy{ template @@ -31,7 +33,8 @@ namespace rexy{ public: template - constexpr steal(U&& u): + constexpr steal(U&& u) + noexcept(std::is_nothrow_constructible::value): m_val(std::forward(u)){} steal(const steal&) = delete; @@ -39,10 +42,10 @@ namespace rexy{ steal& operator=(const steal&) = delete; steal& operator=(steal&&) = delete; - constexpr T&& value(void){ + constexpr T&& value(void)noexcept{ return std::forward(m_val); } - constexpr const T& value(void)const{ + constexpr const T& value(void)const noexcept{ return m_val; } }; diff --git a/include/rexy/string.hpp b/include/rexy/string.hpp index cdfc7bc..80bfc91 100644 --- a/include/rexy/string.hpp +++ b/include/rexy/string.hpp @@ -29,4 +29,8 @@ namespace rexy{ } +#ifdef REXY_BINARY_HPP +#include "detail/binary_string_conv.hpp" +#endif + #endif diff --git a/include/rexy/string_base.hpp b/include/rexy/string_base.hpp index 5a2460a..9fa3ed5 100644 --- a/include/rexy/string_base.hpp +++ b/include/rexy/string_base.hpp @@ -22,6 +22,7 @@ #include //is_same, integral_contant, enable_if, etc #include //forward #include //size_t +#include //strlen #include "steal.hpp" #include "cx/utility.hpp" @@ -40,35 +41,36 @@ namespace rexy{ char* m_data = nullptr; protected: - constexpr string_base(void) = default; - constexpr string_base(size_t len): + constexpr string_base(void)noexcept = default; + constexpr string_base(size_t len)noexcept: m_cap(len){} //Initialize without copying - constexpr string_base(char* data, size_t len): + constexpr string_base(char* data, size_t len)noexcept: m_cap(len), m_data(data){} - constexpr string_base(char* data, size_t len, size_t cap): + constexpr string_base(char* data, size_t len, size_t cap)noexcept: m_length(len), m_cap(cap), m_data(data){} //Copy ctor (do nothing) - constexpr string_base(const string_base&){} - ~string_base(void) = default; + constexpr string_base(const string_base&)noexcept{} + ~string_base(void)noexcept = default; public: //Stop managing stored pointer. Does not free. - constexpr char* release(void){return cx::exchange(m_data, nullptr);} + constexpr char* release(void)noexcept(noexcept(cx::exchange(m_data, nullptr))) + {return cx::exchange(m_data, nullptr);} //Length of string not including null terminator - constexpr size_t length(void)const{return m_length;} - constexpr size_t capacity(void)const{return m_cap;} + constexpr size_t length(void)const noexcept{return m_length;} + constexpr size_t capacity(void)const noexcept{return m_cap;} //direct access to managed pointer - constexpr char* get(void){return m_data;} - constexpr const char* get(void)const{return m_data;} - constexpr operator char*(void){return m_data;} - constexpr operator const char*(void)const{return m_data;} + constexpr char* get(void)noexcept{return m_data;} + constexpr const char* get(void)const noexcept{return m_data;} + constexpr operator char*(void)noexcept{return m_data;} + constexpr operator const char*(void)const noexcept{return m_data;} //true if m_data is not null - constexpr bool valid(void)const{return m_data;} + constexpr bool valid(void)const noexcept{return m_data;} - constexpr char& operator[](size_t i){return m_data[i];} - constexpr const char& operator[](size_t i)const{return m_data[i];} + constexpr char& operator[](size_t i)noexcept{return m_data[i];} + constexpr const char& operator[](size_t i)const noexcept{return m_data[i];} }; @@ -79,46 +81,56 @@ namespace rexy{ public: using allocator_type = Allocator; + private: + string_intermediary& _copy_string(const char* s, size_t len)noexcept(noexcept(Allocator::free(m_data)) && + noexcept(Allocator::copy(s, len))); + public: - constexpr string_intermediary(void); - constexpr string_intermediary(rexy::steal data, size_t len); - constexpr string_intermediary(rexy::steal data, size_t len, size_t cap); - [[deprecated]] constexpr string_intermediary(char* data, size_t len); - string_intermediary(const char* data, size_t len); - [[deprecated]] constexpr string_intermediary(char* data, size_t len, size_t cap); - string_intermediary(const char* data); - constexpr string_intermediary(rexy::steal); - string_intermediary(size_t len); - string_intermediary(size_t len, size_t cap); + constexpr string_intermediary(void)noexcept; + constexpr string_intermediary(rexy::steal data, size_t len)noexcept; + constexpr string_intermediary(rexy::steal data, size_t len, size_t cap)noexcept; + constexpr string_intermediary(rexy::steal data)noexcept; + [[deprecated]] constexpr string_intermediary(char* data, size_t len)noexcept; + [[deprecated]] constexpr string_intermediary(char* data, size_t len, size_t cap)noexcept; + string_intermediary(const char* data, size_t len)noexcept(noexcept(Allocator::copy(data,len))); + string_intermediary(const char* data)noexcept(noexcept(strlen(data)) && noexcept(Allocator::copy(data, m_cap))); + string_intermediary(size_t len)noexcept(noexcept(Allocator::allocate(len))); + string_intermediary(size_t len, size_t cap)noexcept(noexcept(Allocator::allocate(len))); //normal copy and move ctors - string_intermediary(const string_intermediary& b); - constexpr string_intermediary(string_intermediary&& s); + string_intermediary(const string_intermediary& b)noexcept(noexcept(Allocator::copy(b.m_data, b.m_length))); + constexpr string_intermediary(string_intermediary&& s)noexcept(noexcept(cx::exchange(s.m_data, nullptr))); - string_intermediary(const string_base& b); + string_intermediary(const string_base& b)noexcept(noexcept(Allocator::copy(b.get(), b.length()))); //dtor - ~string_intermediary(void); + ~string_intermediary(void)noexcept(noexcept(Allocator::free(m_data))); - string_intermediary& operator=(const string_intermediary& s); - constexpr string_intermediary& operator=(string_intermediary&& s); + string_intermediary& operator=(const string_intermediary& s) + noexcept(std::is_nothrow_copy_constructible>::value && + std::is_nothrow_move_assignable>::value); + constexpr string_intermediary& operator=(string_intermediary&& s)noexcept(noexcept(cx::swap(m_data, s.m_data))); //Copy from c string - string_intermediary& operator=(const char* c); + string_intermediary& operator=(const char* c)noexcept(noexcept(_copy_string(c, 0))); //Copy from other string_base - string_intermediary& operator=(const string_base& s); + string_intermediary& operator=(const string_base& s)noexcept(noexcept(_copy_string(s.get(), 0))); //Replace managed pointer. Frees existing value - void reset(char* val = nullptr); - void reset(char* val, size_t len); - bool resize(size_t newsize); - void append(const char* data, size_t len); - void append(const char* data); - void append(const string_base& s); + void reset(char* val = nullptr)noexcept(noexcept(Allocator::free(m_data))); + void reset(char* val, size_t len)noexcept(noexcept(Allocator::free(m_data))); + bool resize(size_t newsize)noexcept(std::is_nothrow_copy_constructible>::value && + std::is_nothrow_move_assignable>::value); + void append(const char* data, size_t len)noexcept(std::is_nothrow_constructible,decltype(m_length)>::value); + void append(const char* data)noexcept(std::is_nothrow_constructible,decltype(m_length)>::value); + void append(const string_base& s)noexcept(std::is_nothrow_constructible,decltype(m_length)>::value); - private: - string_intermediary& _copy_string(const char* s, size_t len); }; + namespace detail{ + template + struct string_appender; + } + //Like an expression template but not really template class string_cat_expr : public string_expr @@ -129,14 +141,18 @@ namespace rexy{ public: template - constexpr string_cat_expr(T&& l, U&& r); - constexpr string_cat_expr(string_cat_expr&& s); + constexpr string_cat_expr(T&& l, U&& r)noexcept(std::is_nothrow_constructible::value && + std::is_nothrow_constructible::value); + constexpr string_cat_expr(string_cat_expr&& s)noexcept(std::is_nothrow_constructible::value && + std::is_nothrow_constructible::value); - constexpr size_t length(void)const; + constexpr size_t length(void)const noexcept(noexcept(m_l.length()) && noexcept(m_r.length())); template - operator string_intermediary(void); - constexpr const Left& left(void)const; - constexpr const Right& right(void)const; + operator string_intermediary(void) + noexcept(std::is_nothrow_constructible, size_t>::value && + std::is_nothrow_invocable>,decltype(*this)>::value); + constexpr const Left& left(void)const noexcept; + constexpr const Right& right(void)const noexcept; }; template string_cat_expr(Left&, Right&) -> string_cat_expr; @@ -153,16 +169,16 @@ namespace rexy{ class static_string : public string_base { public: - constexpr static_string(void) = default; - constexpr static_string(const char* str, size_t len); - constexpr static_string(const char* c); - constexpr static_string(const static_string& s); - constexpr static_string(static_string&& s); - ~static_string(void) = default; + constexpr static_string(void)noexcept = default; + constexpr static_string(const char* str, size_t len)noexcept; + constexpr static_string(const char* c)noexcept; + constexpr static_string(const static_string& s)noexcept; + constexpr static_string(static_string&& s)noexcept; + ~static_string(void)noexcept = default; - constexpr static_string& operator=(const char* c); - constexpr static_string& operator=(const static_string& s); - constexpr static_string& operator=(static_string&&); + constexpr static_string& operator=(const char* c)noexcept; + constexpr static_string& operator=(const static_string& s)noexcept; + constexpr static_string& operator=(static_string&&)noexcept; }; @@ -189,43 +205,55 @@ namespace rexy{ private: Targ& m_targ; public: - constexpr string_appender(Targ& t); + constexpr string_appender(Targ& t)noexcept; template - constexpr void operator()(const string_cat_expr& str); + constexpr void operator()(const string_cat_expr& str) + noexcept(noexcept((*this)(str.left())) && noexcept((*this)(str.right()))); template::value,int> = 0> - constexpr void operator()(Str&& str); + constexpr void operator()(Str&& str)noexcept(noexcept(m_targ.append(str.get(), str.length()))); }; } //namespace detail template = 0> - constexpr bool operator==(Str1&& left, Str2&& right){ + constexpr bool operator==(Str1&& left, Str2&& right)noexcept{ return left.valid() && right.valid() && left.length() == right.length() && !cx::strcmp(left.get(), right.get()); } template = 0> - constexpr bool operator!=(Str1&& left, Str2&& right){ + constexpr bool operator!=(Str1&& left, Str2&& right)noexcept{ return !(left == right); } template = 0> - constexpr auto operator+(Left&& l, Right&& r){ + constexpr auto operator+(Left&& l, Right&& r) + //uses deduction guide whereas std::is_nothrow_constructible couldn't + noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward(l), std::forward(r)))) + { return string_cat_expr(std::forward(l), std::forward(r)); } template = 0> - constexpr auto operator+(const char* left, Right&& right){ + constexpr auto operator+(const char* left, Right&& right) + noexcept(noexcept(::new (nullptr) string_cat_expr(rexy::static_string(left), std::forward(right)))) + { return string_cat_expr(rexy::static_string(left), std::forward(right)); } template = 0> - constexpr auto operator+(Left&& left, const char* right){ + constexpr auto operator+(Left&& left, const char* right) + noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward(left), rexy::static_string(right)))) + { return rexy::string_cat_expr(std::forward(left), rexy::static_string(right)); } template = 0, detail::enable_if_string = 0> - decltype(auto) operator+=(Left& l, Right&& r){ + decltype(auto) operator+=(Left& l, Right&& r) + noexcept(noexcept(l + std::forward(r)) && std::is_nothrow_assignable(r))>::value) + { return l = (l + std::forward(r)); } template = 0> - decltype(auto) operator+=(Left& l, const char* r){ + decltype(auto) operator+=(Left& l, const char* r) + noexcept(noexcept(l + r) && std::is_nothrow_assignable::value) + { return l = (l + r); } } @@ -233,15 +261,11 @@ namespace rexy{ #include "string_base.tpp" namespace{ - constexpr inline rexy::static_string operator"" _ss(const char* str, size_t len){ + constexpr inline rexy::static_string operator"" _ss(const char* str, size_t len)noexcept{ return rexy::static_string(str, len); } } -#ifdef REXY_BINARY_HPP -#include "detail/binary_string_conv.hpp" -#endif - #ifdef REXY_CX_HASH_HPP #include "cx/string_hash.hpp" #endif diff --git a/include/rexy/string_base.tpp b/include/rexy/string_base.tpp index fdb32bc..19994aa 100644 --- a/include/rexy/string_base.tpp +++ b/include/rexy/string_base.tpp @@ -30,27 +30,37 @@ namespace rexy{ template - constexpr string_intermediary::string_intermediary(void){} + constexpr string_intermediary::string_intermediary(void)noexcept{} template - /*deprecated*/ constexpr string_intermediary::string_intermediary(char* data, size_t len): - string_base(data, len){} + constexpr string_intermediary::string_intermediary(rexy::steal data)noexcept: + string_base(data.value() ? cx::strlen(data.value()) : 0) + { + m_data = data.value(); + m_length = m_cap; + } template - constexpr string_intermediary::string_intermediary(rexy::steal data, size_t len): + constexpr string_intermediary::string_intermediary(rexy::steal data, size_t len)noexcept: string_base(data.value(), len){} template - /*deprecated*/ constexpr string_intermediary::string_intermediary(char* data, size_t len, size_t cap): - string_base(data, len, cap){} - template - constexpr string_intermediary::string_intermediary(rexy::steal data, size_t len, size_t cap): + constexpr string_intermediary::string_intermediary(rexy::steal data, size_t len, size_t cap)noexcept: string_base(data.value(), len, cap){} template - string_intermediary::string_intermediary(const char* data, size_t len): + /*deprecated*/ constexpr string_intermediary::string_intermediary(char* data, size_t len)noexcept: + string_base(data, len){} + template + /*deprecated*/ constexpr string_intermediary::string_intermediary(char* data, size_t len, size_t cap)noexcept: + string_base(data, len, cap){} + template + string_intermediary::string_intermediary(const char* data, size_t len) + noexcept(noexcept(Allocator::copy(data,len))): string_base(reinterpret_cast(len ? Allocator::copy(data, len+1) : nullptr), len) { m_data[len] = 0; } template - string_intermediary::string_intermediary(const char* data): + string_intermediary::string_intermediary(const char* data) + noexcept(noexcept(strlen(data)) && + noexcept(Allocator::copy(data, m_cap))): string_base(data ? strlen(data) : 0) { if(m_cap){ @@ -59,20 +69,15 @@ namespace rexy{ } } template - constexpr string_intermediary::string_intermediary(rexy::steal data): - string_base(data.value() ? cx::strlen(data.value()) : 0) - { - m_data = data.value(); - m_length = m_cap; - } - template - string_intermediary::string_intermediary(size_t len): + string_intermediary::string_intermediary(size_t len) + noexcept(noexcept(Allocator::allocate(len))): string_base(reinterpret_cast(len ? Allocator::allocate(len+1) : nullptr), len) { m_data[len] = 0; } template - string_intermediary::string_intermediary(size_t len, size_t cap): + string_intermediary::string_intermediary(size_t len, size_t cap) + noexcept(noexcept(Allocator::allocate(len))): string_base(reinterpret_cast(len ? Allocator::allocate(len+1) : nullptr), len, cap) { m_data[len] = 0; @@ -80,24 +85,32 @@ namespace rexy{ //normal copy and move ctors template - string_intermediary::string_intermediary(const string_intermediary& b): + string_intermediary::string_intermediary(const string_intermediary& b) + noexcept(noexcept(Allocator::copy(b.m_data, b.m_length))): 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): + constexpr string_intermediary::string_intermediary(string_intermediary&& s) + noexcept(noexcept(cx::exchange(s.m_data, nullptr))): string_base(cx::exchange(s.m_data, nullptr), s.m_length, s.m_cap){} template - string_intermediary::string_intermediary(const string_base& b): + string_intermediary::string_intermediary(const string_base& b) + noexcept(noexcept(Allocator::copy(b.get(), b.length()))): string_base(reinterpret_cast(b.length() ? Allocator::copy(b.get(), b.length()+1) : nullptr), b.length(), b.capacity()){} //dtor template - string_intermediary::~string_intermediary(void){ + string_intermediary::~string_intermediary(void) + noexcept(noexcept(Allocator::free(m_data))) + { Allocator::free(m_data); } template - string_intermediary& string_intermediary::operator=(const string_intermediary& s){ + string_intermediary& string_intermediary::operator=(const string_intermediary& s) + noexcept(std::is_nothrow_copy_constructible>::value && + std::is_nothrow_move_assignable>::value) + { if(s.m_length < m_length){ memcpy(m_data, s.m_data, s.m_length+1); m_length = s.m_length; @@ -107,7 +120,9 @@ namespace rexy{ return (*this = std::move(tmp)); } template - constexpr string_intermediary& string_intermediary::operator=(string_intermediary&& s){ + constexpr string_intermediary& string_intermediary::operator=(string_intermediary&& s) + noexcept(noexcept(cx::swap(m_data, s.m_data))) + { cx::swap(m_data, s.m_data); m_length = s.m_length; m_cap = s.m_cap; @@ -115,32 +130,43 @@ namespace rexy{ } //Copy from c string template - string_intermediary& string_intermediary::operator=(const char* c){ + string_intermediary& string_intermediary::operator=(const char* c) + noexcept(noexcept(_copy_string(c, 0))) + { return _copy_string(c, strlen(c)); } //Copy from other string_base template - string_intermediary& string_intermediary::operator=(const string_base& s){ + string_intermediary& string_intermediary::operator=(const string_base& s) + noexcept(noexcept(_copy_string(s.get(), 0))) + { return _copy_string(s.get(), s.length()); } //Replace managed pointer. Frees existing value template - void string_intermediary::reset(char* val){ + void string_intermediary::reset(char* val) + noexcept(noexcept(Allocator::free(m_data))) + { Allocator::free(m_data); m_data = val; m_length = val ? strlen(val) : 0; m_cap = m_length; } template - void string_intermediary::reset(char* val, size_t len){ + void string_intermediary::reset(char* val, size_t len) + noexcept(noexcept(Allocator::free(m_data))) + { Allocator::free(m_data); m_data = val; m_length = len; m_cap = len; } template - bool string_intermediary::resize(size_t newsize){ + bool string_intermediary::resize(size_t newsize) + noexcept(std::is_nothrow_copy_constructible>::value && + std::is_nothrow_move_assignable>::value) + { if(newsize < m_cap) return false; string_intermediary tmp(newsize); @@ -152,7 +178,9 @@ namespace rexy{ return true; } template - void string_intermediary::append(const char* data, size_t len){ + void string_intermediary::append(const char* data, size_t len) + noexcept(std::is_nothrow_constructible,decltype(m_length)>::value) + { if(len+m_length <= m_cap){ memcpy(m_data+m_length, data, len); m_length += len; @@ -160,25 +188,32 @@ namespace rexy{ }else{ string_intermediary tmp(cx::max(m_length + len, m_cap*2)); if(m_data) - memcpy(STOP_STRING_ALIASING_WARNING(tmp).m_data, m_data, m_length); - memcpy(STOP_STRING_ALIASING_WARNING(tmp).m_data+m_length, data, len); - STOP_STRING_ALIASING_WARNING(tmp).m_length = len+m_length; + memcpy(STOP_STRICT_ALIAS_WARNING(tmp).m_data, m_data, m_length); + memcpy(STOP_STRICT_ALIAS_WARNING(tmp).m_data+m_length, data, len); + STOP_STRICT_ALIAS_WARNING(tmp).m_length = len+m_length; tmp[m_length+len] = 0; *this = std::move(tmp); } } template - void string_intermediary::append(const char* data){ + void string_intermediary::append(const char* data) + noexcept(std::is_nothrow_constructible,decltype(m_length)>::value) + { if(data) append(data, strlen(data)); } template - void string_intermediary::append(const string_base& s){ + void string_intermediary::append(const string_base& s) + noexcept(std::is_nothrow_constructible,decltype(m_length)>::value) + { append(s.get(), s.length()); } template - string_intermediary& string_intermediary::_copy_string(const char* s, size_t len){ + string_intermediary& string_intermediary::_copy_string(const char* s, size_t len) + noexcept(noexcept(Allocator::free(m_data)) && + noexcept(Allocator::copy(s, len))) + { if(!len){ Allocator::free(m_data); m_length = 0; @@ -204,21 +239,30 @@ namespace rexy{ template template - constexpr string_cat_expr::string_cat_expr(T&& l, U&& r): + constexpr string_cat_expr::string_cat_expr(T&& l, U&& r) + noexcept(std::is_nothrow_constructible::value && + std::is_nothrow_constructible::value): m_l(std::forward(l)), m_r(std::forward(r)){} template - constexpr string_cat_expr::string_cat_expr(string_cat_expr&& s): + constexpr string_cat_expr::string_cat_expr(string_cat_expr&& s) + noexcept(std::is_nothrow_constructible::value && + std::is_nothrow_constructible::value): m_l(std::forward(s.m_l)), m_r(std::forward(s.m_r)){} template - constexpr size_t string_cat_expr::length(void)const{ + constexpr size_t string_cat_expr::length(void)const + noexcept(noexcept(m_l.length()) && noexcept(m_r.length())) + { return m_l.length() + m_r.length(); } template template - string_cat_expr::operator string_intermediary(void){ + string_cat_expr::operator string_intermediary(void) + noexcept(std::is_nothrow_constructible, size_t>::value && + std::is_nothrow_invocable>,decltype(*this)>::value) + { size_t len = length(); string_intermediary ret(len); detail::string_appender> append(ret); @@ -226,34 +270,34 @@ namespace rexy{ return ret; } template - constexpr const Left& string_cat_expr::left(void)const{ + constexpr const Left& string_cat_expr::left(void)const noexcept{ return m_l; } template - constexpr const Right& string_cat_expr::right(void)const{ + constexpr const Right& string_cat_expr::right(void)const noexcept{ return m_r; } - constexpr static_string::static_string(const char* str, size_t len): + constexpr static_string::static_string(const char* str, size_t len)noexcept: string_base(const_cast(str), len, len){} - constexpr static_string::static_string(const static_string& s): + constexpr static_string::static_string(const static_string& s)noexcept: string_base(s.m_data, s.m_length, s.m_length){} - constexpr static_string::static_string(static_string&& s): + constexpr static_string::static_string(static_string&& s)noexcept: string_base(s.m_data, s.m_length, s.m_length){} - constexpr static_string& static_string::operator=(const static_string& s){ + constexpr static_string& static_string::operator=(const static_string& s)noexcept{ m_data = s.m_data; m_length = s.m_length; return *this; } - constexpr static_string::static_string(const char* c): + constexpr static_string::static_string(const char* c)noexcept: static_string(const_cast(c), cx::strlen(c)){} - constexpr static_string& static_string::operator=(const char* c){ + constexpr static_string& static_string::operator=(const char* c)noexcept{ m_data = const_cast(c); m_length = cx::strlen(c); return *this; } - constexpr static_string& static_string::operator=(static_string&& s){ + constexpr static_string& static_string::operator=(static_string&& s)noexcept{ m_data = s.m_data; m_length = s.m_length; return *this; @@ -261,16 +305,20 @@ namespace rexy{ namespace detail{ template - constexpr string_appender::string_appender(Targ& t): m_targ(t){} + constexpr string_appender::string_appender(Targ& t)noexcept: m_targ(t){} template template - constexpr void string_appender::operator()(const string_cat_expr& str){ + constexpr void string_appender::operator()(const string_cat_expr& str) + noexcept(noexcept((*this)(str.left())) && noexcept((*this)(str.right()))) + { (*this)(str.left()); (*this)(str.right()); } template template::value,int>> - constexpr void string_appender::operator()(Str&& str){ + constexpr void string_appender::operator()(Str&& str) + noexcept(noexcept(m_targ.append(str.get(), str.length()))) + { m_targ.append(str.get(), str.length()); } } diff --git a/src/binary.cpp b/src/binary.cpp index 523c07a..45296eb 100644 --- a/src/binary.cpp +++ b/src/binary.cpp @@ -20,11 +20,6 @@ namespace rexy{ - binary_base::binary_base(binary_base&& b): - m_data(std::exchange(b.m_data, nullptr)), - m_size(b.m_size), - m_cap(b.m_cap){} - char* binary_base::release(void){ return std::exchange(m_data, nullptr); } diff --git a/src/ensure.cpp b/src/ensure.cpp index f81db15..1a6c3f2 100644 --- a/src/ensure.cpp +++ b/src/ensure.cpp @@ -1,13 +1,21 @@ //Never actually used in the project. This just ensures that all syntax is correct during builds. -#include "rexy/string.hpp" #include "rexy/binary.hpp" #include "rexy/filerd.hpp" #include "rexy/steal.hpp" +#include "rexy/string_base.hpp" +#include "rexy/string_base.tpp" +#include "rexy/string.hpp" +#include "rexy/traits.hpp" + +#include "rexy/detail/binary_string_conv.hpp" +#include "rexy/detail/default_allocator.hpp" + #include "rexy/cx/algorithm.hpp" +#include "rexy/cx/array.hpp" +#include "rexy/cx/hash.hpp" +#include "rexy/cx/hashmap.hpp" +#include "rexy/cx/string_hash.hpp" +#include "rexy/cx/string.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" diff --git a/src/filerd.cpp b/src/filerd.cpp index d91acd7..f76fbbc 100644 --- a/src/filerd.cpp +++ b/src/filerd.cpp @@ -20,25 +20,26 @@ #include //fopen, fclose #include //exchange, swap +#include namespace rexy{ - filerd::filerd(const char* f, const char* mode): + filerd::filerd(const char* f, const char* mode)noexcept: m_fp(fopen(f, mode)){} - filerd::~filerd(void){ + filerd::~filerd(void)noexcept{ if(m_fp) fclose(m_fp); } - void filerd::reset(FILE* fp){ + void filerd::reset(FILE* fp)noexcept{ if(m_fp) fclose(m_fp); m_fp = fp; } - FILE* filerd::release(void){ + FILE* filerd::release(void)noexcept{ return std::exchange(m_fp, nullptr); } - size_t filerd::length(void){ + size_t filerd::length(void)noexcept{ if(!m_fp) return 0; size_t tmp, ret; @@ -48,38 +49,38 @@ namespace rexy{ fseek(m_fp, tmp, SEEK_SET); return ret; } - size_t filerd::position(void)const{ + size_t filerd::position(void)const noexcept{ return ftell(m_fp); } - void filerd::rewind(size_t pos){ + void filerd::rewind(size_t pos)noexcept{ fseek(m_fp, pos, SEEK_SET); } - filerd::operator FILE*(void){ + filerd::operator FILE*(void)noexcept{ return m_fp; } - filerd::operator const FILE*(void)const{ + filerd::operator const FILE*(void)const noexcept{ return m_fp; } - FILE* filerd::get(void){ + FILE* filerd::get(void)noexcept{ return m_fp; } - const FILE* filerd::get(void)const{ + const FILE* filerd::get(void)const noexcept{ return m_fp; } - filerd::operator bool(void)const{ + filerd::operator bool(void)const noexcept{ return m_fp; } - size_t filerd::read(char* dest, size_t bytes){ + size_t filerd::read(char* dest, size_t bytes)noexcept{ return fread(dest, 1, bytes, m_fp); } - rexy::string filerd::read(size_t bytes){ + rexy::string filerd::read(size_t bytes)noexcept{ char* tmp = reinterpret_cast(rexy::string::allocator_type::allocate(bytes)); size_t written = read(tmp, bytes); return rexy::string(rexy::steal(tmp), written); } - rexy::string filerd::readln(size_t max){ + rexy::string filerd::readln(size_t max)noexcept{ rexy::string ret; char c; size_t count = 0; @@ -90,15 +91,17 @@ namespace rexy{ } return ret; } - rexy::binary filerd::read_bin(size_t bytes){ + rexy::binary filerd::read_bin(size_t bytes) + noexcept(std::is_nothrow_constructible, size_t, size_t>::value) + { char* tmp = reinterpret_cast(rexy::binary::allocator_type::allocate(bytes)); size_t written = read(tmp, bytes); return rexy::binary(rexy::steal(tmp), written, written); } - size_t filerd::write(const char* c, size_t bytes){ + size_t filerd::write(const char* c, size_t bytes)noexcept{ return fwrite(c, 1, bytes, m_fp); } - size_t filerd::write(const rexy::string_base& c){ + size_t filerd::write(const rexy::string_base& c)noexcept{ return write(c.get(), c.length()); }