Skip to content

Commit ce4d82c

Browse files
Merge pull request #284 from apache/req_converting_constructor
REQ type converting copy constructor
2 parents 9172868 + 3b098a5 commit ce4d82c

5 files changed

Lines changed: 142 additions & 5 deletions

File tree

req/include/req_compactor.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ class req_compactor {
3838
req_compactor& operator=(const req_compactor& other);
3939
req_compactor& operator=(req_compactor&& other);
4040

41+
template<typename TT, typename CC, typename AA>
42+
req_compactor(const req_compactor<TT, CC, AA>& other, const Allocator& allocator);
43+
4144
bool is_sorted() const;
4245
uint32_t get_num_items() const;
4346
uint32_t get_nom_capacity() const;
@@ -128,6 +131,9 @@ class req_compactor {
128131
template<typename S>
129132
static std::pair<std::unique_ptr<T, items_deleter>, size_t> deserialize_items(const void* bytes, size_t size, const S& serde, const Allocator& allocator, uint32_t num);
130133

134+
// for type converting constructor
135+
template<typename TT, typename CC, typename AA>
136+
friend class req_compactor;
131137
};
132138

133139
} /* namespace datasketches */

req/include/req_compactor_impl.hpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,33 @@ req_compactor<T, C, A>& req_compactor<T, C, A>::operator=(req_compactor&& other)
132132
return *this;
133133
}
134134

135+
template<typename T, typename C, typename A>
136+
template<typename TT, typename CC, typename AA>
137+
req_compactor<T, C, A>::req_compactor(const req_compactor<TT, CC, AA>& other, const A& allocator):
138+
allocator_(allocator),
139+
lg_weight_(other.lg_weight_),
140+
hra_(other.hra_),
141+
coin_(other.coin_),
142+
sorted_(other.sorted_),
143+
section_size_raw_(other.section_size_raw_),
144+
section_size_(other.section_size_),
145+
num_sections_(other.num_sections_),
146+
state_(other.state_),
147+
num_items_(other.num_items_),
148+
capacity_(other.capacity_),
149+
items_(nullptr)
150+
{
151+
if (other.items_ != nullptr) {
152+
items_ = allocator_.allocate(capacity_);
153+
const uint32_t from = hra_ ? capacity_ - num_items_ : 0;
154+
const uint32_t to = hra_ ? capacity_ : num_items_;
155+
for (uint32_t i = from; i < to; ++i) new (items_ + i) T(other.items_[i]);
156+
if (sorted_ && !std::is_sorted(items_ + from, items_ + to, C())) {
157+
throw std::logic_error("items must be sorted");
158+
}
159+
}
160+
}
161+
135162
template<typename T, typename C, typename A>
136163
bool req_compactor<T, C, A>::is_sorted() const {
137164
return sorted_;

req/include/req_sketch.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ class req_sketch {
5858
req_sketch& operator=(const req_sketch& other);
5959
req_sketch& operator=(req_sketch&& other);
6060

61+
/*
62+
* Type converting constructor.
63+
* @param other sketch of a different type
64+
* @param allocator instance of an Allocator
65+
*/
66+
template<typename TT, typename CC, typename SS, typename AA>
67+
explicit req_sketch(const req_sketch<TT, CC, SS, AA>& other, const Allocator& allocator = Allocator());
68+
6169
/**
6270
* Returns configured parameter K
6371
* @return parameter K
@@ -408,6 +416,9 @@ class req_sketch {
408416
}
409417
}
410418

419+
// for type converting constructor
420+
template<typename TT, typename CC, typename SS, typename AA>
421+
friend class req_sketch;
411422
};
412423

413424
template<typename T, typename C, typename S, typename A>

req/include/req_sketch_impl.hpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ compactors_(other.compactors_),
6464
min_value_(nullptr),
6565
max_value_(nullptr)
6666
{
67-
if (other.min_value_ != nullptr) min_value_ = new (A().allocate(1)) T(*other.min_value_);
68-
if (other.max_value_ != nullptr) max_value_ = new (A().allocate(1)) T(*other.max_value_);
67+
if (other.min_value_ != nullptr) min_value_ = new (allocator_.allocate(1)) T(*other.min_value_);
68+
if (other.max_value_ != nullptr) max_value_ = new (allocator_.allocate(1)) T(*other.max_value_);
6969
}
7070

7171
template<typename T, typename C, typename S, typename A>
@@ -113,6 +113,33 @@ req_sketch<T, C, S, A>& req_sketch<T, C, S, A>::operator=(req_sketch&& other) {
113113
return *this;
114114
}
115115

116+
template<typename T, typename C, typename S, typename A>
117+
template<typename TT, typename CC, typename SS, typename AA>
118+
req_sketch<T, C, S, A>::req_sketch(const req_sketch<TT, CC, SS, AA>& other, const A& allocator):
119+
allocator_(allocator),
120+
k_(other.k_),
121+
hra_(other.hra_),
122+
max_nom_size_(other.max_nom_size_),
123+
num_retained_(other.num_retained_),
124+
n_(other.n_),
125+
compactors_(allocator),
126+
min_value_(nullptr),
127+
max_value_(nullptr)
128+
{
129+
static_assert(
130+
std::is_constructible<T, TT>::value,
131+
"Type converting constructor requires new type to be constructible from existing type"
132+
);
133+
compactors_.reserve(other.compactors_.size());
134+
for (const auto& compactor: other.compactors_) {
135+
compactors_.push_back(req_compactor<T, C, A>(compactor, allocator_));
136+
}
137+
if (!other.is_empty()) {
138+
min_value_ = new (allocator_.allocate(1)) T(other.get_min_value());
139+
max_value_ = new (allocator_.allocate(1)) T(other.get_max_value());
140+
}
141+
}
142+
116143
template<typename T, typename C, typename S, typename A>
117144
uint16_t req_sketch<T, C, S, A>::get_k() const {
118145
return k_;

req/test/req_sketch_test.cpp

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const std::string input_path = "test/";
3535
#endif
3636

3737
TEST_CASE("req sketch: empty", "[req_sketch]") {
38-
std::cout << "sizeof(req_float_sketch)=" << sizeof(req_sketch<float>) << "\n";
38+
//std::cout << "sizeof(req_float_sketch)=" << sizeof(req_sketch<float>) << "\n";
3939
req_sketch<float> sketch(12);
4040
REQUIRE(sketch.get_k() == 12);
4141
REQUIRE(sketch.is_HRA());
@@ -245,7 +245,7 @@ TEST_CASE("req sketch: byte serialize-deserialize single item", "[req_sketch]")
245245
auto bytes = sketch.serialize();
246246
REQUIRE(bytes.size() == sketch.get_serialized_size_bytes());
247247
auto sketch2 = req_sketch<float>::deserialize(bytes.data(), bytes.size());
248-
std::cout << sketch2.to_string(true);
248+
//std::cout << sketch2.to_string(true);
249249
REQUIRE(bytes.size() == sketch2.get_serialized_size_bytes());
250250
REQUIRE(sketch2.is_empty() == sketch.is_empty());
251251
REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
@@ -282,7 +282,7 @@ TEST_CASE("req sketch: byte serialize-deserialize exact mode", "[req_sketch]") {
282282
auto bytes = sketch.serialize();
283283
REQUIRE(bytes.size() == sketch.get_serialized_size_bytes());
284284
auto sketch2 = req_sketch<float>::deserialize(bytes.data(), bytes.size());
285-
std::cout << sketch2.to_string(true);
285+
//std::cout << sketch2.to_string(true);
286286
REQUIRE(bytes.size() == sketch2.get_serialized_size_bytes());
287287
REQUIRE(sketch2.is_empty() == sketch.is_empty());
288288
REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
@@ -485,6 +485,72 @@ TEST_CASE("req sketch: merge incompatible HRA and LRA", "[req_sketch]") {
485485
REQUIRE_THROWS_AS(sketch1.merge(sketch2), std::invalid_argument);
486486
}
487487

488+
TEST_CASE("req sketch: type conversion - empty", "[req_sketch]") {
489+
req_sketch<double> req_double(12);
490+
req_sketch<float> req_float(req_double);
491+
REQUIRE(req_float.is_empty());
492+
REQUIRE(req_float.get_k() == req_double.get_k());
493+
REQUIRE(req_float.get_n() == 0);
494+
REQUIRE(req_float.get_num_retained() == 0);
495+
}
496+
497+
TEST_CASE("req sketch: type conversion - several levels", "[req_sketch]") {
498+
req_sketch<double> req_double(12);
499+
for (int i = 0; i < 1000; ++i) req_double.update(static_cast<double>(i));
500+
req_sketch<float> req_float(req_double);
501+
REQUIRE(!req_float.is_empty());
502+
REQUIRE(req_float.get_k() == req_double.get_k());
503+
REQUIRE(req_float.get_n() == req_double.get_n());
504+
REQUIRE(req_float.get_num_retained() == req_double.get_num_retained());
505+
506+
auto sv_float = req_float.get_sorted_view(false);
507+
auto sv_double = req_double.get_sorted_view(false);
508+
auto sv_float_it = sv_float.begin();
509+
auto sv_double_it = sv_double.begin();
510+
while (sv_float_it != sv_float.end()) {
511+
REQUIRE(sv_double_it != sv_double.end());
512+
auto float_pair = *sv_float_it;
513+
auto double_pair = *sv_double_it;
514+
REQUIRE(float_pair.first == Approx(double_pair.first).margin(0.01));
515+
REQUIRE(float_pair.second == double_pair.second);
516+
++sv_float_it;
517+
++sv_double_it;
518+
}
519+
REQUIRE(sv_double_it == sv_double.end());
520+
}
521+
522+
class A {
523+
int val;
524+
public:
525+
A(int val): val(val) {}
526+
int get_val() const { return val; }
527+
};
528+
529+
struct less_A {
530+
bool operator()(const A& a1, const A& a2) const { return a1.get_val() < a2.get_val(); }
531+
};
532+
533+
class B {
534+
int val;
535+
public:
536+
explicit B(const A& a): val(a.get_val()) {}
537+
int get_val() const { return val; }
538+
};
539+
540+
struct less_B {
541+
bool operator()(const B& b1, const B& b2) const { return b1.get_val() < b2.get_val(); }
542+
};
543+
544+
TEST_CASE("req sketch: type conversion - custom types") {
545+
req_sketch<A, less_A> sa(4);
546+
sa.update(1);
547+
sa.update(2);
548+
sa.update(3);
549+
550+
req_sketch<B, less_B> sb(sa);
551+
REQUIRE(sb.get_n() == 3);
552+
}
553+
488554
//TEST_CASE("for manual comparison with Java") {
489555
// req_sketch<float> sketch(12, false);
490556
// for (size_t i = 0; i < 100000; ++i) sketch.update(i);

0 commit comments

Comments
 (0)