rec/fplus/container_traits.hpp
2020-03-18 14:42:46 +08:00

157 lines
6.9 KiB
C++
Executable File

// Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
// https://github.com/Dobiasd/FunctionalPlus
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <array>
#include <deque>
#include <forward_list>
#include <list>
#include <map>
#include <limits>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#include <fplus/internal/invoke.hpp>
namespace fplus
{
namespace internal
{
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#endif
template<class T> struct has_order : public std::false_type {};
template<class T, std::size_t N> struct has_order<std::array<T, N>> : public std::true_type {};
template<class T, class Alloc> struct has_order<std::vector<T, Alloc>> : public std::true_type {};
template<class T, class Alloc> struct has_order<std::deque<T, Alloc>> : public std::true_type {};
template<class T, class Alloc> struct has_order<std::forward_list<T, Alloc>> : public std::true_type {};
template<class T, class Alloc> struct has_order<std::list<T, Alloc>> : public std::true_type {};
template<class T, class Alloc> struct has_order<std::set<T, Alloc>> : public std::false_type {};
template<class T, class Container> struct has_order<std::stack<T, Container>> : public std::true_type {};
template<class T, class Container> struct has_order<std::queue<T, Container>> : public std::true_type {};
template<class T, class Container, class Compare> struct has_order<std::priority_queue<T, Container, Compare>> : public std::false_type {};
template<class CharT, class Traits, class Alloc> struct has_order<std::basic_string<CharT, Traits, Alloc>> : public std::true_type {};
// http://stackoverflow.com/a/33828321/1866775
template<class Cont, class NewT, int SizeOffset = std::numeric_limits<int>::lowest()> struct same_cont_new_t : public std::false_type{};
template<class T, std::size_t N, class NewT, int SizeOffset> struct same_cont_new_t<std::array<T, N>, NewT, SizeOffset>
{
static_assert(SizeOffset != std::numeric_limits<int>::lowest(), "Size of std::array must be known at compile-time.");
typedef typename std::array<NewT, static_cast<std::size_t>(static_cast<int>(N) + SizeOffset)> type;
};
template<class T, class Alloc, class NewT, int SizeOffset> struct same_cont_new_t<std::vector<T, Alloc>, NewT, SizeOffset> { typedef typename std::vector<NewT> type; };
template<class T, class Alloc, class NewT, int SizeOffset> struct same_cont_new_t<std::deque<T, Alloc>, NewT, SizeOffset> { typedef typename std::deque<NewT> type; };
template<class T, class Alloc, class NewT, int SizeOffset> struct same_cont_new_t<std::forward_list<T, Alloc>, NewT, SizeOffset> { typedef typename std::forward_list<NewT> type; };
template<class T, class Alloc, class NewT, int SizeOffset> struct same_cont_new_t<std::list<T, Alloc>, NewT, SizeOffset> { typedef typename std::list<NewT> type; };
template<class T, class Alloc, class NewT, int SizeOffset> struct same_cont_new_t<std::set<T, Alloc>, NewT, SizeOffset> { typedef typename std::set<NewT> type; };
template<class T, class Container, class NewT, int SizeOffset> struct same_cont_new_t<std::stack<T, Container>, NewT, SizeOffset> { typedef typename std::stack<NewT, Container> type; };
template<class T, class Container, class NewT, int SizeOffset> struct same_cont_new_t<std::queue<T, Container>, NewT, SizeOffset> { typedef typename std::queue<NewT, Container> type; };
template<class T, class Container, class Compare, class NewT, int SizeOffset> struct same_cont_new_t<std::priority_queue<T, Container, Compare>, NewT, SizeOffset> { typedef typename std::priority_queue<NewT, Container, Compare> type; };
template<class CharT, class Traits, class Alloc, class NewT, int SizeOffset> struct same_cont_new_t<std::basic_string<CharT, Traits, Alloc>, NewT, SizeOffset> { typedef typename std::basic_string<NewT, Traits, Alloc> type; };
template<class Cont, class NewKey, class NewVal> struct SameMapTypeNewTypes : public std::false_type {};
template<class Key, class T, class Compare, class Alloc, class NewKey, class NewVal> struct SameMapTypeNewTypes<std::map<Key, T, Compare, Alloc>, NewKey, NewVal> { typedef typename std::map<NewKey, NewVal> type; };
template<class Key, class T, class Compare, class Alloc, class NewKey, class NewVal> struct SameMapTypeNewTypes<std::unordered_map<Key, T, Compare, Alloc>, NewKey, NewVal> { typedef typename std::unordered_map<NewKey, NewVal> type; };
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
template<
typename ContIn,
typename F,
int SizeOffset = std::numeric_limits<int>::lowest(),
typename T = typename ContIn::value_type,
typename ContOut = typename same_cont_new_t<ContIn, std::decay_t<internal::invoke_result_t<F, T>>, SizeOffset>::type>
struct same_cont_new_t_from_unary_f
{
typedef ContOut type;
};
template<
typename ContIn,
typename F,
typename T1,
typename T2,
int SizeOffset = std::numeric_limits<int>::lowest(),
typename ContOut = typename same_cont_new_t<ContIn, std::decay_t<internal::invoke_result_t<F, T1, T2>>, SizeOffset>::type>
struct same_cont_new_t_from_binary_f
{
typedef ContOut type;
};
// https://stackoverflow.com/a/44549820/1866775
template<class T>
struct can_self_assign {
using type = std::is_assignable<T&, T>;
};
template<typename T>
using can_self_assign_t = typename can_self_assign<T>::type;
template<typename T0, typename T1>
struct can_self_assign<std::pair<T0, T1>>
{
enum { t0 = can_self_assign_t<T0>::value, t1 = can_self_assign_t<T1>::value, x = t0&&t1 };
using type = std::integral_constant<bool, x>;
};
template<>
struct can_self_assign<std::tuple<>>
{
using type = std::integral_constant<bool, true>;
};
template<typename T0, typename...Ts>
struct can_self_assign<std::tuple<T0, Ts...>>
{
using type = std::integral_constant<bool, can_self_assign_t<T0>::value && can_self_assign_t<std::tuple<Ts...>>::value >;
};
template<class T, T v>
struct reuse_container_bool_t {
};
using create_new_container_t = reuse_container_bool_t<bool, false>;
using reuse_container_t = reuse_container_bool_t<bool, true>;
template <typename Container>
struct can_reuse
{
using dContainer = typename std::decay<Container>::type;
using can_assign = can_self_assign_t<typename dContainer::value_type>;
using cannot_reuse = std::is_lvalue_reference<Container>;
using value = reuse_container_bool_t<bool, can_assign::value && !cannot_reuse::value>;
};
template<typename Container>
using can_reuse_v = typename can_reuse<Container>::value;
template <typename T>
struct remove_const_and_ref
{
using type = typename std::remove_const<typename std::remove_reference<T>::type>::type;
};
template<typename T>
using remove_const_and_ref_t = typename remove_const_and_ref<T>::type;
} // namespace internal
} // namespace fplus