Skip to content

Instantly share code, notes, and snippets.

@cesarkawakami
Last active January 1, 2022 20:58
Show Gist options
  • Save cesarkawakami/c9d3f9e7312f56479fd02200c63cd2fe to your computer and use it in GitHub Desktop.
Save cesarkawakami/c9d3f9e7312f56479fd02200c63cd2fe to your computer and use it in GitHub Desktop.
Bad attempt at a mini range library
#include "minirange.h"
#include <algorithm>
#include <gtest/gtest.h>
TEST(MiniRange, SimpleIotaForRange) {
std::vector<int> v;
for (auto i : mr::iota(10)) {
v.push_back(i);
}
const std::vector expected{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
EXPECT_EQ(v, expected);
}
TEST(MiniRange, SimpleIotaIterator) {
std::vector<int> v;
std::copy(IALL(mr::iota(10)), std::back_inserter(v));
const std::vector expected{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
EXPECT_EQ(v, expected);
}
TEST(MiniRange, IotaStep1) {
std::vector<int> v;
std::copy(IALL(mr::iota(2, 6, 2)), std::back_inserter(v));
const std::vector expected{2, 4};
EXPECT_EQ(v, expected);
}
TEST(MiniRange, IotaStep2) {
std::vector<int> v;
std::copy(IALL(mr::iota(2, 5, 2)), std::back_inserter(v));
const std::vector expected{2, 4};
EXPECT_EQ(v, expected);
}
TEST(MiniRange, IotaStep3) {
std::vector<int> v;
std::copy(IALL(mr::iota(2, 7, 2)), std::back_inserter(v));
const std::vector expected{2, 4, 6};
EXPECT_EQ(v, expected);
}
TEST(MiniRange, IotaNegativeStep1) {
std::vector<int> v;
std::copy(IALL(mr::iota(6, 2, -2)), std::back_inserter(v));
const std::vector expected{6, 4};
EXPECT_EQ(v, expected);
}
TEST(MiniRange, IotaNegativeStep2) {
std::vector<int> v;
std::copy(IALL(mr::iota(6, 3, -2)), std::back_inserter(v));
const std::vector expected{6, 4};
EXPECT_EQ(v, expected);
}
TEST(MiniRange, IotaNegativeStep3) {
std::vector<int> v;
std::copy(IALL(mr::iota(6, 4, -2)), std::back_inserter(v));
const std::vector expected{6};
EXPECT_EQ(v, expected);
}
TEST(MiniRange, Map1) {
std::vector<int> v;
std::copy(IALL(mr::iota(3) |
mr::Map{[](int x) { return x * 2; }}),
std::back_inserter(v));
const std::vector expected{0, 2, 4};
EXPECT_EQ(v, expected);
}
#pragma once
#include <iterator>
#include <optional>
#define IALL(v) (v).begin(), decltype(v)::end_inst
#define ALL(v) (v).begin(), (v).end()
namespace mr {
template <class T, typename V = std::invoke_result_t<T>::value_type>
struct Iter {
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = V;
using pointer = V *;
using reference = V &;
using fn_type = T;
std::optional<T> fn;
std::optional<V> val;
static_assert(std::is_same_v<std::invoke_result_t<T>, std::optional<V>>);
static const Iter<T, V> end_inst;
Iter(T fn_) : fn(fn_) {
val = fn.value()();
}
Iter<T, V> begin() {
return *this;
}
static Iter<T, V> end() {
return end_inst;
}
V operator*() const {
return val.value();
}
V *operator->() const {
return &val;
}
Iter<T, V> &operator++() {
val = fn.value()();
return *this;
}
Iter<T, V> operator++(int) {
Iter<T, V> prev{*this};
++*this;
return prev;
}
bool operator==(const Iter<T, V> &other) const {
return !val.has_value() && !other.val.has_value();
}
bool operator!=(const Iter<T, V> &other) const {
return !(*this == other);
}
protected:
Iter() : fn{std::nullopt}, val{std::nullopt} {}
};
template <class T, typename V>
inline const Iter<T, V> Iter<T, V>::end_inst;
template <class T, class V>
auto map(const T &iter, V &fn) {
using W = std::invoke_result_t<V, typename std::invoke_result_t<typename T::fn_type>::value_type>;
return Iter{[inner = iter.fn.value(), &fn]() mutable -> std::optional<W> {
std::invoke_result_t<typename T::fn_type> val{inner()};
if (val.has_value()) {
return fn(*val);
} else {
return std::nullopt;
}
}};
}
template <class T>
struct Map {
T fn;
auto transform(auto &&in) {
return map(in, fn);
}
};
template <class T, typename V>
auto operator|(Iter<T, V> &&in, auto &&right) {
return right.transform(in);
}
template <typename T = int>
auto iota(T start, T stop, T step = 1) {
return Iter{[start, stop, step, cur = start]() mutable -> std::optional<T> {
if ((step > 0 && cur < stop) || (step < 0 && cur > stop)) {
T prev = cur;
cur += step;
return prev;
} else {
return std::nullopt;
}
}};
}
template <typename T = int>
auto iota(T stop) {
return iota(0, stop);
}
} // namespace mr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment