more noexcept and readme note
parent
1586cedd17
commit
519c9c7624
23
README.md
23
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.
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue