Skip to content

Instantly share code, notes, and snippets.

@seanchas116
Last active December 23, 2015 06:59
Show Gist options
  • Save seanchas116/6597889 to your computer and use it in GitHub Desktop.
Save seanchas116/6597889 to your computer and use it in GitHub Desktop.
Deferred "map" function for ranges
#include <type_traits>
#include <vector>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
template <typename TImpl>
class Enumerator
{
public:
template <typename TEnumerator>
class Iterator
{
public:
using value_type = typename TEnumerator::value_type;
Iterator() {}
Iterator(const Iterator &other) = default;
Iterator(const TEnumerator *e) : m_e(e) {}
value_type operator*()
{
return m_e->current();
}
Iterator &operator++()
{
if (!m_e->move_next()) {
m_e = nullptr;
}
return *this;
}
Iterator operator++(int)
{
auto original = *this;
this->operator++();
return original;
}
bool operator==(const Iterator &other)
{
return this->m_e == other.m_e;
}
bool operator!=(const Iterator &other)
{
return !operator==(other);
}
private:
const TEnumerator *m_e = nullptr;
};
using self_type = Enumerator<TImpl>;
using value_type = typename TImpl::value_type;
using reference = typename std::add_lvalue_reference<value_type>::type;
using difference_type = std::ptrdiff_t;
using size_type = std::size_t;
using const_iterator = Iterator<self_type>;
Enumerator(TImpl &&impl) : m_impl(std::move(impl)) {}
const_iterator begin() const
{
reset();
return const_iterator(this);
}
const_iterator end() const
{
return const_iterator();
}
value_type current() const
{
return m_impl.current();
}
bool move_next() const
{
return m_impl.move_next();
}
void reset() const
{
m_impl.reset();
}
private:
mutable TImpl m_impl;
};
template <typename TImpl>
auto make_enumerator(TImpl &&impl)
{
return Enumerator<TImpl>(std::move(impl));
}
template <typename TSourceRange>
class RangeEnumeratorImpl
{
public:
using value_type = typename TSourceRange::value_type;
RangeEnumeratorImpl(const TSourceRange &source) :
m_source(source)
{
m_iter = source.begin();
m_end = source.end();
}
value_type current() const
{
return *m_iter;
}
bool move_next()
{
++m_iter;
return m_iter != m_end;
}
void reset()
{
m_iter = m_source.begin();
}
private:
const TSourceRange &m_source;
typename TSourceRange::const_iterator m_iter, m_end;
};
template <typename TSourceRange>
auto make_range_enumerator(const TSourceRange &range)
{
return make_enumerator(RangeEnumeratorImpl<TSourceRange>(range));
}
template <typename TSourceEnumerator, typename TProc>
class MapEnumeratorImpl
{
public:
MapEnumeratorImpl(TSourceEnumerator &&source, TProc proc) :
m_source(std::move(source)),
m_proc(proc)
{}
using value_type = typename std::result_of<TProc(typename TSourceEnumerator::value_type)>::type;
value_type current() const
{
return m_proc(m_source.current());
}
bool move_next()
{
return m_source.move_next();
}
void reset()
{
return m_source.reset();
}
private:
TSourceEnumerator m_source;
TProc m_proc;
};
template <typename TSourceEnumeratorImpl, typename TSourceProc>
auto map(Enumerator<TSourceEnumeratorImpl> &&enumerator, TSourceProc proc)
{
return make_enumerator(MapEnumeratorImpl<Enumerator<TSourceEnumeratorImpl>, TSourceProc>(std::move(enumerator), proc));
}
template <typename TSourceRange, typename TSourceProc>
auto map(const TSourceRange &range, TSourceProc proc)
{
return map(make_range_enumerator(range), proc);
}
void benchmark()
{
constexpr std::size_t count = 100000000;
std::srand(std::clock());
std::vector<int> values(count);
for (std::size_t i = 0; i < count; ++i)
values[i] = std::rand();
auto mapped = map(values, [](int x){return x * 0.5;});
volatile double result;
auto print_elapsed = [](std::clock_t d) {
std::cout << "elapsed " << double(d) / CLOCKS_PER_SEC << " s" << std::endl;
};
{
auto start = std::clock();
for (auto x : mapped)
result = x;
print_elapsed(std::clock() - start);
}
{
auto start = std::clock();
for (auto x : values)
result = x * 0.5;
print_elapsed(std::clock() - start);
}
}
void test()
{
std::vector<int> values = { 1, 2, 3 };
auto mapped = map(values, [](int x){return std::pow(0.5, x);});
for (auto x : mapped)
std::cout << x << std::endl;
}
int main()
{
test();
benchmark();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment