From 519c9c7624f442bee645d2b2eddd726aa47629b7 Mon Sep 17 00:00:00 2001 From: q66 Date: Sun, 11 Sep 2016 21:17:49 +0200 Subject: [PATCH] more noexcept and readme note --- README.md | 23 +++++++++++++++++++ ostd/array.hh | 49 ++++++++++++++++++++-------------------- ostd/initializer_list.hh | 16 +++++++------ ostd/internal/tuple.hh | 24 ++++++++++---------- ostd/platform.hh | 18 +++++++-------- ostd/tuple.hh | 16 ++++++------- ostd/utility.hh | 43 ++++++++++++++++++++++------------- 7 files changed, 113 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 3bfe3d9..1561996 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/ostd/array.hh b/ostd/array.hh index e5503d7..0a205a4 100644 --- a/ostd/array.hh +++ b/ostd/array.hh @@ -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; using ConstRange = PointerRange; - 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(), declval()))) { ostd::swap_ranges(iter(), v.iter()); } @@ -89,22 +90,22 @@ struct TupleElementBase> { }; template -inline TupleElement> &get(Array &a) { +inline TupleElement> &get(Array &a) noexcept { return a[I]; } template -inline TupleElement> const &get(Array const &a) { +inline TupleElement> const &get(Array const &a) noexcept { return a[I]; } template -inline TupleElement> &&get(Array &&a) { +inline TupleElement> &&get(Array &&a) noexcept { return move(a.p_buf[I]); } template -inline TupleElement> const &&get(Array const &&a) { +inline TupleElement> const &&get(Array const &&a) noexcept { return move(a.p_buf[I]); } diff --git a/ostd/initializer_list.hh b/ostd/initializer_list.hh index 14e0fb2..709dcb5 100644 --- a/ostd/initializer_list.hh +++ b/ostd/initializer_list.hh @@ -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 using InitializerList = std::initializer_list; template -PointerRange iter(std::initializer_list init) { +PointerRange iter(std::initializer_list init) noexcept { return PointerRange(init.begin(), init.end()); } template -PointerRange citer(std::initializer_list init) { +PointerRange citer(std::initializer_list init) noexcept { return PointerRange(init.begin(), init.end()); } diff --git a/ostd/internal/tuple.hh b/ostd/internal/tuple.hh index c585fd1..d4b619d 100644 --- a/ostd/internal/tuple.hh +++ b/ostd/internal/tuple.hh @@ -69,16 +69,16 @@ template constexpr bool IsTupleLike> = true; template -inline TupleElement> &get(Tuple &); +inline TupleElement> &get(Tuple &) noexcept; template -inline const TupleElement> &get(const Tuple &); +inline const TupleElement> &get(const Tuple &) noexcept; template -inline TupleElement> &&get(Tuple &&); +inline TupleElement> &&get(Tuple &&) noexcept; template -inline const TupleElement> &&get(const Tuple &&); +inline const TupleElement> &&get(const Tuple &&) noexcept; /* pair specializations */ @@ -86,16 +86,16 @@ template constexpr bool IsTupleLike> = true; template -inline TupleElement> &get(Pair &); +inline TupleElement> &get(Pair &) noexcept; template -inline const TupleElement> &get(const Pair &); +inline const TupleElement> &get(const Pair &) noexcept; template -inline TupleElement> &&get(Pair &&); +inline TupleElement> &&get(Pair &&) noexcept; template -inline const TupleElement> &&get(const Pair &&); +inline const TupleElement> &&get(const Pair &&) noexcept; /* array specializations */ @@ -103,16 +103,16 @@ template constexpr bool IsTupleLike> = true; template -inline T &get(Array &); +inline T &get(Array &) noexcept; template -inline const T &get(const Array &); +inline const T &get(const Array &) noexcept; template -inline T &&get(Array &&); +inline T &&get(Array &&) noexcept; template -inline const T &&get(const Array &&); +inline const T &&get(const Array &&) noexcept; /* make tuple indices */ diff --git a/ostd/platform.hh b/ostd/platform.hh index 7870d8a..ddb9309 100644 --- a/ostd/platform.hh +++ b/ostd/platform.hh @@ -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 ); diff --git a/ostd/tuple.hh b/ostd/tuple.hh index e498b5a..d389f5a 100644 --- a/ostd/tuple.hh +++ b/ostd/tuple.hh @@ -323,16 +323,16 @@ class Tuple { Base p_base; template - friend TupleElement> &get(Tuple &); + friend TupleElement> &get(Tuple &) noexcept; template - friend TupleElement> const &get(Tuple const &); + friend TupleElement> const &get(Tuple const &) noexcept; template - friend TupleElement> &&get(Tuple &&); + friend TupleElement> &&get(Tuple &&) noexcept; template - friend TupleElement> const &&get(Tuple const &&); + friend TupleElement> const &&get(Tuple const &&) noexcept; public: template -inline TupleElement> &get(Tuple &t) { +inline TupleElement> &get(Tuple &t) noexcept { using Type = TupleElement>; return static_cast &>(t.p_base).get(); } template -inline TupleElement> const &get(Tuple const &t) { +inline TupleElement> const &get(Tuple const &t) noexcept { using Type = TupleElement>; return static_cast const &>(t.p_base).get(); } template -inline TupleElement> &&get(Tuple &&t) { +inline TupleElement> &&get(Tuple &&t) noexcept { using Type = TupleElement>; return static_cast( static_cast &&>(t.p_base).get()); } template -inline TupleElement> const &&get(Tuple const &&t) { +inline TupleElement> const &&get(Tuple const &&t) noexcept { using Type = TupleElement>; return static_cast( static_cast const &&>(t.p_base).get()); diff --git a/ostd/utility.hh b/ostd/utility.hh index 78877b1..104093b 100644 --- a/ostd/utility.hh +++ b/ostd/utility.hh @@ -16,19 +16,19 @@ namespace ostd { /* move */ template -inline constexpr RemoveReference &&move(T &&v) { +inline constexpr RemoveReference &&move(T &&v) noexcept { return static_cast &&>(v); } /* forward */ template -inline constexpr T &&forward(RemoveReference &v) { +inline constexpr T &&forward(RemoveReference &v) noexcept { return static_cast(v); } template -inline constexpr T &&forward(RemoveReference &&v) { +inline constexpr T &&forward(RemoveReference &&v) noexcept { return static_cast(v); } @@ -58,14 +58,14 @@ namespace detail { template inline void swap_fb( T &a, T &b, EnableIf(0))::value, bool> = true - ) { + ) noexcept(noexcept(a.swap(b))) { a.swap(b); } template inline void swap_fb( T &a, T &b, EnableIf(0))::value, bool> = true - ) { + ) noexcept(IsNothrowMoveConstructible && IsNothrowMoveAssignable) { T c(move(a)); a = move(b); b = move(c); @@ -73,22 +73,28 @@ namespace detail { } template -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 -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 - inline void swap_adl(T &a, T &b) { + namespace adl_swap { using ostd::swap; - swap(a, b); + template + inline void swap_adl(T &a, T &b) noexcept(noexcept(swap(a, b))) { + swap(a, b); + } + } + template + 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 && IsNothrowMoveAssignable + ) { 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 -inline TupleElement> &get(Pair &p) { +inline TupleElement> &get(Pair &p) noexcept { return detail::GetPair::get(p); } template -inline TupleElement> const &get(Pair const &p) { +inline TupleElement> const &get(Pair const &p) noexcept { return detail::GetPair::get(p); } template -inline TupleElement> &&get(Pair &&p) { +inline TupleElement> &&get(Pair &&p) noexcept { return detail::GetPair::get(move(p)); } template -inline TupleElement> const &&get(Pair const &&p) { +inline TupleElement> const &&get(Pair const &&p) noexcept { return detail::GetPair::get(move(p)); }