My Project
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 
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:29