forked from OctaForge/libostd
allow constructing unordered_maps from any 2-tuple range
This commit is contained in:
parent
407d4a524f
commit
9e87d372de
|
@ -33,6 +33,19 @@ struct ranged_traits<std::unordered_map<K, T, H, E, A> const> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template<typename T>
|
||||||
|
std::integral_constant<
|
||||||
|
bool, std::tuple_size<T>::value == 2
|
||||||
|
> tuple2_like_test(typename std::tuple_size<T>::type *);
|
||||||
|
|
||||||
|
template<typename>
|
||||||
|
std::false_type tuple2_like_test(...);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr bool is_2tuple_like = decltype(tuple2_like_test<T>(0))::value;
|
||||||
|
}
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename K, typename T, typename H = std::hash<K>,
|
typename K, typename T, typename H = std::hash<K>,
|
||||||
typename E = std::equal_to<K>,
|
typename E = std::equal_to<K>,
|
||||||
|
@ -42,14 +55,39 @@ inline std::unordered_map<K, T, H, E, A> make_unordered_map(
|
||||||
R range, size_t bcount = 1, H const &hash = H{},
|
R range, size_t bcount = 1, H const &hash = H{},
|
||||||
E const &kequal = E{}, A const &alloc = A{}
|
E const &kequal = E{}, A const &alloc = A{}
|
||||||
) {
|
) {
|
||||||
|
static_assert(
|
||||||
|
detail::is_2tuple_like<RangeValue<R>>,
|
||||||
|
"the range element must be a pair/2-tuple"
|
||||||
|
);
|
||||||
|
|
||||||
|
using MP = std::pair<K const, T>;
|
||||||
|
using AK = std::tuple_element_t<0, RangeValue<R>>;
|
||||||
|
using AV = std::tuple_element_t<1, RangeValue<R>>;
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_constructible_v<K const, AK> && std::is_constructible_v<T, AV>,
|
||||||
|
"incompatible range element type"
|
||||||
|
);
|
||||||
|
|
||||||
std::unordered_map<K, T, H, E, A> ret{bcount, hash, kequal, alloc};
|
std::unordered_map<K, T, H, E, A> ret{bcount, hash, kequal, alloc};
|
||||||
|
|
||||||
using C = RangeCategory<R>;
|
using C = RangeCategory<R>;
|
||||||
if constexpr(std::is_convertible_v<C, FiniteRandomAccessRangeTag>) {
|
if constexpr(std::is_convertible_v<C, FiniteRandomAccessRangeTag>) {
|
||||||
/* at least try to preallocate here... */
|
/* at least try to preallocate here... */
|
||||||
ret.reserve(range.size());
|
ret.reserve(range.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; !range.empty(); range.pop_front()) {
|
for (; !range.empty(); range.pop_front()) {
|
||||||
ret.emplace(range.front());
|
if constexpr(std::is_constructible_v<MP, RangeValue<R>>) {
|
||||||
|
ret.emplace(range.front());
|
||||||
|
} else {
|
||||||
|
/* store a temporary to prevent calling front() twice; however,
|
||||||
|
* for values that can be used to construct the pair directly
|
||||||
|
* we can just do the above
|
||||||
|
*/
|
||||||
|
RangeValue<R> v{range.front()};
|
||||||
|
ret.emplace(std::move(std::get<0>(v)), std::move(std::get<1>(v)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -59,19 +97,24 @@ template<
|
||||||
typename H = std::hash<typename RangeValue<R>::first_type>,
|
typename H = std::hash<typename RangeValue<R>::first_type>,
|
||||||
typename E = std::equal_to<typename RangeValue<R>::first_type>,
|
typename E = std::equal_to<typename RangeValue<R>::first_type>,
|
||||||
typename A = std::allocator<std::pair<
|
typename A = std::allocator<std::pair<
|
||||||
typename RangeValue<R>::first_type, typename RangeValue<R>::second_type
|
std::tuple_element_t<0, RangeValue<R>>,
|
||||||
|
std::tuple_element_t<1, RangeValue<R>>
|
||||||
>>
|
>>
|
||||||
>
|
>
|
||||||
inline std::unordered_map<
|
inline std::unordered_map<
|
||||||
typename RangeValue<R>::first_type,
|
std::tuple_element_t<0, RangeValue<R>>,
|
||||||
typename RangeValue<R>::second_type, H, E, A
|
std::tuple_element_t<1, RangeValue<R>>, H, E, A
|
||||||
> make_unordered_map(
|
> make_unordered_map(
|
||||||
R &&range, size_t bcount = 1, H const &hash = H{},
|
R &&range, size_t bcount = 1, H const &hash = H{},
|
||||||
E const &kequal = E{}, A const &alloc = A{}
|
E const &kequal = E{}, A const &alloc = A{}
|
||||||
) {
|
) {
|
||||||
|
static_assert(
|
||||||
|
detail::is_2tuple_like<RangeValue<R>>,
|
||||||
|
"the range elements must be pairs/2-tuples"
|
||||||
|
);
|
||||||
return make_unordered_map<
|
return make_unordered_map<
|
||||||
typename RangeValue<R>::first_type,
|
std::tuple_element_t<0, RangeValue<R>>,
|
||||||
typename RangeValue<R>::second_type, H, E, A
|
std::tuple_element_t<1, RangeValue<R>>, H, E, A
|
||||||
>(std::forward<R>(range), bcount, hash, kequal, alloc);
|
>(std::forward<R>(range), bcount, hash, kequal, alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue