Skip to content

Instantly share code, notes, and snippets.

@Trass3r
Last active August 29, 2015 14:10
Show Gist options
  • Save Trass3r/4b9ef3be73877de61fa0 to your computer and use it in GitHub Desktop.
Save Trass3r/4b9ef3be73877de61fa0 to your computer and use it in GitHub Desktop.
fun with range templates
#include <type_traits>
//! range spanned by 2 iterators
template <typename Iterator>
struct IteratorRange
{
IteratorRange(Iterator begin, Iterator end)
: _begin(std::move(begin)),
_end(std::move(end))
{
}
Iterator begin() const
{
return _begin;
}
Iterator end() const
{
return _end;
}
private:
Iterator _begin;
Iterator _end;
};
//! create an iterator range
template <typename Iterator>
inline IteratorRange<Iterator> make_range(Iterator begin, Iterator end)
{
return IteratorRange<Iterator>(std::move(begin), std::move(end));
}
//! stupid adapter for range-based for
template <typename Range>
struct RangeIterator
{
Range& r;
RangeIterator(Range& r)
: r(r)
{
}
void operator++()
{
r.advance();
}
bool operator!=(const RangeIterator& /*that*/) const
{
return !r.empty();
}
auto operator*() const -> decltype(r.current())
{
return r.current();
}
};
//! auto-deref if it is a pointer
template <typename T>
auto dereference(T&& t) -> decltype(std::forward<T>(t))
{
return std::forward<T>(t);
}
template <typename T>
auto dereference(T* t) -> decltype(*t)
{
return *t;
}
//! basic range with custom interface
template <typename ContainerType>
struct Range
{
using ItType = decltype(std::declval<ContainerType>().begin());
using value_type = typename ContainerType::value_type;
protected:
ItType it, endit;
public:
Range() = default;
Range(ContainerType& container)
: it(container.begin()),
endit(container.end())
{
}
RangeIterator<Range> begin() { return RangeIterator<Range>(*this); }
RangeIterator<Range> end() { return RangeIterator<Range>(*this); }
bool empty() const { return it == endit; }
auto current() const -> decltype(*it) { return *it; }
void advance() { ++it; }
};
//! flatten nested ranges into 1 range
// Terminator is the desired target element type used to stop the recursion
template <typename ContainerType, typename Terminator>
struct FlattenedRange : Range<ContainerType>
{
using Base = Range<ContainerType>;
using SubRange = FlattenedRange<std::remove_pointer_t<typename ContainerType::value_type>, Terminator>;
using value_type = typename SubRange::value_type;
private:
SubRange innerIt;
public:
FlattenedRange() = default;
FlattenedRange(ContainerType& container)
: Base(container)
{
skipEmpties();
}
using Base::empty;
auto current() const -> decltype(innerIt.current()) { return innerIt.current(); }
void advance()
{
if (!innerIt.empty())
innerIt.advance();
if (innerIt.empty())
{
++this->it;
skipEmpties();
}
}
private:
void skipEmpties()
{
while (!empty())
{
innerIt = SubRange(dereference(*this->it));
if (!innerIt.empty())
break;
++this->it;
}
}
};
//! recursion base case: container with desired Terminator element type
template <typename ContainerType>
struct FlattenedRange <ContainerType, typename ContainerType::value_type> : Range<ContainerType>
{
FlattenedRange() = default;
FlattenedRange(ContainerType& container)
: Range<ContainerType>(container)
{}
};
//! convenience method
template <typename Terminator, typename T>
FlattenedRange<std::remove_reference_t<T>, Terminator> makeFlattenedRange(T&& container)
{
static_assert(!std::is_pointer<T>::value, "no pointers allowed");
return FlattenedRange<std::remove_reference_t<T>, Terminator>(std::forward<T>(container));
}
#include <vector>
struct Bar
{
};
struct Foo
{
Foo() = default;
std::vector<Bar*> v = std::vector<Bar*>{new Bar, new Bar, new Bar};
using value_type = Bar*;
using iterator = std::vector<Bar*>::iterator;
using const_iterator = std::vector<Bar*>::const_iterator;
const_iterator begin() const { return v.begin(); }
const_iterator end() const { return v.end(); }
};
int main()
{
std::vector<int> v{1};
const std::vector<Foo*> v2 = {new Foo, new Foo};
std::vector<Foo*> sv(1, nullptr);
const std::vector<Foo*> csv(1, nullptr);
std::vector<const Foo*> svc(1, nullptr);
const std::vector<const Foo*> csvc(1, nullptr);
printf("Result: ");
for (Bar* el : makeFlattenedRange<Bar*>(v2))
{
printf("%x, ", el);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment