Skip to content

Commit 52a5ef0

Browse files
committed
[misc] simplify bio::ranges::dictionary
1 parent 3938762 commit 52a5ef0

File tree

4 files changed

+41
-51
lines changed

4 files changed

+41
-51
lines changed

include/bio/ranges/container/dictionary.hpp

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ namespace bio::ranges
4545
* \ingroup container
4646
* \tparam key_t The key type; must be convertible to std::string_view (e.g. also std::string).
4747
* \tparam mapped_t The mapped type; must be an object type.
48-
* \tparam mapped_t_is_context_aware See below.
4948
*
5049
* This container behaves like a mixture of std::vector and std::unordered_map.
5150
*
@@ -76,18 +75,13 @@ namespace bio::ranges
7675
*
7776
* \include test/snippet/ranges/container/dictionary.cpp
7877
*
79-
* ### Context-aware mapped value types
78+
* ### Static string element access
8079
*
81-
* If the template parameter `mapped_t_is_context_aware` is set to true, the #reference type of the dictionary
82-
* becomes `bio::meta::tuple<key_t const &, mapped_t const &>`, i.e. the mapped value in dictionary elements cannot be
83-
* changed via regular element access.
84-
*
85-
* Additionally, given an object `o` of type `mapped_t`, if `get<"foo">(o)` is valid,
80+
* Given an object `o` of type `mapped_t`, if `get<"foo">(o)` is valid,
8681
* this container provides a special interface:
8782
*
8883
* * A `get<"foo">(dict)` friend function that calls `get<"foo">(dict.at("foo"))`.
8984
* * The `.at("foo"_vtag)` and `operator["foo"_vtag]` member functions with identical semantics.
90-
* * These functions may or may not expose mutable references to the mapped value (or one of its members).
9185
*
9286
* In combination with element types that are derived from std::variant (and additionally provide the aforementioned
9387
* string-based get-interface), this can be used to create heterogeneous dictionaries, i.e. transparent access
@@ -96,7 +90,7 @@ namespace bio::ranges
9690
* \include test/snippet/ranges/container/dictionary_het.cpp
9791
*
9892
*/
99-
template <typename key_t, typename mapped_t, bool mapped_t_is_context_aware = false>
93+
template <typename key_t, typename mapped_t>
10094
class dictionary
10195
{
10296
public:
@@ -108,17 +102,13 @@ class dictionary
108102
/*!\name Associated types
109103
* \{
110104
*/
111-
using mapped_ref_t =
112-
std::conditional_t<mapped_t_is_context_aware, mapped_t const &, mapped_t &>; //!< Usually `mapped_t &`.
113-
using value_type = meta::tuple<key_t, mapped_t>; //!< The value_type type.
114-
using reference = meta::tuple<key_t const &, mapped_ref_t>; //!< The reference type.
115-
using const_reference = meta::tuple<key_t const &, mapped_t const &>; //!< The const_reference type.
116-
using difference_type = ptrdiff_t; //!< The difference_type type.
117-
using size_type = size_t; //!< The size_type type.
118-
using const_iterator = detail::random_access_iterator<dictionary const>; //!< The const_iterator type.
119-
using iterator = std::conditional_t<mapped_t_is_context_aware,
120-
const_iterator,
121-
detail::random_access_iterator<dictionary>>; //!< The iterator type.
105+
using value_type = meta::tuple<key_t, mapped_t>; //!< The value_type type.
106+
using reference = meta::tuple<key_t const &, mapped_t &>; //!< The reference type.
107+
using const_reference = meta::tuple<key_t const &, mapped_t const &>; //!< The const_reference type.
108+
using difference_type = ptrdiff_t; //!< The difference_type type.
109+
using size_type = size_t; //!< The size_type type.
110+
using iterator = detail::random_access_iterator<dictionary>; //!< The iterator type.
111+
using const_iterator = detail::random_access_iterator<dictionary const>; //!< The const_iterator type.
122112
//!\}
123113

124114
//!\cond
@@ -536,7 +526,7 @@ class dictionary
536526
*
537527
* Basic exception guarantee.
538528
*/
539-
mapped_ref_t at(het_key_t key)
529+
mapped_t & at(het_key_t key)
540530
{
541531
auto it = key_to_index.find(key);
542532
if (it == key_to_index.end())
@@ -570,7 +560,7 @@ class dictionary
570560
*
571561
* Basic exception guarantee.
572562
*/
573-
mapped_ref_t operator[](het_key_t key) { return at(key); }
563+
mapped_t & operator[](het_key_t key) { return at(key); }
574564

575565
//!\copydoc operator[](het_key_t key)
576566
mapped_t const & operator[](het_key_t key) const { return at(key); }
@@ -601,7 +591,7 @@ class dictionary
601591
*/
602592
template <small_string key>
603593
friend decltype(auto) get(meta::decays_to<dictionary> auto && dict)
604-
requires(mapped_t_is_context_aware && requires { get<key>(get<1>(dict.storage[0])); })
594+
requires(requires { get<key>(get<1>(dict.storage[0])); })
605595
{
606596
#ifdef __cpp_lib_generic_unordered_lookup
607597
auto it = dict.key_to_index.find(key);

test/snippet/ranges/container/dictionary.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ int main()
1111
employee_status.emplace_back("Maria", "promoted");
1212

1313
/* Access by position in dictionary; same as insert-order */
14-
auto && first = employee_status[0]; // a tuple of key and mapped_value
15-
fmt::print("{}\n", first); // prints '("Bob", "hired")'
16-
//get<0>(first) = "Rob"; // key cannot be changed
17-
get<1>(first) = "tired"; // mapped_value can be changed
18-
fmt::print("{}\n", employee_status[0]); // prints '("Bob", "tired")'
14+
auto && first = employee_status[0]; // a tuple of key and mapped_value
15+
fmt::print("{}\n", first); // prints '("Bob", "hired")'
16+
//get<0>(first) = "Rob"; // key cannot be changed
17+
get<1>(first) = "tired"; // mapped_value can be changed
18+
fmt::print("{}\n", employee_status[0]); // prints '("Bob", "tired")'
1919

2020
/* Access by key */
21-
auto && jane = employee_status["Jane"]; // the mapped_value belonging to Jane
22-
fmt::print("{}\n", jane); // prints 'hired'
23-
jane = "wired"; // can be changed
24-
fmt::print("{}\n", employee_status["Jane"]);// prints 'wired'
21+
auto && janes_status = employee_status["Jane"]; // the mapped_value belonging to Jane
22+
fmt::print("{}\n", janes_status); // prints 'hired'
23+
janes_status = "wired"; // can be changed
24+
fmt::print("{}\n", employee_status["Jane"]); // prints 'wired'
2525

2626
/* No implicit inserts like std::unordered_map */
27-
//employee_status["Shane"] = "hired"; // DOES NOT WORK.
27+
//employee_status["Shane"] = "hired"; // DOES NOT WORK.
2828
}

test/snippet/ranges/container/dictionary_het.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ using namespace bio::meta::literals;
2020
*/
2121
struct sam_optional_field : std::variant<std::string, int32_t>
2222
{
23+
sam_optional_field() = default;
24+
using base_t = std::variant<std::string, int32_t>;
25+
using base_t::base_t; // inherit constructors from variant
26+
2327
/* Declare the get<"foo">(obj) interface; overloads for cv-qualified versions omitted here. */
2428
template <bio::ranges::small_string tag>
2529
friend decltype(auto) get(sam_optional_field const & me)
@@ -51,19 +55,24 @@ struct sam_optional_field : std::variant<std::string, int32_t>
5155

5256
int main()
5357
{
54-
bio::ranges::dictionary<std::string, sam_optional_field, true> sam_optional_fields;
58+
bio::ranges::dictionary<std::string, sam_optional_field> sam_optional_fields;
5559

5660
/* You can easily insert elements of different types, but you need to make sure they match the predefined IDs! */
5761
sam_optional_fields.emplace_back("CO", "This is a comment.");
5862
sam_optional_fields.emplace_back("AS", 42); // Alignment score 42
5963
sam_optional_fields.emplace_back("NM", 23); // Edit distance 23
6064
sam_optional_fields.emplace_back("OA", "23M3I11M"); // Original cigar
6165

62-
// std::string s = sam_optional_fields["CO"]; // ["CO"] returns sam_optional_field
63-
std::string s = sam_optional_fields["CO"_vtag]; // ["CO"_vtag] returns std::string (type "inside variant")
64-
fmt::print("{}\n", s); // prints "This is a comment."
66+
// sam_optional_field s = sam_optional_fields["CO"]; // ["CO"] returns sam_optional_field
67+
std::string s = sam_optional_fields["CO"_vtag]; // ["CO"_vtag] returns std::string (type "inside variant")
68+
fmt::print("{}\n", s); // prints "This is a comment."
69+
70+
// sam_optional_field i = sam_optional_fields["AS"]; // ["AS"] returns sam_optional_field
71+
int32_t i = sam_optional_fields["AS"_vtag]; // ["AS"_vtag] returns int (type "inside variant")
72+
fmt::print("{}\n", i); // prints "42"
6573

66-
// int32_t i = sam_optional_fields["AS"]; // ["AS"] returns sam_optional_field
67-
int32_t i = sam_optional_fields["AS"_vtag]; // ["AS"_vtag] returns int (type "inside variant")
68-
fmt::print("{}\n", i); // prints "42"
74+
/* Do not do the following: */
75+
sam_optional_fields["CO"] = 3; // element type changed to int
76+
//std::string s2 = sam_optional_fields["CO"_vtag]; // ["CO"_vtag] still returns std::string!
77+
// (this throws std::bad_variant_access)
6978
}

test/unit/ranges/container/dictionary_test.cpp

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -455,20 +455,11 @@ TEST(het_dictionary_test, elem_t_test)
455455
EXPECT_SAME_TYPE(decltype(get<"int">(elem2)), int &);
456456
}
457457

458-
inline bio::ranges::dictionary<std::string, elem_t, true> dict{
458+
inline bio::ranges::dictionary<std::string, elem_t> dict{
459459
bio::meta::tuple{"string"s, elem1},
460460
bio::meta::tuple{ "int"s, elem2}
461461
};
462-
inline bio::ranges::dictionary<std::string, elem_t, true> const & cdict = dict;
463-
464-
TEST(het_dictionary_test, associated_types)
465-
{
466-
EXPECT_SAME_TYPE((bio::meta::tuple<std::string const &, elem_t const &>), decltype(dict[0]));
467-
EXPECT_SAME_TYPE(elem_t const &, decltype(dict["foo"]));
468-
469-
EXPECT_SAME_TYPE(decltype(dict)::reference, decltype(dict)::const_reference);
470-
EXPECT_SAME_TYPE(decltype(dict)::iterator, decltype(dict)::const_iterator);
471-
}
462+
inline bio::ranges::dictionary<std::string, elem_t> const & cdict = dict;
472463

473464
TEST(het_dictionary_test, get)
474465
{

0 commit comments

Comments
 (0)