Skip to content

Instantly share code, notes, and snippets.

@kimyongin
Created February 1, 2016 06:22
Show Gist options
  • Save kimyongin/15d561d24f9094d45c47 to your computer and use it in GitHub Desktop.
Save kimyongin/15d561d24f9094d45c47 to your computer and use it in GitHub Desktop.
#include <boost/range/concepts.hpp>
#include <boost/range/iterator_range_core.hpp>
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
// -------------------------------------------------------------
// assign
// -------------------------------------------------------------
namespace my
{
namespace assign_detail
{
template< class C >
class call_push_back
{
C& c_;
public:
call_push_back(C& c) : c_(c)
{ }
template< class T >
void operator()(T r)
{
c_.push_back(r);
}
};
struct forward_n_arguments {};
}
namespace assign
{
template< class Function, class Argument = assign_detail::forward_n_arguments >
class list_inserter
{
public:
list_inserter(Function fun) : insert_(fun)
{}
template< class T >
list_inserter& operator,(const T& r)
{
insert_(r);
return *this;
}
template< class T >
list_inserter& operator()(const T& t)
{
insert_(t);
return *this;
}
private:
Function insert_;
};
template< class Function, class Argument >
inline list_inserter<Function, Argument>
make_list_inserter(Function fun, Argument*)
{
return list_inserter<Function, Argument>(fun);
}
template< class C >
inline list_inserter< assign_detail::call_push_back<C>, typename C::value_type >
push_back(C& c)
{
static typename C::value_type* p = 0;
return make_list_inserter(assign_detail::call_push_back<C>(c), p);
}
template< class V, class A, class V2 >
inline list_inserter< assign_detail::call_push_back< std::vector<V, A> >, V >
operator+=(std::vector<V, A>& c, V2 v)
{
return push_back(c)(v);
}
}
}
// -------------------------------------------------------------
// holder
// -------------------------------------------------------------
namespace my
{
namespace range_detail
{
template< class T >
struct holder
{
T val;
holder(T t) : val(t)
{ }
};
template< class T >
struct adjacent_holder : holder<T>
{
adjacent_holder(T r) : holder<T>(r)
{ }
};
template< template<class> class Holder >
struct forwarder
{
template< class T >
Holder<T> operator()(T t) const
{
return Holder<T>(t);
}
};
}
namespace adaptors
{
namespace
{
const range_detail::forwarder<range_detail::adjacent_holder>
adjacent_filtered =
range_detail::forwarder<range_detail::adjacent_holder>();
}
}
}
// -------------------------------------------------------------
// iterator
// -------------------------------------------------------------
namespace my
{
namespace range_detail
{
using namespace boost;
// -------------------------------------------------------------
// skip_iterator
// -------------------------------------------------------------
template< class Iter, class Pred, bool default_pass >
class skip_iterator
: public boost::iterator_adaptor<
skip_iterator<Iter, Pred, default_pass>,
Iter,
BOOST_DEDUCED_TYPENAME std::iterator_traits<Iter>::value_type,
boost::forward_traversal_tag,
BOOST_DEDUCED_TYPENAME std::iterator_traits<Iter>::reference,
BOOST_DEDUCED_TYPENAME std::iterator_traits<Iter>::difference_type
>
, private Pred
{
private:
typedef boost::iterator_adaptor<
skip_iterator<Iter, Pred, default_pass>,
Iter,
BOOST_DEDUCED_TYPENAME std::iterator_traits<Iter>::value_type,
boost::forward_traversal_tag,
BOOST_DEDUCED_TYPENAME std::iterator_traits<Iter>::reference,
BOOST_DEDUCED_TYPENAME std::iterator_traits<Iter>::difference_type
> base_t;
public:
typedef Pred pred_t;
typedef Iter iter_t;
skip_iterator() : m_last() {}
skip_iterator(iter_t it, iter_t last, const Pred& pred)
: base_t(it)
, pred_t(pred)
, m_last(last)
{
}
template<class OtherIter>
skip_iterator(const skip_iterator<OtherIter, pred_t, default_pass>& other)
: base_t(other.base())
, pred_t(other)
, m_last(other.m_last)
{
}
void increment()
{
iter_t& it = this->base_reference();
BOOST_ASSERT(it != m_last);
pred_t& bi_pred = *this;
iter_t prev = it;
++it;
if (it != m_last)
{
if (default_pass)
{
while (it != m_last && !bi_pred(*prev, *it))
{
++it;
++prev;
}
}
else
{
for (; it != m_last; ++it, ++prev)
{
if (bi_pred(*prev, *it))
{
break;
}
}
}
}
}
iter_t m_last;
};
// -------------------------------------------------------------
// adjacent_filtered_range
// -------------------------------------------------------------
template< class P, class R, bool default_pass >
struct adjacent_filtered_range
: iterator_range< skip_iterator<BOOST_DEDUCED_TYPENAME range_iterator<R>::type, P, default_pass>>
{
private:
typedef skip_iterator<BOOST_DEDUCED_TYPENAME range_iterator<R>::type, P, default_pass> skip_iter;
typedef iterator_range<skip_iter> base_range;
typedef BOOST_DEDUCED_TYPENAME range_iterator<R>::type raw_iterator;
public:
adjacent_filtered_range(const P& p, R& r)
: base_range(skip_iter(boost::begin(r), boost::end(r), p),
skip_iter(boost::end(r), boost::end(r), p))
{
}
};
template< class ForwardRng, class BinPredicate >
inline adjacent_filtered_range<BinPredicate, ForwardRng, true>
operator|(ForwardRng& r, const adjacent_holder<BinPredicate>& f)
{
BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<ForwardRng>));
return adjacent_filtered_range<BinPredicate, ForwardRng, true>(f.val, r);
}
}
}
int main()
{
using namespace my::assign;
using namespace my::adaptors;
// TEST 1
std::cout << "\nTEST 1 ================================" << std::endl;
std::vector<int> input;
input += 1, 1, 2, 2, 2, 3, 4, 5, 6;
for (auto item : input){
std::cout << item << std::endl;
}
// TEST 2
std::cout << "\nTEST 2 ================================" << std::endl;
auto filter = adjacent_filtered(std::not_equal_to<int>());
std::cout << filter.val(1, 1) << std::endl;
std::cout << filter.val(0, 1) << std::endl;
// TEST 3
std::cout << "\nTEST 3 ================================" << std::endl;
auto filtered_output_iterator = input | filter;
for (auto filterdItem : filtered_output_iterator) {
std::cout << filterdItem << std::endl;
}
// TEST 4
std::cout << "\nTEST 4 ================================" << std::endl;
std::copy(std::begin(filtered_output_iterator),
std::end(filtered_output_iterator),
std::ostream_iterator<int>(std::cout, ","));
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment