opm-common
Toggle main menu visibility
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
29
namespace
Opm
{
30
31
namespace
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
202
class
const_iterator {
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
Opm::fun::iota::const_iterator
Definition
Functional.hpp:202
Opm
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition
Exceptions.hpp:30
opm
input
eclipse
Utility
Functional.hpp
Generated by
1.17.0