more noexcept and readme note

master
Daniel Kolesa 2016-09-11 21:17:49 +02:00
parent 1586cedd17
commit 519c9c7624
7 changed files with 113 additions and 76 deletions

View File

@ -53,3 +53,26 @@ or clang, etc.).
Windows is supported with GCC (MinGW) and Clang. The MS C runtime is supported
as well, so compiling with Clang targeting MSVC compatibility will work.
## Exceptions
The library is written with the idea that no API in it ever throws exceptions (with
possibly some rare... exceptions ;)). However, this does not mean it cannot be used
in code that utilizes exceptions. Because of this, the library attempts to provide
some degree of exception safety as well as proper `noexcept` annotations. It also
provides type traits to check things such as whether something can be constructed
or assigned to without throwing.
This is currently a work in progress though. Here is a list of files where things
have been correctly annotated:
* array.hh
* initializer_list.hh
* memory.hh
* new.hh
* platform.hh
* utility.hh
* type_traits.hh
This list will expand over time. As for exception safety of containers, it's is
currently not done/checked. They will be made exception safe over time too.

View File

@ -11,6 +11,7 @@
#include "ostd/algorithm.hh"
#include "ostd/range.hh"
#include "ostd/string.hh"
#include "ostd/utility.hh"
#include "ostd/internal/tuple.hh"
namespace ostd {
@ -27,53 +28,53 @@ struct Array {
using Range = PointerRange<T>;
using ConstRange = PointerRange<T const>;
T &operator[](Size i) { return p_buf[i]; }
T const &operator[](Size i) const { return p_buf[i]; }
T &operator[](Size i) noexcept { return p_buf[i]; }
T const &operator[](Size i) const noexcept { return p_buf[i]; }
T *at(Size i) {
T *at(Size i) noexcept {
if (!in_range(i)) {
return nullptr;
}
return &p_buf[i];
}
T const *at(Size i) const {
T const *at(Size i) const noexcept {
if (!in_range(i)) {
return nullptr;
}
return &p_buf[i];
}
T &front() { return p_buf[0]; }
T const &front() const { return p_buf[0]; }
T &front() noexcept { return p_buf[0]; }
T const &front() const noexcept { return p_buf[0]; }
T &back() { return p_buf[(N > 0) ? (N - 1) : 0]; }
T const &back() const { return p_buf[(N > 0) ? (N - 1) : 0]; }
T &back() noexcept { return p_buf[(N > 0) ? (N - 1) : 0]; }
T const &back() const noexcept { return p_buf[(N > 0) ? (N - 1) : 0]; }
Size size() const { return N; }
Size max_size() const { return Size(~0) / sizeof(T); }
Size size() const noexcept { return N; }
Size max_size() const noexcept { return Size(~0) / sizeof(T); }
bool empty() const { return N == 0; }
bool empty() const noexcept { return N == 0; }
bool in_range(Size idx) { return idx < N; }
bool in_range(int idx) { return idx >= 0 && Size(idx) < N; }
bool in_range(ConstPointer ptr) {
bool in_range(Size idx) noexcept { return idx < N; }
bool in_range(int idx) noexcept { return idx >= 0 && Size(idx) < N; }
bool in_range(ConstPointer ptr) noexcept {
return ptr >= &p_buf[0] && ptr < &p_buf[N];
}
Pointer data() { return p_buf; }
ConstPointer data() const { return p_buf; }
Pointer data() noexcept { return p_buf; }
ConstPointer data() const noexcept { return p_buf; }
Range iter() {
Range iter() noexcept {
return Range(p_buf, p_buf + N);
}
ConstRange iter() const {
ConstRange iter() const noexcept {
return ConstRange(p_buf, p_buf + N);
}
ConstRange citer() const {
ConstRange citer() const noexcept {
return ConstRange(p_buf, p_buf + N);
}
void swap(Array &v) {
void swap(Array &v) noexcept(noexcept(swap(declval<T &>(), declval<T &>()))) {
ostd::swap_ranges(iter(), v.iter());
}
@ -89,22 +90,22 @@ struct TupleElementBase<I, Array<T, N>> {
};
template<Size I, typename T, Size N>
inline TupleElement<I, Array<T, N>> &get(Array<T, N> &a) {
inline TupleElement<I, Array<T, N>> &get(Array<T, N> &a) noexcept {
return a[I];
}
template<Size I, typename T, Size N>
inline TupleElement<I, Array<T, N>> const &get(Array<T, N> const &a) {
inline TupleElement<I, Array<T, N>> const &get(Array<T, N> const &a) noexcept {
return a[I];
}
template<Size I, typename T, Size N>
inline TupleElement<I, Array<T, N>> &&get(Array<T, N> &&a) {
inline TupleElement<I, Array<T, N>> &&get(Array<T, N> &&a) noexcept {
return move(a.p_buf[I]);
}
template<Size I, typename T, Size N>
inline TupleElement<I, Array<T, N>> const &&get(Array<T, N> const &&a) {
inline TupleElement<I, Array<T, N>> const &&get(Array<T, N> const &&a) noexcept {
return move(a.p_buf[I]);
}

View File

@ -19,14 +19,16 @@ class initializer_list {
T const *p_buf;
ostd::Size p_len;
constexpr initializer_list(T const *v, ostd::Size n): p_buf(v), p_len(n) {}
constexpr initializer_list(T const *v, ostd::Size n) noexcept:
p_buf(v), p_len(n)
{}
public:
constexpr initializer_list(): p_buf(nullptr), p_len(0) {}
constexpr initializer_list() noexcept: p_buf(nullptr), p_len(0) {}
constexpr ostd::Size size() const { return p_len; }
constexpr ostd::Size size() const noexcept { return p_len; }
constexpr T const *begin() const { return p_buf; }
constexpr T const *end() const { return p_buf + p_len; }
constexpr T const *begin() const noexcept { return p_buf; }
constexpr T const *end() const noexcept { return p_buf + p_len; }
};
}
@ -40,12 +42,12 @@ template<typename T>
using InitializerList = std::initializer_list<T>;
template<typename T>
PointerRange<T const> iter(std::initializer_list<T> init) {
PointerRange<T const> iter(std::initializer_list<T> init) noexcept {
return PointerRange<T const>(init.begin(), init.end());
}
template<typename T>
PointerRange<T const> citer(std::initializer_list<T> init) {
PointerRange<T const> citer(std::initializer_list<T> init) noexcept {
return PointerRange<T const>(init.begin(), init.end());
}

View File

@ -69,16 +69,16 @@ template<typename ...A>
constexpr bool IsTupleLike<Tuple<A...>> = true;
template<Size I, typename ...A>
inline TupleElement<I, Tuple<A...>> &get(Tuple<A...> &);
inline TupleElement<I, Tuple<A...>> &get(Tuple<A...> &) noexcept;
template<Size I, typename ...A>
inline const TupleElement<I, Tuple<A...>> &get(const Tuple<A...> &);
inline const TupleElement<I, Tuple<A...>> &get(const Tuple<A...> &) noexcept;
template<Size I, typename ...A>
inline TupleElement<I, Tuple<A...>> &&get(Tuple<A...> &&);
inline TupleElement<I, Tuple<A...>> &&get(Tuple<A...> &&) noexcept;
template<Size I, typename ...A>
inline const TupleElement<I, Tuple<A...>> &&get(const Tuple<A...> &&);
inline const TupleElement<I, Tuple<A...>> &&get(const Tuple<A...> &&) noexcept;
/* pair specializations */
@ -86,16 +86,16 @@ template<typename T, typename U>
constexpr bool IsTupleLike<Pair<T, U>> = true;
template<Size I, typename T, typename U>
inline TupleElement<I, Pair<T, U>> &get(Pair<T, U> &);
inline TupleElement<I, Pair<T, U>> &get(Pair<T, U> &) noexcept;
template<Size I, typename T, typename U>
inline const TupleElement<I, Pair<T, U>> &get(const Pair<T, U> &);
inline const TupleElement<I, Pair<T, U>> &get(const Pair<T, U> &) noexcept;
template<Size I, typename T, typename U>
inline TupleElement<I, Pair<T, U>> &&get(Pair<T, U> &&);
inline TupleElement<I, Pair<T, U>> &&get(Pair<T, U> &&) noexcept;
template<Size I, typename T, typename U>
inline const TupleElement<I, Pair<T, U>> &&get(const Pair<T, U> &&);
inline const TupleElement<I, Pair<T, U>> &&get(const Pair<T, U> &&) noexcept;
/* array specializations */
@ -103,16 +103,16 @@ template<typename T, Size I>
constexpr bool IsTupleLike<Array<T, I>> = true;
template<Size I, typename T, Size S>
inline T &get(Array<T, S> &);
inline T &get(Array<T, S> &) noexcept;
template<Size I, typename T, Size S>
inline const T &get(const Array<T, S> &);
inline const T &get(const Array<T, S> &) noexcept;
template<Size I, typename T, Size S>
inline T &&get(Array<T, S> &&);
inline T &&get(Array<T, S> &&) noexcept;
template<Size I, typename T, Size S>
inline const T &&get(const Array<T, S> &&);
inline const T &&get(const Array<T, S> &&) noexcept;
/* make tuple indices */

View File

@ -102,40 +102,40 @@ namespace ostd {
#if defined(OSTD_TOOLCHAIN_GNU)
/* using gcc/clang builtins */
inline uint16_t endian_swap16(uint16_t x) {
inline uint16_t endian_swap16(uint16_t x) noexcept {
return __builtin_bswap16(x);
}
inline uint32_t endian_swap32(uint32_t x) {
inline uint32_t endian_swap32(uint32_t x) noexcept {
return __builtin_bswap32(x);
}
inline uint64_t endian_swap64(uint64_t x) {
inline uint64_t endian_swap64(uint64_t x) noexcept {
return __builtin_bswap64(x);
}
#elif defined(OSTD_TOOLCHAIN_MSVC)
/* using msvc builtins */
inline uint16_t endian_swap16(uint16_t x) {
inline uint16_t endian_swap16(uint16_t x) noexcept {
return _byteswap_ushort(x);
}
inline uint32_t endian_swap32(uint32_t x) {
inline uint32_t endian_swap32(uint32_t x) noexcept {
/* win64 is llp64 */
return _byteswap_ulong(x);
}
inline uint64_t endian_swap64(uint64_t x) {
inline uint64_t endian_swap64(uint64_t x) noexcept {
return _byteswap_uint64(x);
}
#else
/* fallback */
inline uint16_t endian_swap16(uint16_t x) {
inline uint16_t endian_swap16(uint16_t x) noexcept {
return (x << 8) | (x >> 8);
}
inline uint32_t endian_swap32(uint32_t x) {
inline uint32_t endian_swap32(uint32_t x) noexcept {
return (x << 24) | (x >> 24) | ((x >> 8) & 0xFF00) | ((x << 8) & 0xFF0000);
}
inline uint64_t endian_swap64(uint64_t x) {
inline uint64_t endian_swap64(uint64_t x) noexcept {
return endian_swap32(
uint32_t(x >> 32)) | (uint64_t(endian_swap32(uint32_t(x))) << 32
);

View File

@ -323,16 +323,16 @@ class Tuple {
Base p_base;
template<Size I, typename ...T>
friend TupleElement<I, Tuple<T...>> &get(Tuple<T...> &);
friend TupleElement<I, Tuple<T...>> &get(Tuple<T...> &) noexcept;
template<Size I, typename ...T>
friend TupleElement<I, Tuple<T...>> const &get(Tuple<T...> const &);
friend TupleElement<I, Tuple<T...>> const &get(Tuple<T...> const &) noexcept;
template<Size I, typename ...T>
friend TupleElement<I, Tuple<T...>> &&get(Tuple<T...> &&);
friend TupleElement<I, Tuple<T...>> &&get(Tuple<T...> &&) noexcept;
template<Size I, typename ...T>
friend TupleElement<I, Tuple<T...>> const &&get(Tuple<T...> const &&);
friend TupleElement<I, Tuple<T...>> const &&get(Tuple<T...> const &&) noexcept;
public:
template<bool D = true, typename = EnableIf<
@ -484,26 +484,26 @@ public:
/* get */
template<Size I, typename ...A>
inline TupleElement<I, Tuple<A...>> &get(Tuple<A...> &t) {
inline TupleElement<I, Tuple<A...>> &get(Tuple<A...> &t) noexcept {
using Type = TupleElement<I, Tuple<A...>>;
return static_cast<detail::TupleLeaf<I, Type> &>(t.p_base).get();
}
template<Size I, typename ...A>
inline TupleElement<I, Tuple<A...>> const &get(Tuple<A...> const &t) {
inline TupleElement<I, Tuple<A...>> const &get(Tuple<A...> const &t) noexcept {
using Type = TupleElement<I, Tuple<A...>>;
return static_cast<detail::TupleLeaf<I, Type> const &>(t.p_base).get();
}
template<Size I, typename ...A>
inline TupleElement<I, Tuple<A...>> &&get(Tuple<A...> &&t) {
inline TupleElement<I, Tuple<A...>> &&get(Tuple<A...> &&t) noexcept {
using Type = TupleElement<I, Tuple<A...>>;
return static_cast<Type &&>(
static_cast<detail::TupleLeaf<I, Type> &&>(t.p_base).get());
}
template<Size I, typename ...A>
inline TupleElement<I, Tuple<A...>> const &&get(Tuple<A...> const &&t) {
inline TupleElement<I, Tuple<A...>> const &&get(Tuple<A...> const &&t) noexcept {
using Type = TupleElement<I, Tuple<A...>>;
return static_cast<Type const &&>(
static_cast<detail::TupleLeaf<I, Type> const &&>(t.p_base).get());

View File

@ -16,19 +16,19 @@ namespace ostd {
/* move */
template<typename T>
inline constexpr RemoveReference<T> &&move(T &&v) {
inline constexpr RemoveReference<T> &&move(T &&v) noexcept {
return static_cast<RemoveReference<T> &&>(v);
}
/* forward */
template<typename T>
inline constexpr T &&forward(RemoveReference<T> &v) {
inline constexpr T &&forward(RemoveReference<T> &v) noexcept {
return static_cast<T &&>(v);
}
template<typename T>
inline constexpr T &&forward(RemoveReference<T> &&v) {
inline constexpr T &&forward(RemoveReference<T> &&v) noexcept {
return static_cast<T &&>(v);
}
@ -58,14 +58,14 @@ namespace detail {
template<typename T>
inline void swap_fb(
T &a, T &b, EnableIf<decltype(test_swap<T>(0))::value, bool> = true
) {
) noexcept(noexcept(a.swap(b))) {
a.swap(b);
}
template<typename T>
inline void swap_fb(
T &a, T &b, EnableIf<!decltype(test_swap<T>(0))::value, bool> = true
) {
) noexcept(IsNothrowMoveConstructible<T> && IsNothrowMoveAssignable<T>) {
T c(move(a));
a = move(b);
b = move(c);
@ -73,22 +73,28 @@ namespace detail {
}
template<typename T>
inline void swap(T &a, T &b) {
inline void swap(T &a, T &b) noexcept(noexcept(detail::swap_fb(a, b))) {
detail::swap_fb(a, b);
}
template<typename T, Size N>
inline void swap(T (&a)[N], T (&b)[N]) {
inline void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b))) {
for (Size i = 0; i < N; ++i) {
swap(a[i], b[i]);
}
}
namespace detail {
template<typename T>
inline void swap_adl(T &a, T &b) {
namespace adl_swap {
using ostd::swap;
swap(a, b);
template<typename T>
inline void swap_adl(T &a, T &b) noexcept(noexcept(swap(a, b))) {
swap(a, b);
}
}
template<typename T>
inline void swap_adl(T &a, T &b) noexcept(noexcept(adl_swap::swap_adl(a, b))) {
adl_swap::swap_adl(a, b);
}
}
@ -145,7 +151,9 @@ struct Pair {
return *this;
}
Pair &operator=(Pair &&v) {
Pair &operator=(Pair &&v) noexcept(
IsNothrowMoveAssignable<T> && IsNothrowMoveAssignable<U>
) {
first = move(v.first);
second = move(v.second);
return *this;
@ -158,7 +166,10 @@ struct Pair {
return *this;
}
void swap(Pair &v) {
void swap(Pair &v) noexcept(
noexcept(detail::swap_adl(first, v.first)) &&
noexcept(detail::swap_adl(second, v.second))
) {
detail::swap_adl(first, v.first);
detail::swap_adl(second, v.second);
}
@ -284,22 +295,22 @@ namespace detail {
}
template<Size I, typename T, typename U>
inline TupleElement<I, Pair<T, U>> &get(Pair<T, U> &p) {
inline TupleElement<I, Pair<T, U>> &get(Pair<T, U> &p) noexcept {
return detail::GetPair<I>::get(p);
}
template<Size I, typename T, typename U>
inline TupleElement<I, Pair<T, U>> const &get(Pair<T, U> const &p) {
inline TupleElement<I, Pair<T, U>> const &get(Pair<T, U> const &p) noexcept {
return detail::GetPair<I>::get(p);
}
template<Size I, typename T, typename U>
inline TupleElement<I, Pair<T, U>> &&get(Pair<T, U> &&p) {
inline TupleElement<I, Pair<T, U>> &&get(Pair<T, U> &&p) noexcept {
return detail::GetPair<I>::get(move(p));
}
template<Size I, typename T, typename U>
inline TupleElement<I, Pair<T, U>> const &&get(Pair<T, U> const &&p) {
inline TupleElement<I, Pair<T, U>> const &&get(Pair<T, U> const &&p) noexcept {
return detail::GetPair<I>::get(move(p));
}