Skip to content

Commit c24523d

Browse files
committed
factor out machinery for creating adaptor
1 parent 9b9620b commit c24523d

File tree

3 files changed

+147
-75
lines changed

3 files changed

+147
-75
lines changed

tests/grtestutils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ add_library(grtestutils
8080
# files outside of the googletest subdirectory
8181
# -> these shouldn't include headers from the googletest subdirectory
8282
cmd.hpp cmd.cpp
83+
iterator_adaptor.hpp
8384
os.hpp os.cpp
8485
preset.hpp preset.cpp
8586
utils.hpp utils.cpp
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// See the LICENSE file for license and copyright information
4+
// SPDX-License-Identifier: NCSA AND BSD-3-Clause
5+
//
6+
//===----------------------------------------------------------------------===//
7+
///
8+
/// @file
9+
/// Declare and implement the IteratorAdaptor
10+
///
11+
//===----------------------------------------------------------------------===//
12+
#ifndef GRTESTUTILS_ITERATOR_ADAPTOR_HPP
13+
#define GRTESTUTILS_ITERATOR_ADAPTOR_HPP
14+
15+
#include <iterator>
16+
#include <string>
17+
18+
#include "grackle.h"
19+
#include "preset.hpp"
20+
21+
namespace grtest {
22+
23+
/// the standard value-type that an IteratorAdaptor instantiation refers to
24+
struct NameIdPair {
25+
std::string name;
26+
long long id;
27+
};
28+
29+
/// implements a C++ style InputIterator by adapting a simple Plugin type
30+
/// that wraps a set of Grackle functions
31+
///
32+
/// This is useful for making use of C++ standard library algorithms and
33+
/// (arguably more importantly) making use of range-based for-loops
34+
template <class Plugin>
35+
class IteratorAdaptor {
36+
unsigned long long counter_;
37+
unsigned long long n_rates_;
38+
Plugin plugin_;
39+
NameIdPair current_pair_;
40+
41+
/// Updates current_pair_ and returns `*this`
42+
IteratorAdaptor& update_pair_and_ret_(unsigned long long current_count) {
43+
if (current_count < this->n_rates_) {
44+
this->current_pair_ = this->plugin_(current_count);
45+
}
46+
return *this;
47+
}
48+
49+
public:
50+
using iterator_category = std::input_iterator_tag;
51+
using value_type = NameIdPair;
52+
using difference_type = std::ptrdiff_t;
53+
using pointer = const NameIdPair*;
54+
using reference = const NameIdPair;
55+
56+
/// construct a new instance
57+
IteratorAdaptor(unsigned long long counter, unsigned long long n_rates,
58+
Plugin plugin)
59+
: counter_(counter), n_rates_(n_rates), plugin_(plugin) {
60+
update_pair_and_ret_(counter);
61+
}
62+
63+
/// implements the equality operation
64+
bool operator==(const IteratorAdaptor& other) const {
65+
return (counter_ == other.counter_) && (plugin_ == other.plugin_);
66+
}
67+
68+
/// implements the inequality operation
69+
bool operator!=(const IteratorAdaptor& other) const {
70+
return !(*this == other);
71+
}
72+
73+
/// implements the dereference operation
74+
reference operator*() const { return current_pair_; }
75+
76+
/// implements the prefix increment operation
77+
///
78+
/// This effectively implements `++x`, which increments the value of `x`
79+
/// before determining the returned value. In other words, `++x` returns the
80+
/// value of `x` from **after** after the increment
81+
IteratorAdaptor& operator++() { return update_pair_and_ret_(++counter_); }
82+
83+
/// implements the prefix increment operation
84+
///
85+
/// This effectively implements `x++`, which increments the value of `x`
86+
/// after determining the returned value. In other words, `x++` returns the
87+
/// value of `x` from **before** the increment
88+
IteratorAdaptor operator++(int) {
89+
IteratorAdaptor ret = *this;
90+
++(*this);
91+
return ret;
92+
}
93+
};
94+
95+
// Now lets use this machinery to implement logic iterating over the names
96+
// accessible through the ratequery api
97+
98+
struct RateQueryPlugin {
99+
chemistry_data_storage* my_rates;
100+
101+
NameIdPair operator()(unsigned long long i) const {
102+
grunstable_rateid_type tmp;
103+
const char* name = grunstable_ith_rate(i, &tmp);
104+
return NameIdPair{name, tmp};
105+
}
106+
107+
bool operator==(const RateQueryPlugin& other) const {
108+
return my_rates == other.my_rates;
109+
}
110+
};
111+
112+
// will be implemented (in a much more robust manner) in the near future
113+
inline unsigned long long grunstable_ratequery_nrates(
114+
const chemistry_data_storage* my_rates) {
115+
// current implementation is stupid! (in future, will use my_rates)
116+
unsigned long long i = 0;
117+
while (nullptr != grunstable_ith_rate(i, nullptr)) {
118+
i++;
119+
}
120+
return i;
121+
}
122+
123+
/// used for creating the iterator and within range-based for-loops
124+
class RateQueryRange {
125+
RateQueryPlugin plugin_;
126+
using iterator = IteratorAdaptor<RateQueryPlugin>;
127+
long long n_rates_;
128+
129+
public:
130+
explicit RateQueryRange(grtest::GrackleCtxPack& pack)
131+
: plugin_(RateQueryPlugin{pack.my_rates()}),
132+
n_rates_(grunstable_ratequery_nrates(pack.my_rates())) {}
133+
134+
iterator begin() { return iterator(0, n_rates_, plugin_); }
135+
iterator end() { return iterator(n_rates_, n_rates_, plugin_); }
136+
};
137+
138+
} // namespace grtest
139+
140+
#endif // GRTESTUTILS_ITERATOR_ADAPTOR_HPP

tests/unit/test_api_ratequery.cpp

Lines changed: 6 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <set>
1616
#include <string>
1717
#include <gtest/gtest.h>
18+
#include "grtestutils/iterator_adaptor.hpp"
1819
#include "grtestutils/googletest/fixtures.hpp"
1920

2021
#include "grackle.h"
@@ -51,98 +52,28 @@ TEST_F(SimpleRateQueryTest, PtrInvalidRateId) {
5152
EXPECT_EQ(ptr, nullptr);
5253
}
5354

54-
// will be implemented (in a much more robust manner) in the near future
55-
unsigned long long grunstable_ratequery_nrates(
56-
const chemistry_data_storage* my_rates) {
57-
// current implementation is stupid! (in future, will use my_rates)
58-
unsigned long long i = 0;
59-
while (nullptr != grunstable_ith_rate(i, nullptr)) {
60-
i++;
61-
}
62-
return i;
63-
}
64-
6555
// most of the remaining tests (and future planned tests) involve iterating
6656
// through all rates made available via the ratequery interface. To make the
6757
// tests themselves as easy to read as possible, we implate a C++-style
6858
// iterator to wrap part of the interface
6959

70-
struct RateNameIdPair {
71-
std::string name;
72-
grunstable_rateid_type rateid;
73-
};
74-
75-
class RQIterator {
76-
chemistry_data_storage* my_rates_;
77-
unsigned long long counter_;
78-
unsigned long long n_rates_;
79-
RateNameIdPair pair_;
80-
81-
RQIterator& update_pair_and_ret_(unsigned long long val) {
82-
if (val < n_rates_) {
83-
pair_.name = std::string(grunstable_ith_rate(val, &pair_.rateid));
84-
}
85-
return *this;
86-
}
87-
88-
public:
89-
using iterator_category = std::input_iterator_tag;
90-
using value_type = RateNameIdPair;
91-
using difference_type = std::ptrdiff_t;
92-
using pointer = const RateNameIdPair*;
93-
using reference = const RateNameIdPair;
94-
95-
RQIterator(unsigned long long counter, unsigned long long n_rates,
96-
chemistry_data_storage* my_rates)
97-
: my_rates_(my_rates), counter_(counter), n_rates_(n_rates) {
98-
update_pair_and_ret_(counter);
99-
}
100-
101-
bool operator==(RQIterator other) const {
102-
return (counter_ == other.counter_) && (my_rates_ == other.my_rates_);
103-
}
104-
105-
bool operator!=(RQIterator other) const { return !(*this == other); }
106-
reference operator*() const { return pair_; }
107-
RQIterator& operator++() { return update_pair_and_ret_(++counter_); }
108-
109-
RQIterator operator++(int) {
110-
RQIterator ret = *this;
111-
++(*this);
112-
return ret;
113-
}
114-
};
115-
116-
// used for creating the iterator and within range-based for-loops
117-
class RateQueryRange {
118-
grtest::GrackleCtxPack& pack_;
119-
long long n_rates_;
120-
121-
public:
122-
explicit RateQueryRange(grtest::GrackleCtxPack& pack)
123-
: pack_(pack), n_rates_(grunstable_ratequery_nrates(pack.my_rates())) {}
124-
125-
RQIterator begin() { return RQIterator(0, n_rates_, pack_.my_rates()); }
126-
RQIterator end() { return RQIterator(n_rates_, n_rates_, pack_.my_rates()); }
127-
};
128-
12960
using ParametrizedRateQueryTest = grtest::ParametrizedConfigPresetFixture;
13061

13162
TEST_P(ParametrizedRateQueryTest, AllUnique) {
13263
std::set<std::string> name_set;
13364
std::set<grunstable_rateid_type> id_set;
134-
for (const RateNameIdPair pair : RateQueryRange(pack)) {
65+
for (const grtest::NameIdPair pair : grtest::RateQueryRange(pack)) {
13566
ASSERT_TRUE(name_set.insert(pair.name).second)
13667
<< "the name, \"" << pair.name << "\" appears more than once";
137-
ASSERT_TRUE(id_set.insert(pair.rateid).second)
138-
<< "the id, " << pair.rateid << " appears more than once";
68+
ASSERT_TRUE(id_set.insert(pair.id).second)
69+
<< "the id, " << pair.id << " appears more than once";
13970
}
14071
}
14172

14273
TEST_P(ParametrizedRateQueryTest, ConsistentIDs) {
143-
for (const RateNameIdPair pair : RateQueryRange(pack)) {
74+
for (const grtest::NameIdPair pair : grtest::RateQueryRange(pack)) {
14475
grunstable_rateid_type rateid = grunstable_ratequery_id(pair.name.c_str());
145-
EXPECT_EQ(rateid, pair.rateid);
76+
EXPECT_EQ(rateid, pair.id);
14677
}
14778
}
14879

0 commit comments

Comments
 (0)