My Project
Loading...
Searching...
No Matches
Functional.hpp
1/*
2 Copyright 2016 Statoil ASA.
3
4 This file is part of the Open Porous Media project (OPM).
5
6 OPM is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 OPM is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with OPM. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#ifndef OPM_FUNCTIONAL_HPP
21#define OPM_FUNCTIONAL_HPP
22
23#include <algorithm>
24#include <iterator>
25#include <vector>
26#include <numeric>
27#include <functional>
28
29namespace Opm {
30
31namespace fun {
32
33 /*
34 * The Utility/Functional library provides convenient high level
35 * functionality and higher order functions inspiried by functional
36 * languages (in particular Haskell) and modern C++. The goal is to provide
37 * lightweight features that reduce boilerplate and make code more
38 * declarative.
39 */
40
41 /*
42 * map :: (a -> b) -> [a] -> [b]
43 *
44 * maps the elements [a] of the passed container C to [b], by using the
45 * passed function f :: a -> b. Works like map in haskell, lisp, python etc.
46 *
47 * C can be any foreach-compatible container (that supports .begin,
48 * .end), but will always return a vector.
49 *
50 * F can be any Callable, that is both function pointer,
51 * operator()-providing class or std::function, including lambdas. F is
52 * typically passed by reference. F must be unary of type A (which must
53 * match what C::const_iterator::operator* returns) and have return
54 * type B (by value).
55 *
56 * In short, this function deal with vector allocation, resizing and
57 * population based on some function f.
58 *
59 * fun::map( f, vec ) is equivalent to:
60 * vector dst;
61 * for( auto& x : vec ) dst.push_back( f( x ) );
62 * return dst;
63 *
64 * The behaviour is undefined if F has any side effects.
65 *
66 * --
67 *
68 * int plus1( int x ) { return x + 1; }
69 * base_vec = { 0, 1, 2, 3, 4 };
70 * vec = fun::map( &plus1, base_vec );
71 *
72 * vec => { 1, 2, 3, 4, 5 }
73 *
74 * --
75 *
76 * int mul2 = []( int x ) { return x * 2; };
77 * base_vec = { 0, 1, 2, 3, 4 };
78 * vec = fun::map( mul2, base_vec );
79 *
80 * vec => { 0, 2, 4, 6, 8 };
81 *
82 */
83 template <typename F, typename C>
84 auto map(F&& f, C&& c)
85 {
86 using Val = std::remove_cv_t<std::remove_reference_t<
87 decltype(std::invoke(std::forward<F>(f), *std::begin(std::forward<C>(c))))>>;
88
89 std::vector<Val> ret{};
90 ret.reserve(std::size(std::forward<C>(c)));
91
92 std::transform(std::begin(c), std::end(c), std::back_inserter(ret), std::forward<F>(f));
93 return ret;
94 }
95 /*
96 * concat :: [[a]] -> [a]
97 *
98 * A primitive concat taking a vector of vectors, flattened into a
99 * single 1 dimensional vector. Moves all the elements so no unecessary
100 * copies are done.
101 *
102 * vec = { { 1 }, { 2, 2 }, { 3, 3, 3 } }
103 * cvec = concat( vec ) => { 1, 2, 2, 3, 3, 3 }
104 */
105 template< typename A >
106 std::vector< A > concat( std::vector< std::vector< A > >&& src ) {
107 const auto size = std::accumulate( src.begin(), src.end(), 0,
108 []( std::size_t acc, const std::vector< A >& x ) {
109 return acc + x.size();
110 }
111 );
112
113 std::vector< A > dst;
114 dst.reserve( size );
115
116 for( auto& x : src )
117 std::move( x.begin(), x.end(), std::back_inserter( dst ) );
118
119 return dst;
120 }
121
122
123 /*
124 * iota :: int -> [int]
125 * iota :: (int,int) -> [int]
126 *
127 * iota (ι) is borrowed from the APL programming language. This particular
128 * implementation behaves as a generator-like constant-space consecutive
129 * sequence of integers [m,n). Written to feel similar to std::iota, but as
130 * a producer instead of straight-up writer. This is similar to python2.7s
131 * xrange(), python3s range() and haskell's [0..(n-1)]. Some examples
132 * follow.
133 *
134 * Notes:
135 * * iota defaults to [0,n)
136 * * iota uses 0 indexing to feel more familiar to C++'s zero indexing.
137 * * iota can start at negative indices, but will always count upwards.
138 * * iota::const_iterator does not support operator-- (which would allow
139 * support for reverse iterators). This can be implemented if need arises.
140 * * iota is meant to play nice with the rest of fun and to be able to
141 * replace mundane for loops when the loops only purpose is to create the
142 * sequence of elements. iota can feel more declarative and work better
143 * with functions.
144 * * iota adds value semantics to things that in C++ normally relies on
145 * variable mutations. iota is meant to make it less painful to write
146 * immutable and declarative code.
147 * * as with all iterators, iota( n, m ) behaviour is undefined if m < n
148 * * unlike python's range, iota doesn't support steps (only increments).
149 * this is by design to keep this simple and minimal, as well as the name
150 * iota being somewhat unsuitable for stepping ranges. If the need for
151 * this arises it will be a separate function.
152 *
153 * fun::iota( 5 ) => [ 0, 1, 2, 3, 4 ]
154 * fun::iota( 3 ) => [ 0, 1, 2 ]
155 * fun::iota( 1, 6 ) => [ 1, 2, 3, 4, 5 ]
156 *
157 * --
158 *
159 * std::vector< int > vec ( 5, 0 );
160 * std::iota( vec.begin(), vec.end(), 0 );
161 * vec => [ 0, 1, 2, 3, 4 ]
162 *
163 * fun::iota i( 5 );
164 * std::vector vec( i.begin(), i.end() );
165 * vec => [ 0, 1, 2, 3, 4 ]
166 *
167 * --
168 *
169 * int plus( int x ) { return x + 1; }
170 * auto vec = fun::map( &plus, fun::iota( 5 ) );
171 * vec => [ 1, 2, 3, 4, 5 ]
172 *
173 * is equivalent to
174 *
175 * int plus( int x ) { return x + 1; }
176 * std::vector< int > vec;
177 * for( int i = 0; i < 5; ++i )
178 * vec.push_back( plus( i ) );
179 * vec => [ 1, 2, 3, 4, 5 ]
180 *
181 * --
182 *
183 * While not the primary intended use case, this enables foreach loop
184 * syntax over intervals:
185 *
186 * for( auto i : fun::iota( 5 ) )
187 * std::cout << i << " ";
188 *
189 * => 0 1 2 3 4
190 *
191 * for( auto i : fun::iota( 1, 6 ) )
192 * std::cout << i << " ";
193 *
194 * => 1 2 3 4 5
195 *
196 */
197 class iota {
198 public:
199 explicit iota( int end );
200 iota( int begin, int end );
201
203 public:
204 using difference_type = int;
205 using value_type = int;
206 using pointer = int*;
207 using reference = int&;
208 using iterator_category = std::forward_iterator_tag;
209
210 const_iterator() = default;
211
212 int operator*() const;
213
214 const_iterator& operator++();
215 const_iterator operator++( int );
216
217 bool operator==( const const_iterator& rhs ) const;
218 bool operator!=( const const_iterator& rhs ) const;
219
220 private:
221 explicit const_iterator( int );
222 int value;
223
224 friend class iota;
225 };
226
227 size_t size() const;
228
229 const_iterator begin() const;
230 const_iterator end() const;
231
232 private:
233 int first;
234 int last;
235 };
236
237}
238}
239
240#endif //OPM_FUNCTIONAL_HPP
Definition Functional.hpp:202
Definition Functional.hpp:197
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition Exceptions.hpp:30