#include <type_traits>
#include <unordered_map>
#include <vector>
#include <queue>
#include <iostream>
#include <map>
#include <memory>
#include <functional>
#include <cmath>
#include <list>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/core/demangle.hpp>
namespace xstd
{
template <typename Container>
struct container_traits
{
};
template <template <typename, typename> typename ValueContainer,
typename Value,
typename Allocator>
struct container_traits<ValueContainer<Value, Allocator>> {
using container_type = ValueContainer<Value, Allocator>;
using allocator_type = typename container_type::allocator_type;
using allocator_traits = std::allocator_traits<allocator_type>;
using value_type = Value;
template <typename U>
using rebound_allocator_type = typename allocator_traits::template rebind_alloc<U>;
template <typename U>
using rebound_container_type = ValueContainer<U, rebound_allocator_type<U>>;
};
template <template <typename, typename, typename, typename> typename KeyValueContainer,
typename Key,
typename Value,
template <typename> typename Less,
typename Allocator>
struct container_traits<KeyValueContainer<Key, Value, Less<Key>, Allocator>> {
using container_type = KeyValueContainer<Key, Value, Less<Key>, Allocator>;
using allocator_type = typename container_type::allocator_type;
using less_type = Less<Key>;
using allocator_traits = std::allocator_traits<allocator_type>;
using key_type = Key;
using value_type = Value;
template <typename U>
using rebound_allocator_type = typename allocator_traits::template rebind_alloc<U>;
template <typename U>
using rebound_compare_type = Less<U>;
template <typename T, typename U>
using rebound_kv_container_type = KeyValueContainer<T, U, rebound_compare_type<T>, rebound_allocator_type<std::pair<T, U>>>;
template <typename T,
typename U = rebound_allocator_type<T>,
template <typename, typename> typename Container = std::vector>
using rebound_container_type = Container<T, U>;
};
template <template <typename, size_t> typename Container, typename T, size_t N>
struct container_traits<Container<T, N>>
{
using container_type = Container<T, N>;
using value_type = T;
constexpr static const size_t arity = N;
template <typename U>
using rebound_container_type = Container<U, arity>;
};
template <typename T,
typename Container,
typename U>
auto transform(Container const& source, std::function<U(T*)> fn)
-> std::enable_if<
std::is_same<
typename container_traits<Container>::value_type,
typename std::add_pointer<T>::type
>::value,
typename container_traits<Container>::template rebound_container_type<U>
> {
auto begin = boost::make_transform_iterator(source.begin(), fn);
auto end = boost::make_transform_iterator(source.end(), fn);
using target_t = typename container_traits<Container>::template rebound_container_type<U>;
target_t transformed(begin, end);
return transformed;
}
template <typename T,
typename Container,
typename U>
auto transform(Container const& source, std::function<U(T const&)> fn)
-> typename container_traits<Container>::template rebound_container_type<U> {
auto begin = boost::make_transform_iterator(source.begin(), fn);
auto end = boost::make_transform_iterator(source.end(), fn);
using target_t = typename container_traits<Container>::template rebound_container_type<U>;
target_t transformed(begin, end);
return transformed;
}
// Resolves for free-standing function pointer arguments
template <typename U, typename Container, typename T>
auto transform(Container const& source, U (*fn)(T))
-> typename container_traits<Container>::template rebound_container_type<U> {
auto begin = boost::make_transform_iterator(source.begin(), fn);
auto end = boost::make_transform_iterator(source.end(), fn);
using target_t = typename container_traits<Container>::template rebound_container_type<U>;
target_t transformed(begin, end);
return transformed;
}
template <typename Container, typename Transform>
auto transform(Container const& source, Transform fn)
-> typename container_traits<Container>::template rebound_container_type<
typename std::result_of<Transform(typename container_traits<Container>::value_type)>::type
> {
auto begin = boost::make_transform_iterator(source.begin(), fn);
auto end = boost::make_transform_iterator(source.end(), fn);
using U = typename std::result_of<Transform(typename container_traits<Container>::value_type)>::type;
using target_t = typename container_traits<Container>::template rebound_container_type<U>;
target_t transformed(begin, end);
return transformed;
}
template <template <typename, size_t> typename Container, typename T, size_t N, typename Transform>
auto transform(Container<T, N> const& source, Transform fn)
-> typename container_traits<Container<T, N>>::template rebound_container_type<
typename std::result_of<Transform(typename container_traits<Container<T, N>>::value_type)>::type
> {
using U = typename std::result_of<Transform(typename container_traits<Container<T, N>>::value_type)>::type;
using target_t = typename container_traits<Container<T, N>>::template rebound_container_type<U>;
target_t transformed;
for (size_t i = 0; i < N; ++i) {
transformed[i] = fn(source[i]);
}
return transformed;
}
}
int round(float f) { return std::round(f); }
int main()
{
using vint_trait = xstd::container_traits<std::vector<int>>;
using ftype = typename vint_trait::template rebound_container_type<float>;
using mintfloat_trait = xstd::container_traits<std::map<int, float>>;
using miftype = typename mintfloat_trait::template rebound_kv_container_type<float, int>;
using mitype = typename mintfloat_trait::template rebound_container_type<float>;
std::cout << boost::core::demangle(typeid(ftype).name()) << std::endl;
std::cout << boost::core::demangle(typeid(miftype).name()) << std::endl;
std::cout << boost::core::demangle(typeid(mitype).name()) << std::endl;
{
std::vector<int> is { 1, 2, 3, 4, 5 };
std::vector<float> fs = xstd::transform(is, [](int i) -> float { return float(0.5f + i); });
for (auto&& itr : fs) {
std::cout << itr << " ";
}std::cout << std::endl;
}
{
std::array<int, 5> ia { 1, 2, 3, 4, 5 };
std::array<float, 5> fa = xstd::transform(ia, [](int i) -> float { return float(0.75f + i); });
for (auto&& itr : fa) {
std::cout << itr << " ";
}
std::cout << std::endl;
}
return 0;
}