noexcept the library

master
Daniel Kolesa 2015-04-28 18:48:58 +01:00
parent f4b0691003
commit 1a2d606ae7
7 changed files with 323 additions and 194 deletions

View File

@ -23,32 +23,32 @@ namespace octa {
typedef PointerRange< T> range;
typedef PointerRange<const T> const_range;
T &operator[](size_t i) { return p_buf[i]; }
const T &operator[](size_t i) const { return p_buf[i]; }
T &operator[](size_t i) noexcept { return p_buf[i]; }
const T &operator[](size_t i) const noexcept { return p_buf[i]; }
T &at(size_t i) { return p_buf[i]; }
const T &at(size_t i) const { return p_buf[i]; }
T &at(size_t i) noexcept { return p_buf[i]; }
const T &at(size_t i) const noexcept { return p_buf[i]; }
T &first() { return p_buf[0]; }
const T &first() const { return p_buf[0]; }
T &first() noexcept { return p_buf[0]; }
const T &first() const noexcept { return p_buf[0]; }
T &last() { return p_buf[N - 1]; }
const T &last() const { return p_buf[N - 1]; }
T &last() noexcept { return p_buf[N - 1]; }
const T &last() const noexcept { return p_buf[N - 1]; }
bool empty() const { return (N > 0); }
size_t length() const { return N; }
bool empty() const noexcept { return (N > 0); }
size_t length() const noexcept { return N; }
T *get() { return p_buf; }
const T *get() const { return p_buf; }
T *get() noexcept { return p_buf; }
const T *get() const noexcept { return p_buf; }
void swap(Array &v) {
void swap(Array &v) noexcept {
swap(p_buf, v.p_buf);
}
range each() {
range each() noexcept {
return PointerRange<T>(p_buf, p_buf + N);
}
const_range each() const {
const_range each() const noexcept {
return PointerRange<const T>(p_buf, p_buf + N);
}
@ -56,7 +56,7 @@ namespace octa {
};
template<typename T, size_t N>
void swap(Array<T, N> &a, Array<T, N> &b) {
void swap(Array<T, N> &a, Array<T, N> &b) noexcept {
a.swap(b);
}
}

View File

@ -43,13 +43,13 @@ namespace octa {
#undef __OCTA_DEFINE_BINARY_OP
template<typename T> struct LogicalNot {
bool operator()(const T &x) const { return !x; }
bool operator()(const T &x) const noexcept(noexcept(!x)) { return !x; }
typedef T argument_type;
typedef bool result_type;
};
template<typename T> struct Negate {
bool operator()(const T &x) const { return -x; }
bool operator()(const T &x) const noexcept(noexcept(-x)) { return -x; }
typedef T argument_type;
typedef T result_type;
};
@ -59,7 +59,9 @@ namespace octa {
typedef typename T::second_argument_type second_argument_type;
typedef bool result_type;
explicit BinaryNegate(const T &f): p_fn(f) {}
explicit BinaryNegate(const T &f)
noexcept(IsNothrowCopyConstructible<T>::value): p_fn(f) {}
bool operator()(const first_argument_type &x,
const second_argument_type &y)
noexcept(noexcept(p_fn(x, y))) {
@ -73,7 +75,8 @@ namespace octa {
typedef typename T::argument_type argument_type;
typedef bool result_type;
explicit UnaryNegate(const T &f) noexcept: p_fn(f) {}
explicit UnaryNegate(const T &f)
noexcept(IsNothrowCopyConstructible<T>::value): p_fn(f) {}
bool operator()(const argument_type &x) noexcept(noexcept(p_fn(x))) {
return !p_fn(x);
}
@ -82,12 +85,12 @@ namespace octa {
};
template<typename T> UnaryNegate<T> not1(const T &fn)
noexcept(noexcept(UnaryNegate<T>(fn))) {
noexcept(IsNothrowCopyConstructible<UnaryNegate<T>>::value) {
return UnaryNegate<T>(fn);
}
template<typename T> BinaryNegate<T> not2(const T &fn)
noexcept(noexcept(BinaryNegate<T>(fn))) {
noexcept(IsNothrowCopyConstructible<BinaryNegate<T>>::value) {
return BinaryNegate<T>(fn);
}
@ -97,7 +100,7 @@ namespace octa {
struct ReferenceWrapper {
typedef T type;
ReferenceWrapper(T &v): p_ptr(address_of(v)) {}
ReferenceWrapper(T &v) noexcept: p_ptr(address_of(v)) {}
ReferenceWrapper(const ReferenceWrapper &) = default;
ReferenceWrapper(T &&) = delete;
@ -216,15 +219,15 @@ namespace octa {
new (&get_ref(s)) T(forward<T>(v));
}
static void move_f(__OctaFunctorData &lhs, __OctaFunctorData &&rhs) {
static void move_f(__OctaFunctorData &lhs, __OctaFunctorData &&rhs) noexcept {
new (&get_ref(lhs)) T(move(get_ref(rhs)));
}
static void destroy_f(__OctaFunctorData &s) {
static void destroy_f(__OctaFunctorData &s) noexcept {
get_ref(s).~T();
}
static T &get_ref(const __OctaFunctorData &s) {
static T &get_ref(const __OctaFunctorData &s) noexcept {
return (T &)s;
}
};
@ -240,27 +243,27 @@ namespace octa {
new (&get_ptr_ref(s)) T *(new T(forward<T>(v)));
}
static void move_f(__OctaFunctorData &lhs, __OctaFunctorData &&rhs) {
static void move_f(__OctaFunctorData &lhs, __OctaFunctorData &&rhs) noexcept {
new (&get_ptr_ref(lhs)) T *(get_ptr_ref(rhs));
get_ptr_ref(rhs) = nullptr;
}
static void destroy_f(__OctaFunctorData &s) {
static void destroy_f(__OctaFunctorData &s) noexcept {
T *&ptr = get_ptr_ref(s);
if (!ptr) return;
delete ptr;
ptr = nullptr;
}
static T &get_ref(const __OctaFunctorData &s) {
static T &get_ref(const __OctaFunctorData &s) noexcept {
return *get_ptr_ref(s);
}
static T *&get_ptr_ref(__OctaFunctorData &s) {
static T *&get_ptr_ref(__OctaFunctorData &s) noexcept {
return (T *&)s;
}
static T *&get_ptr_ref(const __OctaFunctorData &s) {
static T *&get_ptr_ref(const __OctaFunctorData &s) noexcept {
return (T *&)s;
}
};
@ -345,17 +348,17 @@ namespace octa {
Function( ) noexcept { initialize_empty(); }
Function(nullptr_t) noexcept { initialize_empty(); }
Function(Function &&f) {
Function(Function &&f) noexcept {
initialize_empty();
swap(f);
}
Function(const Function &f): p_call(f.p_call) {
Function(const Function &f) noexcept: p_call(f.p_call) {
f.p_stor.manager->call_copy(p_stor, f.p_stor);
}
template<typename T>
Function(T f) {
Function(T f) noexcept(__OctaFunctorInPlace<T>::value) {
if (func_is_null(f)) {
initialize_empty();
return;
@ -367,13 +370,13 @@ namespace octa {
p_stor.manager->call_destroy(p_stor);
}
Function &operator=(Function &&f) {
Function &operator=(Function &&f) noexcept {
p_stor.manager->call_destroy(p_stor);
swap(f);
return *this;
}
Function &operator=(const Function &f) {
Function &operator=(const Function &f) noexcept {
p_stor.manager->call_destroy(p_stor);
f.p_stor.manager->call_copy(p_stor, f.p_stor);
return *this;
@ -384,7 +387,7 @@ namespace octa {
}
template<typename F>
void assign(F &&f) {
void assign(F &&f) noexcept(__OctaFunctorInPlace<F>::value) {
Function(forward<F>(f)).swap(*this);
}
@ -409,7 +412,7 @@ namespace octa {
__OctaFunctorDataManager<T>::store_f(p_stor.data, forward<T>(f));
}
void initialize_empty() {
void initialize_empty() noexcept {
typedef R(*emptyf)(A...);
p_call = nullptr;
p_stor.manager = &__octa_get_default_fm<emptyf>();

View File

@ -17,7 +17,7 @@ namespace std {
const T *p_buf;
size_t p_len;
initializer_list(const T *v, size_t n): p_buf(v), p_len(n) {}
initializer_list(const T *v, size_t n) noexcept: p_buf(v), p_len(n) {}
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
@ -27,13 +27,13 @@ namespace std {
typedef T *pointer;
typedef const T *const_pointer;
initializer_list(): p_buf(nullptr), p_len(0) {}
initializer_list() noexcept: p_buf(nullptr), p_len(0) {}
size_t length() const { return p_len; }
size_t length() const noexcept { return p_len; }
const T *get() const { return p_buf; }
const T *get() const noexcept { return p_buf; }
octa::PointerRange<const T> range() {
octa::PointerRange<const T> range() noexcept {
return octa::PointerRange<const T>(p_buf, p_len);
}
};

View File

@ -10,6 +10,7 @@
#include "octa/types.h"
#include "octa/utility.h"
#include "octa/type_traits.h"
namespace octa {
struct InputRangeTag {};
@ -28,6 +29,7 @@ namespace octa {
template<typename T>
struct __OctaRangeIterator {
/* no need to mark noexcept as it's never instantiated directly */
__OctaRangeIterator(): p_range() {}
explicit __OctaRangeIterator(const T &range): p_range(range) {}
__OctaRangeIterator &operator++() {
@ -53,10 +55,12 @@ namespace octa {
typedef V value_type;
typedef R reference;
__OctaRangeIterator<B> begin() {
__OctaRangeIterator<B> begin()
noexcept(IsNothrowCopyConstructible<B>::value) {
return __OctaRangeIterator<B>((const B &)*this);
}
__OctaRangeIterator<B> end() {
__OctaRangeIterator<B> end()
noexcept(IsNothrowDefaultConstructible<B>::value) {
return __OctaRangeIterator<B>();
}
};
@ -80,67 +84,99 @@ namespace octa {
typedef typename RangeTraits<T>::reference r_ref;
typedef typename RangeTraits<T>::size_type r_size;
public:
ReverseRange(): p_range() {}
ReverseRange(const T &range): p_range(range) {}
ReverseRange(const ReverseRange &it): p_range(it.p_range) {}
ReverseRange(ReverseRange &&it): p_range(move(it.p_range)) {}
T p_range;
ReverseRange &operator=(const ReverseRange &v) {
public:
ReverseRange()
noexcept(IsNothrowDefaultConstructible<T>::value): p_range() {}
ReverseRange(const T &range)
noexcept(IsNothrowCopyConstructible<T>::value): p_range(range) {}
ReverseRange(const ReverseRange &it)
noexcept(IsNothrowCopyConstructible<T>::value): p_range(it.p_range) {}
ReverseRange(ReverseRange &&it)
noexcept(IsNothrowMoveConstructible<T>::value):
p_range(move(it.p_range)) {}
ReverseRange &operator=(const ReverseRange &v)
noexcept(IsNothrowCopyAssignable<T>::value) {
p_range = v.p_range;
return *this;
}
ReverseRange &operator=(ReverseRange &&v) {
ReverseRange &operator=(ReverseRange &&v)
noexcept(IsNothrowMoveAssignable<T>::value) {
p_range = move(v.p_range);
return *this;
}
ReverseRange &operator=(const T &v) {
ReverseRange &operator=(const T &v)
noexcept(IsNothrowCopyAssignable<T>::value) {
p_range = v;
return *this;
}
ReverseRange &operator=(T &&v) {
p_range = forward<T>(v);
ReverseRange &operator=(T &&v)
noexcept(IsNothrowMoveAssignable<T>::value) {
p_range = move(v);
return *this;
}
bool empty() const { return p_range.empty(); }
bool empty() const noexcept(noexcept(p_range.empty())) {
return p_range.empty();
}
r_size length() const { return p_range.length(); }
r_size length() const noexcept(noexcept(p_range.length())) {
return p_range.length();
}
void pop_first() { p_range.pop_last (); }
void pop_last () { p_range.pop_first(); }
void pop_first() noexcept(noexcept(p_range.pop_last())) {
p_range.pop_last();
}
void pop_last() noexcept(noexcept(p_range.pop_first())) {
p_range.pop_first();
}
bool operator==(const ReverseRange &v) const {
bool operator==(const ReverseRange &v) const
noexcept(noexcept(p_range == v.p_range)) {
return p_range == v.p_range;
}
bool operator!=(const ReverseRange &v) const {
bool operator!=(const ReverseRange &v) const
noexcept(noexcept(p_range != v.p_range)) {
return p_range != v.p_range;
}
r_ref first() { return p_range.last(); }
r_ref first() const { return p_range.last(); }
r_ref first() noexcept(noexcept(p_range.last())) {
return p_range.last();
}
r_ref first() const noexcept(noexcept(p_range.last())) {
return p_range.last();
}
r_ref last() { return p_range.first(); }
r_ref last() const { return p_range.first(); }
r_ref last() noexcept(noexcept(p_range.first())) {
return p_range.first();
}
r_ref last() const noexcept(noexcept(p_range.first())) {
return p_range.first();
}
r_ref operator[](r_size i) {
r_ref operator[](r_size i) noexcept(noexcept(p_range[0])) {
return p_range[length() - i - 1];
}
r_ref operator[](r_size i) const {
r_ref operator[](r_size i) const noexcept(noexcept(p_range[0])) {
return p_range[length() - i - 1];
}
ReverseRange<T> slice(r_size start, r_size end) {
ReverseRange<T> slice(r_size start, r_size end)
noexcept(noexcept(ReverseRange<T>(p_range.slice(0, 0)))
&& noexcept(p_range.length())) {
r_size len = p_range.length();
return ReverseRange<T>(p_range.slice(len - end, len - start));
}
private:
T p_range;
};
template<typename T>
ReverseRange<T> make_reverse_range(const T &it) {
ReverseRange<T> make_reverse_range(const T &it)
noexcept(noexcept(ReverseRange<T>(it))) {
return ReverseRange<T>(it);
}
@ -156,143 +192,176 @@ namespace octa {
typedef typename RangeTraits<T>::value_type &&r_ref;
typedef typename RangeTraits<T>::size_type r_size;
public:
MoveRange(): p_range() {}
MoveRange(const T &range): p_range(range) {}
MoveRange(const MoveRange &it): p_range(it.p_range) {}
MoveRange(MoveRange &&it): p_range(move(it.p_range)) {}
T p_range;
MoveRange &operator=(const MoveRange &v) {
public:
MoveRange()
noexcept(IsNothrowDefaultConstructible<T>::value): p_range() {}
MoveRange(const T &range)
noexcept(IsNothrowCopyConstructible<T>::value): p_range(range) {}
MoveRange(const MoveRange &it)
noexcept(IsNothrowCopyConstructible<T>::value): p_range(it.p_range) {}
MoveRange(MoveRange &&it)
noexcept(IsNothrowMoveConstructible<T>::value):
p_range(move(it.p_range)) {}
MoveRange &operator=(const MoveRange &v)
noexcept(IsNothrowCopyAssignable<T>::value) {
p_range = v.p_range;
return *this;
}
MoveRange &operator=(MoveRange &&v) {
MoveRange &operator=(MoveRange &&v)
noexcept(IsNothrowMoveAssignable<T>::value) {
p_range = move(v.p_range);
return *this;
}
MoveRange &operator=(const T &v) {
MoveRange &operator=(const T &v)
noexcept(IsNothrowCopyAssignable<T>::value) {
p_range = v;
return *this;
}
MoveRange &operator=(T &&v) {
p_range = forward<T>(v);
MoveRange &operator=(T &&v)
noexcept(IsNothrowMoveAssignable<T>::value) {
p_range = move(v);
return *this;
}
bool empty () const { return p_range.empty (); }
r_size length() const { return p_range.length(); }
bool empty() const noexcept(noexcept(p_range.empty())) {
return p_range.empty();
}
r_size length() const noexcept(noexcept(p_range.length())) {
return p_range.length();
}
void pop_first() { p_range.pop_first(); }
void pop_last () { p_range.pop_last (); }
void pop_first() noexcept(noexcept(p_range.pop_first())) {
p_range.pop_first();
}
void pop_last() noexcept(noexcept(p_range.pop_last())) {
p_range.pop_last();
}
bool operator==(const MoveRange &v) const {
bool operator==(const MoveRange &v) const
noexcept(noexcept(p_range == v.p_range)) {
return p_range == v.p_range;
}
bool operator!=(const MoveRange &v) const {
bool operator!=(const MoveRange &v) const
noexcept(noexcept(p_range != v.p_range)) {
return p_range != v.p_range;
}
r_ref first() { return move(p_range.first()); }
r_ref last () { return move(p_range.last()); }
r_ref first() noexcept(noexcept(p_range.first())) {
return move(p_range.first());
}
r_ref last() noexcept(noexcept(p_range.last())) {
return move(p_range.last());
}
r_ref operator[](r_size i) {
r_ref operator[](r_size i) noexcept(noexcept(p_range[0])) {
return move(p_range[i]);
}
MoveRange<T> slice(r_size start, r_size end) {
MoveRange<T> slice(r_size start, r_size end)
noexcept(noexcept(MoveRange<T>(p_range.slice(start, end)))) {
return MoveRange<T>(p_range.slice(start, end));
}
void put(r_val &v) { p_range.put(v); }
private:
T p_range;
void put(r_val &v) noexcept(noexcept(p_range.put(v))) {
p_range.put(v);
}
};
template<typename T>
MoveRange<T> make_move_range(const T &it) {
MoveRange<T> make_move_range(const T &it)
noexcept(noexcept(MoveRange<T>(it))) {
return MoveRange<T>(it);
}
template<typename T>
struct NumberRange: InputRange<NumberRange<T>, ForwardRangeTag, T> {
NumberRange(): p_a(0), p_b(0), p_step(0) {}
NumberRange(const NumberRange &it): p_a(it.p_a), p_b(it.p_b),
NumberRange() noexcept: p_a(0), p_b(0), p_step(0) {}
NumberRange(const NumberRange &it) noexcept: p_a(it.p_a), p_b(it.p_b),
p_step(it.p_step) {}
NumberRange(T a, T b, T step = 1): p_a(a), p_b(b), p_step(step) {}
NumberRange(T v): p_a(0), p_b(v), p_step(1) {}
NumberRange(T a, T b, T step = 1) noexcept: p_a(a), p_b(b),
p_step(step) {}
NumberRange(T v) noexcept: p_a(0), p_b(v), p_step(1) {}
bool operator==(const NumberRange &v) const {
bool operator==(const NumberRange &v) const noexcept {
return p_a == v.p_a && p_b == v.p_b && p_step == v.p_step;
}
bool operator!=(const NumberRange &v) const {
bool operator!=(const NumberRange &v) const noexcept {
return p_a != v.p_a || p_b != v.p_b || p_step != v.p_step;
}
bool empty() const { return p_a * p_step >= p_b * p_step; }
void pop_first() { p_a += p_step; }
T &first() { return p_a; }
bool empty() const noexcept { return p_a * p_step >= p_b * p_step; }
void pop_first() noexcept { p_a += p_step; }
T &first() noexcept { return p_a; }
private:
T p_a, p_b, p_step;
};
template<typename T>
NumberRange<T> range(T a, T b, T step = 1) {
NumberRange<T> range(T a, T b, T step = 1) noexcept {
return NumberRange<T>(a, b, step);
}
template<typename T>
NumberRange<T> range(T v) {
NumberRange<T> range(T v) noexcept {
return NumberRange<T>(v);
}
template<typename T>
struct PointerRange: InputRange<PointerRange<T>, RandomAccessRangeTag, T> {
PointerRange(): p_beg(nullptr), p_end(nullptr) {}
PointerRange(const PointerRange &v): p_beg(v.p_beg), p_end(v.p_end) {}
PointerRange(T *beg, T *end): p_beg(beg), p_end(end) {}
PointerRange(T *beg, size_t n): p_beg(beg), p_end(beg + n) {}
PointerRange() noexcept: p_beg(nullptr), p_end(nullptr) {}
PointerRange(const PointerRange &v) noexcept: p_beg(v.p_beg),
p_end(v.p_end) {}
PointerRange(T *beg, T *end) noexcept: p_beg(beg), p_end(end) {}
PointerRange(T *beg, size_t n) noexcept: p_beg(beg), p_end(beg + n) {}
bool operator==(const PointerRange &v) const {
bool operator==(const PointerRange &v) const noexcept {
return p_beg == v.p_beg && p_end == v.p_end;
}
bool operator!=(const PointerRange &v) const {
bool operator!=(const PointerRange &v) const noexcept {
return p_beg != v.p_beg || p_end != v.p_end;
}
/* satisfy InputRange / ForwardRange */
bool empty() const { return p_beg == nullptr; }
bool empty() const noexcept { return p_beg == nullptr; }
void pop_first() {
void pop_first() noexcept {
if (p_beg == nullptr) return;
if (++p_beg == p_end) p_beg = p_end = nullptr;
}
T &first() { return *p_beg; }
const T &first() const { return *p_beg; }
T &first() noexcept { return *p_beg; }
const T &first() const noexcept { return *p_beg; }
/* satisfy BidirectionalRange */
void pop_last() {
void pop_last() noexcept {
if (p_end-- == p_beg) { p_end = nullptr; return; }
if (p_end == p_beg) p_beg = p_end = nullptr;
}
T &last() { return *(p_end - 1); }
const T &last() const { return *(p_end - 1); }
T &last() noexcept { return *(p_end - 1); }
const T &last() const noexcept { return *(p_end - 1); }
/* satisfy RandomAccessRange */
size_t length() const { return p_end - p_beg; }
size_t length() const noexcept { return p_end - p_beg; }
PointerRange slice(size_t start, size_t end) {
PointerRange slice(size_t start, size_t end) noexcept {
return PointerRange(p_beg + start, p_beg + end);
}
T &operator[](size_t i) { return p_beg[i]; }
const T &operator[](size_t i) const { return p_beg[i]; }
T &operator[](size_t i) noexcept { return p_beg[i]; }
const T &operator[](size_t i) const noexcept { return p_beg[i]; }
/* satisfy OutputRange */
void put(const T &v) { *(p_beg++) = v; }
void put(const T &v) noexcept(IsNothrowCopyAssignable<T>::value) {
*(p_beg++) = v;
}
private:
T *p_beg, *p_end;
@ -315,60 +384,81 @@ namespace octa {
typedef typename RangeTraits<T>::reference r_ref;
typedef typename RangeTraits<T>::size_type r_size;
T p_range;
r_size p_index;
public:
EnumeratedRange(): p_range(), p_index(0) {}
EnumeratedRange(const T &range): p_range(range), p_index(0) {}
EnumeratedRange(const EnumeratedRange &it): p_range(it.p_range),
p_index(it.p_index) {}
EnumeratedRange(EnumeratedRange &&it): p_range(move(it.p_range)),
EnumeratedRange()
noexcept(IsNothrowDefaultConstructible<T>::value): p_range(),
p_index(0) {}
EnumeratedRange(const T &range)
noexcept(IsNothrowCopyConstructible<T>::value): p_range(range),
p_index(0) {}
EnumeratedRange(const EnumeratedRange &it)
noexcept(IsNothrowCopyConstructible<T>::value): p_range(it.p_range),
p_index(it.p_index) {}
EnumeratedRange &operator=(const EnumeratedRange &v) {
EnumeratedRange(EnumeratedRange &&it)
noexcept(IsNothrowMoveConstructible<T>::value):
p_range(move(it.p_range)), p_index(it.p_index) {}
EnumeratedRange &operator=(const EnumeratedRange &v)
noexcept(IsNothrowCopyAssignable<T>::value) {
p_range = v.p_range;
p_index = v.p_index;
return *this;
}
EnumeratedRange &operator=(EnumeratedRange &&v) {
EnumeratedRange &operator=(EnumeratedRange &&v)
noexcept(IsNothrowMoveAssignable<T>::value) {
p_range = move(v.p_range);
p_index = v.p_index;
return *this;
}
EnumeratedRange &operator=(const T &v) {
EnumeratedRange &operator=(const T &v)
noexcept(IsNothrowCopyAssignable<T>::value) {
p_range = v;
p_index = 0;
return *this;
}
EnumeratedRange &operator=(T &&v) {
p_range = forward<T>(v);
EnumeratedRange &operator=(T &&v)
noexcept(IsNothrowMoveAssignable<T>::value) {
p_range = move(v);
p_index = 0;
return *this;
}
bool empty() const { return p_range.empty(); }
bool empty() const noexcept(noexcept(p_range.empty())) {
return p_range.empty();
}
void pop_first() { ++p_index; p_range.pop_first(); }
void pop_first() noexcept(noexcept(p_range.pop_last())) {
++p_index; p_range.pop_first();
}
EnumeratedValue<r_ref, r_size> first() {
EnumeratedValue<r_ref, r_size> first()
noexcept(noexcept(p_range.first())) {
return EnumeratedValue<r_ref, r_size> { p_index, p_range.first() };
}
EnumeratedValue<r_ref, r_size> first() const {
EnumeratedValue<r_ref, r_size> first() const
noexcept(noexcept(p_range.first())) {
return EnumeratedValue<r_ref, r_size> { p_index, p_range.first() };
}
bool operator==(const EnumeratedRange &v) const {
bool operator==(const EnumeratedRange &v) const
noexcept(noexcept(p_range == v.p_range)) {
return p_range == v.p_range;
}
bool operator!=(const EnumeratedRange &v) const {
bool operator!=(const EnumeratedRange &v) const
noexcept(noexcept(p_range != v.p_range)) {
return p_range != v.p_range;
}
private:
T p_range;
r_size p_index;
};
template<typename T>
EnumeratedRange<T> enumerate(const T &it) {
EnumeratedRange<T> enumerate(const T &it)
noexcept(noexcept(EnumeratedRange<T>(it))) {
return EnumeratedRange<T>(it);
}
}

View File

@ -656,8 +656,11 @@ namespace octa {
template<typename, bool> struct __OctaIsNothrowDtible;
template<typename T>
struct __OctaIsNothrowDtible<T, false>: IntegralConstant<bool,
noexcept(__octa_declval<T>().~T())
struct __OctaIsNothrowDtible<T, false>: False {};
template<typename T>
struct __OctaIsNothrowDtible<T, true>: IntegralConstant<bool,
(IsScalar<T>::value || noexcept(__octa_declval<T>().~T()))
> {};
template<typename T>

View File

@ -31,12 +31,15 @@ namespace octa {
template<typename T> AddRvalueReference<T> declval();
template<typename T> void swap(T &a, T &b) {
template<typename T> void swap(T &a, T &b)
noexcept(IsNothrowMoveConstructible<T>::value
&& IsNothrowMoveAssignable<T>::value) {
T c(move(a));
a = move(b);
b = move(c);
}
template<typename T, size_t N> void swap(T (&a)[N], T (&b)[N]) {
template<typename T, size_t N> void swap(T (&a)[N], T (&b)[N])
noexcept(noexcept(swap(*a, *b))) {
for (size_t i = 0; i < N; ++i) {
swap(a[i], b[i]);
}

View File

@ -22,7 +22,10 @@ namespace octa {
T *p_buf;
size_t p_len, p_cap;
void insert_base(size_t idx, size_t n) {
void insert_base(size_t idx, size_t n)
noexcept(IsNothrowDestructible<T>::value
&& IsNothrowMoveConstructible<T>::value
&& IsNothrowMoveAssignable<T>::value) {
if (p_len + n > p_cap) reserve(p_len + n);
p_len += n;
for (size_t i = p_len - 1; i > idx + n - 1; --i) {
@ -43,25 +46,30 @@ namespace octa {
typedef PointerRange< T> range;
typedef PointerRange<const T> const_range;
Vector(): p_buf(nullptr), p_len(0), p_cap(0) {}
Vector() noexcept: p_buf(nullptr), p_len(0), p_cap(0) {}
explicit Vector(size_t n, const T &val = T()): Vector() {
explicit Vector(size_t n, const T &val = T())
noexcept(IsNothrowCopyConstructible<T>::value): Vector() {
p_buf = new uchar[n * sizeof(T)];
p_len = p_cap = n;
T *cur = p_buf, *last = p_buf + n;
while (cur != last) new (cur++) T(val);
}
Vector(const Vector &v): Vector() {
Vector(const Vector &v)
noexcept(IsNothrowDestructible<T>::value
&& IsNothrowCopyConstructible<T>::value): Vector() {
*this = v;
}
Vector(Vector &&v): p_buf(v.p_buf), p_len(v.p_len), p_cap(v.p_cap) {
Vector(Vector &&v) noexcept: p_buf(v.p_buf), p_len(v.p_len),
p_cap(v.p_cap) {
v.p_buf = nullptr;
v.p_len = v.p_cap = 0;
}
Vector(InitializerList<T> v): Vector() {
Vector(InitializerList<T> v)
noexcept(IsNothrowCopyConstructible<T>::value): Vector() {
size_t len = v.length();
const T *ptr = v.get();
reserve(len);
@ -70,11 +78,11 @@ namespace octa {
p_len = len;
}
~Vector() {
~Vector() noexcept(IsNothrowDestructible<T>::value) {
clear();
}
void clear() {
void clear() noexcept(IsNothrowDestructible<T>::value) {
if (p_cap > 0) {
if (!octa::IsPod<T>()) {
T *cur = p_buf, *last = p_buf + p_len;
@ -86,7 +94,9 @@ namespace octa {
}
}
Vector<T> &operator=(const Vector<T> &v) {
Vector<T> &operator=(const Vector<T> &v)
noexcept(IsNothrowDestructible<T>::value
&& IsNothrowCopyConstructible<T>::value) {
if (this == &v) return *this;
if (p_cap >= v.p_cap) {
@ -115,7 +125,8 @@ namespace octa {
return *this;
}
Vector<T> &operator=(Vector<T> &&v) {
Vector<T> &operator=(Vector<T> &&v)
noexcept(IsNothrowDestructible<T>::value) {
clear();
p_len = v.p_len;
p_cap = v.p_cap;
@ -123,7 +134,10 @@ namespace octa {
return *this;
}
void resize(size_t n, const T &v = T()) {
void resize(size_t n, const T &v = T())
noexcept(IsNothrowDestructible<T>::value
&& IsNothrowMoveConstructible<T>::value
&& IsNothrowCopyConstructible<T>::value) {
size_t len = p_len;
reserve(n);
p_len = n;
@ -138,7 +152,9 @@ namespace octa {
}
}
void reserve(size_t n) {
void reserve(size_t n)
noexcept(IsNothrowDestructible<T>::value
&& IsNothrowMoveConstructible<T>::value) {
if (n <= p_len) {
if (n == p_len) return;
while (p_len > n) pop();
@ -167,19 +183,21 @@ namespace octa {
p_buf = tmp;
}
T &operator[](size_t i) { return p_buf[i]; }
const T &operator[](size_t i) const { return p_buf[i]; }
T &operator[](size_t i) noexcept { return p_buf[i]; }
const T &operator[](size_t i) const noexcept { return p_buf[i]; }
T &at(size_t i) { return p_buf[i]; }
const T &at(size_t i) const { return p_buf[i]; }
T &at(size_t i) noexcept { return p_buf[i]; }
const T &at(size_t i) const noexcept { return p_buf[i]; }
T &push(const T &v) {
T &push(const T &v) noexcept(noexcept(reserve(p_len + 1))
&& IsNothrowCopyConstructible<T>::value) {
if (p_len == p_cap) reserve(p_len + 1);
new (&p_buf[p_len]) T(v);
return p_buf[p_len++];
}
T &push() {
T &push() noexcept(noexcept(reserve(p_len + 1))
&& IsNothrowDefaultConstructible<T>::value) {
if (p_len == p_cap) reserve(p_len + 1);
new (&p_buf[p_len]) T;
return p_buf[p_len++];
@ -192,7 +210,7 @@ namespace octa {
return p_buf[p_len++];
}
void pop() {
void pop() noexcept(IsNothrowDestructible<T>::value) {
if (!octa::IsPod<T>()) {
p_buf[--p_len].~T();
} else {
@ -200,50 +218,55 @@ namespace octa {
}
}
T &pop_ret() {
T &pop_ret() noexcept {
return p_buf[--p_len];
}
T &first() { return p_buf[0]; }
const T &first() const { return p_buf[0]; };
T &first() noexcept { return p_buf[0]; }
const T &first() const noexcept { return p_buf[0]; };
T &last() { return p_buf[p_len - 1]; }
const T &last() const { return p_buf[p_len - 1]; }
T &last() noexcept { return p_buf[p_len - 1]; }
const T &last() const noexcept { return p_buf[p_len - 1]; }
T *get() { return p_buf; }
const T *get() const { return p_buf; }
T *get() noexcept { return p_buf; }
const T *get() const noexcept { return p_buf; }
size_t length() const { return p_len; }
size_t capacity() const { return p_cap; }
size_t length() const noexcept { return p_len; }
size_t capacity() const noexcept { return p_cap; }
bool empty() const { return (p_len == 0); }
bool empty() const noexcept { return (p_len == 0); }
bool in_range(size_t idx) { return idx < p_len; }
bool in_range(int idx) { return idx >= 0 && idx < p_len; }
bool in_range(const T *ptr) {
bool in_range(size_t idx) noexcept { return idx < p_len; }
bool in_range(int idx) noexcept { return idx >= 0 && idx < p_len; }
bool in_range(const T *ptr) noexcept {
return ptr >= p_buf && ptr < &p_buf[p_len];
}
T *disown() {
T *disown() noexcept {
T *r = p_buf;
p_buf = nullptr;
p_len = p_cap = 0;
return r;
}
T *insert(size_t idx, T &&v) {
T *insert(size_t idx, T &&v)
noexcept(noexcept(insert_base(idx, 1))) {
insert_base(idx, 1);
p_buf[idx] = forward<T>(v);
p_buf[idx] = move(v);
return &p_buf[idx];
}
T *insert(size_t idx, const T &v) {
T *insert(size_t idx, const T &v)
noexcept(noexcept(insert_base(idx, 1))
&& IsNothrowCopyAssignable<T>::value) {
insert_base(idx, 1);
p_buf[idx] = v;
return &p_buf[idx];
}
T *insert(size_t idx, size_t n, const T &v) {
T *insert(size_t idx, size_t n, const T &v)
noexcept(noexcept(insert_base(idx, 1))
&& IsNothrowCopyAssignable<T>::value) {
insert_base(idx, n);
for (size_t i = 0; i < n; ++i) {
p_buf[idx + i] = v;
@ -252,7 +275,13 @@ namespace octa {
}
template<typename U>
T *insert_range(size_t idx, U range) {
T *insert_range(size_t idx, U range)
noexcept(IsNothrowDestructible<T>::value
&& IsNothrowMoveConstructible<T>::value
&& IsNothrowMoveAssignable<T>::value
&& noexcept(range.first())
&& noexcept(range.pop_first())
&& noexcept((*p_buf = range.first()))) {
size_t len = range.length();
insert_base(idx, len);
for (size_t i = 0; i < len; ++i) {
@ -262,18 +291,19 @@ namespace octa {
return &p_buf[idx];
}
T *insert(size_t idx, InitializerList<T> il) {
T *insert(size_t idx, InitializerList<T> il)
noexcept(noexcept(insert_range(idx, il.range()))) {
return insert_range(idx, il.range());
}
range each() {
range each() noexcept {
return PointerRange<T>(p_buf, p_buf + p_len);
}
const_range each() const {
const_range each() const noexcept {
return PointerRange<const T>(p_buf, p_buf + p_len);
}
void swap(Vector &v) {
void swap(Vector &v) noexcept {
swap(p_len, v.p_len);
swap(p_cap, v.p_cap);
swap(p_buf, v.p_buf);
@ -281,7 +311,7 @@ namespace octa {
};
template<typename T>
void swap(Vector<T> &a, Vector<T> &b) {
void swap(Vector<T> &a, Vector<T> &b) noexcept {
a.swap(b);
}
}