Last active
July 25, 2018 04:11
-
-
Save rolandschulz/629387fa63a430b74b9ba5edf768df5a to your computer and use it in GitHub Desktop.
This file contains 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 <unordered_map> | |
#include <vector> | |
#include <iostream> | |
#include <type_traits> | |
#include <memory> | |
//iteator pair - very crude range | |
template <typename I1, typename I2=I1> | |
struct iter_pair : std::pair<I1, I2> | |
{ | |
using std::pair<I1, I2>::pair; | |
I1 begin() { return this->first; } | |
I2 end() { return this->second; } | |
}; | |
//from pair of iterators | |
template<typename T1, typename T2> | |
iter_pair<T1,T2> make_iter_pair(T1&& a, T2&& b) { | |
return {std::forward<T1>(a), std::forward<T2>(b)}; | |
} | |
//from container | |
template<typename T> | |
auto make_iter_pair(T& a) -> iter_pair<typename T::iterator> { | |
return {a.begin(), a.end()}; | |
} | |
//from const constainer | |
template<typename T> | |
auto make_iter_pair(const T& a) -> iter_pair<typename T::const_iterator> { | |
return {a.begin(), a.end()}; | |
} | |
//transform iterator. operator* returns callable fn applied to iterator's reference | |
template<typename It, typename Fn> | |
class transform_iter : public It { | |
public: | |
using reference = typename std::result_of<Fn(typename It::reference)>::type; | |
transform_iter(const It &it, Fn fn) : It(it), fn_(fn) {} | |
reference operator*() const { return fn_(It::operator*()); } | |
reference operator[](typename It::difference_type n) const { return fn_(It::operator[](n)); } | |
private: | |
//Optimization opportunity: Inheriting from functor (with wrapper for function pointer), would allow | |
//empty base class optimization and avoid wasting space for 0-size lambda. | |
/*[[no_unique_address]]*/ Fn fn_; | |
}; | |
template<typename Fn, typename ...A> | |
#if __cplusplus >= 201703L | |
//slightly nicer error in clang | |
using enable_if_is_invocable_t = typename std::enable_if_t<std::is_invocable_v<Fn, A...>>; | |
#else | |
using enable_if_is_invocable_t = typename std::result_of<Fn(A...)>::type; | |
#endif | |
template<typename T, typename Fn, typename=enable_if_is_invocable_t<Fn, typename T::const_reference>> | |
auto make_transform_iter_pair(const T& a, Fn fn) -> iter_pair<transform_iter<typename T::const_iterator, Fn>> { | |
return {{a.begin(), fn}, {a.end(), fn}}; | |
} | |
template<typename T, typename Fn, typename=enable_if_is_invocable_t<Fn, typename T::reference>, | |
typename=typename std::enable_if<!std::is_const<T>::value>::type> | |
auto make_transform_iter_pair(T& a, Fn fn) -> iter_pair<transform_iter<typename T::iterator, Fn>> { | |
return {{a.begin(), fn}, {a.end(), fn}}; | |
} | |
//Testing | |
template<typename T> | |
void printRange(T r) | |
{ | |
for(const auto &x: r) { | |
std::cout<<x<<"\n"; | |
} | |
} | |
static const std::string& getKey(const std::pair<const std::string, std::string>& p) { | |
return p.first; | |
} | |
[[maybe_unused]]static std::string& getValue(std::pair<const std::string, std::string>& p) { | |
return p.second; | |
} | |
int main() { | |
//-- Test data begin | |
std::unordered_map<std::string, std::string> u = { | |
{"RED","#FF0000"}, | |
{"GREEN","#00FF00"}, | |
{"BLUE","#0000FF"} | |
}; | |
const auto cu = u; //const copy | |
std::vector<std::string> v = {"a", "b", "c"}; | |
const auto cv = v; //const copy | |
//-- Test data end | |
printRange(make_transform_iter_pair(u, [](const std::pair<const std::string, std::string>& x){return x.first;})); | |
//Using C++14 | |
//printRange(make_transform_iter_pair(u, [](const auto& x){return x.first;})); //C++14 | |
//Function rather than lambda: | |
//printRange(make_transform_iter_pair(u, &getKey)); | |
printRange(make_transform_iter_pair(cu, &getKey)); | |
//Test with const container: | |
//printRange(make_transform_iter_pair(cu, [](std::pair<std::string, std::string> x){return x.first;})); | |
//Testing with incorrect lambda: | |
//printRange(make_transform_iter_pair(u, [](std::pair<std::string, int> x){return x.first;})); | |
//Testing with vector: | |
printRange(v); | |
//Same as: | |
//printRange(make_iter_pair(v)); | |
//Testing modification through iterator: | |
//for (auto &s: make_transform_iter_pair(u, &getValue)) s = "BLA"; | |
//Using lambda: | |
//for (auto &s: make_transform_iter_pair(u, [](auto& x) -> auto& {return x.second;})) s = "BLA"; | |
//Tesing [] operator | |
//std::cout << make_transform_iter_pair(v, [](const auto& x){return x.size();}).begin()[1]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment