Skip to content

Commit

Permalink
Closes #7
Browse files Browse the repository at this point in the history
Also add all_traits<Args...>, any_traits<Args...>, no_traits<Args...>.

These allow short circuiting of type traits. (A similar form of template
meta functions are found in MNMLSTC Unittest. These hadn't been added
until now because a name that didn't conflict with all_of, any_of, and
none_of couldn't be decided upon)
  • Loading branch information
Tres Walsh committed Mar 31, 2014
1 parent f8ae30c commit 3027316
Show file tree
Hide file tree
Showing 16 changed files with 141 additions and 95 deletions.
17 changes: 17 additions & 0 deletions docs/type-traits.rst
Expand Up @@ -80,3 +80,20 @@ also documented here.
It will be ``std::true_type`` if a given swap call on a type is actually
marked as *noexcept*, and ``std::false_type`` otherwise. This type
is comparable to libc++'s internal ``__is_nothrow_swappable``.

.. type:: all_traits<Args>

Given a typelist *Args*, where each type in *Args* is a type trait property
that contains a boolean member value, it will ether be equivalent to
``std::true_type`` if *all* of the traits ``value`` members are true.
Otherwise, it will be equivalent to ``std::false_type``

.. type:: any_traits<Args>

Works much like :type:`all_traits\<Args>`, however only *one* of the given
traits in *Args* must be true.

.. type:: no_traits<Args>

The inverse of :type:`all_traits\<Args>`. Will only be true if every
trait in *Args* is false.
13 changes: 5 additions & 8 deletions include/core/any.hpp
Expand Up @@ -194,8 +194,9 @@ class any final {
}

void swap (any& that) noexcept {
std::swap(this->table, that.table);
std::swap(this->data, that.data);
using std::swap;
swap(this->table, that.table);
swap(this->data, that.data);
}

void clear () noexcept {
Expand Down Expand Up @@ -264,12 +265,8 @@ template <
return *pointer;
}

}} /* namespace core::v1 */

namespace std {
inline void swap (any& lhs, any& rhs) noexcept { lhs.swap(rhs); }

inline void swap (core::any& lhs, core::any& rhs) noexcept { lhs.swap(rhs); }

} /* namespace std */
}} /* namespace core::v1 */

#endif /* CORE_ANY_HPP */
24 changes: 11 additions & 13 deletions include/core/expected.hpp
Expand Up @@ -128,18 +128,17 @@ struct expected final {
}

void swap (expected& that) noexcept(
std::is_nothrow_move_constructible<value_type>::value and
noexcept(
std::swap(std::declval<value_type&>(), std::declval<value_type&>())
)
is_nothrow_swappable<value_type>::value
) {
using std::swap;

if (not this->valid and not that.valid) {
std::swap(this->ptr, that.ptr);
swap(this->ptr, that.ptr);
return;
}

if (this->valid and that.valid) {
std::swap(this->val, that.val);
swap(this->val, that.val);
return;
}

Expand Down Expand Up @@ -206,7 +205,10 @@ struct expected<void> final {
explicit operator bool () const noexcept { return not this->ptr; }

std::exception_ptr get_ptr () const noexcept { return this->ptr; }
void swap (expected& that) noexcept { std::swap(this->ptr, that.ptr); }
void swap (expected& that) noexcept {
using std::swap;
swap(this->ptr, that.ptr);
}

template <class E> E expect () const noexcept(false) {
try { this->raise(); }
Expand Down Expand Up @@ -285,15 +287,11 @@ auto make_expected (std::exception_ptr error) noexcept -> expected<T> {
return expected<T> { error };
}

}} /* namespace core::v1 */

namespace std {

template <class T>
void swap (core::v1::expected<T>& lhs, core::v1::expected<T>& rhs) noexcept(
void swap (expected<T>& lhs, expected<T>& rhs) noexcept(
noexcept(lhs.swap(rhs))
) { lhs.swap(rhs); }

} /* namespace std */
}} /* namespace core::v1 */

#endif /* CORE_EXPECTED_HPP */
52 changes: 29 additions & 23 deletions include/core/memory.hpp
Expand Up @@ -205,8 +205,9 @@ struct poly_ptr final {
}

void swap (poly_ptr& that) noexcept {
std::swap(this->get_copier(), that.get_copier());
std::swap(this->ptr, that.ptr);
using std::swap;
swap(this->get_copier(), that.get_copier());
swap(this->ptr, that.ptr);
}

private:
Expand Down Expand Up @@ -235,6 +236,8 @@ template <
"deleter_type and copier_type have differing pointer types"
);

using data_type = std::tuple<pointer, deleter_type, copier_type>;

deep_ptr (
pointer ptr,
impl::deep_lvalue<deleter_type> deleter,
Expand Down Expand Up @@ -328,15 +331,18 @@ template <
}

void reset (pointer ptr = pointer { }) noexcept {
std::swap(std::get<0>(this->data), ptr);
using std::swap;
swap(std::get<0>(this->data), ptr);
if (not ptr) { return; }
this->get_deleter()(ptr);
}

void swap (deep_ptr& that) noexcept { std::swap(this->data, that.data); }
void swap (deep_ptr& that) noexcept(is_nothrow_swappable<data_type>::value) {
using std::swap;
swap(this->data, that.data);
}

private:
using data_type = std::tuple<pointer, deleter_type, copier_type>;
data_type data;
};

Expand Down Expand Up @@ -391,7 +397,10 @@ struct observer_ptr final {
return *this;
}

void swap (observer_ptr& that) noexcept { std::swap(this->ptr, that.ptr); }
void swap (observer_ptr& that) noexcept {
using std::swap;
swap(this->ptr, that.ptr);
}

explicit operator const_pointer () const noexcept { return this->get(); }
explicit operator pointer () noexcept { return this->get(); }
Expand Down Expand Up @@ -761,27 +770,24 @@ template <
class... Args
> auto make_unique(Args&&...) -> void = delete;

}} /* namespace core::v1 */

namespace std {

template <class T, class D>
void swap (
core::v1::poly_ptr<T, D>& lhs,
core::v1::poly_ptr<T, D>& rhs
) noexcept { lhs.swap(rhs); }
void swap (poly_ptr<T, D>& lhs, poly_ptr<T, D>& rhs) noexcept(
noexcept(lhs.swap(rhs))
) { lhs.swap(rhs); }

template <class T, class Deleter, class Copier>
void swap (
core::v1::deep_ptr<T, Deleter, Copier>& lhs,
core::v1::deep_ptr<T, Deleter, Copier>& rhs
) noexcept { lhs.swap(rhs); }
template <class T, class D, class C>
void swap (deep_ptr<T, D, C>& lhs, deep_ptr<T, D, C>& rhs) noexcept(
noexcept(lhs.swap(rhs))
) { lhs.swap(rhs); }

template <class W>
void swap (
core::v1::observer_ptr<W>& lhs,
core::v1::observer_ptr<W>& rhs
) noexcept { lhs.swap(rhs); }
void swap (observer_ptr<W>& lhs, observer_ptr<W>& rhs) noexcept(
noexcept(lhs.swap(rhs))
) { lhs.swap(rhs); }

}} /* namespace core::v1 */

namespace std {

template <class T, class D>
struct hash<core::v1::poly_ptr<T, D>> {
Expand Down
18 changes: 8 additions & 10 deletions include/core/optional.hpp
Expand Up @@ -218,14 +218,12 @@ struct optional final {
}

void swap (optional& that) noexcept (
std::is_nothrow_move_constructible<value_type>::value and
noexcept(
std::swap(std::declval<value_type&>(), std::declval<value_type&>())
)
is_nothrow_swappable<value_type>::value
) {
using std::swap;
if (not this->engaged and not that.engaged) { return; }
if (this->engaged and that.engaged) {
std::swap(**this, *that);
swap(**this, *that);
return;
}

Expand Down Expand Up @@ -326,15 +324,15 @@ bool operator < (optional<T> const& opt, T const& value) noexcept {
return bool(opt) ? std::less<T>{ }(*opt, value) : true;
}

template <class T>
void swap (optional<T>& lhs, optional<T>& rhs) noexcept(
noexcept(lhs.swap(rhs))
) { lhs.swap(rhs); }

}} /* namespace core::v1 */

namespace std {

template <class Type>
void swap (core::optional<Type>& lhs, core::optional<Type>& rhs) noexcept(
noexcept(lhs.swap(rhs))
) { lhs.swap(rhs); }

template <class Type>
struct hash<core::optional<Type>> {
using result_type = typename hash<Type>::result_type;
Expand Down
20 changes: 8 additions & 12 deletions include/core/range.hpp
Expand Up @@ -257,9 +257,10 @@ struct range {
);
}

void swap (range& that) noexcept {
std::swap(this->begin_, that.begin_);
std::swap(this->end_, that.end_);
void swap (range& that) noexcept(is_nothrow_swappable<iterator>::value) {
using std::swap;
swap(this->begin_, that.begin_);
swap(this->end_, that.end_);
}

private:
Expand Down Expand Up @@ -302,16 +303,11 @@ auto make_range (std::basic_streambuf<CharT, Traits>* buffer) -> range<
return make_range(iterator { buffer }, iterator { });
}

}} /* namespace core::v1 */

namespace std {

template <class Iterator>
void swap (
core::v1::range<Iterator>& lhs,
core::v1::range<Iterator>& rhs
) noexcept { lhs.swap(rhs); }
void swap (range<Iterator>& lhs, range<Iterator>& rhs) noexcept(
noexcept(lhs.swap(rhs))
) { lhs.swap(rhs); }

} /* namespace std */
}} /* namespace core::v1 */

#endif /* CORE_RANGE_HPP */
17 changes: 9 additions & 8 deletions include/core/string.hpp
Expand Up @@ -270,8 +270,9 @@ struct basic_string_view {
}

void swap (basic_string_view& that) noexcept {
std::swap(this->str, that.str);
std::swap(this->len, that.len);
using std::swap;
swap(this->str, that.str);
swap(this->len, that.len);
}

private:
Expand Down Expand Up @@ -326,16 +327,16 @@ std::basic_ostream<CharT, Traits>& operator << (
basic_string_view<CharT, Traits> const& str
) { for (auto ch : str) { os << ch; } return os; }

}} /* namespace core::v1 */

namespace std {

template <class CharT, class Traits>
void swap (
core::v1::basic_string_view<CharT, Traits>& lhs,
core::v1::basic_string_view<CharT, Traits>& rhs
basic_string_view<CharT, Traits>& lhs,
basic_string_view<CharT, Traits>& rhs
) noexcept { return lhs.swap(rhs); }

}} /* namespace core::v1 */

namespace std {

template <typename CharT, typename Traits>
struct hash<core::v1::basic_string_view<CharT, Traits>> {
using argument_type = core::v1::basic_string_view<CharT, Traits>;
Expand Down
21 changes: 21 additions & 0 deletions include/core/type_traits.hpp
Expand Up @@ -238,6 +238,27 @@ using is_swappable = std::integral_constant<
template <class T, class U=T>
using is_nothrow_swappable = impl::is_nothrow_swappable<T, U>;

/* all-traits */
template <class...> struct all_traits;
template <class T, class... Args>
struct all_traits<T, Args...> : std::integral_constant<bool,
T::value and all_traits<Args...>::value
> { };
template <> struct all_traits<> : std::true_type { };

/* any-traits */
template <class...> struct any_traits;
template <class T, class... Args>
struct any_traits<T, Args...> : std::integral_constant<bool,
T::value or any_traits<Args...>::value
> { };
template <> struct any_traits<> : std::false_type { };

/* no-traits */
template <class... Args> struct no_traits : std::integral_constant<bool,
not all_traits<Args...>::value
> { };

}} /* namespace core::v1 */

#endif /* CORE_TYPE_TRAITS_HPP */
21 changes: 12 additions & 9 deletions include/core/variant.hpp
Expand Up @@ -135,9 +135,10 @@ class variant final {
using data_type = std::reference_wrapper<storage_type>;
data_type data;
template <class T>
void operator ()(T&& value) noexcept(
noexcept(std::swap(std::declval<T&>(), std::declval<T&>()))
) { std::swap(reinterpret_cast<decay_t<T>&>(this->data.get()), value); }
void operator ()(T&& value) noexcept(is_nothrow_swappable<T>::value) {
using std::swap;
swap(reinterpret_cast<decay_t<T>&>(this->data.get()), value);
}
};

struct equality final {
Expand Down Expand Up @@ -259,7 +260,9 @@ class variant final {
return that.visit(less_than { std::cref(this->data) });
}

void swap (variant& that) noexcept {
void swap (variant& that) noexcept(
all_traits<is_nothrow_swappable<Ts>...>::value
) {
if (this->which() == that.which()) {
that.visit(swapper { std::ref(this->data) });
return;
Expand Down Expand Up @@ -361,15 +364,15 @@ class variant final {
std::uint8_t tag;
};

template <class... Ts>
void swap (variant<Ts...>& lhs, variant<Ts...>& rhs) noexcept(
noexcept(lhs.swap(rhs))
) { lhs.swap(rhs); }

}} /* namespace core::v1 */

namespace std {

template <class... Ts>
void swap (core::v1::variant<Ts...>& lhs, core::v1::variant<Ts...>& rhs) {
lhs.swap(rhs);
}

template <class... Ts>
struct hash<core::v1::variant<Ts...>> {
using argument_type = core::v1::variant<Ts...>;
Expand Down
3 changes: 2 additions & 1 deletion tests/any.cpp
Expand Up @@ -88,10 +88,11 @@ int main () {
},

task("swap") = [] {
using std::swap;
std::uint64_t integer = 42;
core::any value { integer };
core::any to_swap { };
std::swap(value, to_swap);
swap(value, to_swap);
assert::is_true(value.empty());
assert::is_false(to_swap.empty());
},
Expand Down

0 comments on commit 3027316

Please sign in to comment.