Add noexcept specs to all the things

This commit is contained in:
rexy712 2020-05-06 15:23:58 -07:00
parent b97e7d7c1b
commit daac14dddf
18 changed files with 501 additions and 329 deletions

View File

@ -39,18 +39,14 @@ namespace rexy{
size_t m_cap = 0; size_t m_cap = 0;
public: public:
protected: protected:
constexpr binary_base(void) = default; constexpr binary_base(void)noexcept = default;
constexpr binary_base(char* data, size_t size): constexpr binary_base(char* data, size_t size)noexcept:
m_data(data), m_cap(size){} 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){} m_data(data), m_size(size), m_cap(cap){}
template<class Allocator> template<class Allocator>
binary_base(const binary_base& b): binary_base(const binary_base& b)noexcept{}
m_data(Allocator::copy(b.m_data, b.m_cap)), ~binary_base(void)noexcept = default;
m_size(b.m_size),
m_cap(b.m_cap){}
binary_base(binary_base&&);
~binary_base(void) = default;
public: public:
char* release(void); char* release(void);
@ -71,64 +67,83 @@ namespace rexy{
public: public:
using allocator_type = Allocator; using allocator_type = Allocator;
public: public:
constexpr binary_data(void) = default; constexpr binary_data(void)noexcept = default;
[[deprecated]] binary_data(char* data, size_t size): [[deprecated]] binary_data(char* data, size_t size)noexcept:
binary_base(data, size){} binary_base(data, size){}
binary_data(rexy::steal<char*> data, size_t size): [[deprecated]] binary_data(char* data, size_t cap, size_t size)noexcept:
binary_base(data.value(), size){}
binary_data(const char* data, size_t size):
binary_base(reinterpret_cast<char*>(Allocator::copy(data, size)), size){}
[[deprecated]] binary_data(char* data, size_t cap, size_t size):
binary_base(data, cap, size){} binary_base(data, cap, size){}
binary_data(rexy::steal<char*> 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<char*>(Allocator::copy(data, size)), size){}
constexpr binary_data(rexy::steal<char*> data, size_t size)noexcept:
binary_base(data.value(), size){}
constexpr binary_data(rexy::steal<char*> data, size_t cap, size_t size)noexcept:
binary_base(data.value(), cap, size){} 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<char*>(Allocator::copy(data, size)), cap, size){} binary_base(reinterpret_cast<char*>(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<char*>(Allocator::allocate(size)), size){} binary_base(reinterpret_cast<char*>(Allocator::allocate(size)), size){}
binary_data(const binary_data& b): binary_data(const binary_data& b)
binary_base(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); m_data = Allocator::copy(b.m_data, b.m_cap);
} }
binary_data(binary_data&& b): constexpr binary_data(binary_data&& b)noexcept:
binary_base(std::move(b)){} binary_base(cx::exchange(b.m_data, nullptr), b.m_cap, b.m_size){}
~binary_data(void){ ~binary_data(void)
noexcept(noexcept(Allocator::free(m_data)))
{
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<binary_data<Allocator>>::value &&
std::is_nothrow_move_assignable<binary_data<Allocator>>::value)
{
binary_data<allocator_type> tmp(b); binary_data<allocator_type> tmp(b);
return (*this = std::move(tmp)); 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_size = b.m_size;
m_cap = b.m_cap; m_cap = b.m_cap;
std::swap(m_data, b.m_data); cx::swap(m_data, b.m_data);
return *this; return *this;
} }
void reset(void){ void reset(void)
noexcept(noexcept(Allocator::free(m_data)))
{
Allocator::free(m_data); Allocator::free(m_data);
m_data = nullptr; m_data = nullptr;
m_cap = m_size = 0; 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); Allocator::free(m_data);
m_data = val; m_data = val;
m_cap = cap; m_cap = cap;
m_size = size; m_size = size;
} }
bool resize(size_t newsize){ bool resize(size_t newsize)
noexcept(std::is_nothrow_constructible<binary_data<Allocator>,size_t>::value)
{
if(newsize < m_cap) if(newsize < m_cap)
return false; return false;
binary_data<allocator_type> tmp(newsize); binary_data<allocator_type> tmp(newsize);
if(!tmp) if(!tmp)
return false; return false;
memcpy(STOP_STRICT_ALIAS_WARNING(tmp).m_data, m_data, m_size); 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; m_cap = STOP_STRICT_ALIAS_WARNING(tmp).m_cap;
return true; 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) if(m_size + len > m_cap)
resize(cx::max(m_cap*2, m_size+len)); resize(cx::max(m_cap*2, m_size+len));
memcpy(m_data+m_size, data, len); memcpy(m_data+m_size, data, len);
@ -151,22 +166,26 @@ namespace rexy{
} }
template<class Left, class Right, detail::enable_if_binary<Left,Right> = 0> template<class Left, class Right, detail::enable_if_binary<Left,Right> = 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()); return l && r && l.size() == r.size() && l.capacity() == r.capacity() && !memcmp(l.get(), r.get(), l.size());
} }
template<class Left, class Right, detail::enable_if_binary<Left,Right> = 0> template<class Left, class Right, detail::enable_if_binary<Left,Right> = 0>
bool operator!=(Left&& l, Right&& r){ bool operator!=(Left&& l, Right&& r)noexcept{
return !(std::forward<Left>(l) == std::forward<Right>(r)); return !(std::forward<Left>(l) == std::forward<Right>(r));
} }
template<class All, class Alr> template<class All, class Alr>
auto operator+(const rexy::binary_data<All>& l, const rexy::binary_data<Alr>& r){ auto operator+(const rexy::binary_data<All>& l, const rexy::binary_data<Alr>& r)
noexcept(std::is_nothrow_constructible<binary_data<All>, size_t>::value)
{
rexy::binary_data<All> retval(l.size() + r.size()); rexy::binary_data<All> retval(l.size() + r.size());
memcpy(retval.get(), l.get(), l.size()); memcpy(retval.get(), l.get(), l.size());
memcpy(retval.get()+l.size(), r.get(), r.size()); memcpy(retval.get()+l.size(), r.get(), r.size());
return retval; return retval;
} }
template<class All, class Alr> template<class All, class Alr>
decltype(auto) operator+=(rexy::binary_data<All>& l, const rexy::binary_data<Alr>& r){ decltype(auto) operator+=(rexy::binary_data<All>& l, const rexy::binary_data<Alr>& r)
noexcept(noexcept(l.resize(0)))
{
l.resize(l.size() + r.size()); l.resize(l.size() + r.size());
memcpy(l.get()+l.size(), r.get(), r.size()); memcpy(l.get()+l.size(), r.get(), r.size());
return l; return l;

View File

@ -21,10 +21,15 @@
#include "utility.hpp" //swap #include "utility.hpp" //swap
#include <type_traits>
namespace rexy::cx{ namespace rexy::cx{
template<class Iter, class Compare> template<class Iter, class Compare>
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<Compare,decltype(*left),decltype(*right)>::value &&
noexcept(cx::swap(*left,*right)))
{
auto range = right - left; auto range = right - left;
auto pivot = left + (range / 2); auto pivot = left + (range / 2);
auto value = *pivot; auto value = *pivot;
@ -42,7 +47,9 @@ namespace rexy::cx{
return left; return left;
} }
template<class Iter, class Compare> template<class Iter, class Compare>
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){ while(left < right){
auto real_right = right-1; auto real_right = right-1;
auto pivot = qs_partition(left, real_right, cmp); auto pivot = qs_partition(left, real_right, cmp);

View File

@ -22,6 +22,8 @@
#include <cstddef> //size_t #include <cstddef> //size_t
#include "utility.hpp" //swap #include "utility.hpp" //swap
#include <type_traits>
namespace rexy::cx{ namespace rexy::cx{
template<class T, size_t N> template<class T, size_t N>
@ -44,76 +46,80 @@ namespace rexy::cx{
T m_elements[N] = {}; T m_elements[N] = {};
public: public:
constexpr reference at(size_type pos){ constexpr reference at(size_type pos)noexcept{
return m_elements[pos]; 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]; return m_elements[pos];
} }
constexpr reference operator[](size_type pos){ constexpr reference operator[](size_type pos)noexcept{
return m_elements[pos]; 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]; return m_elements[pos];
} }
constexpr reference front(void){ constexpr reference front(void)noexcept{
return m_elements[0]; return m_elements[0];
} }
constexpr const_reference front(void)const{ constexpr const_reference front(void)const noexcept{
return m_elements[0]; return m_elements[0];
} }
constexpr reference back(void){ constexpr reference back(void)noexcept{
return m_elements[max_elements-1]; 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]; return m_elements[max_elements-1];
} }
constexpr pointer data(void){ constexpr pointer data(void)noexcept{
return m_elements; return m_elements;
} }
constexpr const_pointer data(void)const{ constexpr const_pointer data(void)const noexcept{
return m_elements; return m_elements;
} }
constexpr iterator begin(void){ constexpr iterator begin(void)noexcept{
return m_elements; return m_elements;
} }
constexpr const_iterator begin(void)const{ constexpr const_iterator begin(void)const noexcept{
return m_elements; return m_elements;
} }
constexpr const_iterator cbegin(void)const{ constexpr const_iterator cbegin(void)const noexcept{
return m_elements; return m_elements;
} }
constexpr iterator end(void){ constexpr iterator end(void)noexcept{
return m_elements+max_elements; return m_elements+max_elements;
} }
constexpr const_iterator end(void)const{ constexpr const_iterator end(void)const noexcept{
return m_elements+max_elements; return m_elements+max_elements;
} }
constexpr const_iterator cend(void)const{ constexpr const_iterator cend(void)const noexcept{
return m_elements+max_elements; return m_elements+max_elements;
} }
constexpr bool empty(void)const{ constexpr bool empty(void)const noexcept{
if constexpr(max_elements == 0){ if constexpr(max_elements == 0){
return true; return true;
}else{ }else{
return false; return false;
} }
} }
constexpr size_type size(void)const{ constexpr size_type size(void)const noexcept{
return max_elements; return max_elements;
} }
constexpr size_type max_size(void)const{ constexpr size_type max_size(void)const noexcept{
return max_elements; return max_elements;
} }
constexpr void fill(const T& value){ constexpr void fill(const T& value)
noexcept(std::is_nothrow_copy_assignable<T>::value)
{
for(auto it = begin();it != end();++it){ for(auto it = begin();it != end();++it){
*it = value; *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){ 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]);
} }
} }
}; };

View File

@ -25,7 +25,7 @@ namespace rexy::cx{
template<class T> template<class T>
struct hash{ 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); constexpr size_t bytes = sizeof(size_t);
size_t val = static_cast<size_t>(t); size_t val = static_cast<size_t>(t);
size_t hash = 5381 + salt; //magic hash number size_t hash = 5381 + salt; //magic hash number

View File

@ -73,9 +73,9 @@ namespace rexy::cx{
//no key checks. give a correct key or get a random answer :) //no key checks. give a correct key or get a random answer :)
template<class U, class UHash = hash<std::decay_t<U>>> template<class U, class UHash = hash<std::decay_t<U>>>
constexpr reference operator[](U&& u); constexpr reference operator[](U&& u)noexcept;
template<class U, class UHash = hash<std::decay_t<U>>> template<class U, class UHash = hash<std::decay_t<U>>>
constexpr const_reference operator[](U&& u)const; constexpr const_reference operator[](U&& u)const noexcept;
}; };
template<class Key, class Value, size_t N, class Hash> template<class Key, class Value, size_t N, class Hash>
@ -90,7 +90,7 @@ namespace rexy::cx{
} }
//sort the buckets based on size, largest first //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(); return left.size() > right.size();
}); });
@ -148,7 +148,7 @@ namespace rexy::cx{
//no key checks. give a correct key or get a random answer :) //no key checks. give a correct key or get a random answer :)
template<class Key, class Value, size_t N, class Hash> template<class Key, class Value, size_t N, class Hash>
template<class U, class UHash> template<class U, class UHash>
constexpr auto hashmap<Key,Value,N,Hash>::operator[](U&& key) -> reference{ constexpr auto hashmap<Key,Value,N,Hash>::operator[](U&& key)noexcept -> reference{
auto d = m_g[UHash{}(std::forward<U>(key)) % max_size]; auto d = m_g[UHash{}(std::forward<U>(key)) % max_size];
if(d & single_bucket_bit) if(d & single_bucket_bit)
return m_values[d & ~single_bucket_bit]; return m_values[d & ~single_bucket_bit];
@ -156,7 +156,7 @@ namespace rexy::cx{
} }
template<class Key, class Value, size_t N, class Hash> template<class Key, class Value, size_t N, class Hash>
template<class U, class UHash> template<class U, class UHash>
constexpr auto hashmap<Key,Value,N,Hash>::operator[](U&& key)const -> const_reference{ constexpr auto hashmap<Key,Value,N,Hash>::operator[](U&& key)const noexcept -> const_reference{
auto d = m_g[UHash{}(std::forward<U>(key)) % max_size]; auto d = m_g[UHash{}(std::forward<U>(key)) % max_size];
if(d & single_bucket_bit) if(d & single_bucket_bit)
return m_values[d & ~single_bucket_bit]; return m_values[d & ~single_bucket_bit];

View File

@ -26,7 +26,7 @@ namespace rexy::cx{
#include "../string_base.hpp" #include "../string_base.hpp"
#include "utility.hpp" #include "utility.hpp"
#include <type_traits>
//This is different from rexy::static_string in that this doesn't hold a pointer to a constant string array. //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 //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: public:
constexpr string(void) = default; constexpr string(void) = default;
template<size_t M> template<size_t M>
constexpr string(const char(&data)[M]): constexpr string(const char(&data)[M])noexcept:
m_length(M) m_length(M)
{ {
static_assert(M <= N); static_assert(M <= N);
@ -54,14 +54,14 @@ namespace rexy::cx{
m_data[i] = data[i]; m_data[i] = data[i];
} }
} }
constexpr string(const char* data): constexpr string(const char* data)noexcept:
m_length(cx::strlen(data)) m_length(cx::strlen(data))
{ {
for(size_t i = 0;i < m_length;++i){ for(size_t i = 0;i < m_length;++i){
m_data[i] = data[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) m_length(len)
{ {
for(size_t i = 0;i < m_length;++i){ 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()) m_length(str.length())
{ {
for(size_t i = 0;i < m_length;++i){ for(size_t i = 0;i < m_length;++i){
@ -77,56 +77,58 @@ namespace rexy::cx{
} }
} }
template<class Left, class Right> template<class Left, class Right>
constexpr string(const rexy::string_cat_expr<Left,Right>& expr){ constexpr string(const rexy::string_cat_expr<Left,Right>& expr)
noexcept(std::is_nothrow_invocable<rexy::detail::string_appender<cx::string<N>>, decltype(expr)>::value)
{
rexy::detail::string_appender<cx::string<N>> append(*this); rexy::detail::string_appender<cx::string<N>> append(*this);
append(expr); append(expr);
} }
constexpr string(const string&) = default; constexpr string(const string&)noexcept = default;
constexpr string(string&&) = default; constexpr string(string&&)noexcept = default;
~string(void) = default; ~string(void)noexcept = default;
constexpr string& operator=(const char* c){ constexpr string& operator=(const char* c)noexcept{
m_length = cx::strlen(c); m_length = cx::strlen(c);
for(size_t i = 0;i < m_length;++i){ for(size_t i = 0;i < m_length;++i){
m_data[i] = c[i]; m_data[i] = c[i];
} }
return *this; return *this;
} }
constexpr string& operator=(const string&) = default; constexpr string& operator=(const string&)noexcept = default;
constexpr string& operator=(string&&) = default; constexpr string& operator=(string&&)noexcept = default;
constexpr size_t length(void)const{ constexpr size_t length(void)const noexcept{
return m_length; return m_length;
} }
constexpr size_t capacity(void)const{ constexpr size_t capacity(void)const noexcept{
return max_size; return max_size;
} }
constexpr char* get(void){ constexpr char* get(void)noexcept{
return m_data; return m_data;
} }
constexpr const char* get(void)const{ constexpr const char* get(void)const noexcept{
return m_data; return m_data;
} }
constexpr operator char*(void){ constexpr operator char*(void)noexcept{
return m_data; return m_data;
} }
constexpr operator const char*(void)const{ constexpr operator const char*(void)const noexcept{
return m_data; return m_data;
} }
constexpr bool valid(void)const{ constexpr bool valid(void)const noexcept{
return m_length > 0; return m_length > 0;
} }
constexpr char& operator[](size_t i){ constexpr char& operator[](size_t i)noexcept{
return m_data[i]; 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]; return m_data[i];
} }
constexpr bool resize(size_t i){ constexpr bool resize(size_t i)noexcept{
if(i >= capacity()) if(i >= capacity())
return false; return false;
m_length = i; m_length = i;
@ -134,18 +136,18 @@ namespace rexy::cx{
return true; 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){ for(size_t i = 0;i < len;++i){
m_data[m_length++] = data[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)); append(data, cx::strlen(data));
} }
constexpr void append(const string& s){ constexpr void append(const string& s)noexcept{
append(s.get(), s.length()); 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()); append(s.get(), s.length());
} }
}; };
@ -166,15 +168,15 @@ namespace rexy::cx{
} }
template<class Str1, class Str2, std::enable_if_t<detail::is_cx_string<Str1,Str2>::value,int> = 0> template<class Str1, class Str2, std::enable_if_t<detail::is_cx_string<Str1,Str2>::value,int> = 0>
constexpr auto operator+(Str1&& l, Str2&& r){ constexpr auto operator+(Str1&& l, Str2&& r)noexcept{
return string_cat_expr(std::forward<Str1>(l), std::forward<Str2>(r)); return string_cat_expr(std::forward<Str1>(l), std::forward<Str2>(r));
} }
template<class Str1, std::enable_if_t<detail::is_cx_string<Str1>::value,int> = 0> template<class Str1, std::enable_if_t<detail::is_cx_string<Str1>::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<Str1>(l), rexy::static_string(r)); return string_cat_expr(std::forward<Str1>(l), rexy::static_string(r));
} }
template<class Str1, std::enable_if_t<detail::is_cx_string<Str1>::value,int> = 0> template<class Str1, std::enable_if_t<detail::is_cx_string<Str1>::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<Str1>(r)); return string_cat_expr(rexy::static_string(l), std::forward<Str1>(r));
} }
} }

View File

@ -28,7 +28,7 @@ namespace rexy::cx{
//jenkns one at a time hash //jenkns one at a time hash
template<class Str> template<class Str>
struct string_hash{ 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; size_t hash = salt;
for(size_t i = 0;i < s.length();++i){ for(size_t i = 0;i < s.length();++i){
hash += s[i]; hash += s[i];

View File

@ -20,45 +20,55 @@
#define REXY_CX_UTILITY_HPP #define REXY_CX_UTILITY_HPP
#include <utility> //forward, move #include <utility> //forward, move
#include <type_traits>
namespace rexy::cx{ namespace rexy::cx{
namespace{ namespace{
template<class T> template<class T>
constexpr void swap(T& l, T& r){ constexpr void swap(T& l, T& r)
noexcept(std::is_nothrow_copy_assignable<T>::value)
{
T tmp = l; T tmp = l;
l = r; l = r;
r = tmp; r = tmp;
} }
template<class T, class U = T> template<class T, class U = T>
constexpr T exchange(T& l, U&& r){ constexpr T exchange(T& l, U&& r)
noexcept(std::is_nothrow_assignable<T,U&&>::value &&
std::is_nothrow_move_assignable<T>::value)
{
T old = std::move(l); T old = std::move(l);
l = std::forward<U>(r); l = std::forward<U>(r);
return old; return old;
} }
template<class T> template<class T>
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; return l < r ? l : r;
} }
template<class T, class Compare> template<class T, class Compare>
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<Compare,const T&,const T&>::value)
{
return cmp(l, r) ? l : r; return cmp(l, r) ? l : r;
} }
template<class T> template<class T>
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; return l > r ? l : r;
} }
template<class T, class Compare> template<class T, class Compare>
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<Compare,const T&,const T&>::value)
{
return cmp(l, r) ? l : r; 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; size_t i = 0;
for(;c[i];++i); for(;c[i];++i);
return 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; using uchar = unsigned char;
for(;*l == *r && *l;++l, ++r); for(;*l == *r && *l;++l, ++r);
return (static_cast<uchar>(*l)) - (static_cast<uchar>(*r)); return (static_cast<uchar>(*l)) - (static_cast<uchar>(*r));

View File

@ -24,6 +24,8 @@
#include "utility.hpp" //swap #include "utility.hpp" //swap
#include <type_traits>
namespace rexy::cx{ namespace rexy::cx{
template<class T, size_t N> template<class T, size_t N>
@ -47,83 +49,88 @@ namespace rexy::cx{
size_type m_size = 0; size_type m_size = 0;
public: public:
constexpr vector(void) = default; constexpr vector(void)noexcept(std::is_nothrow_default_constructible<T>::value) = default;
constexpr vector(const vector&) = default; constexpr vector(const vector&)noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
constexpr vector(vector&&) = default; constexpr vector(vector&&)noexcept(std::is_nothrow_move_constructible<T>::value) = default;
constexpr vector(size_type count, const T& value){ constexpr vector(size_type count, const T& value)
noexcept(std::is_nothrow_copy_assignable<T>::value)
{
for(size_type i = 0;i < min(count, max_elements);++i){ for(size_type i = 0;i < min(count, max_elements);++i){
m_elements[i] = value; m_elements[i] = value;
} }
} }
~vector(void) = default; ~vector(void)noexcept = default;
constexpr vector& operator=(const vector&) = default; constexpr vector& operator=(const vector&)noexcept(std::is_nothrow_copy_assignable<T>::value) = default;
constexpr vector& operator=(vector&&) = default; constexpr vector& operator=(vector&&)noexcept(std::is_nothrow_move_assignable<T>::value) = default;
constexpr reference at(size_type pos){ constexpr reference at(size_type pos)noexcept{
return m_elements[pos]; 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]; return m_elements[pos];
} }
constexpr reference operator[](size_type pos){ constexpr reference operator[](size_type pos)noexcept{
return m_elements[pos]; 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]; return m_elements[pos];
} }
constexpr reference front(void){ constexpr reference front(void)noexcept{
return m_elements[0]; return m_elements[0];
} }
constexpr const_reference front(void)const{ constexpr const_reference front(void)const noexcept{
return m_elements[0]; return m_elements[0];
} }
constexpr reference back(void){ constexpr reference back(void)noexcept{
return m_elements[m_size-1]; 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]; return m_elements[m_size-1];
} }
constexpr const_pointer data(void)const{ constexpr const_pointer data(void)const noexcept{
return m_elements; return m_elements;
} }
constexpr iterator begin(void){ constexpr iterator begin(void)noexcept{
return m_elements; return m_elements;
} }
constexpr const_iterator begin(void)const{ constexpr const_iterator begin(void)const noexcept{
return m_elements; return m_elements;
} }
constexpr const_iterator cbegin(void)const{ constexpr const_iterator cbegin(void)const noexcept{
return m_elements; return m_elements;
} }
constexpr iterator end(void){ constexpr iterator end(void)noexcept{
return m_elements+max_elements; return m_elements+max_elements;
} }
constexpr const_iterator end(void)const{ constexpr const_iterator end(void)const noexcept{
return m_elements+max_elements; return m_elements+max_elements;
} }
constexpr const_iterator cend(void)const{ constexpr const_iterator cend(void)const noexcept{
return m_elements+max_elements; return m_elements+max_elements;
} }
constexpr bool empty(void)const{ constexpr bool empty(void)const noexcept{
return m_size == 0; return m_size == 0;
} }
constexpr size_type size(void)const{ constexpr size_type size(void)const noexcept{
return m_size; return m_size;
} }
constexpr size_type max_size(void)const{ constexpr size_type max_size(void)const noexcept{
return max_elements; return max_elements;
} }
constexpr size_type capacity(void)const{ constexpr size_type capacity(void)const noexcept{
return max_elements; return max_elements;
} }
constexpr void clear(void){ constexpr void clear(void)noexcept{
m_size = 0; 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<T>::value &&
std::is_nothrow_copy_assignable<T>::value)
{
auto start = pos; auto start = pos;
auto it = pos; auto it = pos;
++pos; ++pos;
@ -133,7 +140,9 @@ namespace rexy::cx{
*start = value; *start = value;
return start; return start;
} }
constexpr iterator insert(const_iterator pos, T&& value){ constexpr iterator insert(const_iterator pos, T&& value)
noexcept(std::is_nothrow_move_assignable<T>::value)
{
auto start = pos; auto start = pos;
auto it = pos; auto it = pos;
++pos; ++pos;
@ -144,7 +153,10 @@ namespace rexy::cx{
return start; return start;
} }
template<class... Args> template<class... Args>
constexpr iterator emplace(const_iterator pos, Args&&... args){ constexpr iterator emplace(const_iterator pos, Args&&... args)
noexcept(std::is_nothrow_move_assignable<T>::value &&
std::is_nothrow_constructible<T,Args&&...>::value)
{
auto start = pos; auto start = pos;
auto it = pos; auto it = pos;
++pos; ++pos;
@ -154,7 +166,9 @@ namespace rexy::cx{
*start = T{std::forward<Args>(args)...}; *start = T{std::forward<Args>(args)...};
return start; return start;
} }
constexpr iterator erase(const_iterator pos){ constexpr iterator erase(const_iterator pos)
noexcept(std::is_nothrow_move_assignable<T>::value)
{
auto start = pos; auto start = pos;
auto it = pos; auto it = pos;
++pos; ++pos;
@ -163,23 +177,27 @@ namespace rexy::cx{
} }
return start; return start;
} }
constexpr iterator push_back(const T& value){ constexpr iterator push_back(const T& value)
noexcept(std::is_nothrow_copy_assignable<T>::value)
{
m_elements[m_size] = value; m_elements[m_size] = value;
return m_elements+(m_size++); return m_elements+(m_size++);
} }
template<class... Args> template<class... Args>
constexpr iterator emplace_back(Args&&... args){ constexpr iterator emplace_back(Args&&... args)
noexcept(std::is_nothrow_constructible<T,Args&&...>::value)
{
m_elements[m_size++] = T{std::forward<Args>(args)...}; m_elements[m_size++] = T{std::forward<Args>(args)...};
return m_elements+(m_size++); return m_elements+(m_size++);
} }
constexpr void pop_back(void){ constexpr void pop_back(void)noexcept{
--m_size; --m_size;
} }
constexpr void resize(size_type count){ constexpr void resize(size_type count)noexcept{
if(count <= max_size()) if(count <= max_size())
m_size = count; 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 > m_size){
if(count <= max_size()){ if(count <= max_size()){
for(size_type i = m_size;i < count;++i){ for(size_type i = m_size;i < count;++i){
@ -190,20 +208,24 @@ namespace rexy::cx{
m_size = count; m_size = count;
} }
} }
constexpr void fill(const T& value){ constexpr void fill(const T& value)
noexcept(std::is_nothrow_copy_assignable<T>::value)
{
for(auto it = begin();it != end();++it){ for(auto it = begin();it != end();++it){
*it = value; *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; size_type i = 0;
for(;i < m_size;++i){ 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){ 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);
} }
}; };

View File

@ -25,44 +25,64 @@
namespace rexy{ namespace rexy{
template<class Al, class Str = rexy::string, detail::enable_if_concrete_string<Str> = 0> template<class Al, class Str = rexy::string, detail::enable_if_concrete_string<Str> = 0>
auto binary_to_string(const binary_data<Al>& b){ auto binary_to_string(const binary_data<Al>& b)
noexcept(std::is_nothrow_constructible<Str, decltype(b.size())>::value)
{
Str s(b.size()+1); Str s(b.size()+1);
memcpy(s.get(), b.get(), b.size()); memcpy(s.get(), b.get(), b.size());
s[b.size()] = 0; s[b.size()] = 0;
return s; return s;
} }
template<class Al, class Str = rexy::string, detail::enable_if_concrete_string<Str> = 0, std::enable_if_t<std::is_same<std::decay_t<Al>,typename Str::allocator_type>::value,int> = 0> template<class Al, class Str = rexy::string, detail::enable_if_concrete_string<Str> = 0, std::enable_if_t<std::is_same<std::decay_t<Al>,typename Str::allocator_type>::value,int> = 0>
auto binary_to_string(binary_data<Al>&& b){ auto binary_to_string(binary_data<Al>&& b)
noexcept(std::is_nothrow_default_constructible<Str>::value &&
noexcept(std::declval<Str>().reset(nullptr, 0)) &&
noexcept(b.release()))
{
Str s; Str s;
s.reset(b.get(), b.size()); s.reset(b.get(), b.size());
b.release(); b.release();
return s; return s;
} }
template<class Bin = rexy::binary, detail::enable_if_binary<Bin> = 0> template<class Bin = rexy::binary, detail::enable_if_binary<Bin> = 0>
auto string_to_binary(const string_base& s){ auto string_to_binary(const string_base& s)
noexcept(std::is_nothrow_constructible<Bin, decltype(s.length())>::value &&
noexcept(std::declval<Bin>().append(nullptr, 0)))
{
Bin b(s.length()+1); Bin b(s.length()+1);
b.append(s.get(), s.length()+1); b.append(s.get(), s.length()+1);
return b; return b;
} }
template<class Al, class Bin = rexy::binary, detail::enable_if_binary<Bin> = 0, std::enable_if_t<std::is_same<std::decay_t<Al>,typename Bin::allocator_type>::value,int> = 0> template<class Al, class Bin = rexy::binary, detail::enable_if_binary<Bin> = 0, std::enable_if_t<std::is_same<std::decay_t<Al>,typename Bin::allocator_type>::value,int> = 0>
auto string_to_binary(string_intermediary<Al>&& s){ auto string_to_binary(string_intermediary<Al>&& s)
noexcept(std::is_nothrow_default_constructible<Bin>::value &&
noexcept(std::declval<Bin>().reset(nullptr, 0)) &&
noexcept(s.release()))
{
Bin b; Bin b;
b.reset(s.get(), s.length()+1); b.reset(s.get(), s.length()+1);
s.release(); s.release();
return b; return b;
} }
template<class L, class R, detail::enable_if_binary<L> = 0, detail::enable_if_concrete_string<R> = 0> template<class L, class R, detail::enable_if_binary<L> = 0, detail::enable_if_concrete_string<R> = 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); l.append(r.get(), r.length()+1);
return l; return l;
} }
template<class L, class R, detail::enable_if_binary<L> = 0, detail::enable_if_string<R> = 0, std::enable_if_t<!detail::is_concrete_string<R>::value,int> = 0> template<class L, class R, detail::enable_if_binary<L> = 0, detail::enable_if_string<R> = 0, std::enable_if_t<!detail::is_concrete_string<R>::value,int> = 0>
decltype(auto) operator+=(L& l, R&& r){ decltype(auto) operator+=(L& l, R&& r)
noexcept(std::is_nothrow_constructible<rexy::string,R&&>::value &&
std::is_nothrow_assignable<L,rexy::string>::value)
{
rexy::string concrete = r; rexy::string concrete = r;
return (l = concrete); return (l = concrete);
} }
template<class L, class R, detail::enable_if_concrete_string<L> = 0, detail::enable_if_binary<R> = 0> template<class L, class R, detail::enable_if_concrete_string<L> = 0, detail::enable_if_binary<R> = 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); l.resize(l.length(), r.size() + 1);
memcpy(l.get()+l.length()+1, r.get(), r.size()); memcpy(l.get()+l.length()+1, r.get(), r.size());
return l; return l;

View File

@ -25,6 +25,7 @@
#include "string.hpp" #include "string.hpp"
#include "binary.hpp" #include "binary.hpp"
#include "cx/utility.hpp" #include "cx/utility.hpp"
#include <type_traits>
namespace rexy{ namespace rexy{
@ -35,37 +36,37 @@ namespace rexy{
FILE* m_fp = nullptr; FILE* m_fp = nullptr;
public: public:
constexpr filerd(void) = default; constexpr filerd(void)noexcept = default;
filerd(const char* f, const char* mode = "r"); filerd(const char* f, const char* mode = "r")noexcept;
filerd(const filerd&) = delete; filerd(const filerd&) = delete;
constexpr filerd(filerd&& f): constexpr filerd(filerd&& f)noexcept:
m_fp(cx::exchange(f.m_fp, nullptr)){} m_fp(cx::exchange(f.m_fp, nullptr)){}
~filerd(void); ~filerd(void)noexcept;
filerd& operator=(const filerd&) = delete; filerd& operator=(const filerd&) = delete;
constexpr filerd& operator=(filerd&& f){ constexpr filerd& operator=(filerd&& f)noexcept{
cx::swap(m_fp, f.m_fp); cx::swap(m_fp, f.m_fp);
return *this; return *this;
} }
void reset(FILE* fp = nullptr); void reset(FILE* fp = nullptr)noexcept;
FILE* release(void); FILE* release(void)noexcept;
size_t length(void); size_t length(void)noexcept;
size_t position(void)const; size_t position(void)const noexcept;
void rewind(size_t pos = 0); void rewind(size_t pos = 0)noexcept;
operator FILE*(void); operator FILE*(void)noexcept;
operator const FILE*(void)const; operator const FILE*(void)const noexcept;
FILE* get(void); FILE* get(void)noexcept;
const FILE* get(void)const; const FILE* get(void)const noexcept;
operator bool(void)const; operator bool(void)const noexcept;
size_t read(char* dest, size_t bytes); size_t read(char* dest, size_t bytes)noexcept;
rexy::string read(size_t bytes); rexy::string read(size_t bytes)noexcept;
rexy::string readln(size_t max = 0); rexy::string readln(size_t max = 0)noexcept;
rexy::binary read_bin(size_t bytes); rexy::binary read_bin(size_t bytes)noexcept(std::is_nothrow_constructible<rexy::binary, rexy::steal<char*>, size_t, size_t>::value);
size_t write(const char* c, size_t bytes); size_t write(const char* c, size_t bytes)noexcept;
size_t write(const rexy::string_base&); size_t write(const rexy::string_base&)noexcept;
}; };
} }

View File

@ -21,6 +21,8 @@
#include <utility> //forward #include <utility> //forward
#include <type_traits>
namespace rexy{ namespace rexy{
template<class T> template<class T>
@ -31,7 +33,8 @@ namespace rexy{
public: public:
template<class U> template<class U>
constexpr steal(U&& u): constexpr steal(U&& u)
noexcept(std::is_nothrow_constructible<T,U&&>::value):
m_val(std::forward<U>(u)){} m_val(std::forward<U>(u)){}
steal(const steal&) = delete; steal(const steal&) = delete;
@ -39,10 +42,10 @@ namespace rexy{
steal& operator=(const steal&) = delete; steal& operator=(const steal&) = delete;
steal& operator=(steal&&) = delete; steal& operator=(steal&&) = delete;
constexpr T&& value(void){ constexpr T&& value(void)noexcept{
return std::forward<T>(m_val); return std::forward<T>(m_val);
} }
constexpr const T& value(void)const{ constexpr const T& value(void)const noexcept{
return m_val; return m_val;
} }
}; };

View File

@ -29,4 +29,8 @@ namespace rexy{
} }
#ifdef REXY_BINARY_HPP
#include "detail/binary_string_conv.hpp"
#endif
#endif #endif

View File

@ -22,6 +22,7 @@
#include <type_traits> //is_same, integral_contant, enable_if, etc #include <type_traits> //is_same, integral_contant, enable_if, etc
#include <utility> //forward #include <utility> //forward
#include <cstdlib> //size_t #include <cstdlib> //size_t
#include <cstring> //strlen
#include "steal.hpp" #include "steal.hpp"
#include "cx/utility.hpp" #include "cx/utility.hpp"
@ -40,35 +41,36 @@ namespace rexy{
char* m_data = nullptr; char* m_data = nullptr;
protected: protected:
constexpr string_base(void) = default; constexpr string_base(void)noexcept = default;
constexpr string_base(size_t len): constexpr string_base(size_t len)noexcept:
m_cap(len){} m_cap(len){}
//Initialize without copying //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){} 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){} m_length(len), m_cap(cap), m_data(data){}
//Copy ctor (do nothing) //Copy ctor (do nothing)
constexpr string_base(const string_base&){} constexpr string_base(const string_base&)noexcept{}
~string_base(void) = default; ~string_base(void)noexcept = default;
public: public:
//Stop managing stored pointer. Does not free. //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 //Length of string not including null terminator
constexpr size_t length(void)const{return m_length;} constexpr size_t length(void)const noexcept{return m_length;}
constexpr size_t capacity(void)const{return m_cap;} constexpr size_t capacity(void)const noexcept{return m_cap;}
//direct access to managed pointer //direct access to managed pointer
constexpr char* get(void){return m_data;} constexpr char* get(void)noexcept{return m_data;}
constexpr const char* get(void)const{return m_data;} constexpr const char* get(void)const noexcept{return m_data;}
constexpr operator char*(void){return m_data;} constexpr operator char*(void)noexcept{return m_data;}
constexpr operator const char*(void)const{return m_data;} constexpr operator const char*(void)const noexcept{return m_data;}
//true if m_data is not null //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 char& operator[](size_t i)noexcept{return m_data[i];}
constexpr const char& operator[](size_t i)const{return m_data[i];} constexpr const char& operator[](size_t i)const noexcept{return m_data[i];}
}; };
@ -79,46 +81,56 @@ namespace rexy{
public: public:
using allocator_type = Allocator; 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: public:
constexpr string_intermediary(void); constexpr string_intermediary(void)noexcept;
constexpr string_intermediary(rexy::steal<char*> data, size_t len); constexpr string_intermediary(rexy::steal<char*> data, size_t len)noexcept;
constexpr string_intermediary(rexy::steal<char*> data, size_t len, size_t cap); constexpr string_intermediary(rexy::steal<char*> data, size_t len, size_t cap)noexcept;
[[deprecated]] constexpr string_intermediary(char* data, size_t len); constexpr string_intermediary(rexy::steal<char*> data)noexcept;
string_intermediary(const char* data, size_t len); [[deprecated]] constexpr string_intermediary(char* data, size_t len)noexcept;
[[deprecated]] constexpr string_intermediary(char* data, size_t len, size_t cap); [[deprecated]] constexpr string_intermediary(char* data, size_t len, size_t cap)noexcept;
string_intermediary(const char* data); string_intermediary(const char* data, size_t len)noexcept(noexcept(Allocator::copy(data,len)));
constexpr string_intermediary(rexy::steal<char*>); string_intermediary(const char* data)noexcept(noexcept(strlen(data)) && noexcept(Allocator::copy(data, m_cap)));
string_intermediary(size_t len); string_intermediary(size_t len)noexcept(noexcept(Allocator::allocate(len)));
string_intermediary(size_t len, size_t cap); string_intermediary(size_t len, size_t cap)noexcept(noexcept(Allocator::allocate(len)));
//normal copy and move ctors //normal copy and move ctors
string_intermediary(const string_intermediary& b); string_intermediary(const string_intermediary& b)noexcept(noexcept(Allocator::copy(b.m_data, b.m_length)));
constexpr string_intermediary(string_intermediary&& s); 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 //dtor
~string_intermediary(void); ~string_intermediary(void)noexcept(noexcept(Allocator::free(m_data)));
string_intermediary& operator=(const string_intermediary& s); string_intermediary& operator=(const string_intermediary& s)
constexpr string_intermediary& operator=(string_intermediary&& s); noexcept(std::is_nothrow_copy_constructible<string_intermediary<Allocator>>::value &&
std::is_nothrow_move_assignable<string_intermediary<Allocator>>::value);
constexpr string_intermediary& operator=(string_intermediary&& s)noexcept(noexcept(cx::swap(m_data, s.m_data)));
//Copy from c string //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 //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 //Replace managed pointer. Frees existing value
void reset(char* val = nullptr); void reset(char* val = nullptr)noexcept(noexcept(Allocator::free(m_data)));
void reset(char* val, size_t len); void reset(char* val, size_t len)noexcept(noexcept(Allocator::free(m_data)));
bool resize(size_t newsize); bool resize(size_t newsize)noexcept(std::is_nothrow_copy_constructible<string_intermediary<Allocator>>::value &&
void append(const char* data, size_t len); std::is_nothrow_move_assignable<string_intermediary<Allocator>>::value);
void append(const char* data); void append(const char* data, size_t len)noexcept(std::is_nothrow_constructible<string_intermediary<Allocator>,decltype(m_length)>::value);
void append(const string_base& s); void append(const char* data)noexcept(std::is_nothrow_constructible<string_intermediary<Allocator>,decltype(m_length)>::value);
void append(const string_base& s)noexcept(std::is_nothrow_constructible<string_intermediary<Allocator>,decltype(m_length)>::value);
private:
string_intermediary& _copy_string(const char* s, size_t len);
}; };
namespace detail{
template<class T>
struct string_appender;
}
//Like an expression template but not really //Like an expression template but not really
template<class Left, class Right> template<class Left, class Right>
class string_cat_expr : public string_expr class string_cat_expr : public string_expr
@ -129,14 +141,18 @@ namespace rexy{
public: public:
template<class T, class U> template<class T, class U>
constexpr string_cat_expr(T&& l, U&& r); constexpr string_cat_expr(T&& l, U&& r)noexcept(std::is_nothrow_constructible<Left,T&&>::value &&
constexpr string_cat_expr(string_cat_expr&& s); std::is_nothrow_constructible<Right,U&&>::value);
constexpr string_cat_expr(string_cat_expr&& s)noexcept(std::is_nothrow_constructible<Left,decltype(s.m_l)>::value &&
std::is_nothrow_constructible<Right,decltype(s.m_r)>::value);
constexpr size_t length(void)const; constexpr size_t length(void)const noexcept(noexcept(m_l.length()) && noexcept(m_r.length()));
template<class Alloc> template<class Alloc>
operator string_intermediary<Alloc>(void); operator string_intermediary<Alloc>(void)
constexpr const Left& left(void)const; noexcept(std::is_nothrow_constructible<string_intermediary<Alloc>, size_t>::value &&
constexpr const Right& right(void)const; std::is_nothrow_invocable<detail::string_appender<string_intermediary<Alloc>>,decltype(*this)>::value);
constexpr const Left& left(void)const noexcept;
constexpr const Right& right(void)const noexcept;
}; };
template<class Left, class Right> template<class Left, class Right>
string_cat_expr(Left&, Right&) -> string_cat_expr<Left&,Right&>; string_cat_expr(Left&, Right&) -> string_cat_expr<Left&,Right&>;
@ -153,16 +169,16 @@ namespace rexy{
class static_string : public string_base class static_string : public string_base
{ {
public: public:
constexpr static_string(void) = default; constexpr static_string(void)noexcept = default;
constexpr static_string(const char* str, size_t len); constexpr static_string(const char* str, size_t len)noexcept;
constexpr static_string(const char* c); constexpr static_string(const char* c)noexcept;
constexpr static_string(const static_string& s); constexpr static_string(const static_string& s)noexcept;
constexpr static_string(static_string&& s); constexpr static_string(static_string&& s)noexcept;
~static_string(void) = default; ~static_string(void)noexcept = default;
constexpr static_string& operator=(const char* c); constexpr static_string& operator=(const char* c)noexcept;
constexpr static_string& operator=(const static_string& s); constexpr static_string& operator=(const static_string& s)noexcept;
constexpr static_string& operator=(static_string&&); constexpr static_string& operator=(static_string&&)noexcept;
}; };
@ -189,43 +205,55 @@ namespace rexy{
private: private:
Targ& m_targ; Targ& m_targ;
public: public:
constexpr string_appender(Targ& t); constexpr string_appender(Targ& t)noexcept;
template<class L, class R> template<class L, class R>
constexpr void operator()(const string_cat_expr<L,R>& str); constexpr void operator()(const string_cat_expr<L,R>& str)
noexcept(noexcept((*this)(str.left())) && noexcept((*this)(str.right())));
template<class Str, std::enable_if_t<!rexy::is_template_type<Str,string_cat_expr>::value,int> = 0> template<class Str, std::enable_if_t<!rexy::is_template_type<Str,string_cat_expr>::value,int> = 0>
constexpr void operator()(Str&& str); constexpr void operator()(Str&& str)noexcept(noexcept(m_targ.append(str.get(), str.length())));
}; };
} //namespace detail } //namespace detail
template<class Str1, class Str2, detail::enable_if_concrete_string<Str1,Str2> = 0> template<class Str1, class Str2, detail::enable_if_concrete_string<Str1,Str2> = 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()); return left.valid() && right.valid() && left.length() == right.length() && !cx::strcmp(left.get(), right.get());
} }
template<class Str1, class Str2, detail::enable_if_concrete_string<Str1,Str2> = 0> template<class Str1, class Str2, detail::enable_if_concrete_string<Str1,Str2> = 0>
constexpr bool operator!=(Str1&& left, Str2&& right){ constexpr bool operator!=(Str1&& left, Str2&& right)noexcept{
return !(left == right); return !(left == right);
} }
template<class Left, class Right, detail::enable_if_string<Left,Right> = 0> template<class Left, class Right, detail::enable_if_string<Left,Right> = 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<Left>(l), std::forward<Right>(r))))
{
return string_cat_expr(std::forward<Left>(l), std::forward<Right>(r)); return string_cat_expr(std::forward<Left>(l), std::forward<Right>(r));
} }
template<class Right, detail::enable_if_string<Right> = 0> template<class Right, detail::enable_if_string<Right> = 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>(right))))
{
return string_cat_expr(rexy::static_string(left), std::forward<Right>(right)); return string_cat_expr(rexy::static_string(left), std::forward<Right>(right));
} }
template<class Left, detail::enable_if_string<Left> = 0> template<class Left, detail::enable_if_string<Left> = 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>(left), rexy::static_string(right))))
{
return rexy::string_cat_expr(std::forward<Left>(left), rexy::static_string(right)); return rexy::string_cat_expr(std::forward<Left>(left), rexy::static_string(right));
} }
template<class Left, class Right, detail::enable_if_concrete_string<Left> = 0, detail::enable_if_string<Right> = 0> template<class Left, class Right, detail::enable_if_concrete_string<Left> = 0, detail::enable_if_string<Right> = 0>
decltype(auto) operator+=(Left& l, Right&& r){ decltype(auto) operator+=(Left& l, Right&& r)
noexcept(noexcept(l + std::forward<Right>(r)) && std::is_nothrow_assignable<Left, decltype(l + std::forward<Right>(r))>::value)
{
return l = (l + std::forward<Right>(r)); return l = (l + std::forward<Right>(r));
} }
template<class Left, detail::enable_if_concrete_string<Left> = 0> template<class Left, detail::enable_if_concrete_string<Left> = 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<Left, decltype(l + r)>::value)
{
return l = (l + r); return l = (l + r);
} }
} }
@ -233,15 +261,11 @@ namespace rexy{
#include "string_base.tpp" #include "string_base.tpp"
namespace{ 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); return rexy::static_string(str, len);
} }
} }
#ifdef REXY_BINARY_HPP
#include "detail/binary_string_conv.hpp"
#endif
#ifdef REXY_CX_HASH_HPP #ifdef REXY_CX_HASH_HPP
#include "cx/string_hash.hpp" #include "cx/string_hash.hpp"
#endif #endif

View File

@ -30,27 +30,37 @@
namespace rexy{ namespace rexy{
template<class Allocator> template<class Allocator>
constexpr string_intermediary<Allocator>::string_intermediary(void){} constexpr string_intermediary<Allocator>::string_intermediary(void)noexcept{}
template<class Allocator> template<class Allocator>
/*deprecated*/ constexpr string_intermediary<Allocator>::string_intermediary(char* data, size_t len): constexpr string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data)noexcept:
string_base(data, len){} string_base(data.value() ? cx::strlen(data.value()) : 0)
{
m_data = data.value();
m_length = m_cap;
}
template<class Allocator> template<class Allocator>
constexpr string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data, size_t len): constexpr string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data, size_t len)noexcept:
string_base(data.value(), len){} string_base(data.value(), len){}
template<class Allocator> template<class Allocator>
/*deprecated*/ constexpr string_intermediary<Allocator>::string_intermediary(char* data, size_t len, size_t cap): constexpr string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data, size_t len, size_t cap)noexcept:
string_base(data, len, cap){}
template<class Allocator>
constexpr string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data, size_t len, size_t cap):
string_base(data.value(), len, cap){} string_base(data.value(), len, cap){}
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>::string_intermediary(const char* data, size_t len): /*deprecated*/ constexpr string_intermediary<Allocator>::string_intermediary(char* data, size_t len)noexcept:
string_base(data, len){}
template<class Allocator>
/*deprecated*/ constexpr string_intermediary<Allocator>::string_intermediary(char* data, size_t len, size_t cap)noexcept:
string_base(data, len, cap){}
template<class Allocator>
string_intermediary<Allocator>::string_intermediary(const char* data, size_t len)
noexcept(noexcept(Allocator::copy(data,len))):
string_base(reinterpret_cast<char*>(len ? Allocator::copy(data, len+1) : nullptr), len) string_base(reinterpret_cast<char*>(len ? Allocator::copy(data, len+1) : nullptr), len)
{ {
m_data[len] = 0; m_data[len] = 0;
} }
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>::string_intermediary(const char* data): string_intermediary<Allocator>::string_intermediary(const char* data)
noexcept(noexcept(strlen(data)) &&
noexcept(Allocator::copy(data, m_cap))):
string_base(data ? strlen(data) : 0) string_base(data ? strlen(data) : 0)
{ {
if(m_cap){ if(m_cap){
@ -59,20 +69,15 @@ namespace rexy{
} }
} }
template<class Allocator> template<class Allocator>
constexpr string_intermediary<Allocator>::string_intermediary(rexy::steal<char*> data): string_intermediary<Allocator>::string_intermediary(size_t len)
string_base(data.value() ? cx::strlen(data.value()) : 0) noexcept(noexcept(Allocator::allocate(len))):
{
m_data = data.value();
m_length = m_cap;
}
template<class Allocator>
string_intermediary<Allocator>::string_intermediary(size_t len):
string_base(reinterpret_cast<char*>(len ? Allocator::allocate(len+1) : nullptr), len) string_base(reinterpret_cast<char*>(len ? Allocator::allocate(len+1) : nullptr), len)
{ {
m_data[len] = 0; m_data[len] = 0;
} }
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>::string_intermediary(size_t len, size_t cap): string_intermediary<Allocator>::string_intermediary(size_t len, size_t cap)
noexcept(noexcept(Allocator::allocate(len))):
string_base(reinterpret_cast<char*>(len ? Allocator::allocate(len+1) : nullptr), len, cap) string_base(reinterpret_cast<char*>(len ? Allocator::allocate(len+1) : nullptr), len, cap)
{ {
m_data[len] = 0; m_data[len] = 0;
@ -80,24 +85,32 @@ namespace rexy{
//normal copy and move ctors //normal copy and move ctors
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>::string_intermediary(const string_intermediary& b): string_intermediary<Allocator>::string_intermediary(const string_intermediary& b)
noexcept(noexcept(Allocator::copy(b.m_data, b.m_length))):
string_base(reinterpret_cast<char*>(b.m_length ? Allocator::copy(b.m_data, b.m_length+1) : nullptr), b.m_length, b.m_cap){} string_base(reinterpret_cast<char*>(b.m_length ? Allocator::copy(b.m_data, b.m_length+1) : nullptr), b.m_length, b.m_cap){}
template<class Allocator> template<class Allocator>
constexpr string_intermediary<Allocator>::string_intermediary(string_intermediary&& s): constexpr string_intermediary<Allocator>::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){} string_base(cx::exchange(s.m_data, nullptr), s.m_length, s.m_cap){}
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>::string_intermediary(const string_base& b): string_intermediary<Allocator>::string_intermediary(const string_base& b)
noexcept(noexcept(Allocator::copy(b.get(), b.length()))):
string_base(reinterpret_cast<char*>(b.length() ? Allocator::copy(b.get(), b.length()+1) : nullptr), b.length(), b.capacity()){} string_base(reinterpret_cast<char*>(b.length() ? Allocator::copy(b.get(), b.length()+1) : nullptr), b.length(), b.capacity()){}
//dtor //dtor
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>::~string_intermediary(void){ string_intermediary<Allocator>::~string_intermediary(void)
noexcept(noexcept(Allocator::free(m_data)))
{
Allocator::free(m_data); Allocator::free(m_data);
} }
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(const string_intermediary& s){ string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(const string_intermediary& s)
noexcept(std::is_nothrow_copy_constructible<string_intermediary<Allocator>>::value &&
std::is_nothrow_move_assignable<string_intermediary<Allocator>>::value)
{
if(s.m_length < m_length){ if(s.m_length < m_length){
memcpy(m_data, s.m_data, s.m_length+1); memcpy(m_data, s.m_data, s.m_length+1);
m_length = s.m_length; m_length = s.m_length;
@ -107,7 +120,9 @@ namespace rexy{
return (*this = std::move(tmp)); return (*this = std::move(tmp));
} }
template<class Allocator> template<class Allocator>
constexpr string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(string_intermediary&& s){ constexpr string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(string_intermediary&& s)
noexcept(noexcept(cx::swap(m_data, s.m_data)))
{
cx::swap(m_data, s.m_data); cx::swap(m_data, s.m_data);
m_length = s.m_length; m_length = s.m_length;
m_cap = s.m_cap; m_cap = s.m_cap;
@ -115,32 +130,43 @@ namespace rexy{
} }
//Copy from c string //Copy from c string
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(const char* c){ string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(const char* c)
noexcept(noexcept(_copy_string(c, 0)))
{
return _copy_string(c, strlen(c)); return _copy_string(c, strlen(c));
} }
//Copy from other string_base //Copy from other string_base
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(const string_base& s){ string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(const string_base& s)
noexcept(noexcept(_copy_string(s.get(), 0)))
{
return _copy_string(s.get(), s.length()); return _copy_string(s.get(), s.length());
} }
//Replace managed pointer. Frees existing value //Replace managed pointer. Frees existing value
template<class Allocator> template<class Allocator>
void string_intermediary<Allocator>::reset(char* val){ void string_intermediary<Allocator>::reset(char* val)
noexcept(noexcept(Allocator::free(m_data)))
{
Allocator::free(m_data); Allocator::free(m_data);
m_data = val; m_data = val;
m_length = val ? strlen(val) : 0; m_length = val ? strlen(val) : 0;
m_cap = m_length; m_cap = m_length;
} }
template<class Allocator> template<class Allocator>
void string_intermediary<Allocator>::reset(char* val, size_t len){ void string_intermediary<Allocator>::reset(char* val, size_t len)
noexcept(noexcept(Allocator::free(m_data)))
{
Allocator::free(m_data); Allocator::free(m_data);
m_data = val; m_data = val;
m_length = len; m_length = len;
m_cap = len; m_cap = len;
} }
template<class Allocator> template<class Allocator>
bool string_intermediary<Allocator>::resize(size_t newsize){ bool string_intermediary<Allocator>::resize(size_t newsize)
noexcept(std::is_nothrow_copy_constructible<string_intermediary<Allocator>>::value &&
std::is_nothrow_move_assignable<string_intermediary<Allocator>>::value)
{
if(newsize < m_cap) if(newsize < m_cap)
return false; return false;
string_intermediary tmp(newsize); string_intermediary tmp(newsize);
@ -152,7 +178,9 @@ namespace rexy{
return true; return true;
} }
template<class Allocator> template<class Allocator>
void string_intermediary<Allocator>::append(const char* data, size_t len){ void string_intermediary<Allocator>::append(const char* data, size_t len)
noexcept(std::is_nothrow_constructible<string_intermediary<Allocator>,decltype(m_length)>::value)
{
if(len+m_length <= m_cap){ if(len+m_length <= m_cap){
memcpy(m_data+m_length, data, len); memcpy(m_data+m_length, data, len);
m_length += len; m_length += len;
@ -160,25 +188,32 @@ namespace rexy{
}else{ }else{
string_intermediary tmp(cx::max(m_length + len, m_cap*2)); string_intermediary tmp(cx::max(m_length + len, m_cap*2));
if(m_data) if(m_data)
memcpy(STOP_STRING_ALIASING_WARNING(tmp).m_data, m_data, m_length); memcpy(STOP_STRICT_ALIAS_WARNING(tmp).m_data, m_data, m_length);
memcpy(STOP_STRING_ALIASING_WARNING(tmp).m_data+m_length, data, len); memcpy(STOP_STRICT_ALIAS_WARNING(tmp).m_data+m_length, data, len);
STOP_STRING_ALIASING_WARNING(tmp).m_length = len+m_length; STOP_STRICT_ALIAS_WARNING(tmp).m_length = len+m_length;
tmp[m_length+len] = 0; tmp[m_length+len] = 0;
*this = std::move(tmp); *this = std::move(tmp);
} }
} }
template<class Allocator> template<class Allocator>
void string_intermediary<Allocator>::append(const char* data){ void string_intermediary<Allocator>::append(const char* data)
noexcept(std::is_nothrow_constructible<string_intermediary<Allocator>,decltype(m_length)>::value)
{
if(data) if(data)
append(data, strlen(data)); append(data, strlen(data));
} }
template<class Allocator> template<class Allocator>
void string_intermediary<Allocator>::append(const string_base& s){ void string_intermediary<Allocator>::append(const string_base& s)
noexcept(std::is_nothrow_constructible<string_intermediary<Allocator>,decltype(m_length)>::value)
{
append(s.get(), s.length()); append(s.get(), s.length());
} }
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>& string_intermediary<Allocator>::_copy_string(const char* s, size_t len){ string_intermediary<Allocator>& string_intermediary<Allocator>::_copy_string(const char* s, size_t len)
noexcept(noexcept(Allocator::free(m_data)) &&
noexcept(Allocator::copy(s, len)))
{
if(!len){ if(!len){
Allocator::free(m_data); Allocator::free(m_data);
m_length = 0; m_length = 0;
@ -204,21 +239,30 @@ namespace rexy{
template<class Left, class Right> template<class Left, class Right>
template<class T, class U> template<class T, class U>
constexpr string_cat_expr<Left,Right>::string_cat_expr(T&& l, U&& r): constexpr string_cat_expr<Left,Right>::string_cat_expr(T&& l, U&& r)
noexcept(std::is_nothrow_constructible<Left,T&&>::value &&
std::is_nothrow_constructible<Right,U&&>::value):
m_l(std::forward<T>(l)), m_l(std::forward<T>(l)),
m_r(std::forward<U>(r)){} m_r(std::forward<U>(r)){}
template<class Left, class Right> template<class Left, class Right>
constexpr string_cat_expr<Left,Right>::string_cat_expr(string_cat_expr&& s): constexpr string_cat_expr<Left,Right>::string_cat_expr(string_cat_expr&& s)
noexcept(std::is_nothrow_constructible<Left,decltype(s.m_l)>::value &&
std::is_nothrow_constructible<Right,decltype(s.m_r)>::value):
m_l(std::forward<Left>(s.m_l)), m_l(std::forward<Left>(s.m_l)),
m_r(std::forward<Right>(s.m_r)){} m_r(std::forward<Right>(s.m_r)){}
template<class Left, class Right> template<class Left, class Right>
constexpr size_t string_cat_expr<Left,Right>::length(void)const{ constexpr size_t string_cat_expr<Left,Right>::length(void)const
noexcept(noexcept(m_l.length()) && noexcept(m_r.length()))
{
return m_l.length() + m_r.length(); return m_l.length() + m_r.length();
} }
template<class Left, class Right> template<class Left, class Right>
template<class Alloc> template<class Alloc>
string_cat_expr<Left,Right>::operator string_intermediary<Alloc>(void){ string_cat_expr<Left,Right>::operator string_intermediary<Alloc>(void)
noexcept(std::is_nothrow_constructible<string_intermediary<Alloc>, size_t>::value &&
std::is_nothrow_invocable<detail::string_appender<string_intermediary<Alloc>>,decltype(*this)>::value)
{
size_t len = length(); size_t len = length();
string_intermediary<Alloc> ret(len); string_intermediary<Alloc> ret(len);
detail::string_appender<string_intermediary<Alloc>> append(ret); detail::string_appender<string_intermediary<Alloc>> append(ret);
@ -226,34 +270,34 @@ namespace rexy{
return ret; return ret;
} }
template<class Left, class Right> template<class Left, class Right>
constexpr const Left& string_cat_expr<Left,Right>::left(void)const{ constexpr const Left& string_cat_expr<Left,Right>::left(void)const noexcept{
return m_l; return m_l;
} }
template<class Left, class Right> template<class Left, class Right>
constexpr const Right& string_cat_expr<Left,Right>::right(void)const{ constexpr const Right& string_cat_expr<Left,Right>::right(void)const noexcept{
return m_r; 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<char*>(str), len, len){} string_base(const_cast<char*>(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){} 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){} 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_data = s.m_data;
m_length = s.m_length; m_length = s.m_length;
return *this; return *this;
} }
constexpr static_string::static_string(const char* c): constexpr static_string::static_string(const char* c)noexcept:
static_string(const_cast<char*>(c), cx::strlen(c)){} static_string(const_cast<char*>(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<char*>(c); m_data = const_cast<char*>(c);
m_length = cx::strlen(c); m_length = cx::strlen(c);
return *this; 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_data = s.m_data;
m_length = s.m_length; m_length = s.m_length;
return *this; return *this;
@ -261,16 +305,20 @@ namespace rexy{
namespace detail{ namespace detail{
template<class Targ> template<class Targ>
constexpr string_appender<Targ>::string_appender(Targ& t): m_targ(t){} constexpr string_appender<Targ>::string_appender(Targ& t)noexcept: m_targ(t){}
template<class Targ> template<class Targ>
template<class L, class R> template<class L, class R>
constexpr void string_appender<Targ>::operator()(const string_cat_expr<L,R>& str){ constexpr void string_appender<Targ>::operator()(const string_cat_expr<L,R>& str)
noexcept(noexcept((*this)(str.left())) && noexcept((*this)(str.right())))
{
(*this)(str.left()); (*this)(str.left());
(*this)(str.right()); (*this)(str.right());
} }
template<class Targ> template<class Targ>
template<class Str, std::enable_if_t<!rexy::is_template_type<Str,string_cat_expr>::value,int>> template<class Str, std::enable_if_t<!rexy::is_template_type<Str,string_cat_expr>::value,int>>
constexpr void string_appender<Targ>::operator()(Str&& str){ constexpr void string_appender<Targ>::operator()(Str&& str)
noexcept(noexcept(m_targ.append(str.get(), str.length())))
{
m_targ.append(str.get(), str.length()); m_targ.append(str.get(), str.length());
} }
} }

View File

@ -20,11 +20,6 @@
namespace rexy{ 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){ char* binary_base::release(void){
return std::exchange(m_data, nullptr); return std::exchange(m_data, nullptr);
} }

View File

@ -1,13 +1,21 @@
//Never actually used in the project. This just ensures that all syntax is correct during builds. //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/binary.hpp"
#include "rexy/filerd.hpp" #include "rexy/filerd.hpp"
#include "rexy/steal.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/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/utility.hpp"
#include "rexy/cx/vector.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"

View File

@ -20,25 +20,26 @@
#include <cstdio> //fopen, fclose #include <cstdio> //fopen, fclose
#include <utility> //exchange, swap #include <utility> //exchange, swap
#include <type_traits>
namespace rexy{ namespace rexy{
filerd::filerd(const char* f, const char* mode): filerd::filerd(const char* f, const char* mode)noexcept:
m_fp(fopen(f, mode)){} m_fp(fopen(f, mode)){}
filerd::~filerd(void){ filerd::~filerd(void)noexcept{
if(m_fp) if(m_fp)
fclose(m_fp); fclose(m_fp);
} }
void filerd::reset(FILE* fp){ void filerd::reset(FILE* fp)noexcept{
if(m_fp) if(m_fp)
fclose(m_fp); fclose(m_fp);
m_fp = fp; m_fp = fp;
} }
FILE* filerd::release(void){ FILE* filerd::release(void)noexcept{
return std::exchange(m_fp, nullptr); return std::exchange(m_fp, nullptr);
} }
size_t filerd::length(void){ size_t filerd::length(void)noexcept{
if(!m_fp) if(!m_fp)
return 0; return 0;
size_t tmp, ret; size_t tmp, ret;
@ -48,38 +49,38 @@ namespace rexy{
fseek(m_fp, tmp, SEEK_SET); fseek(m_fp, tmp, SEEK_SET);
return ret; return ret;
} }
size_t filerd::position(void)const{ size_t filerd::position(void)const noexcept{
return ftell(m_fp); return ftell(m_fp);
} }
void filerd::rewind(size_t pos){ void filerd::rewind(size_t pos)noexcept{
fseek(m_fp, pos, SEEK_SET); fseek(m_fp, pos, SEEK_SET);
} }
filerd::operator FILE*(void){ filerd::operator FILE*(void)noexcept{
return m_fp; return m_fp;
} }
filerd::operator const FILE*(void)const{ filerd::operator const FILE*(void)const noexcept{
return m_fp; return m_fp;
} }
FILE* filerd::get(void){ FILE* filerd::get(void)noexcept{
return m_fp; return m_fp;
} }
const FILE* filerd::get(void)const{ const FILE* filerd::get(void)const noexcept{
return m_fp; return m_fp;
} }
filerd::operator bool(void)const{ filerd::operator bool(void)const noexcept{
return m_fp; 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); 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<char*>(rexy::string::allocator_type::allocate(bytes)); char* tmp = reinterpret_cast<char*>(rexy::string::allocator_type::allocate(bytes));
size_t written = read(tmp, bytes); size_t written = read(tmp, bytes);
return rexy::string(rexy::steal(tmp), written); 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; rexy::string ret;
char c; char c;
size_t count = 0; size_t count = 0;
@ -90,15 +91,17 @@ namespace rexy{
} }
return ret; return ret;
} }
rexy::binary filerd::read_bin(size_t bytes){ rexy::binary filerd::read_bin(size_t bytes)
noexcept(std::is_nothrow_constructible<rexy::binary, rexy::steal<char*>, size_t, size_t>::value)
{
char* tmp = reinterpret_cast<char*>(rexy::binary::allocator_type::allocate(bytes)); char* tmp = reinterpret_cast<char*>(rexy::binary::allocator_type::allocate(bytes));
size_t written = read(tmp, bytes); size_t written = read(tmp, bytes);
return rexy::binary(rexy::steal(tmp), written, written); 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); 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()); return write(c.get(), c.length());
} }