4 changed files with 197 additions and 0 deletions
-
26f-composition/Makefile
-
116f-composition/functional.hpp
-
29f-composition/main.cpp
-
26f-composition/pretty_print.hpp
@ -0,0 +1,26 @@ |
|||
EXE=a.out |
|||
CC=clang++ |
|||
DEBUG?=0 |
|||
CFLAGS=-O2 -std=c++20 -Wall -Wextra -D DEBUG=$(DEBUG) |
|||
|
|||
.PHONY: all clean test |
|||
test: |
|||
- @rm $(EXE) |
|||
$(CC) $(CFLAGS) -o $(EXE) main.cpp |
|||
./$(EXE) |
|||
|
|||
all: $(EXE) |
|||
|
|||
clean: |
|||
rm -rf $(EXE) ./*.out ./*.gch |
|||
|
|||
|
|||
$(EXE): main.cpp pretty_print.hpp.gch functional.hpp.gch |
|||
$(CC) $(CFLAGS) -o $(EXE) main.cpp |
|||
|
|||
functional.hpp.gch: functional.hpp |
|||
$(CC) $(CFLAGS) -c functional.hpp |
|||
|
|||
pretty_print.hpp.gch: pretty_print.hpp |
|||
$(CC) $(CFLAGS) -c pretty_print.hpp |
|||
|
|||
@ -0,0 +1,116 @@ |
|||
#ifndef FUNCTIONAL_H
|
|||
#define FUNCTIONAL_H
|
|||
|
|||
|
|||
#include <iostream>
|
|||
#include <vector>
|
|||
#include <utility>
|
|||
|
|||
/*
|
|||
* Composition of functions through operator* |
|||
* |
|||
* Immediate evaluation of <lambda> * <rvalue> |
|||
*/ |
|||
template<typename F, typename G> |
|||
auto composition_h(F&& f, G&& g, std::true_type) { |
|||
#if DEBUG==1
|
|||
std::cout << "<Lambda> * <Lambda> -> <Lambda>" << std::endl; // DEBLURG
|
|||
#endif
|
|||
return [f, g](auto&& t){ |
|||
return f( g( std::forward<decltype(t)>(t) ) ); |
|||
}; |
|||
} |
|||
|
|||
template<typename F, typename G> |
|||
auto composition_h(F&& f, G&& g, std::false_type) { |
|||
#if DEBUG==1
|
|||
std::cout << "<Lambda> * T -> T" << std::endl; // DEBLURG
|
|||
#endif
|
|||
return f( g ); |
|||
} |
|||
|
|||
template<typename F, typename G> |
|||
auto operator*(F&& f, G&& g) { |
|||
#if DEBUG==1
|
|||
std::cout << "f * g -> "; |
|||
#endif
|
|||
return composition_h(f, g, std::is_lvalue_reference<G&&>()); |
|||
} |
|||
|
|||
|
|||
/*
|
|||
* Following templates handle mapping of transforming function |
|||
* onto vector<T> types |
|||
*/ |
|||
template<typename Transform, typename T> |
|||
auto operator*(Transform&& transform, std::vector<T> const& vec) { |
|||
#if DEBUG==1
|
|||
std::cout << "<Lambda> * vec<T> -> vec<T> \t[const]" << std::endl; // DEBLURG
|
|||
#endif
|
|||
std::vector<T> transformed_vec; |
|||
transformed_vec.reserve( vec.size() ); |
|||
|
|||
for (auto const& v : vec) { |
|||
transformed_vec.push_back( transform(v) ); |
|||
} |
|||
|
|||
return transformed_vec; |
|||
} |
|||
|
|||
template<typename Transform, typename T> |
|||
auto operator*(Transform&& transform, std::vector<T>&& vec) { |
|||
#if DEBUG==1
|
|||
std::cout << "<Lambda> * vec<T> -> vec<T> \t[rvalue]" << std::endl; // DEBLURG
|
|||
#endif
|
|||
std::vector<T> transformed_vec; |
|||
transformed_vec.reserve( vec.size() ); |
|||
|
|||
for (auto const& v : vec) { |
|||
transformed_vec.push_back( transform(v) ); |
|||
} |
|||
|
|||
return transformed_vec; |
|||
} |
|||
|
|||
template<typename Transform, typename T> |
|||
auto operator*(Transform&& transform, std::vector<T>& vec) { |
|||
#if DEBUG==1
|
|||
std::cout << "<Lambda> * vec<T> -> vec<T> \t[non-const]" << std::endl; |
|||
#endif
|
|||
|
|||
std::vector<T> transformed_vec; |
|||
transformed_vec.reserve( vec.size() ); |
|||
|
|||
for (auto const& v : vec) { |
|||
transformed_vec.push_back( transform(v) ); |
|||
} |
|||
|
|||
return transformed_vec; |
|||
} |
|||
|
|||
|
|||
auto const id = [](auto&& t) -> decltype(t)&& { |
|||
return std::forward<decltype(t)>(t); |
|||
}; |
|||
|
|||
|
|||
|
|||
/*
|
|||
* Maps a transform function onto each element in vector<T> |
|||
* |
|||
* Obsolete |
|||
*/ |
|||
template<typename F, typename T> |
|||
auto map = [](F&& transform) { |
|||
return [transform](std::vector<T> const& vec) { |
|||
std::vector<T> transformed_vec; |
|||
transformed_vec.reserve( vec.size() ); |
|||
for (auto const& v : vec) { |
|||
transformed_vec.push_back( transform(v) ); |
|||
} |
|||
return transformed_vec; |
|||
}; |
|||
}; |
|||
|
|||
|
|||
#endif
|
|||
@ -0,0 +1,29 @@ |
|||
#include <iostream>
|
|||
#include <typeinfo>
|
|||
#include <stdint.h>
|
|||
#include <vector>
|
|||
|
|||
|
|||
#include "functional.hpp" // (f * g)(t) == f(g(t))
|
|||
#include "pretty_print.hpp" // ostream << vector
|
|||
|
|||
|
|||
int main() |
|||
{ |
|||
std::vector<int> const vec{1,2,3,4,5}; |
|||
|
|||
auto const dec = [](int const& v) { |
|||
return v-1; |
|||
}; |
|||
auto const sq = [](int const& v) { |
|||
return v*v; |
|||
}; |
|||
|
|||
std::vector<int> const transformed_vec{ dec * sq * vec }; |
|||
|
|||
std::cout << "Orig: \t" << vec << '\n'; |
|||
std::cout << "Sq: \t" << sq * vec << '\n'; |
|||
std::cout << "Sq-1: \t" << transformed_vec << "\n\n"; |
|||
|
|||
std::cout << "Const:\t" << sq*dec*7 << std::endl; |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
#ifndef PRETTY_PRINT_H
|
|||
#define PRETTY_PRINT_H
|
|||
|
|||
#include <iostream>
|
|||
#include <iomanip>
|
|||
#include <vector>
|
|||
|
|||
template<typename T> |
|||
std::ostream& operator<<(std::ostream& os, std::vector<T> const& vec) |
|||
{ |
|||
if (vec.size() == 0) { return os; } // Empty
|
|||
os << "[" << vec[0]; // First
|
|||
|
|||
if (1 < vec.size()) { // Rest
|
|||
for (auto it = ++vec.cbegin(); it != vec.cend(); ++it) { |
|||
os << ", " << std::setw(2) << *it; |
|||
} |
|||
} |
|||
|
|||
os << "]"; |
|||
|
|||
return os; |
|||
} |
|||
|
|||
|
|||
#endif
|
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue