Skip to content

Commit 5736f98

Browse files
committed
VctrBase: Added toStdMap member function
1 parent f4eb882 commit 5736f98

File tree

4 files changed

+58
-7
lines changed

4 files changed

+58
-7
lines changed

include/vctr/Containers/VctrBase.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,23 @@ class VctrBase : private Config,
931931
/** Returns true if any real or imaginary part of an element is NaN. */
932932
constexpr bool anyElementIsNaN() requires is::complexFloatNumber<ElementType>;
933933

934+
//==============================================================================
935+
// Conversion operators
936+
//==============================================================================
937+
/** If value_type is std::pair, this converts the content into a std::map with pair::first_type being the key and pair::second_type the value. */
938+
constexpr auto toStdMap() &&
939+
requires is::stdPair<value_type> && (! is::view<StorageType>)
940+
{
941+
return std::map<typename value_type::first_type, typename value_type::second_type> { std::make_move_iterator (begin()), std::make_move_iterator (end()) };
942+
}
943+
944+
/** If value_type is std::pair, this converts the content into a std::map with pair::first_type being the key and pair::second_type the value. */
945+
constexpr auto toStdMap() const &
946+
requires is::stdPair<value_type>
947+
{
948+
return std::map<typename value_type::first_type, typename value_type::second_type> { begin(), end() };
949+
}
950+
934951
protected:
935952
//==============================================================================
936953
constexpr VctrBase()

include/vctr/TypeTraitsAndConcepts/GenericConcepts.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,6 @@ struct IsStdUniquePtr : std::false_type {};
6666

6767
template <class T, class D>
6868
struct IsStdUniquePtr<std::unique_ptr<T, D>> : std::true_type {};
69-
70-
template <class T>
71-
struct IsStdTuple : std::false_type {};
72-
73-
template <class... T>
74-
struct IsStdTuple<std::tuple<T...>> : std::true_type {};
7569
// clang-format on
7670

7771
} // namespace vctr::detail
@@ -103,9 +97,13 @@ concept uniquePtr = detail::IsStdUniquePtr<T>::value;
10397
template <class T>
10498
concept lvalueReference = std::is_lvalue_reference_v<T>;
10599

100+
/** Constrains the type to be any instance of std::pair */
101+
template <class T>
102+
concept stdPair = requires (T& t) { [] <class A, class B> (std::pair<A, B>&) {} (t); };
103+
106104
/** Constrains the type to be any instance of std::tuple */
107105
template <class T>
108-
concept stdTuple = detail::IsStdTuple<T>::value;
106+
concept stdTuple = requires (T& t) { [] <class... Ts> (std::tuple<Ts...>&) {} (t); };
109107

110108
template <class T, class... TupleTypes>
111109
concept stdTupleWithTypes = std::same_as<T, std::tuple<TupleTypes...>>;

include/vctr/vctr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include <vector>
4747
#include <array>
4848
#include <span>
49+
#include <map>
4950
#include <concepts>
5051
#include <cmath>
5152
#include <ostream>

test/TestCases/VctrBaseMemberFunctions.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,41 @@ TEMPLATE_TEST_CASE ("anyElementIsNaN", "[VCTR][VctrBaseMemberFunctions]", float,
494494
REQUIRE (cplx.anyElementIsNaN());
495495
}
496496

497+
TEST_CASE ("toStdMap", "[VCTR][VctrBaseMemberFunctions]")
498+
{
499+
vctr::Vector<std::pair<int, std::string>> pairs { { 1, "one" }, { 2, "two" }, { 3, "three_appended_with_a_long_string_to_avoid_small_string_optimization" } };
500+
auto pairsSub = pairs.subSpan<1>();
501+
502+
// Deliberately moving here to check if moving a view results in leaving the source intact
503+
auto subMap = std::move (pairsSub).toStdMap();
504+
505+
// Check if the generated map is correct
506+
REQUIRE_FALSE (subMap.contains (1));
507+
REQUIRE (subMap.contains (2));
508+
REQUIRE (subMap.contains (3));
509+
REQUIRE (subMap[2] == "two");
510+
REQUIRE (subMap[3] == "three_appended_with_a_long_string_to_avoid_small_string_optimization");
511+
REQUIRE (subMap.size() == 2);
512+
513+
// Check if the original values stayed valid. There is no guarantee that a string is empty after
514+
// moving but it's likely that this is at least the case after moving a long string, so this test
515+
// tries to catch that kind of mistake
516+
const auto& [key, value] = pairs.back();
517+
REQUIRE (key == 3);
518+
REQUIRE (value == "three_appended_with_a_long_string_to_avoid_small_string_optimization");
519+
520+
// This time we expect the move iterator to be used
521+
auto map = std::move (pairs).toStdMap();
522+
523+
REQUIRE (map.contains (1));
524+
REQUIRE (map.contains (2));
525+
REQUIRE (map.contains (3));
526+
REQUIRE (map[1] == "one");
527+
REQUIRE (map[2] == "two");
528+
REQUIRE (map[3] == "three_appended_with_a_long_string_to_avoid_small_string_optimization");
529+
REQUIRE (map.size() == 3);
530+
}
531+
497532
TEMPLATE_TEST_CASE ("operator==", "[VCTR][VctrBaseFreeFunctions]", float, uint64_t, std::string)
498533
{
499534
auto a = UnitTestValues<TestType>::template array<100, 0>();

0 commit comments

Comments
 (0)