Skip to content

Instantly share code, notes, and snippets.

@jbandela
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jbandela/25d85e8b5aba31c1a4cd to your computer and use it in GitHub Desktop.
Save jbandela/25d85e8b5aba31c1a4cd to your computer and use it in GitHub Desktop.
set_iterators
#include <boost/iterator/iterator_facade.hpp>
#include <boost/range/iterator_range.hpp>
#include <iterator>
#include <utility>
template<class Iter1, class Iter2,class Comp>
struct set_intersection_iterator:public boost::iterator_facade<set_intersection_iterator<Iter1,Iter2,Comp>,const typename std::iterator_traits<Iter1>::value_type,std::forward_iterator_tag>
{
Iter1 begin1_;
Iter1 end1_;
Iter2 begin2_;
Iter2 end2_;
Comp comp_;
bool at_end_;
typedef const typename std::iterator_traits<Iter1>::value_type value_type;
set_intersection_iterator(Iter1 b1, Iter1 e1, Iter2 b2, Iter2 e2, Comp c = Comp()) :begin1_{ b1 }, end1_{ e1 }, begin2_{ b2 }, end2_{ e2 }, comp_{ c }, at_end_{ false }
{
increment();
}
set_intersection_iterator() :begin1_{ }, end1_{ }, begin2_{ }, end2_{ }, comp_{ }, at_end_{ true }{}
bool equal(const set_intersection_iterator& other) const{
if (at_end_ || other.at_end_){
return other.at_end_ && at_end_;
}
return begin1_ == other.begin1_ && end1_ == other.end1_ && begin2_ == other.begin2_ && end2_ == other.end2_;
}
bool check_end()const{
return begin1_ == end1_ || begin2_ == end2_;
}
void increment(){
if (check_end()){
at_end_ = true;
return;
}
do{
while (!check_end() && comp_(*begin1_, *begin2_)){
++begin1_;
}
while (!check_end() && comp_(*begin2_, *begin1_)){
++begin2_;
}
if (check_end()){
at_end_ = true;
}
} while (!at_end_ && comp_(*begin1_, *begin2_));
assert(at_end_ || *begin1_ == *begin2_);
if (check_end()){
at_end_ = true;
}
else{
++begin2_;
}
}
value_type& dereference()const{
assert(!at_end_);
assert(!check_end());
return *begin1_;
}
};
template<class Iter1, class Iter2, class Comp>
struct set_union_iterator :public boost::iterator_facade<set_union_iterator<Iter1, Iter2, Comp>, const typename std::iterator_traits<Iter1>::value_type, std::forward_iterator_tag>
{
Iter1 begin1_;
Iter1 end1_;
Iter2 begin2_;
Iter2 end2_;
Comp comp_;
int select_ = -1;
typedef const typename std::iterator_traits<Iter1>::value_type value_type;
set_union_iterator(Iter1 b1, Iter1 e1, Iter2 b2, Iter2 e2, Comp c = Comp()) :begin1_{ b1 }, end1_{ e1 }, begin2_{ b2 }, end2_{ e2 }, comp_{ c }
{
set_select();
}
void set_select(){
if (!check_end()){
if (begin1_ == end1_){
select_ = 2;
}
else if (begin2_ == end2_){
select_ = 1;
}
else if (comp_(*begin1_, *begin2_)){
select_ = 1;
}
else if (comp_(*begin2_, *begin1_)){
select_ = 2;
}
else{
select_ = 3;
}
}
else{
select_ = -1;
}
}
set_union_iterator() :begin1_{}, end1_{}, begin2_{}, end2_{}, comp_{}{}
bool equal(const set_union_iterator& other) const{
if (select_ == -1 || other.select_ == -1){
return other.select_ == select_;
}
return begin1_ == other.begin1_ && end1_ == other.end1_ && begin2_ == other.begin2_ && end2_ == other.end2_ && select_ == other.select_;
}
bool check_end()const{
return begin1_ == end1_ && begin2_ == end2_;
}
void increment(){
if (select_ == 1){
++begin1_;
}
else if (select_ == 2){
++begin2_;
}
else if (select_ == 3){
++begin1_; ++begin2_;
}
set_select();
}
value_type& dereference()const{
assert(select_ != -1);
assert(!check_end());
if (select_ == 1 || select_ == 3){
return *begin1_;
}
else{
return *begin2_;
}
}
};
template<class Iter1, class Iter2>
boost::iterator_range<set_intersection_iterator<Iter1, Iter2,std::less<typename std::iterator_traits<Iter1>::value_type>>> make_set_intersection_range(Iter1 b1, Iter1 e1, Iter2 b2, Iter2 e2){
typedef set_intersection_iterator<Iter1, Iter2, std::less<typename std::iterator_traits<Iter1>::value_type>> iter_t;
return boost::make_iterator_range(iter_t {b1, e1, b2, e2}, iter_t{});
}
template<class C1, class C2>
auto make_set_intersection_range(const C1& c1, const C2& c2)->decltype(make_set_intersection_range(c1.begin(),c1.end(),c2.begin(),c2.end())){
return make_set_intersection_range(c1.begin(), c1.end(), c2.begin(), c2.end());
}
template<class Iter1, class Iter2>
boost::iterator_range<set_union_iterator<Iter1, Iter2, std::less<typename std::iterator_traits<Iter1>::value_type>>> make_set_union_range(Iter1 b1, Iter1 e1, Iter2 b2, Iter2 e2){
typedef set_union_iterator<Iter1, Iter2, std::less<typename std::iterator_traits<Iter1>::value_type>> iter_t;
return boost::make_iterator_range(iter_t{ b1, e1, b2, e2 }, iter_t{});
}
template<class C1, class C2>
auto make_set_union_range(const C1& c1, const C2& c2)->decltype(make_set_union_range(c1.begin(), c1.end(), c2.begin(), c2.end())){
return make_set_union_range(c1.begin(), c1.end(), c2.begin(), c2.end());
}
#include <vector>
#include <iostream>
template<class V>
void print_range(const V& vec){
std::cout << "Printing range\n";
for (auto& v : vec){
std::cout << v << "\n";
}
}
int main(){
std::vector<int> v1{ 1, 2, 3, 4, 5 };
std::vector<int> v2{ 2, 4, 6, 8 };
std::vector<int> v3{ 1, 3, 5, 9 };
std::vector<int> v4;
std::vector<int> v5;
auto rng = make_set_intersection_range(v1, v2);
auto rng2 = make_set_intersection_range(v1, v3);
auto rng3 = make_set_intersection_range(v2, v3);
auto rng4 = make_set_union_range(v2, v3);
auto rng5 = make_set_union_range(v4, v5);
print_range(rng);
print_range(rng2);
print_range(rng3);
print_range(rng4);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment