Compare commits

...

3 commits

Author SHA1 Message Date
Bruno BELANYI 2317285d0f Fix edge-case in identify 'end' upper-bound
All checks were successful
ci/woodpecker/push/check Pipeline was successful
Just my luck, this was found immediately in the CI, right when I
uploaded the project thinking I was done.

Thankfully the fix is easy and (in hindsight) quite obvious.
2024-08-24 20:59:14 +01:00
Bruno BELANYI 8ea4fd373b Fix Meson install
Some checks failed
ci/woodpecker/push/check Pipeline failed
2024-08-24 20:37:27 +01:00
Bruno BELANYI 2a6b89e420 Make implementation follow assignment rules
Some checks failed
ci/woodpecker/push/check Pipeline failed
From what I could find, the rules of the assignment seem to be:

1. Restrict oneself to at most *one* O(log(N)) call, and otherwise use
   constant time operations on the map.
2. Don't use more operations than strictly necessary on `K` and `V`.
3. Prefer simplicity to performance.

I think my solution would fair well under those constraints.
2024-08-24 20:32:14 +01:00
3 changed files with 38 additions and 11 deletions

View file

@ -15,26 +15,45 @@ public:
if (!(begin < end)) if (!(begin < end))
return; return;
auto const end_val = (*this)[end]; auto it = underlying_.upper_bound(end);
underlying_.erase(underlying_.lower_bound(begin), auto const end_val = at_upper_bound(it);
underlying_.upper_bound(end));
if (!((*this)[begin] == val)) bool insert_begin = !(val == init_);
underlying_.insert({begin, val});
if (!((*this)[end] == end_val)) while (it != underlying_.begin()) {
underlying_.insert({end, end_val}); it = std::prev(it);
auto begin_found = it->first < begin;
if (begin_found) {
insert_begin = !(val == it->second);
break;
}
if (it != underlying_.end())
// Account for up-coming `std::prev` with `++`
underlying_.erase(it++);
}
if (insert_begin)
it = underlying_.insert(it, {begin, val});
// Get the proper upper-bound for `end`
it = (it == underlying_.end() || end < it->first) ? it : std::next(it);
if (!(at_upper_bound(it) == end_val))
underlying_.insert(it, {end, end_val});
} }
V const& operator[](K const& key) const { V const& operator[](K const& key) const {
auto it = underlying_.upper_bound(key); return at_upper_bound(underlying_.upper_bound(key));
if (it == underlying_.begin())
return init_;
return std::prev(it)->second;
} }
// Used in testing // Used in testing
friend class ::IntervalMapTest; friend class ::IntervalMapTest;
private: private:
V const& at_upper_bound(std::map<K, V>::const_iterator it) const {
if (it == underlying_.begin())
return init_;
return std::prev(it)->second;
}
V init_; V init_;
std::map<K, V> underlying_{}; std::map<K, V> underlying_{};
}; };

View file

@ -1 +1,3 @@
interval_map_dep = declare_dependency(include_directories: 'include') interval_map_dep = declare_dependency(include_directories: 'include')
install_headers('include/interval-map/interval-map.hh', subdir: 'interval-map')

View file

@ -242,6 +242,12 @@ TEST_F(IntervalMapTest, fuzzing_003) {
assign(-110, -10, 4); assign(-110, -10, 4);
} }
TEST_F(IntervalMapTest, fuzzing_004) {
assign(-20, 120, 1);
assign(50, 110, 0);
assign(-120, 100, 0);
}
TEST_F(IntervalMapTest, randomized_test) { TEST_F(IntervalMapTest, randomized_test) {
auto const seed = []() { auto const seed = []() {
std::random_device r; std::random_device r;