Last active
January 1, 2022 20:58
-
-
Save cesarkawakami/c9d3f9e7312f56479fd02200c63cd2fe to your computer and use it in GitHub Desktop.
Bad attempt at a mini range library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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