├── .clang-format ├── .gitmodules ├── CMakeLists.txt ├── example ├── CMakeLists.txt └── exampleUsage.cpp ├── include └── lazyCode │ ├── basicCollectors.h │ ├── basicGenerators.h │ ├── collector.h │ ├── generator.h │ ├── lazyCode.h │ └── utils.h ├── readme.md ├── single_header ├── lazyCode.h └── makeSingleHeader.py ├── src └── CMakeLists.txt └── vendor └── CMakeLists.txt /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | # We'll use defaults from the google style, but with 4 columns indentation. 3 | BasedOnStyle: google 4 | IndentWidth: 4 5 | --- 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/optional-lite"] 2 | path = vendor/optional-lite 3 | url = https://github.com/martinmoene/optional-lite 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required (VERSION 3.6) 3 | 4 | project (LazyCode 5 | VERSION 1.0.0 6 | LANGUAGES CXX) 7 | 8 | add_subdirectory (vendor) 9 | add_subdirectory (src) 10 | 11 | if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) 12 | add_subdirectory (example) 13 | endif() 14 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required (VERSION 3.6) 3 | set(CMAKE_CXX_STANDARD 14) 4 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wextra -Wall") 5 | 6 | add_executable (exampleUsage exampleUsage.cpp) 7 | target_link_libraries (exampleUsage PRIVATE lazyCode) 8 | -------------------------------------------------------------------------------- /example/exampleUsage.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | namespace lz = LazyCode; 8 | using namespace std; 9 | void readmeExample1() { 10 | auto lines = lz::readLines(cin) | lz::append(vector()); 11 | std::sort(lines.begin(), lines.end()); 12 | lz::generator(lines) | lz::write(cout, "\n"); 13 | } 14 | 15 | void readmeExample2() { 16 | int total = lz::read(ifstream("test.txt")) | lz::limit(10) | 17 | lz::filter([](int i) { return i % 2 == 0; }) | 18 | lz::map([](int i) { return i * i; }) | lz::sum(); 19 | 20 | cout << total << endl; 21 | } 22 | 23 | void readmeExample3() { 24 | auto numbers = lz::read(ifstream("test.txt")) | lz::limit(10); 25 | auto evenFilter = numbers | lz::filter([](int i) { return i % 2 == 0; }); 26 | auto squares = evenFilter | lz::map([](int i) { return i * i; }); 27 | int total = squares | lz::sum(); 28 | cout << total << endl; 29 | } 30 | 31 | void readmeExample4() { 32 | auto numbers = lz::limit(10, lz::read(ifstream("test.txt"))); 33 | auto evenFilter = lz::filter([](int i) { return i % 2 == 0; }, numbers); 34 | auto squares = lz::map([](int i) { return i * i; }, evenFilter); 35 | int total = lz::sum(squares); 36 | cout << total << endl; 37 | } 38 | 39 | void readmeExample5() { 40 | int total = lz::read(cin) | lz::limit(10) | 41 | lz::filter(lambda(i, i % 2 == 0)) | lz::map(lambda(i, i * i)) | 42 | lz::sum(); 43 | cout << total << endl; 44 | } 45 | int main() {} -------------------------------------------------------------------------------- /include/lazyCode/basicCollectors.h: -------------------------------------------------------------------------------- 1 | #ifndef LAZYCODE_BASICCOLLECTORS_H_ 2 | #define LAZYCODE_BASICCOLLECTORS_H_ 3 | #include 4 | #include "collector.h" 5 | namespace LazyCode { 6 | 7 | /* 8 | * Apply the given function to each value produced by the 9 | * given generator. The return value of the function is ignored and may be 10 | * void. If the generator is not specified, a collector is returned. Collectors 11 | * remember the operation to be executed. The operation is executed when a 12 | * generator is piped `|` to it. 13 | */ 14 | template = 0> 16 | decltype(auto) forEach(Func&& func, Generator&& gen = GeneratorHole()) { 17 | return buildOrApply(collector(std::forward(func)), 18 | std::forward(gen)); 19 | } 20 | 21 | /* 22 | * Count the number of values yielded by the given generator. If the generator 23 | * is not specified, a collector is returned. Collectors remember the operation 24 | * to be executed. The operation is executed when a generator is piped `|` to 25 | * it. 26 | */ 27 | template = 0> 29 | decltype(auto) count(Generator&& gen = GeneratorHole()) { 30 | return buildOrApply( 31 | collector(((size_t)0), [](size_t& count, auto&&) { ++count; }), 32 | std::forward(gen)); 33 | } 34 | 35 | /* 36 | * Combine the values produced by a generator using the 37 | * specified function and return the result. The function should take two 38 | * arguments and return a single value. The accum parameter (accumulator) 39 | * specifies the initial value. The return type of the function must be 40 | * convertible to the accum type. If the generator is not specified, a collector 41 | * is returned. Collectors remember the operation to be executed. The operation 42 | * is executed when a generator is piped `|` to it. 43 | */ 44 | template = 0> 46 | decltype(auto) fold(Func&& func, Accum accum, 47 | Generator&& gen = GeneratorHole()) { 48 | return buildOrApply( 49 | collector(std::move(accum), 50 | [func = std::forward(func)](auto& accum, auto&& val) { 51 | accum = func(accum, val); 52 | }), 53 | std::forward(gen)); 54 | } 55 | 56 | /* 57 | * Return the sum of the values produced by a generator. If 58 | * the generator is not specified, a collector is returned. 59 | * Collectors remember the operation to be executed. The operation is executed 60 | * when a generator is piped `|` to it. 61 | */ 62 | template = 0> 64 | decltype(auto) sum(Generator&& gen = GeneratorHole()) { 65 | return buildOrApply( 66 | [](auto&& gen) { 67 | typedef decltype(gen) Gen; 68 | typedef typename detail::RmRef::NoRefYieldType AccumType; 69 | return fold( 70 | [](const auto& i, const auto& j) { return i + j; }, 0); 71 | }, 72 | std::forward(gen)); 73 | } 74 | 75 | /* 76 | * Return the product (multiplication) of the values produced by a generator.If 77 | * the generator is not specified, a collector is returned. 78 | * Collectors remember the operation to be executed. The operation is executed 79 | * when a generator is piped `|` to it. 80 | */ 81 | template = 0> 83 | decltype(auto) product(Generator&& gen = GeneratorHole()) { 84 | return buildOrApply( 85 | [](auto&& gen) { 86 | typedef decltype(gen) Gen; 87 | typedef typename detail::RmRef::NoRefYieldType AccumType; 88 | return fold( 89 | [](const auto& i, const auto& j) { return i * j; }, 1); 90 | }, 91 | std::forward(gen)); 92 | } 93 | 94 | /* 95 | * Return the minimum value produced by a generator. If the generator yields 96 | * no values, the default value is returned. If a default value is not given, 97 | * an optional is returned. The optional holds a value in the case the 98 | * generator yielded a value, otherwise the optional will be empty (nullopt). 99 | * If the generator is not specified, a collector is returned. Collectors 100 | * remember the operation to be executed. The operation is executed when a 101 | * generator is piped `|` to it. 102 | */ 103 | template = 0> 105 | decltype(auto) min(Generator&& gen = GeneratorHole()) { 106 | return buildOrApply( 107 | [](auto&& gen) { 108 | typedef decltype(gen) Gen; 109 | typedef typename detail::RmRef::NoRefYieldType AccumType; 110 | return fold>( 111 | 112 | [](const auto& i, const auto& j) { 113 | return (i && *i < j) ? *i : j; 114 | }, 115 | nullopt); 116 | }, 117 | std::forward(gen)); 118 | } 119 | 120 | template = 0> 122 | decltype(auto) min(Val defaultVal, Generator&& gen = GeneratorHole()) { 123 | return buildOrApply( 124 | [defaultVal = std::move(defaultVal)](auto&& gen) { 125 | typedef decltype(gen) Gen; 126 | typedef typename detail::RmRef::NoRefYieldType AccumType; 127 | return fold( 128 | [](const auto& i, const auto& j) { return (i < j) ? i : j; }, 129 | defaultVal); 130 | }, 131 | std::forward(gen)); 132 | } 133 | 134 | /* 135 | * Return the maximum value produced by a generator. If the generator yields 136 | * no values, the default value is returned. If a default value is not given, 137 | * an optional is returned. The optional holds a value in the case the 138 | * generator yielded a value, otherwise the optional will be empty (nullopt). 139 | * If the generator is not specified, a collector is returned. Collectors 140 | * remember the operation to be executed. The operation is executed when a 141 | * generator is piped `|` to it. 142 | */ 143 | template = 0> 145 | decltype(auto) max(Generator&& gen = GeneratorHole()) { 146 | return buildOrApply( 147 | [](auto&& gen) { 148 | typedef decltype(gen) Gen; 149 | typedef typename detail::RmRef::NoRefYieldType AccumType; 150 | return fold>( 151 | 152 | [](const auto& i, const auto& j) { 153 | return (i && *i > j) ? *i : j; 154 | }, 155 | nullopt); 156 | }, 157 | std::forward(gen)); 158 | } 159 | 160 | template = 0> 162 | decltype(auto) max(Val defaultVal, Generator&& gen = GeneratorHole()) { 163 | return buildOrApply( 164 | [defaultVal = std::move(defaultVal)](auto&& gen) { 165 | typedef decltype(gen) Gen; 166 | typedef typename detail::RmRef::NoRefYieldType AccumType; 167 | return fold( 168 | [](const auto& i, const auto& j) { return (i > j) ? i : j; }, 169 | defaultVal); 170 | }, 171 | std::forward(gen)); 172 | } 173 | 174 | /* 175 | * Write each value produced by the given generator to the 176 | * given stream. An interleave value can be optionally specified, in which case 177 | * the interleave value will be written to the stream before each generated 178 | * value apart from the first. This is sometimes known as join. Note that a 179 | * rvalue can be given as the stream parameter, for example constructing a new 180 | * stream inline (`write(ostringstream())`), in which case the stream will be 181 | * returned.If the generator is not specified, a collector is returned. 182 | * Collectors remember the operation to be executed. The operation is executed 183 | * when a generator is piped `|` to it. 184 | */ 185 | template = 0> 187 | decltype(auto) write(Stream&& stream, Generator&& gen = GeneratorHole()) { 188 | return buildOrApply( 189 | collector(detail::wrapIfRef(std::forward(stream)), 190 | [](auto& stream, auto&& val) { stream << val; }), 191 | std::forward(gen)); 192 | } 193 | 194 | template = 0> 197 | decltype(auto) write(Stream&& stream, Interleave i, 198 | Generator&& gen = GeneratorHole()) { 199 | bool first = true; 200 | return buildOrApply( 201 | collector(detail::wrapIfRef(std::forward(stream)), 202 | [first, i = std::move(i)](auto& stream, auto&& val) mutable { 203 | if (first) { 204 | first = false; 205 | } else { 206 | stream << i; 207 | } 208 | stream << val; 209 | }), 210 | std::forward(gen)); 211 | } 212 | 213 | /* 214 | * Append each value produced by the given generator to the 215 | * given container, using container.emplace_back(). For unordered containers, 216 | * see `insert`. Note that a rvalue can be given as the container parameter, 217 | * for example constructing a new container inline (`append(vector())`), in 218 | * which case the collector stores the container and returns it after appending 219 | * the values. Otherwise, only a reference to the container is held by the 220 | * collector. If the generator is not specified, a collector is returned. 221 | * Collectors remember the operation to be executed. The operation is executed 222 | * when a generator is piped `|` to it. 223 | */ 224 | template = 0> 226 | decltype(auto) append(Container&& container, 227 | Generator&& gen = GeneratorHole()) { 228 | return buildOrApply( 229 | collector( 230 | detail::wrapIfRef(std::forward(container)), 231 | [](auto& container, auto&& val) { container.emplace_back(val); }), 232 | std::forward(gen)); 233 | } 234 | 235 | /* 236 | * Insert each value produced by the given generator to the 237 | * given container, using container.emplace(). This is for unordered 238 | * containers. For ordered containers, see `append`. Note that a rvalue can be 239 | * given as the container parameter, for example constructing a new container 240 | * inline (`append(set())`), in 241 | * which case the collector stores the container and returns it after inserting 242 | * the values. Otherwise, only a reference to the container is held by the 243 | * collector. If the generator is not specified, a collector is returned. 244 | * Collectors remember the operation to be executed. The operation is executed 245 | * when a generator is piped `|` to it. 246 | */ 247 | template = 0> 249 | decltype(auto) insert(Container&& container, 250 | Generator&& gen = GeneratorHole()) { 251 | return buildOrApply( 252 | collector(detail::wrapIfRef(std::forward(container)), 253 | [](auto& container, auto&& val) { container.emplace(val); }), 254 | std::forward(gen)); 255 | } 256 | 257 | } // namespace LazyCode 258 | #endif /* LAZYCODE_BASICCOLLECTORS_H_*/ 259 | -------------------------------------------------------------------------------- /include/lazyCode/basicGenerators.h: -------------------------------------------------------------------------------- 1 | #ifndef LAZYCODE_BASICGENERATORS_H_ 2 | #define LAZYCODE_BASICGENERATORS_H_ 3 | #include 4 | #include "generator.h" 5 | 6 | #include 7 | namespace LazyCode { 8 | 9 | /* 10 | * Create a never ending generator of sequence of values. Sequence begins at 11 | * specified start point (inclusive) and is followed by values 12 | * increasing/decreasing by the specified increment. 13 | */ 14 | template 15 | auto infRange(Number1 start, Number2 increment) { 16 | return generator(start, [increment](Number1& val) -> optional { 17 | Number1 preVal = val; 18 | val += increment; 19 | return preVal; 20 | }); 21 | } 22 | 23 | /* 24 | * Create a generator of sequence of values. Sequence begins at 25 | * specified start point (inclusive) , is followed by values 26 | * increasing/decreasing by the specified increment and stops at the specified 27 | * last point (exclusive). 28 | */ 29 | template 30 | auto range(Number1 start, Number1 end, Number2 increment) { 31 | auto comparator = (increment >= 0) 32 | ? [](Number1 a, Number1 b) { return a < b; } 33 | : [](Number1 a, Number1 b) { return b < a; }; 34 | return generator( 35 | start, [end, increment, comparator](Number1& val) -> optional { 36 | if (!comparator(val, end)) { 37 | return nullopt; 38 | } 39 | Number1 preVal = val; 40 | val += increment; 41 | return preVal; 42 | }); 43 | } 44 | 45 | /* 46 | * Create a generator of sequence of integral values. Sequence begins at 47 | * specified start point (inclusive) , is followed by values increasing by 1 and 48 | * stops at the specified last point (exclusive). 49 | */ 50 | template ::value, int>::type = 0> 52 | auto range(Number start, Number end) { 53 | return range(start, end, 1); 54 | } 55 | 56 | /* 57 | * Create a generator of sequence of integral values. Sequence begins at 0 58 | * (inclusive) , is followed by values increasing by 1 and stops at the 59 | * specified last point (exclusive). 60 | */ 61 | template ::value, int>::type = 0> 63 | auto range(Number end) { 64 | return range(((Number)0), end, 1); 65 | } 66 | 67 | /* 68 | * Create a generator from a container. The generator uses the containers begin 69 | * and end iterators via `std::begin, std::end`. If an rvalue is given, the 70 | * generator will take ownership of the container and move it into the generator 71 | * object, otherwise the generator will only hold a reference to the container. 72 | */ 73 | template = 0> 75 | decltype(auto) generator(Container&& container) { 76 | typedef detail::RmRef Iter; 77 | typedef decltype(*std::begin(container)) IterValueType; 78 | struct Iterable { 79 | Container container; 80 | Iter first; 81 | Iter last; 82 | Iterable(Container&& container) 83 | : container(std::forward(container)), 84 | first(std::begin(this->container)), 85 | last(std::end(this->container)) {} 86 | }; 87 | return generator(Iterable(std::forward(container)), 88 | [](auto&& iter) mutable -> OptionOrRef { 89 | if (iter.first == iter.last) { 90 | return nullopt; 91 | } 92 | decltype(auto) val = *(iter.first); 93 | ++iter.first; 94 | return val; 95 | }); 96 | } 97 | 98 | /* 99 | * Create a generator from a pair of iterators first and last. The generator 100 | * container yields values from first (inclusive) to last (exclusive). 101 | */ 102 | template 103 | decltype(auto) slice(Iter first, Iter last) { 104 | typedef decltype(*first) IterValueType; 105 | struct Iterable { 106 | Iter first; 107 | Iter last; 108 | Iterable(Iter first, Iter last) 109 | : first(std::move(first)), last(std::move(last)) {} 110 | }; 111 | return generator(Iterable(std::move(first), std::move(last)), 112 | [](auto&& iter) mutable -> OptionOrRef { 113 | if (iter.first == iter.last) { 114 | return nullopt; 115 | } 116 | decltype(auto) val = *(iter.first); 117 | ++iter.first; 118 | return val; 119 | }); 120 | } 121 | 122 | /* 123 | * return a generator that iterates through a container from position start 124 | * (inclusive) to position end (exclusive). 125 | If an rvalue is given, the generator will take ownership of the container and 126 | move it into the generator object, otherwise the generator will only hold a 127 | reference to the container. 128 | */ 129 | template = 0> 131 | decltype(auto) slice(Container&& container, size_t start, size_t last) { 132 | typedef detail::RmRef Iter; 133 | typedef decltype(*std::begin(container)) IterValueType; 134 | struct Iterable { 135 | Container container; 136 | Iter first; 137 | Iter last; 138 | Iterable(Container&& container, size_t start, size_t last) 139 | : container(std::forward(container)), 140 | first(std::begin(this->container) + start), 141 | last(std::begin(this->container) + last) {} 142 | }; 143 | return generator(Iterable(std::forward(container), start, last), 144 | [](auto&& iter) mutable -> OptionOrRef { 145 | if (iter.first == iter.last) { 146 | return nullopt; 147 | } 148 | decltype(auto) val = *(iter.first); 149 | ++iter.first; 150 | return val; 151 | }); 152 | } 153 | /* 154 | * Map one generator to another. Produce a generator that returns the values 155 | * produced by another generator applied to the given function. The given 156 | * function is invoked lazily to each value as requested. If the generator is 157 | * not specified, a GeneratorBuilder is returned. GeneratorBuilders are 158 | * converted to generators by piping `|` a generator to them. 159 | */ 160 | template = 0> 162 | decltype(auto) map(MapperFunc&& mapperIn, Generator&& gen = GeneratorHole()) { 163 | return buildOrDelay( 164 | generatorBuilder([mapperIn1 = std::forward(mapperIn)]( 165 | auto&& gen) mutable { 166 | typedef decltype(gen) Gen; 167 | return generator( 168 | wrapIfRef(std::forward(gen)), 169 | [mapper = std::forward(mapperIn1)]( 170 | auto&& gen) -> OptionOrRef { 171 | decltype(auto) val = next(gen); 172 | if (!val) { 173 | return nullopt; 174 | } else { 175 | return mapper(*val); 176 | } 177 | }); 178 | }), 179 | std::forward(gen)); 180 | } 181 | 182 | /* 183 | * Produce a generator that filters the output of another generator according to 184 | * the given function. The function should accept each value produced by the 185 | * given generator and return true if that value is to be forwarded, false 186 | * otherwise. The given function is invoked lazily to each value as requested. 187 | * If the generator is not specified, a GeneratorBuilder is returned. 188 | * GeneratorBuilders are converted to generators by piping `|` a generator to 189 | * them. 190 | */ 191 | template = 0> 193 | decltype(auto) filter(FilterFunc&& filterIn, 194 | Generator&& gen = GeneratorHole()) { 195 | return buildOrDelay( 196 | generatorBuilder([filterIn1 = std::forward(filterIn)]( 197 | auto&& gen) mutable { 198 | typedef decltype(gen) Gen; 199 | typedef typename detail::RmRef::YieldType YieldType; 200 | return generator(wrapIfRef(std::forward(gen)), 201 | [filter = std::forward(filterIn1)]( 202 | 203 | auto&& gen) -> OptionOrRef { 204 | while (true) { 205 | decltype(auto) val = next(gen); 206 | if (!val || filter(*val)) { 207 | return val; 208 | } 209 | } 210 | }); 211 | }), 212 | std::forward(gen)); 213 | } 214 | 215 | /* 216 | * Produce a generator that takes the first n values produced by another 217 | * generator.If the generator is not specified, a GeneratorBuilder is returned. 218 | * GeneratorBuilders are converted to generators by piping `|` a generator to 219 | * them. 220 | */ 221 | template = 0> 223 | decltype(auto) limit(size_t n, Generator&& gen = GeneratorHole()) { 224 | return buildOrDelay( 225 | generatorBuilder([n](auto&& gen) mutable { 226 | typedef decltype(gen) Gen; 227 | typedef typename detail::RmRef::YieldType YieldType; 228 | size_t count = 0; 229 | return generator( 230 | wrapIfRef(std::forward(gen)), 231 | [count, n](auto&& gen) mutable -> OptionOrRef { 232 | if (count++ < n) { 233 | return next(gen); 234 | } else { 235 | return nullopt; 236 | } 237 | }); 238 | }), 239 | std::forward(gen)); 240 | } 241 | 242 | /* 243 | * Combine two generators x and y into one. Produce a generator that yields 244 | * tuples where the first element of each tuple is a value pulled from x and the 245 | * second element is pulled from y. The generator ends when either x or y 246 | * end.*/ 247 | template = 0, 249 | detail::EnableIfType = 0> 250 | decltype(auto) zip(Gen1&& gen1, Gen2&& gen2) { 251 | typedef typename Gen1::YieldType Gen1YieldType; 252 | typedef typename Gen2::YieldType Gen2YieldType; 253 | typedef std::pair YieldType; 254 | return generator(wrapIfRef(std::forward(gen1)), 255 | [gen2 = std::forward(gen2)]( 256 | auto&& gen1) mutable -> optional { 257 | auto o1 = next(gen1); 258 | auto o2 = next(gen2); 259 | if (!o1 || !o2) { 260 | return nullopt; 261 | } else { 262 | return YieldType(std::forward(*o1), 263 | std::forward(*o2)); 264 | } 265 | }); 266 | } 267 | 268 | /* 269 | * Enumerate a generator. Produce a generator that returns the values 270 | * produced by another generator paired with an increasing count. The default 271 | * initial value of the count is 0. Each yielded item will be 272 | * pair(count,value). If the generator is not specified, a GeneratorBuilder is 273 | * returned. GeneratorBuilders are converted to generators by piping `|` a 274 | * generator to them. 275 | */ 276 | template = 0> 278 | decltype(auto) enumerate(size_t count = 0, Generator&& gen = GeneratorHole()) { 279 | return buildOrDelay(generatorBuilder([count](auto&& gen) mutable { 280 | typedef decltype(gen) Gen; 281 | return zip(infRange(count, 1), 282 | std::forward(gen)); 283 | }), 284 | std::forward(gen)); 285 | } 286 | 287 | /* 288 | * return a generator that reads from the given stream. The generated type (the 289 | * type of values pulled from the stream) must be specified as the first 290 | * template parameter. For example, to read integers from the stream, use 291 | * `read`. If an lvalue is given, only a reference to the stream is held. 292 | * If a rvalue is given, the generator takes ownership, the stream is moved into 293 | * the generator.*/ 294 | template 295 | auto read(Stream&& stream) { 296 | struct Reader { 297 | Stream stream; 298 | std::istream_iterator first; 299 | std::istream_iterator last; 300 | Reader(Stream&& stream) 301 | : stream(std::forward(stream)), first(this->stream) {} 302 | }; 303 | return generator(Reader(std::forward(stream)), 304 | [](auto&& reader) mutable -> optional { 305 | if (reader.first == reader.last) { 306 | return nullopt; 307 | } 308 | decltype(auto) val = *reader.first; 309 | ++reader.first; 310 | return val; 311 | }); 312 | } 313 | 314 | /* 315 | * return a generator that reads lines from the given stream. The generator 316 | * yields a new string for each line. If an lvalue is given, only a reference 317 | * to the stream is held. If a rvalue is given, the generator takes ownership, 318 | * the stream is moved into the generator.*/ 319 | template 320 | auto readLines(Stream&& stream) { 321 | return generator(detail::wrapIfRef(std::forward(stream)), 322 | [](auto&& stream) mutable -> optional { 323 | if (static_cast(stream)) { 324 | std::string s; 325 | std::getline(stream, s); 326 | return s; 327 | } else { 328 | return nullopt; 329 | } 330 | }); 331 | } 332 | 333 | } // namespace LazyCode 334 | #endif /* LAZYCODE_BASICGENERATORS_H_*/ 335 | -------------------------------------------------------------------------------- /include/lazyCode/collector.h: -------------------------------------------------------------------------------- 1 | #ifndef LAZYCODE_COLLECTOR_H_ 2 | #define LAZYCODE_COLLECTOR_H_ 3 | #include 4 | #include 5 | #include 6 | #include "generator.h" 7 | #include "nonstd/optional.hpp" 8 | #include "utils.h" 9 | namespace LazyCode { 10 | namespace detail { 11 | struct CollectorBase {}; 12 | struct GeneratorBase; 13 | 14 | } // namespace detail 15 | 16 | template 17 | class Collector : public detail::CollectorBase { 18 | Member member; 19 | CollectorFunc collector; 20 | 21 | public: 22 | Collector(Member&& member, CollectorFunc&& collector) 23 | : member(std::forward(member)), 24 | collector(std::forward(collector)) {} 25 | 26 | template 27 | void push(V& v) { 28 | collector(member, v); 29 | } 30 | 31 | template 32 | void push(std::reference_wrapper& v) { 33 | collector(member, v.get()); 34 | } 35 | 36 | template 37 | Member apply(Generator&& gen) { 38 | while (true) { 39 | auto val = next(gen); 40 | if (!val) { 41 | return std::forward(member); 42 | } 43 | push(*val); 44 | } 45 | } 46 | }; 47 | 48 | template 49 | class Collector : public detail::CollectorBase { 50 | CollectorFunc collector; 51 | 52 | public: 53 | Collector(CollectorFunc&& collector) 54 | : collector(std::forward(collector)) {} 55 | 56 | template 57 | void push(V& v) { 58 | collector(v); 59 | } 60 | 61 | template 62 | void push(std::reference_wrapper& v) { 63 | collector(v.get()); 64 | } 65 | template 66 | void apply(Generator&& gen) { 67 | while (true) { 68 | auto val = next(gen); 69 | if (!val) { 70 | return; 71 | } 72 | push(*val); 73 | } 74 | } 75 | }; 76 | 77 | template 78 | auto collector(MemberIn member, CollectorFuncIn collector) { 79 | typedef typename detail::StdRefToRef::type Member; 80 | typedef typename detail::StdRefToRef::type CollectorFunc; 81 | return Collector( 82 | std::forward(member), 83 | std::forward(collector)); 84 | } 85 | 86 | template 87 | auto collector(CollectorFuncIn collector) { 88 | typedef typename detail::StdRefToRef::type CollectorFunc; 89 | return Collector( 90 | std::forward(collector)); 91 | } 92 | 93 | template = 0, 95 | detail::EnableIfType = 0> 96 | decltype(auto) buildOrApply(CollectorBuilder&& builder, Generator&& gen) { 97 | return builder(gen).apply(std::forward(gen)); 98 | } 99 | 100 | template = 0, 102 | detail::EnableIfType = 0> 103 | decltype(auto) buildOrApply(Collector&& collector, Generator&& gen) { 104 | return collector.apply(std::forward(gen)); 105 | } 106 | 107 | template 108 | T buildOrApply(T v, GeneratorHole) { 109 | return std::move(v); 110 | } 111 | 112 | template = 0, 114 | detail::EnableIfNotType = 0> 115 | decltype(auto) operator|(Generator&& gen, CollectorBuilder&& builder) { 116 | return buildOrApply(std::forward(builder), 117 | std::forward(gen)); 118 | } 119 | 120 | template = 0> 122 | decltype(auto) operator|(Generator&& gen, Collector& collector) { 123 | return collector.apply(std::forward(gen)); 124 | } 125 | 126 | template = 0> 128 | decltype(auto) operator|(Generator&& gen, Collector collector) { 129 | return collector.apply(std::forward(gen)); 130 | } 131 | 132 | } // namespace LazyCode 133 | #endif /*LAZYCODE_COLLECTOR_H_*/ 134 | -------------------------------------------------------------------------------- /include/lazyCode/generator.h: -------------------------------------------------------------------------------- 1 | #ifndef LAZYCODE_GENERATOR_H_ 2 | #define LAZYCODE_GENERATOR_H_ 3 | #include 4 | #include 5 | #include "nonstd/optional.hpp" 6 | #include "utils.h" 7 | namespace LazyCode { 8 | namespace detail { 9 | struct GeneratorBase {}; 10 | struct GeneratorBuilderBase {}; 11 | struct CollectorBase; 12 | 13 | } // namespace detail 14 | template 15 | class GeneratorIterator; 16 | template 17 | class Generator; 18 | 19 | template 20 | class Generator : public detail::GeneratorBase { 21 | Member member; 22 | ProducerFunc producer; 23 | 24 | public: 25 | typedef typename detail::YieldType()(std::declval()))> 27 | YieldType; 28 | typedef detail::RmRef NoRefYieldType; 29 | 30 | Generator(Member&& member, ProducerFunc&& producer) 31 | : member(std::forward(member)), 32 | producer(std::forward(producer)) {} 33 | 34 | friend inline decltype(auto) next(Generator& gen) { 35 | return gen.producer(gen.member); 36 | } 37 | 38 | inline auto begin() { 39 | return GeneratorIterator>(*this); 40 | } 41 | 42 | inline auto end() { 43 | return GeneratorIterator>(); 44 | } 45 | }; 46 | 47 | struct GeneratorHole : public detail::GeneratorBase {}; 48 | 49 | template 50 | auto generator(MemberIn member, ProducerFuncIn producer) { 51 | typedef typename detail::StdRefToRef::type Member; 52 | typedef typename detail::StdRefToRef::type ProducerFunc; 53 | return Generator( 54 | std::forward(member), std::forward(producer)); 55 | } 56 | 57 | template 58 | struct GeneratorBuilder { 59 | BuilderFunc build; 60 | GeneratorBuilder(BuilderFunc&& build) 61 | : build(std::forward(build)) {} 62 | }; 63 | 64 | template 65 | auto generatorBuilder(BuilderFunc&& builder) { 66 | return GeneratorBuilder(std::forward(builder)); 67 | } 68 | 69 | template = 0> 71 | auto buildOrDelay(GeneratorBuilder builder, Generator&& gen) { 72 | return builder.build(std::forward(gen)); 73 | } 74 | 75 | template 76 | auto buildOrDelay(GeneratorBuilder builder, GeneratorHole) { 77 | return std::move(builder); 78 | } 79 | 80 | template 81 | auto operator|(Gen&& gen, GeneratorBuilder&& builder) { 82 | return builder.build(std::forward(gen)); 83 | } 84 | 85 | template 86 | auto operator|(Gen&& gen, GeneratorBuilder& builder) { 87 | return builder.build(std::forward(gen)); 88 | } 89 | 90 | template 91 | class GeneratorIterator { 92 | Generator* gen = NULL; 93 | typedef OptionOrRef OptionType; 94 | OptionType value; 95 | 96 | public: 97 | typedef typename Generator::NoRefYieldType value_type; 98 | typedef value_type& reference; 99 | typedef value_type* pointer; 100 | 101 | GeneratorIterator() : value(nullopt) {} 102 | GeneratorIterator(Generator& gen) : gen(&gen), value(next(gen)) {} 103 | 104 | decltype(auto) operator*() { return *value; } 105 | GeneratorIterator& operator++() { 106 | value = next(*gen); 107 | return *this; 108 | } 109 | auto operator++(int) { 110 | auto temp = *value; 111 | value = next(*gen); 112 | return temp; 113 | } 114 | inline bool operator!=(const GeneratorIterator&) { 115 | return value.has_value(); 116 | } 117 | inline bool operator==(const GeneratorIterator&) { 118 | return !value.has_value(); 119 | } 120 | }; 121 | 122 | } // namespace LazyCode 123 | #endif /*LAZYCODE_GENERATOR_H_*/ 124 | -------------------------------------------------------------------------------- /include/lazyCode/lazyCode.h: -------------------------------------------------------------------------------- 1 | #ifndef LAZYCODE_LAZYCODE_H_ 2 | #define LAZYCODE_LAZYCODE_H_ 3 | #include "basicCollectors.h" 4 | #include "basicGenerators.h" 5 | #endif /* LAZYCODE_LAZYCODE_H_*/ 6 | -------------------------------------------------------------------------------- /include/lazyCode/utils.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef INCLUDE_LAZYCODE_UTILS_H_ 3 | #define INCLUDE_LAZYCODE_UTILS_H_ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "nonstd/optional.hpp" 9 | #ifdef LAZY_CODE_NO_MACROS 10 | #define lazyCodeMacro(x) // nothing 11 | #else 12 | #define lazyCodeMacro(x) x 13 | #endif 14 | 15 | namespace LazyCode { 16 | 17 | using nonstd::make_optional; 18 | using nonstd::nullopt; 19 | using nonstd::optional; 20 | 21 | template 22 | using optionalref = optional>; 23 | 24 | namespace detail { 25 | 26 | template 27 | using RmRef = typename std::remove_reference::type; 28 | 29 | template 30 | struct StdRefToRef { 31 | typedef T type; 32 | }; 33 | 34 | template 35 | struct StdRefToRef> { 36 | typedef T &type; 37 | }; 38 | 39 | template 40 | struct StdRefToRef &&> { 41 | typedef T &type; 42 | }; 43 | 44 | template 45 | RmRef &&wrapIfRef(T &&v) { 46 | return std::move(v); 47 | } 48 | 49 | template 50 | typename std::reference_wrapper wrapIfRef(T &v) { 51 | return std::ref(v); 52 | } 53 | 54 | template 55 | using EnableIfType = 56 | typename std::enable_if>::value, int>::type; 57 | 58 | template 59 | using EnableIfNotType = 60 | typename std::enable_if>::value, int>::type; 61 | 62 | // unpack tuple into arguments to function 63 | template 64 | constexpr auto index_apply_impl(F &&f, std::index_sequence) { 65 | return f(std::integral_constant{}...); 66 | } 67 | 68 | template 69 | constexpr auto index_apply(F &&f) { 70 | return index_apply_impl(f, std::make_index_sequence{}); 71 | } 72 | 73 | template 74 | constexpr auto apply(F &&f, Tuple &&t) { 75 | return index_apply>::value>([&](auto... Is) { 76 | return f(std::forward(t))>(std::get(t))...); 77 | }); 78 | } 79 | 80 | template 81 | constexpr auto applyWithoutForward(F &&f, Tuple &&t) { 82 | return index_apply>::value>( 83 | [&](auto... Is) { return f(std::get(t)...); }); 84 | } 85 | 86 | } // namespace detail 87 | 88 | template 89 | auto unpack(Func &&func) { 90 | return [funcIn = std::forward(func)](auto &&tup) { 91 | return detail::apply(funcIn, tup); 92 | }; 93 | } 94 | 95 | /** varadic to string function 96 | * 97 | */ 98 | template 99 | std::string toString(Args const &... args) { 100 | std::ostringstream result; 101 | int unpack[]{0, (result << args, 0)...}; 102 | static_cast(unpack); 103 | return result.str(); 104 | } 105 | 106 | template 107 | struct OptionOrRef : public optional { 108 | template 109 | OptionOrRef(V &&v) : optional::optional(std::forward(v)) {} 110 | }; 111 | 112 | template 113 | struct OptionOrRef : public optionalref { 114 | template 115 | OptionOrRef(V &&v) : optionalref::optional(std::forward(v)) {} 116 | 117 | decltype(auto) operator*() { return optionalref::operator*().get(); } 118 | }; 119 | 120 | template 121 | struct OptionOrRef : public optional { 122 | template 123 | OptionOrRef(V &&v) : optional::optional(std::forward(v)) {} 124 | }; 125 | namespace detail { 126 | template 127 | struct YieldTypeImpl; 128 | 129 | template 130 | struct YieldTypeImpl> { 131 | typedef T type; 132 | }; 133 | template 134 | struct YieldTypeImpl> { 135 | typedef T &type; 136 | }; 137 | template 138 | struct YieldTypeImpl> { 139 | typedef T type; 140 | }; 141 | 142 | template 143 | struct YieldTypeImpl> { 144 | typedef T &type; 145 | }; 146 | 147 | template 148 | struct YieldTypeImpl> { 149 | typedef T type; 150 | }; 151 | template 152 | using YieldType = typename YieldTypeImpl::type; 153 | 154 | } // namespace detail 155 | } // namespace LazyCode 156 | 157 | lazyCodeMacro( 158 | #define _completeLambda0(body) ) { return body; } 159 | #define _completeLambda1(arg1, body) auto &&arg1 _completeLambda0(body) 160 | #define _completeLambda2(arg1, arg2, body) \ 161 | auto &&arg1, _completeLambda1(arg2, body) 162 | #define _completeLambda3(arg1, arg2, arg3, body) \ 163 | auto &&arg1, _completeLambda2(arg2, arg3, body) 164 | #define _completeLambda4(arg1, arg2, arg3, arg4, body) \ 165 | auto &&arg1, _completeLambda3(arg2, arg3, arg4, body) 166 | #define _completeLambda5(arg1, arg2, arg3, arg4, arg5, body) \ 167 | auto &&arg1, _completeLambda4(arg2, arg3, arg4, arg5, body) 168 | #define _getCompleteLambdaOverload(_1, _2, _3, _4, _5, _6, NAME, ...) NAME 169 | #define _completeLambda(...) \ 170 | _getCompleteLambdaOverload( \ 171 | __VA_ARGS__, _completeLambda5, _completeLambda4, _completeLambda3, \ 172 | _completeLambda2, _completeLambda1, _completeLambda0)(__VA_ARGS__) 173 | #define lambda(...) [&]( _completeLambda(__VA_ARGS__) 174 | 175 | ) 176 | 177 | #endif /* INCLUDE_LAZYCODE_UTILS_H_ */ 178 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Lazy Code 2 | # Cute and Efficient Is Definitely Possible 3 | 4 | * Compossible, lazily evaluated generators such as map, filter, fold, enumerated ranges and more. 5 | * Easy handling of input and output streams, reading line by line, parsing objects, etc. 6 | * Compact syntax: Choice between 7 | * Functional `fold(...,map(...,filter(...)))` 8 | * Piped `filter(...) | map(...) | fold(...)` 9 | * Zero cost abstractions leveraging C++ templates, no macros involved. 10 | * Easily create new generators and integrate with existing ones. 11 | * _Optionally_ enabled macros to make the syntax even more cute. 12 | 13 | 14 | # Quick examples: 15 | 16 | This is just some demonstrations of the coding style enabled with this library. A full listing comes after the examples. 17 | 18 | 19 | ```c++ 20 | namespace lz = LazyCode; 21 | using namespace std; 22 | ``` 23 | 24 | ## Example 1: 25 | 26 | * Read in lines of text into a vector until EOF is reached, one line per vector element. 27 | * Sort the vector and then reprint the lines. 28 | 29 | ```c++ 30 | auto lines = lz::readLines(cin) | lz::append(vector()); 31 | sort(lines.begin(), lines.end()); 32 | lz::generator(lines) | lz::write(cout, "\n"); 33 | ``` 34 | 35 | Yup, that's it. And it gets better... 36 | 37 | ## Example 2: 38 | 39 | * Read in up to 10 integers from a file "test.txt". 40 | * filter for the even numbers, square them and sum their values. 41 | * Do not store the numbers in a container, after all, it could easily be more than 10 numbers. 42 | 43 | ```c++ 44 | int total = lz::read(ifstream("test.txt")) | lz::limit(10) | 45 | lz::filter([](int i) { return i % 2 == 0; }) | 46 | lz::map([](int i) { return i * i; }) | lz::sum(); 47 | ``` 48 | 49 | __Wow__, that's compact. Maybe too compact? If you are concerned, you can split that line up into multiple expressions. Take a look: 50 | 51 | ```c++ 52 | auto numbers = lz::read(ifstream("test.txt")) | lz::limit(10); 53 | auto evenFilter = numbers | lz::filter([](int i) { return i % 2 == 0; }); 54 | auto squares = evenFilter | lz::map([](int i) { return i * i; }); 55 | int total = squares | lz::sum(); 56 | ``` 57 | 58 | * Even though this expression is split over multiple variable assignments, it is not any less efficient. 59 | * Each intermediate variable simply 60 | describes a unit of code to be executed. All held in stack. Nothing is executed until the final pipe into the `sum()`. 61 | * The final value (the sum of the squares of only even numbers in a file) is calculated in a single pass with no intermediate container or memory allocations required. 62 | * for each number in `test.txt`, evaluate `filter condition`, and add to `total`. 63 | 64 | 65 | ## Use a functional style instead: 66 | 67 | Piping does not work with you? Simply use the functional interface: 68 | 69 | ```c++ 70 | auto numbers = lz::limit(10, lz::read(ifstream("test.txt"))); 71 | auto evenFilter = lz::filter([](int i) { return i % 2 == 0; }, numbers); 72 | auto squares = lz::map([](int i) { return i * i; }, evenFilter); 73 | int total = lz::sum(squares); 74 | ``` 75 | 76 | ## Even more cute: 77 | 78 | Those long lambdas, what can we do? You could use a macro * don't panic* , macros are optional, I only offer a single one for convenience. 79 | 80 | ```c++ 81 | int total = lz::read(cin) | lz::limit(10) | 82 | lz::filter(lambda(i, i % 2 == 0)) | lz::map(lambda(i, i * i)) | 83 | lz::sum(); 84 | ``` 85 | 86 | The lambda macro (* if you want it* ) is there to build the standard lambda, one that captures the surrounding context and that can take both lvalue and references. It simply uses all but the last argument as parameter names and the last argument as the return expression to evaluate. `lambda(a,b,c,expression)` maps to `[&] (auto&& a, auto&& b, auto && c) { return expression; }`. 87 | 88 | __It can be disabled___ by defining `#define LAZY_CODE_NO_MACROS` before including the `lazyCode` header. 89 | 90 | 91 | ## A case for safety: 92 | 93 | Writing the equivalent of the above in plain old c++ is more cumbersome and can be argued to be less safe. For example, this almost equivalent snippet has a bug. Can you spot it? 94 | 95 | ```c++ 96 | int total = 0; 97 | for (int i = 0; i < 10; i++) { 98 | int value; 99 | cin >> value; 100 | if (value % 2 == 0) { 101 | total += value * value; 102 | } 103 | } 104 | ``` 105 | 106 | __The bug?__ What if the user enters less than 10 numbers. You'll be reading `EOF` symbols into your `total`. Silly example, but the idea is there. This is not only more compact and readable, it can enable safer code. 107 | 108 | 109 | # Installation: 110 | 111 | * A __c++14__ or above compiler is required. 112 | * For your convenience, a single header is maintained in the repo's top level directory `single_header`. `LazyCode` can therefore be used just by including this single header, [single_header/lazyCode.h](single_header/lazyCode.h). 113 | * Alternatively, the project is built as a standard Cmake header only interface and can be included into a cmake project via cmake's `add_subdirectory`. 114 | * For contributers, notes on how to recreate the single header after a source change is described at the end of this readme. 115 | 116 | ## Method 1: include the single header (easiest) 117 | 118 | 1. [Download the single header here](single_header/lazyCode.h) 119 | 1. Include it from any `c++` file: `#include "path_to_lazyCode.h"` 120 | 121 | or, to stay up to date with the latest release, consider adding `lazyCode` as a sub module: 122 | 123 | ``` 124 | git submodule add https://github.com/SaadAttieh/lazyCode 125 | ``` 126 | 127 | ## Method 2: as a cmake sub directory. 128 | 129 | ``` 130 | #add lazyCode as a submodule: 131 | git submodule add https://github.com/SaadAttieh/lazyCode 132 | #Tell git to download submodules of lazyCode 133 | git submodule init ; git submodule update 134 | ``` 135 | 136 | Then add this to your cmake file: 137 | ``` 138 | add_subdirectory (lazyCode) 139 | ``` 140 | 141 | 142 | # The docs: 143 | 144 | ## The Basics: 145 | 146 | There are two types of objects that can be created, `generators` and `collectors`. 147 | 148 | A generator is simply a state object paired with a function that can be called to produce values based off the state. This is discussed later in the section *creating your own generators*. A generator by itself does not execute any instructions. This is why we call it lazy evaluation; it merely describes how values may be generated. Values may be pulled from a generator via the `next()` function;, by using a for loop `for (auto i: generator)`, or by passing it to a collector. Collectors pull values from a generator and perform a given action, see the section below on collectors. 149 | 150 | 151 | 152 | ## Basic generators: 153 | 154 | ### range: 155 | 156 | ```c++ 157 | template ::value, int>::type = 0> 159 | auto range(Number end); 160 | ``` 161 | * Create a generator of sequence of integral values. Sequence begins at 0 (inclusive) , is followed by values increasing by 1 and stops at the specified last point (exclusive). 162 | * `range(5)` generates `0,1,2,3,4,` 163 | 164 | 165 | ```c++ 166 | template ::value, int>::type = 0> 168 | auto range(Number start, Number end); 169 | ``` 170 | * Create a generator of sequence of integral values. Sequence begins at specified start point (inclusive) , is followed by values increasing by 1 and stops at the specified last point (exclusive). 171 | * `range(2,5)` generates `2,3,4` 172 | 173 | 174 | 175 | ```c++ 176 | template 177 | auto range(Number1 start, Number1 end, Number2 increment); 178 | ``` 179 | * Create a generator of sequence of values. Sequence begins at specified start point (inclusive) , is followed by values increasing/decreasing by the specified increment and stops at the specified last point (exclusive). 180 | * `range(0.1,1.0,0.2)` generates `0.1,0.3,0.5,0.7,0.9` 181 | 182 | 183 | 184 | ### infRange 185 | 186 | 187 | ```c++ 188 | template 189 | auto infRange(Number1 start, Number2 increment) 190 | ``` 191 | * Create a never ending generator of sequence of values. Sequence begins at specified start point (inclusive) and is followed by values increasing/decreasing by the specified increment. 192 | * `infRange(0,2)` infinite range, generates `0,2,4,6,8,...` 193 | 194 | 195 | 196 | ### readLines 197 | 198 | ```c++ 199 | template 200 | auto readLines(Stream&& stream) 201 | ``` 202 | * return a generator that reads lines from the given stream. The generator yields a new string for each line. If an lvalue is given, only a reference to the stream is held. If a rvalue is given, the generator takes ownership, the stream is moved into the generator. 203 | * `readLines(cout)` reads from std::cout, only a reference to cout is held 204 | * `readLines(istringstream(someString))` reads from the newly created string stream, the string stream is moved into the generator. 205 | 206 | 207 | 208 | 209 | ### read 210 | 211 | ```c++ 212 | template 213 | auto read(Stream&& stream) 214 | ``` 215 | * return a generator that reads from the given stream. The generated type (the type of values pulled from the stream) must be specified as the first template parameter. For example, to read integers from the stream, use `read`. If an lvalue is given, only a reference to the stream is held. If a rvalue is given, the generator takes ownership, the stream is moved into the generator. 216 | * `read(cin)` read double values from cin. 217 | 218 | 219 | 220 | ### generator 221 | 222 | ```c++ 223 | template 224 | decltype(auto) generator(Container&& container) 225 | ``` 226 | * Create a generator from a container. The generator uses the containers begin and end iterators via `std::begin, std::end`. If an rvalue is given, the generator will take ownership of the container and move it into the generator object, otherwise the generator will only hold a reference to the container. 227 | * `generator(v)` v can be a vector, map, set, anything with begin/end iterators. Only a reference to v is held. 228 | * `generator(V())` V can be a vector, map, set, anything with begin/end iterators. Since it is a newly created container, it is moved into the generator. 229 | 230 | 231 | ### slice 232 | 233 | ```c++ 234 | template 235 | decltype(auto) slice(Container&& container, size_t start, size_t last) 236 | ``` 237 | * return a generator that iterates through a container from position start (inclusive) to position end (exclusive). 238 | If an rvalue is given, the generator will take ownership of the container and 239 | move it into the generator object, otherwise the generator will only hold a 240 | reference to the container. 241 | * `slice(v,2,4)` Only a reference to v is held. 242 | * `slice(V(),2,4)` Since `V` is a newly created container, it is moved into the generator. 243 | 244 | 245 | ```c++ 246 | template 247 | decltype(auto) slice(Iter first, Iter last) 248 | ``` 249 | * Create a generator from a pair of iterators first and last. The generator container yields values from first (inclusive) to last (exclusive). 250 | * `string s; slice(s.begin(),s.end());` 251 | 252 | 253 | 254 | 255 | ## Composed generators: 256 | 257 | Composed generators are as the name suggests, building new generators from existing ones. This can be done in the functional style or using the pipe `|` style. In both cases, when building a generator `g2` from `g1`, if `g1` is an rvalue (for example if it was constructed inline or moved), `g2` takes ownership, and `g1` is moved into `g2`. If `g1` is an lvalue, (for example you previously created a generator and assign it to a variable `v`), `g2` will only hold a reference to `g1` meaning that care should be taken to make sure `v` (`g1`) is in scope as long as `g2`. 258 | 259 | 260 | ### Map 261 | 262 | ```c++ 263 | template 264 | decltype(auto) map(MapperFunc&& mapperIn, Generator&& gen = GeneratorHole()) 265 | ``` 266 | * Map one generator to another. Produce a generator that returns the values produced by another generator applied to the given function. The given function is invoked lazily to each value as requested. If the generator is not specified, a GeneratorBuilder is returned. GeneratorBuilders are converted to generators by piping `|` a generator to them. 267 | * `map(func,generator)` or `generator | map(func)` 268 | 269 | 270 | ### filter 271 | 272 | ```c++ 273 | template 274 | decltype(auto) filter(FilterFunc&& filterIn, 275 | Generator&& gen = GeneratorHole()) 276 | ``` 277 | * Produce a generator that filters the output of another generator according to the given function. The function should accept each value produced by the given generator and return true if that value is to be forwarded, false otherwise. The given function is invoked lazily to each value as requested. If the generator is not specified, a GeneratorBuilder is returned. GeneratorBuilders are converted to generators by piping `|` a generator to them. 278 | * `filter(func,generator)` or `generator | filter(func)` 279 | 280 | 281 | 282 | 283 | ### enumerate 284 | 285 | ```c++ 286 | template 287 | decltype(auto) enumerate(size_t count = 0, Generator&& gen = GeneratorHole()) { 288 | ``` 289 | * Enumerate a generator. Produce a generator that returns the values produced by another generator paired with an increasing count. The default initial value of the count is 0. Each yielded item will be pair(count,value). If the generator is not specified, a GeneratorBuilder is returned. GeneratorBuilders are converted to generators by piping `|` a generator to them. 290 | * `enumerate(generator)` or `generator | enumerate()` 291 | * `enumerate(startingValue, generator)` or `generator | enumerate(startingValue)` 292 | 293 | 294 | ### zip 295 | ```c++ 296 | template 297 | decltype(auto) zip(Gen1&& gen1, Gen2&& gen2) 298 | ``` 299 | * Combine two generators gen1 and gen2 into one. Produce a generator that yields tuples where the first element of each tuple is a value pulled from gen1 and the second element is pulled from gen2. The generator ends when either x or y end. 300 | * `zip(generator1,generator2)` 301 | 302 | 303 | ### limit 304 | ```c++ 305 | template 306 | decltype(auto) limit(size_t n, Generator&& gen = GeneratorHole()) 307 | ``` 308 | * Produce a generator that takes the first n values produced by another generator.If the generator is not specified, a GeneratorBuilder is returned. GeneratorBuilders are converted to generators by piping `|` a generator to them. 309 | * `limit(number, generator)` or `generator | limit(number)` 310 | 311 | 312 | ## Collectors 313 | 314 | Collectors evaluate generators. This means pulling all the values from them. Just as with composed generators, this can be done in the functional style or using the pipe `|` style. Note that you can pull values from a generator using its `begin/end` iterators, using a for loop `for (auto i: generator)` or using the `next(generator)` function. 315 | 316 | Lastly, note that if a generator yields references to values, for example a generator yielding values from a container, any collector or for loop applied to the generator will receive these values as references, even if they are passed through another generator such as `filter`. This allows code such as 317 | ```c++ 318 | vector v = ... 319 | auto g = lz::generator(v) | filter(...); 320 | for (auto& i: g) { 321 | //change i and it will be changing values in v 322 | } 323 | 324 | ``` 325 | However, if the generator yields rvalues, for example, the map generator, then the collector or for loop will see these as rvalues. 326 | 327 | 328 | ### forEach 329 | 330 | ```c++ 331 | template 332 | decltype(auto) forEach(Func&& func, Generator&& gen = GeneratorHole()) 333 | ``` 334 | * Apply the given function to each value produced by the given generator. The return value of the function is ignored and may be void. If the generator is not specified, a collector is returned. Collectors remember the operation to be executed. The operation is executed when a generator is piped `|` to it. 335 | * `generator | forEach(func)` or `forEach(func,generator)` 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | ### count 344 | 345 | 346 | ```c++ 347 | template 348 | decltype(auto) count(Generator&& gen = GeneratorHole()) 349 | ``` 350 | * Count the number of values yielded by the given generator. If the generator is not specified, a collector is returned. Collectors remember the operation to be executed. The operation is executed when a generator is piped `|` to it. 351 | * `generator | count(), count(generator)` 352 | 353 | 354 | ### sum 355 | ```c++ 356 | template = 0> 358 | decltype(auto) sum(Generator&& gen = GeneratorHole()) 359 | ``` 360 | * Return the sum of the values produced by a generator. If the generator is not specified, a collector is returned. Collectors remember the operation to be executed. The operation is executed when a generator is piped `|` to it. 361 | * `generator | sum(), sum(generator)` 362 | 363 | 364 | 365 | ### product 366 | 367 | ```c++ 368 | template = 0> 370 | decltype(auto) product(Generator&& gen = GeneratorHole()) 371 | ``` 372 | * Return the product (multiplication) of the values produced by a generator.If the generator is not specified, a collector is returned. Collectors remember the operation to be executed. The operation is executed when a generator is piped `|` to it. 373 | * `generator | product(), product(generator)` 374 | 375 | 376 | ### min 377 | 378 | ```c++ 379 | [1] 380 | template 381 | decltype(auto) min(Generator&& gen = GeneratorHole()) 382 | ``` 383 | 384 | ```c++ 385 | [2] 386 | template 387 | decltype(auto) min(Val defaultVal, Generator&& gen = GeneratorHole()) 388 | ``` 389 | * Return the minimum value produced by a generator. If the generator yields no values, the default value is returned see [2]. If a default value is not given (see [1]), an optional is returned. The optional holds a value in the case the generator yielded a value, otherwise the optional will be empty (nullopt). The optional object is a c++14 implementation of std::optional from c++17. The implementation is taken from GitHub [akrzemi1/Optional](https://github.com/akrzemi1/Optional). If the generator is not specified, a collector is returned. Collectors remember the operation to be executed. The operation is executed when a generator is piped `|` to it. 390 | * `auto m = generator | min(defaultVal) or `auto m =min(defaultVal, generator)`. `m` holds minimum value. `defaultVal` 391 | * `auto m = generator | min()` or `auto m = min(generator)`. Check if not empty with `if (m)`, access min value with `* m` 392 | 393 | 394 | ### max 395 | 396 | ```c++ 397 | [1] 398 | template 399 | decltype(auto) max(Generator&& gen = GeneratorHole()) 400 | ``` 401 | 402 | ```c++ 403 | [2] 404 | template 405 | decltype(auto) max(Val defaultVal, Generator&& gen = GeneratorHole()) 406 | ``` 407 | 408 | * Return the maximum value produced by a generator. If the generator yields no values, the default value is returned see [2]. If a default value is not given (see [1]), an optional is returned. The optional holds a value in the case the generator yielded a value, otherwise the optional will be empty (nullopt). The optional object is a c++14 implementation of std::optional from c++17. The implementation is taken from GitHub [akrzemi1/Optional](https://github.com/akrzemi1/Optional). If the generator is not specified, a collector is returned. Collectors remember the operation to be executed. The operation is executed when a generator is piped `|` to it. 409 | * `auto m = generator | max(defaultVal) or `auto m =max(defaultVal, generator)`. `m` holds maximum value. `defaultVal` 410 | * `auto m = generator | max()` or `auto m = max(generator)`. Check if not empty with `if (m)`, access max value with `* m` 411 | 412 | 413 | 414 | ### fold 415 | 416 | 417 | ```c++ 418 | template = 0> 420 | decltype(auto) fold(Func&& func, Accum accum, 421 | Generator&& gen = GeneratorHole()) 422 | ``` 423 | * Combine the values produced by a generator using the specified function and return the result. The function should take two arguments and return a single value. The accum parameter (accumulator) specifies the initial value. The return type of the function must be convertible to the accum type. If the generator is not specified, a collector is returned. Collectors remember the operation to be executed. The operation is executed when a generator is piped `|` to it. 424 | * `generator | fold(func, accumulator )` or `fold(func,accumulator,generator)` 425 | 426 | 427 | ### append 428 | 429 | ```c++ 430 | template 431 | decltype(auto) append(Container&& container, 432 | Generator&& gen = GeneratorHole()) 433 | ``` 434 | * Append each value produced by the given generator to the given container, using container.emplace_back(). For unordered containers, see `insert`. Note that a rvalue can be given as the container parameter, for example constructing a new container inline (`append(vector())`), in which case the collector stores the container and returns it after appending the values. Otherwise, only a reference to the container is held by the collector. If the generator is not specified, a collector is returned. Collectors remember the operation to be executed. The operation is executed when a generator is piped `|` to it. 435 | * `list c; generator | append(c)` or `append(c,generator)` 436 | * `auto c = generator | append(vector())` or `auto c = append(vector(),generator)` 437 | 438 | 439 | 440 | ### insert 441 | 442 | 443 | ```c++ 444 | template 445 | decltype(auto) insert(Container&& container, 446 | Generator&& gen = GeneratorHole()) 447 | ``` 448 | * Insert each value produced by the given generator to the given container, using container.emplace(). This is for unordered containers. For ordered containers, see `append`. Note that a rvalue can be given as the container parameter, for example constructing a new container inline (`append(set())`), in which case the collector stores the container and returns it after inserting the values. Otherwise, only a reference to the container is held by the collector. If the generator is not specified, a collector is returned. Collectors remember the operation to be executed. The operation is executed when a generator is piped `|` to it. 449 | * `set c; generator | insert(c)` or `insert(c,generator)` 450 | * `auto c = generator | append(map())` or `auto c = append(map(),generator)` 451 | 452 | 453 | 454 | ### write 455 | 456 | ```c++ 457 | [1] 458 | template 459 | decltype(auto) write(Stream&& stream, Generator&& gen = GeneratorHole()) 460 | ``` 461 | 462 | ```c++ 463 | [2] 464 | template 466 | decltype(auto) write(Stream&& stream, Interleave i, 467 | Generator&& gen = GeneratorHole()) 468 | ``` 469 | * Write each value produced by the given generator to the given stream. An interleave value can be optionally specified (see [2]), in which case the interleave value will be written to the stream before each generated value apart from the first. This is sometimes known as join. Note that a rvalue can be given as the stream parameter, for example constructing a new stream inline (`write(ostringstream())`), in which case the collector stores the stream and returns it after printing the values to it. Otherwise, only a reference to the stream is held by the collector. If the generator is not specified, a collector is returned. Collectors remember the operation to be executed. The operation is executed when a generator is piped `|` to it. 470 | * Write to existing stream s: `generator | write(s)` or `write(s,generator)` 471 | * Write to existing stream s interleaved with separator i: `generator | write(s,i)` or `write(s,i,generator)` 472 | * Create new stream and write to it: `auto s = generator | write(Stream())` or `auto s = write(Stream(),generator)` 473 | * Create new stream and write to it with separator i: `auto s = generator | write(Stream(),i)` or `auto s = write(Stream(),i,generator)` 474 | * Do a string join operation, that is, write to a string, using the above interface: `string s = (generator | write(std::ostringstream(),join)).str();` 475 | 476 | 477 | 478 | 479 | ## Useful functions: 480 | * `unpack(f)` Create a function `g` from `f`. `g` accepts pairs/tuples and unpacks the tuple members and gives them as arguments to `f`. 481 | * `map m; generator(m) | forEach(unpack([] (auto&& key, auto&& value) { //something with key and value }))` 482 | * `enumerate(generator) | forEach(unpack([] (auto&& index, auto&& value) { //something with index and value }))` 483 | * `std::string tostring(m1,m2,...,mn)` varadic function, prints `m1,m2,...,mn` using `ooperator<<` to a string. 484 | 485 | ## Creating your own generators: 486 | 487 | 488 | * More details coming soon. Here a toy example, a generator that generates powers of 2 up to 1024. 489 | ```c++ 490 | auto g = lz::generator(1, [](int i) -> lz::optional { 491 | i * = 2; 492 | if (i <= 1024) { 493 | return i; 494 | } else { 495 | return lz::nullopt; 496 | } 497 | }); 498 | 499 | ``` 500 | 501 | 502 | 503 | 504 | # For contributers: rebuilding the single header file: 505 | 506 | * The single header is built via a python3 script: [single_header/makeSingleHeader.py](single_header/makeSingleHeader.py). 507 | * Usage: `./makeSingleHeader.py starting_file [include_path_1] [include_path_2] ... [include_path_n]` 508 | * The script builds a string, copying the source from starting_file, replacing any includes with with the source contained at the file pointed to by the include. This is done recursively for all included files. 509 | * The script (by choice) only identifies includes specified by quotes `include "..."` and not other others such as `include <...>`. This can be trivially changed if necessary. 510 | * Preprocess macros are not executed. The only guard put in place is that a file is not included more than once. 511 | * If a file `a` includes another file `b` via a path not relative to `a`, a path to the parent of `b` must be listed as an additional argument. For example, currently the current source [include/lazyCode/lazyCode.h](include/lazyCode/lazyCode.h) contains the include `#include "optional/optional.hpp"`. However, this file is located in [include/optional/optional.hpp](include/optional/optional.hpp). Therefore, the script is run as follows to specifie [include](include) as an additional include path: 512 | ```single_header/makeSingleHeader.py include/lazyCode/lazyCode.h include > single_header/lazyCode.h``` 513 | -------------------------------------------------------------------------------- /single_header/lazyCode.h: -------------------------------------------------------------------------------- 1 | #ifndef LAZYCODE_LAZYCODE_H_ 2 | #define LAZYCODE_LAZYCODE_H_ 3 | #ifndef LAZYCODE_BASICCOLLECTORS_H_ 4 | #define LAZYCODE_BASICCOLLECTORS_H_ 5 | #include 6 | #ifndef LAZYCODE_COLLECTOR_H_ 7 | #define LAZYCODE_COLLECTOR_H_ 8 | #include 9 | #include 10 | #include 11 | #ifndef LAZYCODE_GENERATOR_H_ 12 | #define LAZYCODE_GENERATOR_H_ 13 | #include 14 | #include 15 | // 16 | // Copyright (c) 2014-2018 Martin Moene 17 | // 18 | // https://github.com/martinmoene/optional-lite 19 | // 20 | // Distributed under the Boost Software License, Version 1.0. 21 | // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 22 | 23 | #pragma once 24 | 25 | #ifndef NONSTD_OPTIONAL_LITE_HPP 26 | #define NONSTD_OPTIONAL_LITE_HPP 27 | 28 | #define optional_lite_MAJOR 3 29 | #define optional_lite_MINOR 1 30 | #define optional_lite_PATCH 1 31 | 32 | #define optional_lite_VERSION optional_STRINGIFY(optional_lite_MAJOR) "." optional_STRINGIFY(optional_lite_MINOR) "." optional_STRINGIFY(optional_lite_PATCH) 33 | 34 | #define optional_STRINGIFY( x ) optional_STRINGIFY_( x ) 35 | #define optional_STRINGIFY_( x ) #x 36 | 37 | // optional-lite configuration: 38 | 39 | #define optional_OPTIONAL_DEFAULT 0 40 | #define optional_OPTIONAL_NONSTD 1 41 | #define optional_OPTIONAL_STD 2 42 | 43 | #if !defined( optional_CONFIG_SELECT_OPTIONAL ) 44 | # define optional_CONFIG_SELECT_OPTIONAL ( optional_HAVE_STD_OPTIONAL ? optional_OPTIONAL_STD : optional_OPTIONAL_NONSTD ) 45 | #endif 46 | 47 | // Control presence of exception handling (try and auto discover): 48 | 49 | #ifndef optional_CONFIG_NO_EXCEPTIONS 50 | # if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) 51 | # define optional_CONFIG_NO_EXCEPTIONS 0 52 | # else 53 | # define optional_CONFIG_NO_EXCEPTIONS 1 54 | # endif 55 | #endif 56 | 57 | // C++ language version detection (C++20 is speculative): 58 | // Note: VC14.0/1900 (VS2015) lacks too much from C++14. 59 | 60 | #ifndef optional_CPLUSPLUS 61 | # if defined(_MSVC_LANG ) && !defined(__clang__) 62 | # define optional_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) 63 | # else 64 | # define optional_CPLUSPLUS __cplusplus 65 | # endif 66 | #endif 67 | 68 | #define optional_CPP98_OR_GREATER ( optional_CPLUSPLUS >= 199711L ) 69 | #define optional_CPP11_OR_GREATER ( optional_CPLUSPLUS >= 201103L ) 70 | #define optional_CPP11_OR_GREATER_ ( optional_CPLUSPLUS >= 201103L ) 71 | #define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L ) 72 | #define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L ) 73 | #define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202000L ) 74 | 75 | // C++ language version (represent 98 as 3): 76 | 77 | #define optional_CPLUSPLUS_V ( optional_CPLUSPLUS / 100 - (optional_CPLUSPLUS > 200000 ? 2000 : 1994) ) 78 | 79 | // Use C++17 std::optional if available and requested: 80 | 81 | #if optional_CPP17_OR_GREATER && defined(__has_include ) 82 | # if __has_include( ) 83 | # define optional_HAVE_STD_OPTIONAL 1 84 | # else 85 | # define optional_HAVE_STD_OPTIONAL 0 86 | # endif 87 | #else 88 | # define optional_HAVE_STD_OPTIONAL 0 89 | #endif 90 | 91 | #define optional_USES_STD_OPTIONAL ( (optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_STD) || ((optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_DEFAULT) && optional_HAVE_STD_OPTIONAL) ) 92 | 93 | // 94 | // in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite: 95 | // 96 | 97 | #ifndef nonstd_lite_HAVE_IN_PLACE_TYPES 98 | #define nonstd_lite_HAVE_IN_PLACE_TYPES 1 99 | 100 | // C++17 std::in_place in : 101 | 102 | #if optional_CPP17_OR_GREATER 103 | 104 | #include 105 | 106 | namespace nonstd { 107 | 108 | using std::in_place; 109 | using std::in_place_type; 110 | using std::in_place_index; 111 | using std::in_place_t; 112 | using std::in_place_type_t; 113 | using std::in_place_index_t; 114 | 115 | #define nonstd_lite_in_place_t( T) std::in_place_t 116 | #define nonstd_lite_in_place_type_t( T) std::in_place_type_t 117 | #define nonstd_lite_in_place_index_t(K) std::in_place_index_t 118 | 119 | #define nonstd_lite_in_place( T) std::in_place_t{} 120 | #define nonstd_lite_in_place_type( T) std::in_place_type_t{} 121 | #define nonstd_lite_in_place_index(K) std::in_place_index_t{} 122 | 123 | } // namespace nonstd 124 | 125 | #else // optional_CPP17_OR_GREATER 126 | 127 | #include 128 | 129 | namespace nonstd { 130 | namespace detail { 131 | 132 | template< class T > 133 | struct in_place_type_tag {}; 134 | 135 | template< std::size_t K > 136 | struct in_place_index_tag {}; 137 | 138 | } // namespace detail 139 | 140 | struct in_place_t {}; 141 | 142 | template< class T > 143 | inline in_place_t in_place( detail::in_place_type_tag = detail::in_place_type_tag() ) 144 | { 145 | return in_place_t(); 146 | } 147 | 148 | template< std::size_t K > 149 | inline in_place_t in_place( detail::in_place_index_tag = detail::in_place_index_tag() ) 150 | { 151 | return in_place_t(); 152 | } 153 | 154 | template< class T > 155 | inline in_place_t in_place_type( detail::in_place_type_tag = detail::in_place_type_tag() ) 156 | { 157 | return in_place_t(); 158 | } 159 | 160 | template< std::size_t K > 161 | inline in_place_t in_place_index( detail::in_place_index_tag = detail::in_place_index_tag() ) 162 | { 163 | return in_place_t(); 164 | } 165 | 166 | // mimic templated typedef: 167 | 168 | #define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) 169 | #define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) 170 | #define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag ) 171 | 172 | #define nonstd_lite_in_place( T) nonstd::in_place_type 173 | #define nonstd_lite_in_place_type( T) nonstd::in_place_type 174 | #define nonstd_lite_in_place_index(K) nonstd::in_place_index 175 | 176 | } // namespace nonstd 177 | 178 | #endif // optional_CPP17_OR_GREATER 179 | #endif // nonstd_lite_HAVE_IN_PLACE_TYPES 180 | 181 | // 182 | // Using std::optional: 183 | // 184 | 185 | #if optional_USES_STD_OPTIONAL 186 | 187 | #include 188 | 189 | namespace nonstd { 190 | 191 | using std::optional; 192 | using std::bad_optional_access; 193 | using std::hash; 194 | 195 | using std::nullopt; 196 | using std::nullopt_t; 197 | 198 | using std::operator==; 199 | using std::operator!=; 200 | using std::operator<; 201 | using std::operator<=; 202 | using std::operator>; 203 | using std::operator>=; 204 | using std::make_optional; 205 | using std::swap; 206 | } 207 | 208 | #else // optional_USES_STD_OPTIONAL 209 | 210 | #include 211 | #include 212 | 213 | // optional-lite alignment configuration: 214 | 215 | #ifndef optional_CONFIG_MAX_ALIGN_HACK 216 | # define optional_CONFIG_MAX_ALIGN_HACK 0 217 | #endif 218 | 219 | #ifndef optional_CONFIG_ALIGN_AS 220 | // no default, used in #if defined() 221 | #endif 222 | 223 | #ifndef optional_CONFIG_ALIGN_AS_FALLBACK 224 | # define optional_CONFIG_ALIGN_AS_FALLBACK double 225 | #endif 226 | 227 | // Compiler warning suppression: 228 | 229 | #if defined(__clang__) 230 | # pragma clang diagnostic push 231 | # pragma clang diagnostic ignored "-Wundef" 232 | #elif defined(__GNUC__) 233 | # pragma GCC diagnostic push 234 | # pragma GCC diagnostic ignored "-Wundef" 235 | #elif defined(_MSC_VER ) 236 | # pragma warning( push ) 237 | #endif 238 | 239 | // half-open range [lo..hi): 240 | #define optional_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) 241 | 242 | // Compiler versions: 243 | // 244 | // MSVC++ 6.0 _MSC_VER == 1200 (Visual Studio 6.0) 245 | // MSVC++ 7.0 _MSC_VER == 1300 (Visual Studio .NET 2002) 246 | // MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio .NET 2003) 247 | // MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) 248 | // MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) 249 | // MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) 250 | // MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) 251 | // MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) 252 | // MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) 253 | // MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017) 254 | 255 | #if defined(_MSC_VER ) && !defined(__clang__) 256 | # define optional_COMPILER_MSVC_VER (_MSC_VER ) 257 | # define optional_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) 258 | #else 259 | # define optional_COMPILER_MSVC_VER 0 260 | # define optional_COMPILER_MSVC_VERSION 0 261 | #endif 262 | 263 | #define optional_COMPILER_VERSION( major, minor, patch ) ( 10 * (10 * major + minor ) + patch ) 264 | 265 | #if defined(__GNUC__) && !defined(__clang__) 266 | # define optional_COMPILER_GNUC_VERSION optional_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) 267 | #else 268 | # define optional_COMPILER_GNUC_VERSION 0 269 | #endif 270 | 271 | #if defined(__clang__) 272 | # define optional_COMPILER_CLANG_VERSION optional_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) 273 | #else 274 | # define optional_COMPILER_CLANG_VERSION 0 275 | #endif 276 | 277 | #if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 140 ) 278 | # pragma warning( disable: 4345 ) // initialization behavior changed 279 | #endif 280 | 281 | #if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 150 ) 282 | # pragma warning( disable: 4814 ) // in C++14 'constexpr' will not imply 'const' 283 | #endif 284 | 285 | // Presence of language and library features: 286 | 287 | #define optional_HAVE(FEATURE) ( optional_HAVE_##FEATURE ) 288 | 289 | #ifdef _HAS_CPP0X 290 | # define optional_HAS_CPP0X _HAS_CPP0X 291 | #else 292 | # define optional_HAS_CPP0X 0 293 | #endif 294 | 295 | // Unless defined otherwise below, consider VC14 as C++11 for optional-lite: 296 | 297 | #if optional_COMPILER_MSVC_VER >= 1900 298 | # undef optional_CPP11_OR_GREATER 299 | # define optional_CPP11_OR_GREATER 1 300 | #endif 301 | 302 | #define optional_CPP11_90 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1500) 303 | #define optional_CPP11_100 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1600) 304 | #define optional_CPP11_110 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1700) 305 | #define optional_CPP11_120 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1800) 306 | #define optional_CPP11_140 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1900) 307 | #define optional_CPP11_141 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1910) 308 | 309 | #define optional_CPP14_000 (optional_CPP14_OR_GREATER) 310 | #define optional_CPP17_000 (optional_CPP17_OR_GREATER) 311 | 312 | // Presence of C++11 language features: 313 | 314 | #define optional_HAVE_CONSTEXPR_11 optional_CPP11_140 315 | #define optional_HAVE_NOEXCEPT optional_CPP11_140 316 | #define optional_HAVE_NULLPTR optional_CPP11_100 317 | #define optional_HAVE_REF_QUALIFIER optional_CPP11_140 318 | 319 | // Presence of C++14 language features: 320 | 321 | #define optional_HAVE_CONSTEXPR_14 optional_CPP14_000 322 | 323 | // Presence of C++17 language features: 324 | 325 | // no flag 326 | 327 | // Presence of C++ library features: 328 | 329 | #define optional_HAVE_CONDITIONAL optional_CPP11_120 330 | #define optional_HAVE_REMOVE_CV optional_CPP11_120 331 | #define optional_HAVE_TYPE_TRAITS optional_CPP11_90 332 | 333 | #define optional_HAVE_TR1_TYPE_TRAITS (!! optional_COMPILER_GNUC_VERSION ) 334 | #define optional_HAVE_TR1_ADD_POINTER (!! optional_COMPILER_GNUC_VERSION ) 335 | 336 | // C++ feature usage: 337 | 338 | #if optional_HAVE( CONSTEXPR_11 ) 339 | # define optional_constexpr constexpr 340 | #else 341 | # define optional_constexpr /*constexpr*/ 342 | #endif 343 | 344 | #if optional_HAVE( CONSTEXPR_14 ) 345 | # define optional_constexpr14 constexpr 346 | #else 347 | # define optional_constexpr14 /*constexpr*/ 348 | #endif 349 | 350 | #if optional_HAVE( NOEXCEPT ) 351 | # define optional_noexcept noexcept 352 | #else 353 | # define optional_noexcept /*noexcept*/ 354 | #endif 355 | 356 | #if optional_HAVE( NULLPTR ) 357 | # define optional_nullptr nullptr 358 | #else 359 | # define optional_nullptr NULL 360 | #endif 361 | 362 | #if optional_HAVE( REF_QUALIFIER ) 363 | # define optional_ref_qual & 364 | # define optional_refref_qual && 365 | #else 366 | # define optional_ref_qual /*&*/ 367 | # define optional_refref_qual /*&&*/ 368 | #endif 369 | 370 | // additional includes: 371 | 372 | #if optional_CONFIG_NO_EXCEPTIONS 373 | // already included: 374 | #else 375 | # include 376 | #endif 377 | 378 | #if optional_CPP11_OR_GREATER 379 | # include 380 | #endif 381 | 382 | #if optional_HAVE( INITIALIZER_LIST ) 383 | # include 384 | #endif 385 | 386 | #if optional_HAVE( TYPE_TRAITS ) 387 | # include 388 | #elif optional_HAVE( TR1_TYPE_TRAITS ) 389 | # include 390 | #endif 391 | 392 | // Method enabling 393 | 394 | #if optional_CPP11_OR_GREATER 395 | 396 | #define optional_REQUIRES_0(...) \ 397 | template< bool B = (__VA_ARGS__), typename std::enable_if::type = 0 > 398 | 399 | #define optional_REQUIRES_T(...) \ 400 | , typename = typename std::enable_if< (__VA_ARGS__), nonstd::optional_lite::detail::enabler >::type 401 | 402 | #define optional_REQUIRES_R(R, ...) \ 403 | typename std::enable_if< (__VA_ARGS__), R>::type 404 | 405 | #define optional_REQUIRES_A(...) \ 406 | , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr 407 | 408 | #endif 409 | 410 | // 411 | // optional: 412 | // 413 | 414 | namespace nonstd { namespace optional_lite { 415 | 416 | namespace std11 { 417 | 418 | #if optional_CPP11_OR_GREATER 419 | using std::move; 420 | #else 421 | template< typename T > T & move( T & t ) { return t; } 422 | #endif 423 | 424 | #if optional_HAVE( CONDITIONAL ) 425 | using std::conditional; 426 | #else 427 | template< bool B, typename T, typename F > struct conditional { typedef T type; }; 428 | template< typename T, typename F > struct conditional { typedef F type; }; 429 | #endif // optional_HAVE_CONDITIONAL 430 | 431 | } // namespace std11 432 | 433 | #if optional_CPP11_OR_GREATER 434 | 435 | /// type traits C++17: 436 | 437 | namespace std17 { 438 | 439 | #if optional_CPP17_OR_GREATER 440 | 441 | using std::is_swappable; 442 | using std::is_nothrow_swappable; 443 | 444 | #elif optional_CPP11_OR_GREATER 445 | 446 | namespace detail { 447 | 448 | using std::swap; 449 | 450 | struct is_swappable 451 | { 452 | template< typename T, typename = decltype( swap( std::declval(), std::declval() ) ) > 453 | static std::true_type test( int ); 454 | 455 | template< typename > 456 | static std::false_type test(...); 457 | }; 458 | 459 | struct is_nothrow_swappable 460 | { 461 | // wrap noexcept(epr) in separate function as work-around for VC140 (VS2015): 462 | 463 | template< typename T > 464 | static constexpr bool test() 465 | { 466 | return noexcept( swap( std::declval(), std::declval() ) ); 467 | } 468 | 469 | template< typename T > 470 | static auto test( int ) -> std::integral_constant()>{} 471 | 472 | template< typename > 473 | static std::false_type test(...); 474 | }; 475 | 476 | } // namespace detail 477 | 478 | // is [nothow] swappable: 479 | 480 | template< typename T > 481 | struct is_swappable : decltype( detail::is_swappable::test(0) ){}; 482 | 483 | template< typename T > 484 | struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test(0) ){}; 485 | 486 | #endif // optional_CPP17_OR_GREATER 487 | 488 | } // namespace std17 489 | 490 | /// type traits C++20: 491 | 492 | namespace std20 { 493 | 494 | template< typename T > 495 | struct remove_cvref 496 | { 497 | typedef typename std::remove_cv< typename std::remove_reference::type >::type type; 498 | }; 499 | 500 | } // namespace std20 501 | 502 | #endif // optional_CPP11_OR_GREATER 503 | 504 | /// class optional 505 | 506 | template< typename T > 507 | class optional; 508 | 509 | namespace detail { 510 | 511 | // for optional_REQUIRES_T 512 | 513 | #if optional_CPP11_OR_GREATER 514 | enum class enabler{}; 515 | #endif 516 | 517 | // C++11 emulation: 518 | 519 | struct nulltype{}; 520 | 521 | template< typename Head, typename Tail > 522 | struct typelist 523 | { 524 | typedef Head head; 525 | typedef Tail tail; 526 | }; 527 | 528 | #if optional_CONFIG_MAX_ALIGN_HACK 529 | 530 | // Max align, use most restricted type for alignment: 531 | 532 | #define optional_UNIQUE( name ) optional_UNIQUE2( name, __LINE__ ) 533 | #define optional_UNIQUE2( name, line ) optional_UNIQUE3( name, line ) 534 | #define optional_UNIQUE3( name, line ) name ## line 535 | 536 | #define optional_ALIGN_TYPE( type ) \ 537 | type optional_UNIQUE( _t ); struct_t< type > optional_UNIQUE( _st ) 538 | 539 | template< typename T > 540 | struct struct_t { T _; }; 541 | 542 | union max_align_t 543 | { 544 | optional_ALIGN_TYPE( char ); 545 | optional_ALIGN_TYPE( short int ); 546 | optional_ALIGN_TYPE( int ); 547 | optional_ALIGN_TYPE( long int ); 548 | optional_ALIGN_TYPE( float ); 549 | optional_ALIGN_TYPE( double ); 550 | optional_ALIGN_TYPE( long double ); 551 | optional_ALIGN_TYPE( char * ); 552 | optional_ALIGN_TYPE( short int * ); 553 | optional_ALIGN_TYPE( int * ); 554 | optional_ALIGN_TYPE( long int * ); 555 | optional_ALIGN_TYPE( float * ); 556 | optional_ALIGN_TYPE( double * ); 557 | optional_ALIGN_TYPE( long double * ); 558 | optional_ALIGN_TYPE( void * ); 559 | 560 | #ifdef HAVE_LONG_LONG 561 | optional_ALIGN_TYPE( long long ); 562 | #endif 563 | 564 | struct Unknown; 565 | 566 | Unknown ( * optional_UNIQUE(_) )( Unknown ); 567 | Unknown * Unknown::* optional_UNIQUE(_); 568 | Unknown ( Unknown::* optional_UNIQUE(_) )( Unknown ); 569 | 570 | struct_t< Unknown ( * )( Unknown) > optional_UNIQUE(_); 571 | struct_t< Unknown * Unknown::* > optional_UNIQUE(_); 572 | struct_t< Unknown ( Unknown::* )(Unknown) > optional_UNIQUE(_); 573 | }; 574 | 575 | #undef optional_UNIQUE 576 | #undef optional_UNIQUE2 577 | #undef optional_UNIQUE3 578 | 579 | #undef optional_ALIGN_TYPE 580 | 581 | #elif defined( optional_CONFIG_ALIGN_AS ) // optional_CONFIG_MAX_ALIGN_HACK 582 | 583 | // Use user-specified type for alignment: 584 | 585 | #define optional_ALIGN_AS( unused ) \ 586 | optional_CONFIG_ALIGN_AS 587 | 588 | #else // optional_CONFIG_MAX_ALIGN_HACK 589 | 590 | // Determine POD type to use for alignment: 591 | 592 | #define optional_ALIGN_AS( to_align ) \ 593 | typename type_of_size< alignment_types, alignment_of< to_align >::value >::type 594 | 595 | template< typename T > 596 | struct alignment_of; 597 | 598 | template< typename T > 599 | struct alignment_of_hack 600 | { 601 | char c; 602 | T t; 603 | alignment_of_hack(); 604 | }; 605 | 606 | template< size_t A, size_t S > 607 | struct alignment_logic 608 | { 609 | enum { value = A < S ? A : S }; 610 | }; 611 | 612 | template< typename T > 613 | struct alignment_of 614 | { 615 | enum { value = alignment_logic< 616 | sizeof( alignment_of_hack ) - sizeof(T), sizeof(T) >::value }; 617 | }; 618 | 619 | template< typename List, size_t N > 620 | struct type_of_size 621 | { 622 | typedef typename std11::conditional< 623 | N == sizeof( typename List::head ), 624 | typename List::head, 625 | typename type_of_size::type >::type type; 626 | }; 627 | 628 | template< size_t N > 629 | struct type_of_size< nulltype, N > 630 | { 631 | typedef optional_CONFIG_ALIGN_AS_FALLBACK type; 632 | }; 633 | 634 | template< typename T> 635 | struct struct_t { T _; }; 636 | 637 | #define optional_ALIGN_TYPE( type ) \ 638 | typelist< type , typelist< struct_t< type > 639 | 640 | struct Unknown; 641 | 642 | typedef 643 | optional_ALIGN_TYPE( char ), 644 | optional_ALIGN_TYPE( short ), 645 | optional_ALIGN_TYPE( int ), 646 | optional_ALIGN_TYPE( long ), 647 | optional_ALIGN_TYPE( float ), 648 | optional_ALIGN_TYPE( double ), 649 | optional_ALIGN_TYPE( long double ), 650 | 651 | optional_ALIGN_TYPE( char *), 652 | optional_ALIGN_TYPE( short * ), 653 | optional_ALIGN_TYPE( int * ), 654 | optional_ALIGN_TYPE( long * ), 655 | optional_ALIGN_TYPE( float * ), 656 | optional_ALIGN_TYPE( double * ), 657 | optional_ALIGN_TYPE( long double * ), 658 | 659 | optional_ALIGN_TYPE( Unknown ( * )( Unknown ) ), 660 | optional_ALIGN_TYPE( Unknown * Unknown::* ), 661 | optional_ALIGN_TYPE( Unknown ( Unknown::* )( Unknown ) ), 662 | 663 | nulltype 664 | > > > > > > > > > > > > > > 665 | > > > > > > > > > > > > > > 666 | > > > > > > 667 | alignment_types; 668 | 669 | #undef optional_ALIGN_TYPE 670 | 671 | #endif // optional_CONFIG_MAX_ALIGN_HACK 672 | 673 | /// C++03 constructed union to hold value. 674 | 675 | template< typename T > 676 | union storage_t 677 | { 678 | //private: 679 | // template< typename > friend class optional; 680 | 681 | typedef T value_type; 682 | 683 | storage_t() {} 684 | 685 | storage_t( value_type const & v ) 686 | { 687 | construct_value( v ); 688 | } 689 | 690 | void construct_value( value_type const & v ) 691 | { 692 | ::new( value_ptr() ) value_type( v ); 693 | } 694 | 695 | #if optional_CPP11_OR_GREATER 696 | 697 | storage_t( value_type && v ) 698 | { 699 | construct_value( std::move( v ) ); 700 | } 701 | 702 | void construct_value( value_type && v ) 703 | { 704 | ::new( value_ptr() ) value_type( std::move( v ) ); 705 | } 706 | 707 | template< class... Args > 708 | void emplace( Args&&... args ) 709 | { 710 | ::new( value_ptr() ) value_type( std::forward(args)... ); 711 | } 712 | 713 | template< class U, class... Args > 714 | void emplace( std::initializer_list il, Args&&... args ) 715 | { 716 | ::new( value_ptr() ) value_type( il, std::forward(args)... ); 717 | } 718 | 719 | #endif 720 | 721 | void destruct_value() 722 | { 723 | value_ptr()->~T(); 724 | } 725 | 726 | value_type const * value_ptr() const 727 | { 728 | return as(); 729 | } 730 | 731 | value_type * value_ptr() 732 | { 733 | return as(); 734 | } 735 | 736 | value_type const & value() const optional_ref_qual 737 | { 738 | return * value_ptr(); 739 | } 740 | 741 | value_type & value() optional_ref_qual 742 | { 743 | return * value_ptr(); 744 | } 745 | 746 | #if optional_CPP11_OR_GREATER 747 | 748 | value_type const && value() const optional_refref_qual 749 | { 750 | return std::move( value() ); 751 | } 752 | 753 | value_type && value() optional_refref_qual 754 | { 755 | return std::move( value() ); 756 | } 757 | 758 | #endif 759 | 760 | #if optional_CPP11_OR_GREATER 761 | 762 | using aligned_storage_t = typename std::aligned_storage< sizeof(value_type), alignof(value_type) >::type; 763 | aligned_storage_t data; 764 | 765 | #elif optional_CONFIG_MAX_ALIGN_HACK 766 | 767 | typedef struct { unsigned char data[ sizeof(value_type) ]; } aligned_storage_t; 768 | 769 | max_align_t hack; 770 | aligned_storage_t data; 771 | 772 | #else 773 | typedef optional_ALIGN_AS(value_type) align_as_type; 774 | 775 | typedef struct { align_as_type data[ 1 + ( sizeof(value_type) - 1 ) / sizeof(align_as_type) ]; } aligned_storage_t; 776 | aligned_storage_t data; 777 | 778 | # undef optional_ALIGN_AS 779 | 780 | #endif // optional_CONFIG_MAX_ALIGN_HACK 781 | 782 | void * ptr() optional_noexcept 783 | { 784 | return &data; 785 | } 786 | 787 | void const * ptr() const optional_noexcept 788 | { 789 | return &data; 790 | } 791 | 792 | template 793 | U * as() 794 | { 795 | return reinterpret_cast( ptr() ); 796 | } 797 | 798 | template 799 | U const * as() const 800 | { 801 | return reinterpret_cast( ptr() ); 802 | } 803 | }; 804 | 805 | } // namespace detail 806 | 807 | /// disengaged state tag 808 | 809 | struct nullopt_t 810 | { 811 | struct init{}; 812 | optional_constexpr nullopt_t( init ) {} 813 | }; 814 | 815 | #if optional_HAVE( CONSTEXPR_11 ) 816 | constexpr nullopt_t nullopt{ nullopt_t::init{} }; 817 | #else 818 | // extra parenthesis to prevent the most vexing parse: 819 | const nullopt_t nullopt(( nullopt_t::init() )); 820 | #endif 821 | 822 | /// optional access error 823 | 824 | #if ! optional_CONFIG_NO_EXCEPTIONS 825 | 826 | class bad_optional_access : public std::logic_error 827 | { 828 | public: 829 | explicit bad_optional_access() 830 | : logic_error( "bad optional access" ) {} 831 | }; 832 | 833 | #endif //optional_CONFIG_NO_EXCEPTIONS 834 | 835 | /// optional 836 | 837 | template< typename T> 838 | class optional 839 | { 840 | private: 841 | template< typename > friend class optional; 842 | 843 | typedef void (optional::*safe_bool)() const; 844 | 845 | public: 846 | typedef T value_type; 847 | 848 | // x.x.3.1, constructors 849 | 850 | // 1a - default construct 851 | optional_constexpr optional() optional_noexcept 852 | : has_value_( false ) 853 | , contained() 854 | {} 855 | 856 | // 1b - construct explicitly empty 857 | optional_constexpr optional( nullopt_t ) optional_noexcept 858 | : has_value_( false ) 859 | , contained() 860 | {} 861 | 862 | // 2 - copy-construct 863 | optional_constexpr14 optional( optional const & other 864 | #if optional_CPP11_OR_GREATER 865 | optional_REQUIRES_A( 866 | true || std::is_copy_constructible::value 867 | ) 868 | #endif 869 | ) 870 | : has_value_( other.has_value() ) 871 | { 872 | if ( other.has_value() ) 873 | contained.construct_value( other.contained.value() ); 874 | } 875 | 876 | #if optional_CPP11_OR_GREATER 877 | 878 | // 3 (C++11) - move-construct from optional 879 | optional_constexpr14 optional( optional && other 880 | optional_REQUIRES_A( 881 | true || std::is_move_constructible::value 882 | ) 883 | ) noexcept( std::is_nothrow_move_constructible::value ) 884 | : has_value_( other.has_value() ) 885 | { 886 | if ( other.has_value() ) 887 | contained.construct_value( std::move( other.contained.value() ) ); 888 | } 889 | 890 | // 4a (C++11) - explicit converting copy-construct from optional 891 | template< typename U > 892 | explicit optional( optional const & other 893 | optional_REQUIRES_A( 894 | std::is_constructible::value 895 | && !std::is_constructible & >::value 896 | && !std::is_constructible && >::value 897 | && !std::is_constructible const & >::value 898 | && !std::is_constructible const && >::value 899 | && !std::is_convertible< optional & , T>::value 900 | && !std::is_convertible< optional && , T>::value 901 | && !std::is_convertible< optional const & , T>::value 902 | && !std::is_convertible< optional const &&, T>::value 903 | && !std::is_convertible< U const & , T>::value /*=> explicit */ 904 | ) 905 | ) 906 | : has_value_( other.has_value() ) 907 | { 908 | if ( other.has_value() ) 909 | contained.construct_value( T{ other.contained.value() } ); 910 | } 911 | #endif // optional_CPP11_OR_GREATER 912 | 913 | // 4b (C++98 and later) - non-explicit converting copy-construct from optional 914 | template< typename U > 915 | optional( optional const & other 916 | #if optional_CPP11_OR_GREATER 917 | optional_REQUIRES_A( 918 | std::is_constructible::value 919 | && !std::is_constructible & >::value 920 | && !std::is_constructible && >::value 921 | && !std::is_constructible const & >::value 922 | && !std::is_constructible const && >::value 923 | && !std::is_convertible< optional & , T>::value 924 | && !std::is_convertible< optional && , T>::value 925 | && !std::is_convertible< optional const & , T>::value 926 | && !std::is_convertible< optional const &&, T>::value 927 | && std::is_convertible< U const & , T>::value /*=> non-explicit */ 928 | ) 929 | #endif // optional_CPP11_OR_GREATER 930 | ) 931 | : has_value_( other.has_value() ) 932 | { 933 | if ( other.has_value() ) 934 | contained.construct_value( other.contained.value() ); 935 | } 936 | 937 | #if optional_CPP11_OR_GREATER 938 | 939 | // 5a (C++11) - explicit converting move-construct from optional 940 | template< typename U > 941 | optional( optional && other 942 | optional_REQUIRES_A( 943 | std::is_constructible::value 944 | && !std::is_constructible & >::value 945 | && !std::is_constructible && >::value 946 | && !std::is_constructible const & >::value 947 | && !std::is_constructible const && >::value 948 | && !std::is_convertible< optional & , T>::value 949 | && !std::is_convertible< optional && , T>::value 950 | && !std::is_convertible< optional const & , T>::value 951 | && !std::is_convertible< optional const &&, T>::value 952 | && !std::is_convertible< U &&, T>::value /*=> explicit */ 953 | ) 954 | ) 955 | : has_value_( other.has_value() ) 956 | { 957 | if ( other.has_value() ) 958 | contained.construct_value( T{ std::move( other.contained.value() ) } ); 959 | } 960 | 961 | // 5a (C++11) - non-explicit converting move-construct from optional 962 | template< typename U > 963 | optional( optional && other 964 | optional_REQUIRES_A( 965 | std::is_constructible::value 966 | && !std::is_constructible & >::value 967 | && !std::is_constructible && >::value 968 | && !std::is_constructible const & >::value 969 | && !std::is_constructible const && >::value 970 | && !std::is_convertible< optional & , T>::value 971 | && !std::is_convertible< optional && , T>::value 972 | && !std::is_convertible< optional const & , T>::value 973 | && !std::is_convertible< optional const &&, T>::value 974 | && std::is_convertible< U &&, T>::value /*=> non-explicit */ 975 | ) 976 | ) 977 | : has_value_( other.has_value() ) 978 | { 979 | if ( other.has_value() ) 980 | contained.construct_value( std::move( other.contained.value() ) ); 981 | } 982 | 983 | // 6 (C++11) - in-place construct 984 | template< typename... Args 985 | optional_REQUIRES_T( 986 | std::is_constructible::value 987 | ) 988 | > 989 | optional_constexpr explicit optional( nonstd_lite_in_place_t(T), Args&&... args ) 990 | : has_value_( true ) 991 | , contained( T( std::forward(args)...) ) 992 | {} 993 | 994 | // 7 (C++11) - in-place construct, initializer-list 995 | template< typename U, typename... Args 996 | optional_REQUIRES_T( 997 | std::is_constructible&, Args&&...>::value 998 | ) 999 | > 1000 | optional_constexpr explicit optional( nonstd_lite_in_place_t(T), std::initializer_list il, Args&&... args ) 1001 | : has_value_( true ) 1002 | , contained( T( il, std::forward(args)...) ) 1003 | {} 1004 | 1005 | // 8a (C++11) - explicit move construct from value 1006 | template< typename U = value_type > 1007 | optional_constexpr explicit optional( U && value 1008 | optional_REQUIRES_A( 1009 | std::is_constructible::value 1010 | && !std::is_same::type, nonstd_lite_in_place_t(U)>::value 1011 | && !std::is_same::type, optional>::value 1012 | && !std::is_convertible::value /*=> explicit */ 1013 | ) 1014 | ) 1015 | : has_value_( true ) 1016 | , contained( T{ std::forward( value ) } ) 1017 | {} 1018 | 1019 | // 8b (C++11) - non-explicit move construct from value 1020 | template< typename U = value_type > 1021 | optional_constexpr optional( U && value 1022 | optional_REQUIRES_A( 1023 | std::is_constructible::value 1024 | && !std::is_same::type, nonstd_lite_in_place_t(U)>::value 1025 | && !std::is_same::type, optional>::value 1026 | && std::is_convertible::value /*=> non-explicit */ 1027 | ) 1028 | ) 1029 | : has_value_( true ) 1030 | , contained( std::forward( value ) ) 1031 | {} 1032 | 1033 | #else // optional_CPP11_OR_GREATER 1034 | 1035 | // 8 (C++98) 1036 | optional( value_type const & value ) 1037 | : has_value_( true ) 1038 | , contained( value ) 1039 | {} 1040 | 1041 | #endif // optional_CPP11_OR_GREATER 1042 | 1043 | // x.x.3.2, destructor 1044 | 1045 | ~optional() 1046 | { 1047 | if ( has_value() ) 1048 | contained.destruct_value(); 1049 | } 1050 | 1051 | // x.x.3.3, assignment 1052 | 1053 | // 1 (C++98and later) - assign explicitly empty 1054 | optional & operator=( nullopt_t ) optional_noexcept 1055 | { 1056 | reset(); 1057 | return *this; 1058 | } 1059 | 1060 | // 2 (C++98and later) - copy-assign from optional 1061 | #if optional_CPP11_OR_GREATER 1062 | optional_REQUIRES_R( 1063 | optional &, 1064 | true 1065 | // std::is_copy_constructible::value 1066 | // && std::is_copy_assignable::value 1067 | ) 1068 | operator=( optional const & other ) 1069 | noexcept( 1070 | std::is_nothrow_move_assignable::value 1071 | && std::is_nothrow_move_constructible::value 1072 | ) 1073 | #else 1074 | optional & operator=( optional const & other ) 1075 | #endif 1076 | { 1077 | if ( has_value() == true && other.has_value() == false ) reset(); 1078 | else if ( has_value() == false && other.has_value() == true ) initialize( *other ); 1079 | else if ( has_value() == true && other.has_value() == true ) contained.value() = *other; 1080 | return *this; 1081 | } 1082 | 1083 | #if optional_CPP11_OR_GREATER 1084 | 1085 | // 3 (C++11) - move-assign from optional 1086 | optional_REQUIRES_R( 1087 | optional &, 1088 | true 1089 | // std::is_move_constructible::value 1090 | // && std::is_move_assignable::value 1091 | ) 1092 | operator=( optional && other ) noexcept 1093 | { 1094 | if ( has_value() == true && other.has_value() == false ) reset(); 1095 | else if ( has_value() == false && other.has_value() == true ) initialize( std::move( *other ) ); 1096 | else if ( has_value() == true && other.has_value() == true ) contained.value() = std::move( *other ); 1097 | return *this; 1098 | } 1099 | 1100 | // 4 (C++11) - move-assign from value 1101 | template< typename U = T > 1102 | optional_REQUIRES_R( 1103 | optional &, 1104 | std::is_constructible::value 1105 | && std::is_assignable::value 1106 | && !std::is_same::type, nonstd_lite_in_place_t(U)>::value 1107 | && !std::is_same::type, optional>::value 1108 | && !(std::is_scalar::value && std::is_same::type>::value) 1109 | ) 1110 | operator=( U && value ) 1111 | { 1112 | if ( has_value() ) contained.value() = std::forward( value ); 1113 | else initialize( T( std::forward( value ) ) ); 1114 | return *this; 1115 | } 1116 | 1117 | #else // optional_CPP11_OR_GREATER 1118 | 1119 | // 4 (C++98) - copy-assign from value 1120 | template< typename U /*= T*/ > 1121 | optional & operator=( U const & value ) 1122 | { 1123 | if ( has_value() ) contained.value() = value; 1124 | else initialize( T( value ) ); 1125 | return *this; 1126 | } 1127 | 1128 | #endif // optional_CPP11_OR_GREATER 1129 | 1130 | // 5 (C++98 and later) - converting copy-assign from optional 1131 | template< typename U > 1132 | #if optional_CPP11_OR_GREATER 1133 | optional_REQUIRES_R( 1134 | optional&, 1135 | std::is_constructible< T , U const &>::value 1136 | && std::is_assignable< T&, U const &>::value 1137 | && !std::is_constructible & >::value 1138 | && !std::is_constructible && >::value 1139 | && !std::is_constructible const & >::value 1140 | && !std::is_constructible const && >::value 1141 | && !std::is_convertible< optional & , T>::value 1142 | && !std::is_convertible< optional && , T>::value 1143 | && !std::is_convertible< optional const & , T>::value 1144 | && !std::is_convertible< optional const &&, T>::value 1145 | && !std::is_assignable< T&, optional & >::value 1146 | && !std::is_assignable< T&, optional && >::value 1147 | && !std::is_assignable< T&, optional const & >::value 1148 | && !std::is_assignable< T&, optional const && >::value 1149 | ) 1150 | #else 1151 | optional& 1152 | #endif // optional_CPP11_OR_GREATER 1153 | operator=( optional const & other ) 1154 | { 1155 | return *this = optional( other ); 1156 | } 1157 | 1158 | #if optional_CPP11_OR_GREATER 1159 | 1160 | // 6 (C++11) - converting move-assign from optional 1161 | template< typename U > 1162 | optional_REQUIRES_R( 1163 | optional&, 1164 | std::is_constructible< T , U>::value 1165 | && std::is_assignable< T&, U>::value 1166 | && !std::is_constructible & >::value 1167 | && !std::is_constructible && >::value 1168 | && !std::is_constructible const & >::value 1169 | && !std::is_constructible const && >::value 1170 | && !std::is_convertible< optional & , T>::value 1171 | && !std::is_convertible< optional && , T>::value 1172 | && !std::is_convertible< optional const & , T>::value 1173 | && !std::is_convertible< optional const &&, T>::value 1174 | && !std::is_assignable< T&, optional & >::value 1175 | && !std::is_assignable< T&, optional && >::value 1176 | && !std::is_assignable< T&, optional const & >::value 1177 | && !std::is_assignable< T&, optional const && >::value 1178 | ) 1179 | operator=( optional && other ) 1180 | { 1181 | return *this = optional( std::move( other ) ); 1182 | } 1183 | 1184 | // 7 (C++11) - emplace 1185 | template< typename... Args 1186 | optional_REQUIRES_T( 1187 | std::is_constructible::value 1188 | ) 1189 | > 1190 | T& emplace( Args&&... args ) 1191 | { 1192 | *this = nullopt; 1193 | contained.emplace( std::forward(args)... ); 1194 | has_value_ = true; 1195 | return contained.value(); 1196 | } 1197 | 1198 | // 8 (C++11) - emplace, initializer-list 1199 | template< typename U, typename... Args 1200 | optional_REQUIRES_T( 1201 | std::is_constructible&, Args&&...>::value 1202 | ) 1203 | > 1204 | T& emplace( std::initializer_list il, Args&&... args ) 1205 | { 1206 | *this = nullopt; 1207 | contained.emplace( il, std::forward(args)... ); 1208 | has_value_ = true; 1209 | return contained.value(); 1210 | } 1211 | 1212 | #endif // optional_CPP11_OR_GREATER 1213 | 1214 | // x.x.3.4, swap 1215 | 1216 | void swap( optional & other ) 1217 | #if optional_CPP11_OR_GREATER 1218 | noexcept( 1219 | std::is_nothrow_move_constructible::value 1220 | && std17::is_nothrow_swappable::value 1221 | ) 1222 | #endif 1223 | { 1224 | using std::swap; 1225 | if ( has_value() == true && other.has_value() == true ) { swap( **this, *other ); } 1226 | else if ( has_value() == false && other.has_value() == true ) { initialize( std11::move(*other) ); other.reset(); } 1227 | else if ( has_value() == true && other.has_value() == false ) { other.initialize( std11::move(**this) ); reset(); } 1228 | } 1229 | 1230 | // x.x.3.5, observers 1231 | 1232 | optional_constexpr value_type const * operator ->() const 1233 | { 1234 | return assert( has_value() ), 1235 | contained.value_ptr(); 1236 | } 1237 | 1238 | optional_constexpr14 value_type * operator ->() 1239 | { 1240 | return assert( has_value() ), 1241 | contained.value_ptr(); 1242 | } 1243 | 1244 | optional_constexpr value_type const & operator *() const optional_ref_qual 1245 | { 1246 | return assert( has_value() ), 1247 | contained.value(); 1248 | } 1249 | 1250 | optional_constexpr14 value_type & operator *() optional_ref_qual 1251 | { 1252 | return assert( has_value() ), 1253 | contained.value(); 1254 | } 1255 | 1256 | #if optional_HAVE( REF_QUALIFIER ) && ( !optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490 ) 1257 | 1258 | optional_constexpr value_type const && operator *() const optional_refref_qual 1259 | { 1260 | return std::move( **this ); 1261 | } 1262 | 1263 | optional_constexpr14 value_type && operator *() optional_refref_qual 1264 | { 1265 | return std::move( **this ); 1266 | } 1267 | 1268 | #endif 1269 | 1270 | #if optional_CPP11_OR_GREATER 1271 | optional_constexpr explicit operator bool() const optional_noexcept 1272 | { 1273 | return has_value(); 1274 | } 1275 | #else 1276 | optional_constexpr operator safe_bool() const optional_noexcept 1277 | { 1278 | return has_value() ? &optional::this_type_does_not_support_comparisons : 0; 1279 | } 1280 | #endif 1281 | 1282 | optional_constexpr bool has_value() const optional_noexcept 1283 | { 1284 | return has_value_; 1285 | } 1286 | 1287 | optional_constexpr14 value_type const & value() const optional_ref_qual 1288 | { 1289 | #if optional_CONFIG_NO_EXCEPTIONS 1290 | assert( has_value() ); 1291 | #else 1292 | if ( ! has_value() ) 1293 | throw bad_optional_access(); 1294 | #endif 1295 | return contained.value(); 1296 | } 1297 | 1298 | optional_constexpr14 value_type & value() optional_ref_qual 1299 | { 1300 | #if optional_CONFIG_NO_EXCEPTIONS 1301 | assert( has_value() ); 1302 | #else 1303 | if ( ! has_value() ) 1304 | throw bad_optional_access(); 1305 | #endif 1306 | return contained.value(); 1307 | } 1308 | 1309 | #if optional_HAVE( REF_QUALIFIER ) && ( !optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490 ) 1310 | 1311 | optional_constexpr value_type const && value() const optional_refref_qual 1312 | { 1313 | return std::move( value() ); 1314 | } 1315 | 1316 | optional_constexpr14 value_type && value() optional_refref_qual 1317 | { 1318 | return std::move( value() ); 1319 | } 1320 | 1321 | #endif 1322 | 1323 | #if optional_CPP11_OR_GREATER 1324 | 1325 | template< typename U > 1326 | optional_constexpr value_type value_or( U && v ) const optional_ref_qual 1327 | { 1328 | return has_value() ? contained.value() : static_cast(std::forward( v ) ); 1329 | } 1330 | 1331 | template< typename U > 1332 | optional_constexpr14 value_type value_or( U && v ) optional_refref_qual 1333 | { 1334 | return has_value() ? std::move( contained.value() ) : static_cast(std::forward( v ) ); 1335 | } 1336 | 1337 | #else 1338 | 1339 | template< typename U > 1340 | optional_constexpr value_type value_or( U const & v ) const 1341 | { 1342 | return has_value() ? contained.value() : static_cast( v ); 1343 | } 1344 | 1345 | #endif // optional_CPP11_OR_GREATER 1346 | 1347 | // x.x.3.6, modifiers 1348 | 1349 | void reset() optional_noexcept 1350 | { 1351 | if ( has_value() ) 1352 | contained.destruct_value(); 1353 | 1354 | has_value_ = false; 1355 | } 1356 | 1357 | private: 1358 | void this_type_does_not_support_comparisons() const {} 1359 | 1360 | template< typename V > 1361 | void initialize( V const & value ) 1362 | { 1363 | assert( ! has_value() ); 1364 | contained.construct_value( value ); 1365 | has_value_ = true; 1366 | } 1367 | 1368 | #if optional_CPP11_OR_GREATER 1369 | template< typename V > 1370 | void initialize( V && value ) 1371 | { 1372 | assert( ! has_value() ); 1373 | contained.construct_value( std::move( value ) ); 1374 | has_value_ = true; 1375 | } 1376 | 1377 | #endif 1378 | 1379 | private: 1380 | bool has_value_; 1381 | detail::storage_t< value_type > contained; 1382 | 1383 | }; 1384 | 1385 | // Relational operators 1386 | 1387 | template< typename T, typename U > 1388 | inline optional_constexpr bool operator==( optional const & x, optional const & y ) 1389 | { 1390 | return bool(x) != bool(y) ? false : !bool( x ) ? true : *x == *y; 1391 | } 1392 | 1393 | template< typename T, typename U > 1394 | inline optional_constexpr bool operator!=( optional const & x, optional const & y ) 1395 | { 1396 | return !(x == y); 1397 | } 1398 | 1399 | template< typename T, typename U > 1400 | inline optional_constexpr bool operator<( optional const & x, optional const & y ) 1401 | { 1402 | return (!y) ? false : (!x) ? true : *x < *y; 1403 | } 1404 | 1405 | template< typename T, typename U > 1406 | inline optional_constexpr bool operator>( optional const & x, optional const & y ) 1407 | { 1408 | return (y < x); 1409 | } 1410 | 1411 | template< typename T, typename U > 1412 | inline optional_constexpr bool operator<=( optional const & x, optional const & y ) 1413 | { 1414 | return !(y < x); 1415 | } 1416 | 1417 | template< typename T, typename U > 1418 | inline optional_constexpr bool operator>=( optional const & x, optional const & y ) 1419 | { 1420 | return !(x < y); 1421 | } 1422 | 1423 | // Comparison with nullopt 1424 | 1425 | template< typename T > 1426 | inline optional_constexpr bool operator==( optional const & x, nullopt_t ) optional_noexcept 1427 | { 1428 | return (!x); 1429 | } 1430 | 1431 | template< typename T > 1432 | inline optional_constexpr bool operator==( nullopt_t, optional const & x ) optional_noexcept 1433 | { 1434 | return (!x); 1435 | } 1436 | 1437 | template< typename T > 1438 | inline optional_constexpr bool operator!=( optional const & x, nullopt_t ) optional_noexcept 1439 | { 1440 | return bool(x); 1441 | } 1442 | 1443 | template< typename T > 1444 | inline optional_constexpr bool operator!=( nullopt_t, optional const & x ) optional_noexcept 1445 | { 1446 | return bool(x); 1447 | } 1448 | 1449 | template< typename T > 1450 | inline optional_constexpr bool operator<( optional const &, nullopt_t ) optional_noexcept 1451 | { 1452 | return false; 1453 | } 1454 | 1455 | template< typename T > 1456 | inline optional_constexpr bool operator<( nullopt_t, optional const & x ) optional_noexcept 1457 | { 1458 | return bool(x); 1459 | } 1460 | 1461 | template< typename T > 1462 | inline optional_constexpr bool operator<=( optional const & x, nullopt_t ) optional_noexcept 1463 | { 1464 | return (!x); 1465 | } 1466 | 1467 | template< typename T > 1468 | inline optional_constexpr bool operator<=( nullopt_t, optional const & ) optional_noexcept 1469 | { 1470 | return true; 1471 | } 1472 | 1473 | template< typename T > 1474 | inline optional_constexpr bool operator>( optional const & x, nullopt_t ) optional_noexcept 1475 | { 1476 | return bool(x); 1477 | } 1478 | 1479 | template< typename T > 1480 | inline optional_constexpr bool operator>( nullopt_t, optional const & ) optional_noexcept 1481 | { 1482 | return false; 1483 | } 1484 | 1485 | template< typename T > 1486 | inline optional_constexpr bool operator>=( optional const &, nullopt_t ) optional_noexcept 1487 | { 1488 | return true; 1489 | } 1490 | 1491 | template< typename T > 1492 | inline optional_constexpr bool operator>=( nullopt_t, optional const & x ) optional_noexcept 1493 | { 1494 | return (!x); 1495 | } 1496 | 1497 | // Comparison with T 1498 | 1499 | template< typename T, typename U > 1500 | inline optional_constexpr bool operator==( optional const & x, U const & v ) 1501 | { 1502 | return bool(x) ? *x == v : false; 1503 | } 1504 | 1505 | template< typename T, typename U > 1506 | inline optional_constexpr bool operator==( U const & v, optional const & x ) 1507 | { 1508 | return bool(x) ? v == *x : false; 1509 | } 1510 | 1511 | template< typename T, typename U > 1512 | inline optional_constexpr bool operator!=( optional const & x, U const & v ) 1513 | { 1514 | return bool(x) ? *x != v : true; 1515 | } 1516 | 1517 | template< typename T, typename U > 1518 | inline optional_constexpr bool operator!=( U const & v, optional const & x ) 1519 | { 1520 | return bool(x) ? v != *x : true; 1521 | } 1522 | 1523 | template< typename T, typename U > 1524 | inline optional_constexpr bool operator<( optional const & x, U const & v ) 1525 | { 1526 | return bool(x) ? *x < v : true; 1527 | } 1528 | 1529 | template< typename T, typename U > 1530 | inline optional_constexpr bool operator<( U const & v, optional const & x ) 1531 | { 1532 | return bool(x) ? v < *x : false; 1533 | } 1534 | 1535 | template< typename T, typename U > 1536 | inline optional_constexpr bool operator<=( optional const & x, U const & v ) 1537 | { 1538 | return bool(x) ? *x <= v : true; 1539 | } 1540 | 1541 | template< typename T, typename U > 1542 | inline optional_constexpr bool operator<=( U const & v, optional const & x ) 1543 | { 1544 | return bool(x) ? v <= *x : false; 1545 | } 1546 | 1547 | template< typename T, typename U > 1548 | inline optional_constexpr bool operator>( optional const & x, U const & v ) 1549 | { 1550 | return bool(x) ? *x > v : false; 1551 | } 1552 | 1553 | template< typename T, typename U > 1554 | inline optional_constexpr bool operator>( U const & v, optional const & x ) 1555 | { 1556 | return bool(x) ? v > *x : true; 1557 | } 1558 | 1559 | template< typename T, typename U > 1560 | inline optional_constexpr bool operator>=( optional const & x, U const & v ) 1561 | { 1562 | return bool(x) ? *x >= v : false; 1563 | } 1564 | 1565 | template< typename T, typename U > 1566 | inline optional_constexpr bool operator>=( U const & v, optional const & x ) 1567 | { 1568 | return bool(x) ? v >= *x : true; 1569 | } 1570 | 1571 | // Specialized algorithms 1572 | 1573 | template< typename T 1574 | #if optional_CPP11_OR_GREATER 1575 | optional_REQUIRES_T( 1576 | std::is_move_constructible::value 1577 | && std17::is_swappable::value ) 1578 | #endif 1579 | > 1580 | void swap( optional & x, optional & y ) 1581 | #if optional_CPP11_OR_GREATER 1582 | noexcept( noexcept( x.swap(y) ) ) 1583 | #endif 1584 | { 1585 | x.swap( y ); 1586 | } 1587 | 1588 | #if optional_CPP11_OR_GREATER 1589 | 1590 | template< typename T > 1591 | optional_constexpr optional< typename std::decay::type > make_optional( T && value ) 1592 | { 1593 | return optional< typename std::decay::type >( std::forward( value ) ); 1594 | } 1595 | 1596 | template< typename T, typename...Args > 1597 | optional_constexpr optional make_optional( Args&&... args ) 1598 | { 1599 | return optional( nonstd_lite_in_place(T), std::forward(args)...); 1600 | } 1601 | 1602 | template< typename T, typename U, typename... Args > 1603 | optional_constexpr optional make_optional( std::initializer_list il, Args&&... args ) 1604 | { 1605 | return optional( nonstd_lite_in_place(T), il, std::forward(args)...); 1606 | } 1607 | 1608 | #else 1609 | 1610 | template< typename T > 1611 | optional make_optional( T const & value ) 1612 | { 1613 | return optional( value ); 1614 | } 1615 | 1616 | #endif // optional_CPP11_OR_GREATER 1617 | 1618 | } // namespace optional_lite 1619 | 1620 | using namespace optional_lite; 1621 | 1622 | } // namespace nonstd 1623 | 1624 | #if optional_CPP11_OR_GREATER 1625 | 1626 | // specialize the std::hash algorithm: 1627 | 1628 | namespace std { 1629 | 1630 | template< class T > 1631 | struct hash< nonstd::optional > 1632 | { 1633 | public: 1634 | std::size_t operator()( nonstd::optional const & v ) const optional_noexcept 1635 | { 1636 | return bool( v ) ? std::hash{}( *v ) : 0; 1637 | } 1638 | }; 1639 | 1640 | } //namespace std 1641 | 1642 | #endif // optional_CPP11_OR_GREATER 1643 | 1644 | #if defined(__clang__) 1645 | # pragma clang diagnostic pop 1646 | #elif defined(__GNUC__) 1647 | # pragma GCC diagnostic pop 1648 | #elif defined(_MSC_VER ) 1649 | # pragma warning( pop ) 1650 | #endif 1651 | 1652 | #endif // optional_USES_STD_OPTIONAL 1653 | 1654 | #endif // NONSTD_OPTIONAL_LITE_HPP 1655 | 1656 | 1657 | #ifndef INCLUDE_LAZYCODE_UTILS_H_ 1658 | #define INCLUDE_LAZYCODE_UTILS_H_ 1659 | #include 1660 | #include 1661 | #include 1662 | #include 1663 | 1664 | #ifdef LAZY_CODE_NO_MACROS 1665 | #define lazyCodeMacro(x) // nothing 1666 | #else 1667 | #define lazyCodeMacro(x) x 1668 | #endif 1669 | 1670 | namespace LazyCode { 1671 | 1672 | using nonstd::make_optional; 1673 | using nonstd::nullopt; 1674 | using nonstd::optional; 1675 | 1676 | template 1677 | using optionalref = optional>; 1678 | 1679 | namespace detail { 1680 | 1681 | template 1682 | using RmRef = typename std::remove_reference::type; 1683 | 1684 | template 1685 | struct StdRefToRef { 1686 | typedef T type; 1687 | }; 1688 | 1689 | template 1690 | struct StdRefToRef> { 1691 | typedef T &type; 1692 | }; 1693 | 1694 | template 1695 | struct StdRefToRef &&> { 1696 | typedef T &type; 1697 | }; 1698 | 1699 | template 1700 | RmRef &&wrapIfRef(T &&v) { 1701 | return std::move(v); 1702 | } 1703 | 1704 | template 1705 | typename std::reference_wrapper wrapIfRef(T &v) { 1706 | return std::ref(v); 1707 | } 1708 | 1709 | template 1710 | using EnableIfType = 1711 | typename std::enable_if>::value, int>::type; 1712 | 1713 | template 1714 | using EnableIfNotType = 1715 | typename std::enable_if>::value, int>::type; 1716 | 1717 | // unpack tuple into arguments to function 1718 | template 1719 | constexpr auto index_apply_impl(F &&f, std::index_sequence) { 1720 | return f(std::integral_constant{}...); 1721 | } 1722 | 1723 | template 1724 | constexpr auto index_apply(F &&f) { 1725 | return index_apply_impl(f, std::make_index_sequence{}); 1726 | } 1727 | 1728 | template 1729 | constexpr auto apply(F &&f, Tuple &&t) { 1730 | return index_apply>::value>([&](auto... Is) { 1731 | return f(std::forward(t))>(std::get(t))...); 1732 | }); 1733 | } 1734 | 1735 | template 1736 | constexpr auto applyWithoutForward(F &&f, Tuple &&t) { 1737 | return index_apply>::value>( 1738 | [&](auto... Is) { return f(std::get(t)...); }); 1739 | } 1740 | 1741 | } // namespace detail 1742 | 1743 | template 1744 | auto unpack(Func &&func) { 1745 | return [funcIn = std::forward(func)](auto &&tup) { 1746 | return detail::apply(funcIn, tup); 1747 | }; 1748 | } 1749 | 1750 | /** varadic to string function 1751 | * 1752 | */ 1753 | template 1754 | std::string toString(Args const &... args) { 1755 | std::ostringstream result; 1756 | int unpack[]{0, (result << args, 0)...}; 1757 | static_cast(unpack); 1758 | return result.str(); 1759 | } 1760 | 1761 | template 1762 | struct OptionOrRef : public optional { 1763 | template 1764 | OptionOrRef(V &&v) : optional::optional(std::forward(v)) {} 1765 | }; 1766 | 1767 | template 1768 | struct OptionOrRef : public optionalref { 1769 | template 1770 | OptionOrRef(V &&v) : optionalref::optional(std::forward(v)) {} 1771 | 1772 | decltype(auto) operator*() { return optionalref::operator*().get(); } 1773 | }; 1774 | 1775 | template 1776 | struct OptionOrRef : public optional { 1777 | template 1778 | OptionOrRef(V &&v) : optional::optional(std::forward(v)) {} 1779 | }; 1780 | namespace detail { 1781 | template 1782 | struct YieldTypeImpl; 1783 | 1784 | template 1785 | struct YieldTypeImpl> { 1786 | typedef T type; 1787 | }; 1788 | template 1789 | struct YieldTypeImpl> { 1790 | typedef T &type; 1791 | }; 1792 | template 1793 | struct YieldTypeImpl> { 1794 | typedef T type; 1795 | }; 1796 | 1797 | template 1798 | struct YieldTypeImpl> { 1799 | typedef T &type; 1800 | }; 1801 | 1802 | template 1803 | struct YieldTypeImpl> { 1804 | typedef T type; 1805 | }; 1806 | template 1807 | using YieldType = typename YieldTypeImpl::type; 1808 | 1809 | } // namespace detail 1810 | } // namespace LazyCode 1811 | 1812 | lazyCodeMacro( 1813 | #define _completeLambda0(body) ) { return body; } 1814 | #define _completeLambda1(arg1, body) auto &&arg1 _completeLambda0(body) 1815 | #define _completeLambda2(arg1, arg2, body) \ 1816 | auto &&arg1, _completeLambda1(arg2, body) 1817 | #define _completeLambda3(arg1, arg2, arg3, body) \ 1818 | auto &&arg1, _completeLambda2(arg2, arg3, body) 1819 | #define _completeLambda4(arg1, arg2, arg3, arg4, body) \ 1820 | auto &&arg1, _completeLambda3(arg2, arg3, arg4, body) 1821 | #define _completeLambda5(arg1, arg2, arg3, arg4, arg5, body) \ 1822 | auto &&arg1, _completeLambda4(arg2, arg3, arg4, arg5, body) 1823 | #define _getCompleteLambdaOverload(_1, _2, _3, _4, _5, _6, NAME, ...) NAME 1824 | #define _completeLambda(...) \ 1825 | _getCompleteLambdaOverload( \ 1826 | __VA_ARGS__, _completeLambda5, _completeLambda4, _completeLambda3, \ 1827 | _completeLambda2, _completeLambda1, _completeLambda0)(__VA_ARGS__) 1828 | #define lambda(...) [&]( _completeLambda(__VA_ARGS__) 1829 | 1830 | ) 1831 | 1832 | #endif /* INCLUDE_LAZYCODE_UTILS_H_ */ 1833 | 1834 | namespace LazyCode { 1835 | namespace detail { 1836 | struct GeneratorBase {}; 1837 | struct GeneratorBuilderBase {}; 1838 | struct CollectorBase; 1839 | 1840 | } // namespace detail 1841 | template 1842 | class GeneratorIterator; 1843 | template 1844 | class Generator; 1845 | 1846 | template 1847 | class Generator : public detail::GeneratorBase { 1848 | Member member; 1849 | ProducerFunc producer; 1850 | 1851 | public: 1852 | typedef typename detail::YieldType()(std::declval()))> 1854 | YieldType; 1855 | typedef detail::RmRef NoRefYieldType; 1856 | 1857 | Generator(Member&& member, ProducerFunc&& producer) 1858 | : member(std::forward(member)), 1859 | producer(std::forward(producer)) {} 1860 | 1861 | friend inline decltype(auto) next(Generator& gen) { 1862 | return gen.producer(gen.member); 1863 | } 1864 | 1865 | inline auto begin() { 1866 | return GeneratorIterator>(*this); 1867 | } 1868 | 1869 | inline auto end() { 1870 | return GeneratorIterator>(); 1871 | } 1872 | }; 1873 | 1874 | struct GeneratorHole : public detail::GeneratorBase {}; 1875 | 1876 | template 1877 | auto generator(MemberIn member, ProducerFuncIn producer) { 1878 | typedef typename detail::StdRefToRef::type Member; 1879 | typedef typename detail::StdRefToRef::type ProducerFunc; 1880 | return Generator( 1881 | std::forward(member), std::forward(producer)); 1882 | } 1883 | 1884 | template 1885 | struct GeneratorBuilder { 1886 | BuilderFunc build; 1887 | GeneratorBuilder(BuilderFunc&& build) 1888 | : build(std::forward(build)) {} 1889 | }; 1890 | 1891 | template 1892 | auto generatorBuilder(BuilderFunc&& builder) { 1893 | return GeneratorBuilder(std::forward(builder)); 1894 | } 1895 | 1896 | template = 0> 1898 | auto buildOrDelay(GeneratorBuilder builder, Generator&& gen) { 1899 | return builder.build(std::forward(gen)); 1900 | } 1901 | 1902 | template 1903 | auto buildOrDelay(GeneratorBuilder builder, GeneratorHole) { 1904 | return std::move(builder); 1905 | } 1906 | 1907 | template 1908 | auto operator|(Gen&& gen, GeneratorBuilder&& builder) { 1909 | return builder.build(std::forward(gen)); 1910 | } 1911 | 1912 | template 1913 | auto operator|(Gen&& gen, GeneratorBuilder& builder) { 1914 | return builder.build(std::forward(gen)); 1915 | } 1916 | 1917 | template 1918 | class GeneratorIterator { 1919 | Generator* gen = NULL; 1920 | typedef OptionOrRef OptionType; 1921 | OptionType value; 1922 | 1923 | public: 1924 | typedef typename Generator::NoRefYieldType value_type; 1925 | typedef value_type& reference; 1926 | typedef value_type* pointer; 1927 | 1928 | GeneratorIterator() : value(nullopt) {} 1929 | GeneratorIterator(Generator& gen) : gen(&gen), value(next(gen)) {} 1930 | 1931 | decltype(auto) operator*() { return *value; } 1932 | GeneratorIterator& operator++() { 1933 | value = next(*gen); 1934 | return *this; 1935 | } 1936 | auto operator++(int) { 1937 | auto temp = *value; 1938 | value = next(*gen); 1939 | return temp; 1940 | } 1941 | inline bool operator!=(const GeneratorIterator&) { 1942 | return value.has_value(); 1943 | } 1944 | inline bool operator==(const GeneratorIterator&) { 1945 | return !value.has_value(); 1946 | } 1947 | }; 1948 | 1949 | } // namespace LazyCode 1950 | #endif /*LAZYCODE_GENERATOR_H_*/ 1951 | 1952 | 1953 | 1954 | namespace LazyCode { 1955 | namespace detail { 1956 | struct CollectorBase {}; 1957 | struct GeneratorBase; 1958 | 1959 | } // namespace detail 1960 | 1961 | template 1962 | class Collector : public detail::CollectorBase { 1963 | Member member; 1964 | CollectorFunc collector; 1965 | 1966 | public: 1967 | Collector(Member&& member, CollectorFunc&& collector) 1968 | : member(std::forward(member)), 1969 | collector(std::forward(collector)) {} 1970 | 1971 | template 1972 | void push(V& v) { 1973 | collector(member, v); 1974 | } 1975 | 1976 | template 1977 | void push(std::reference_wrapper& v) { 1978 | collector(member, v.get()); 1979 | } 1980 | 1981 | template 1982 | Member apply(Generator&& gen) { 1983 | while (true) { 1984 | auto val = next(gen); 1985 | if (!val) { 1986 | return std::forward(member); 1987 | } 1988 | push(*val); 1989 | } 1990 | } 1991 | }; 1992 | 1993 | template 1994 | class Collector : public detail::CollectorBase { 1995 | CollectorFunc collector; 1996 | 1997 | public: 1998 | Collector(CollectorFunc&& collector) 1999 | : collector(std::forward(collector)) {} 2000 | 2001 | template 2002 | void push(V& v) { 2003 | collector(v); 2004 | } 2005 | 2006 | template 2007 | void push(std::reference_wrapper& v) { 2008 | collector(v.get()); 2009 | } 2010 | template 2011 | void apply(Generator&& gen) { 2012 | while (true) { 2013 | auto val = next(gen); 2014 | if (!val) { 2015 | return; 2016 | } 2017 | push(*val); 2018 | } 2019 | } 2020 | }; 2021 | 2022 | template 2023 | auto collector(MemberIn member, CollectorFuncIn collector) { 2024 | typedef typename detail::StdRefToRef::type Member; 2025 | typedef typename detail::StdRefToRef::type CollectorFunc; 2026 | return Collector( 2027 | std::forward(member), 2028 | std::forward(collector)); 2029 | } 2030 | 2031 | template 2032 | auto collector(CollectorFuncIn collector) { 2033 | typedef typename detail::StdRefToRef::type CollectorFunc; 2034 | return Collector( 2035 | std::forward(collector)); 2036 | } 2037 | 2038 | template = 0, 2040 | detail::EnableIfType = 0> 2041 | decltype(auto) buildOrApply(CollectorBuilder&& builder, Generator&& gen) { 2042 | return builder(gen).apply(std::forward(gen)); 2043 | } 2044 | 2045 | template = 0, 2047 | detail::EnableIfType = 0> 2048 | decltype(auto) buildOrApply(Collector&& collector, Generator&& gen) { 2049 | return collector.apply(std::forward(gen)); 2050 | } 2051 | 2052 | template 2053 | T buildOrApply(T v, GeneratorHole) { 2054 | return std::move(v); 2055 | } 2056 | 2057 | template = 0, 2059 | detail::EnableIfNotType = 0> 2060 | decltype(auto) operator|(Generator&& gen, CollectorBuilder&& builder) { 2061 | return buildOrApply(std::forward(builder), 2062 | std::forward(gen)); 2063 | } 2064 | 2065 | template = 0> 2067 | decltype(auto) operator|(Generator&& gen, Collector& collector) { 2068 | return collector.apply(std::forward(gen)); 2069 | } 2070 | 2071 | template = 0> 2073 | decltype(auto) operator|(Generator&& gen, Collector collector) { 2074 | return collector.apply(std::forward(gen)); 2075 | } 2076 | 2077 | } // namespace LazyCode 2078 | #endif /*LAZYCODE_COLLECTOR_H_*/ 2079 | 2080 | namespace LazyCode { 2081 | 2082 | /* 2083 | * Apply the given function to each value produced by the 2084 | * given generator. The return value of the function is ignored and may be 2085 | * void. If the generator is not specified, a collector is returned. Collectors 2086 | * remember the operation to be executed. The operation is executed when a 2087 | * generator is piped `|` to it. 2088 | */ 2089 | template = 0> 2091 | decltype(auto) forEach(Func&& func, Generator&& gen = GeneratorHole()) { 2092 | return buildOrApply(collector(std::forward(func)), 2093 | std::forward(gen)); 2094 | } 2095 | 2096 | /* 2097 | * Count the number of values yielded by the given generator. If the generator 2098 | * is not specified, a collector is returned. Collectors remember the operation 2099 | * to be executed. The operation is executed when a generator is piped `|` to 2100 | * it. 2101 | */ 2102 | template = 0> 2104 | decltype(auto) count(Generator&& gen = GeneratorHole()) { 2105 | return buildOrApply( 2106 | collector(((size_t)0), [](size_t& count, auto&&) { ++count; }), 2107 | std::forward(gen)); 2108 | } 2109 | 2110 | /* 2111 | * Combine the values produced by a generator using the 2112 | * specified function and return the result. The function should take two 2113 | * arguments and return a single value. The accum parameter (accumulator) 2114 | * specifies the initial value. The return type of the function must be 2115 | * convertible to the accum type. If the generator is not specified, a collector 2116 | * is returned. Collectors remember the operation to be executed. The operation 2117 | * is executed when a generator is piped `|` to it. 2118 | */ 2119 | template = 0> 2121 | decltype(auto) fold(Func&& func, Accum accum, 2122 | Generator&& gen = GeneratorHole()) { 2123 | return buildOrApply( 2124 | collector(std::move(accum), 2125 | [func = std::forward(func)](auto& accum, auto&& val) { 2126 | accum = func(accum, val); 2127 | }), 2128 | std::forward(gen)); 2129 | } 2130 | 2131 | /* 2132 | * Return the sum of the values produced by a generator. If 2133 | * the generator is not specified, a collector is returned. 2134 | * Collectors remember the operation to be executed. The operation is executed 2135 | * when a generator is piped `|` to it. 2136 | */ 2137 | template = 0> 2139 | decltype(auto) sum(Generator&& gen = GeneratorHole()) { 2140 | return buildOrApply( 2141 | [](auto&& gen) { 2142 | typedef decltype(gen) Gen; 2143 | typedef typename detail::RmRef::NoRefYieldType AccumType; 2144 | return fold( 2145 | [](const auto& i, const auto& j) { return i + j; }, 0); 2146 | }, 2147 | std::forward(gen)); 2148 | } 2149 | 2150 | /* 2151 | * Return the product (multiplication) of the values produced by a generator.If 2152 | * the generator is not specified, a collector is returned. 2153 | * Collectors remember the operation to be executed. The operation is executed 2154 | * when a generator is piped `|` to it. 2155 | */ 2156 | template = 0> 2158 | decltype(auto) product(Generator&& gen = GeneratorHole()) { 2159 | return buildOrApply( 2160 | [](auto&& gen) { 2161 | typedef decltype(gen) Gen; 2162 | typedef typename detail::RmRef::NoRefYieldType AccumType; 2163 | return fold( 2164 | [](const auto& i, const auto& j) { return i * j; }, 1); 2165 | }, 2166 | std::forward(gen)); 2167 | } 2168 | 2169 | /* 2170 | * Return the minimum value produced by a generator. If the generator yields 2171 | * no values, the default value is returned. If a default value is not given, 2172 | * an optional is returned. The optional holds a value in the case the 2173 | * generator yielded a value, otherwise the optional will be empty (nullopt). 2174 | * If the generator is not specified, a collector is returned. Collectors 2175 | * remember the operation to be executed. The operation is executed when a 2176 | * generator is piped `|` to it. 2177 | */ 2178 | template = 0> 2180 | decltype(auto) min(Generator&& gen = GeneratorHole()) { 2181 | return buildOrApply( 2182 | [](auto&& gen) { 2183 | typedef decltype(gen) Gen; 2184 | typedef typename detail::RmRef::NoRefYieldType AccumType; 2185 | return fold>( 2186 | 2187 | [](const auto& i, const auto& j) { 2188 | return (i && *i < j) ? *i : j; 2189 | }, 2190 | nullopt); 2191 | }, 2192 | std::forward(gen)); 2193 | } 2194 | 2195 | template = 0> 2197 | decltype(auto) min(Val defaultVal, Generator&& gen = GeneratorHole()) { 2198 | return buildOrApply( 2199 | [defaultVal = std::move(defaultVal)](auto&& gen) { 2200 | typedef decltype(gen) Gen; 2201 | typedef typename detail::RmRef::NoRefYieldType AccumType; 2202 | return fold( 2203 | [](const auto& i, const auto& j) { return (i < j) ? i : j; }, 2204 | defaultVal); 2205 | }, 2206 | std::forward(gen)); 2207 | } 2208 | 2209 | /* 2210 | * Return the maximum value produced by a generator. If the generator yields 2211 | * no values, the default value is returned. If a default value is not given, 2212 | * an optional is returned. The optional holds a value in the case the 2213 | * generator yielded a value, otherwise the optional will be empty (nullopt). 2214 | * If the generator is not specified, a collector is returned. Collectors 2215 | * remember the operation to be executed. The operation is executed when a 2216 | * generator is piped `|` to it. 2217 | */ 2218 | template = 0> 2220 | decltype(auto) max(Generator&& gen = GeneratorHole()) { 2221 | return buildOrApply( 2222 | [](auto&& gen) { 2223 | typedef decltype(gen) Gen; 2224 | typedef typename detail::RmRef::NoRefYieldType AccumType; 2225 | return fold>( 2226 | 2227 | [](const auto& i, const auto& j) { 2228 | return (i && *i > j) ? *i : j; 2229 | }, 2230 | nullopt); 2231 | }, 2232 | std::forward(gen)); 2233 | } 2234 | 2235 | template = 0> 2237 | decltype(auto) max(Val defaultVal, Generator&& gen = GeneratorHole()) { 2238 | return buildOrApply( 2239 | [defaultVal = std::move(defaultVal)](auto&& gen) { 2240 | typedef decltype(gen) Gen; 2241 | typedef typename detail::RmRef::NoRefYieldType AccumType; 2242 | return fold( 2243 | [](const auto& i, const auto& j) { return (i > j) ? i : j; }, 2244 | defaultVal); 2245 | }, 2246 | std::forward(gen)); 2247 | } 2248 | 2249 | /* 2250 | * Write each value produced by the given generator to the 2251 | * given stream. An interleave value can be optionally specified, in which case 2252 | * the interleave value will be written to the stream before each generated 2253 | * value apart from the first. This is sometimes known as join. Note that a 2254 | * rvalue can be given as the stream parameter, for example constructing a new 2255 | * stream inline (`write(ostringstream())`), in which case the stream will be 2256 | * returned.If the generator is not specified, a collector is returned. 2257 | * Collectors remember the operation to be executed. The operation is executed 2258 | * when a generator is piped `|` to it. 2259 | */ 2260 | template = 0> 2262 | decltype(auto) write(Stream&& stream, Generator&& gen = GeneratorHole()) { 2263 | return buildOrApply( 2264 | collector(detail::wrapIfRef(std::forward(stream)), 2265 | [](auto& stream, auto&& val) { stream << val; }), 2266 | std::forward(gen)); 2267 | } 2268 | 2269 | template = 0> 2272 | decltype(auto) write(Stream&& stream, Interleave i, 2273 | Generator&& gen = GeneratorHole()) { 2274 | bool first = true; 2275 | return buildOrApply( 2276 | collector(detail::wrapIfRef(std::forward(stream)), 2277 | [first, i = std::move(i)](auto& stream, auto&& val) mutable { 2278 | if (first) { 2279 | first = false; 2280 | } else { 2281 | stream << i; 2282 | } 2283 | stream << val; 2284 | }), 2285 | std::forward(gen)); 2286 | } 2287 | 2288 | /* 2289 | * Append each value produced by the given generator to the 2290 | * given container, using container.emplace_back(). For unordered containers, 2291 | * see `insert`. Note that a rvalue can be given as the container parameter, 2292 | * for example constructing a new container inline (`append(vector())`), in 2293 | * which case the collector stores the container and returns it after appending 2294 | * the values. Otherwise, only a reference to the container is held by the 2295 | * collector. If the generator is not specified, a collector is returned. 2296 | * Collectors remember the operation to be executed. The operation is executed 2297 | * when a generator is piped `|` to it. 2298 | */ 2299 | template = 0> 2301 | decltype(auto) append(Container&& container, 2302 | Generator&& gen = GeneratorHole()) { 2303 | return buildOrApply( 2304 | collector( 2305 | detail::wrapIfRef(std::forward(container)), 2306 | [](auto& container, auto&& val) { container.emplace_back(val); }), 2307 | std::forward(gen)); 2308 | } 2309 | 2310 | /* 2311 | * Insert each value produced by the given generator to the 2312 | * given container, using container.emplace(). This is for unordered 2313 | * containers. For ordered containers, see `append`. Note that a rvalue can be 2314 | * given as the container parameter, for example constructing a new container 2315 | * inline (`append(set())`), in 2316 | * which case the collector stores the container and returns it after inserting 2317 | * the values. Otherwise, only a reference to the container is held by the 2318 | * collector. If the generator is not specified, a collector is returned. 2319 | * Collectors remember the operation to be executed. The operation is executed 2320 | * when a generator is piped `|` to it. 2321 | */ 2322 | template = 0> 2324 | decltype(auto) insert(Container&& container, 2325 | Generator&& gen = GeneratorHole()) { 2326 | return buildOrApply( 2327 | collector(detail::wrapIfRef(std::forward(container)), 2328 | [](auto& container, auto&& val) { container.emplace(val); }), 2329 | std::forward(gen)); 2330 | } 2331 | 2332 | } // namespace LazyCode 2333 | #endif /* LAZYCODE_BASICCOLLECTORS_H_*/ 2334 | 2335 | #ifndef LAZYCODE_BASICGENERATORS_H_ 2336 | #define LAZYCODE_BASICGENERATORS_H_ 2337 | #include 2338 | 2339 | 2340 | #include 2341 | namespace LazyCode { 2342 | 2343 | /* 2344 | * Create a never ending generator of sequence of values. Sequence begins at 2345 | * specified start point (inclusive) and is followed by values 2346 | * increasing/decreasing by the specified increment. 2347 | */ 2348 | template 2349 | auto infRange(Number1 start, Number2 increment) { 2350 | return generator(start, [increment](Number1& val) -> optional { 2351 | Number1 preVal = val; 2352 | val += increment; 2353 | return preVal; 2354 | }); 2355 | } 2356 | 2357 | /* 2358 | * Create a generator of sequence of values. Sequence begins at 2359 | * specified start point (inclusive) , is followed by values 2360 | * increasing/decreasing by the specified increment and stops at the specified 2361 | * last point (exclusive). 2362 | */ 2363 | template 2364 | auto range(Number1 start, Number1 end, Number2 increment) { 2365 | auto comparator = (increment >= 0) 2366 | ? [](Number1 a, Number1 b) { return a < b; } 2367 | : [](Number1 a, Number1 b) { return b < a; }; 2368 | return generator( 2369 | start, [end, increment, comparator](Number1& val) -> optional { 2370 | if (!comparator(val, end)) { 2371 | return nullopt; 2372 | } 2373 | Number1 preVal = val; 2374 | val += increment; 2375 | return preVal; 2376 | }); 2377 | } 2378 | 2379 | /* 2380 | * Create a generator of sequence of integral values. Sequence begins at 2381 | * specified start point (inclusive) , is followed by values increasing by 1 and 2382 | * stops at the specified last point (exclusive). 2383 | */ 2384 | template ::value, int>::type = 0> 2386 | auto range(Number start, Number end) { 2387 | return range(start, end, 1); 2388 | } 2389 | 2390 | /* 2391 | * Create a generator of sequence of integral values. Sequence begins at 0 2392 | * (inclusive) , is followed by values increasing by 1 and stops at the 2393 | * specified last point (exclusive). 2394 | */ 2395 | template ::value, int>::type = 0> 2397 | auto range(Number end) { 2398 | return range(((Number)0), end, 1); 2399 | } 2400 | 2401 | /* 2402 | * Create a generator from a container. The generator uses the containers begin 2403 | * and end iterators via `std::begin, std::end`. If an rvalue is given, the 2404 | * generator will take ownership of the container and move it into the generator 2405 | * object, otherwise the generator will only hold a reference to the container. 2406 | */ 2407 | template = 0> 2409 | decltype(auto) generator(Container&& container) { 2410 | typedef detail::RmRef Iter; 2411 | typedef decltype(*std::begin(container)) IterValueType; 2412 | struct Iterable { 2413 | Container container; 2414 | Iter first; 2415 | Iter last; 2416 | Iterable(Container&& container) 2417 | : container(std::forward(container)), 2418 | first(std::begin(this->container)), 2419 | last(std::end(this->container)) {} 2420 | }; 2421 | return generator(Iterable(std::forward(container)), 2422 | [](auto&& iter) mutable -> OptionOrRef { 2423 | if (iter.first == iter.last) { 2424 | return nullopt; 2425 | } 2426 | decltype(auto) val = *(iter.first); 2427 | ++iter.first; 2428 | return val; 2429 | }); 2430 | } 2431 | 2432 | /* 2433 | * Create a generator from a pair of iterators first and last. The generator 2434 | * container yields values from first (inclusive) to last (exclusive). 2435 | */ 2436 | template 2437 | decltype(auto) slice(Iter first, Iter last) { 2438 | typedef decltype(*first) IterValueType; 2439 | struct Iterable { 2440 | Iter first; 2441 | Iter last; 2442 | Iterable(Iter first, Iter last) 2443 | : first(std::move(first)), last(std::move(last)) {} 2444 | }; 2445 | return generator(Iterable(std::move(first), std::move(last)), 2446 | [](auto&& iter) mutable -> OptionOrRef { 2447 | if (iter.first == iter.last) { 2448 | return nullopt; 2449 | } 2450 | decltype(auto) val = *(iter.first); 2451 | ++iter.first; 2452 | return val; 2453 | }); 2454 | } 2455 | 2456 | /* 2457 | * return a generator that iterates through a container from position start 2458 | * (inclusive) to position end (exclusive). 2459 | If an rvalue is given, the generator will take ownership of the container and 2460 | move it into the generator object, otherwise the generator will only hold a 2461 | reference to the container. 2462 | */ 2463 | template = 0> 2465 | decltype(auto) slice(Container&& container, size_t start, size_t last) { 2466 | typedef detail::RmRef Iter; 2467 | typedef decltype(*std::begin(container)) IterValueType; 2468 | struct Iterable { 2469 | Container container; 2470 | Iter first; 2471 | Iter last; 2472 | Iterable(Container&& container, size_t start, size_t last) 2473 | : container(std::forward(container)), 2474 | first(std::begin(this->container) + start), 2475 | last(std::begin(this->container) + last) {} 2476 | }; 2477 | return generator(Iterable(std::forward(container), start, last), 2478 | [](auto&& iter) mutable -> OptionOrRef { 2479 | if (iter.first == iter.last) { 2480 | return nullopt; 2481 | } 2482 | decltype(auto) val = *(iter.first); 2483 | ++iter.first; 2484 | return val; 2485 | }); 2486 | } 2487 | /* 2488 | * Map one generator to another. Produce a generator that returns the values 2489 | * produced by another generator applied to the given function. The given 2490 | * function is invoked lazily to each value as requested. If the generator is 2491 | * not specified, a GeneratorBuilder is returned. GeneratorBuilders are 2492 | * converted to generators by piping `|` a generator to them. 2493 | */ 2494 | template = 0> 2496 | decltype(auto) map(MapperFunc&& mapperIn, Generator&& gen = GeneratorHole()) { 2497 | return buildOrDelay( 2498 | generatorBuilder([mapperIn1 = std::forward(mapperIn)]( 2499 | auto&& gen) mutable { 2500 | typedef decltype(gen) Gen; 2501 | return generator( 2502 | wrapIfRef(std::forward(gen)), 2503 | [mapper = std::forward(mapperIn1)]( 2504 | auto&& gen) -> OptionOrRef { 2505 | decltype(auto) val = next(gen); 2506 | if (!val) { 2507 | return nullopt; 2508 | } else { 2509 | return mapper(*val); 2510 | } 2511 | }); 2512 | }), 2513 | std::forward(gen)); 2514 | } 2515 | 2516 | /* 2517 | * Produce a generator that filters the output of another generator according to 2518 | * the given function. The function should accept each value produced by the 2519 | * given generator and return true if that value is to be forwarded, false 2520 | * otherwise. The given function is invoked lazily to each value as requested. 2521 | * If the generator is not specified, a GeneratorBuilder is returned. 2522 | * GeneratorBuilders are converted to generators by piping `|` a generator to 2523 | * them. 2524 | */ 2525 | template = 0> 2527 | decltype(auto) filter(FilterFunc&& filterIn, 2528 | Generator&& gen = GeneratorHole()) { 2529 | return buildOrDelay( 2530 | generatorBuilder([filterIn1 = std::forward(filterIn)]( 2531 | auto&& gen) mutable { 2532 | typedef decltype(gen) Gen; 2533 | typedef typename detail::RmRef::YieldType YieldType; 2534 | return generator(wrapIfRef(std::forward(gen)), 2535 | [filter = std::forward(filterIn1)]( 2536 | 2537 | auto&& gen) -> OptionOrRef { 2538 | while (true) { 2539 | decltype(auto) val = next(gen); 2540 | if (!val || filter(*val)) { 2541 | return val; 2542 | } 2543 | } 2544 | }); 2545 | }), 2546 | std::forward(gen)); 2547 | } 2548 | 2549 | /* 2550 | * Produce a generator that takes the first n values produced by another 2551 | * generator.If the generator is not specified, a GeneratorBuilder is returned. 2552 | * GeneratorBuilders are converted to generators by piping `|` a generator to 2553 | * them. 2554 | */ 2555 | template = 0> 2557 | decltype(auto) limit(size_t n, Generator&& gen = GeneratorHole()) { 2558 | return buildOrDelay( 2559 | generatorBuilder([n](auto&& gen) mutable { 2560 | typedef decltype(gen) Gen; 2561 | typedef typename detail::RmRef::YieldType YieldType; 2562 | size_t count = 0; 2563 | return generator( 2564 | wrapIfRef(std::forward(gen)), 2565 | [count, n](auto&& gen) mutable -> OptionOrRef { 2566 | if (count++ < n) { 2567 | return next(gen); 2568 | } else { 2569 | return nullopt; 2570 | } 2571 | }); 2572 | }), 2573 | std::forward(gen)); 2574 | } 2575 | 2576 | /* 2577 | * Combine two generators x and y into one. Produce a generator that yields 2578 | * tuples where the first element of each tuple is a value pulled from x and the 2579 | * second element is pulled from y. The generator ends when either x or y 2580 | * end.*/ 2581 | template = 0, 2583 | detail::EnableIfType = 0> 2584 | decltype(auto) zip(Gen1&& gen1, Gen2&& gen2) { 2585 | typedef typename Gen1::YieldType Gen1YieldType; 2586 | typedef typename Gen2::YieldType Gen2YieldType; 2587 | typedef std::pair YieldType; 2588 | return generator(wrapIfRef(std::forward(gen1)), 2589 | [gen2 = std::forward(gen2)]( 2590 | auto&& gen1) mutable -> optional { 2591 | auto o1 = next(gen1); 2592 | auto o2 = next(gen2); 2593 | if (!o1 || !o2) { 2594 | return nullopt; 2595 | } else { 2596 | return YieldType(std::forward(*o1), 2597 | std::forward(*o2)); 2598 | } 2599 | }); 2600 | } 2601 | 2602 | /* 2603 | * Enumerate a generator. Produce a generator that returns the values 2604 | * produced by another generator paired with an increasing count. The default 2605 | * initial value of the count is 0. Each yielded item will be 2606 | * pair(count,value). If the generator is not specified, a GeneratorBuilder is 2607 | * returned. GeneratorBuilders are converted to generators by piping `|` a 2608 | * generator to them. 2609 | */ 2610 | template = 0> 2612 | decltype(auto) enumerate(size_t count = 0, Generator&& gen = GeneratorHole()) { 2613 | return buildOrDelay(generatorBuilder([count](auto&& gen) mutable { 2614 | typedef decltype(gen) Gen; 2615 | return zip(infRange(count, 1), 2616 | std::forward(gen)); 2617 | }), 2618 | std::forward(gen)); 2619 | } 2620 | 2621 | /* 2622 | * return a generator that reads from the given stream. The generated type (the 2623 | * type of values pulled from the stream) must be specified as the first 2624 | * template parameter. For example, to read integers from the stream, use 2625 | * `read`. If an lvalue is given, only a reference to the stream is held. 2626 | * If a rvalue is given, the generator takes ownership, the stream is moved into 2627 | * the generator.*/ 2628 | template 2629 | auto read(Stream&& stream) { 2630 | struct Reader { 2631 | Stream stream; 2632 | std::istream_iterator first; 2633 | std::istream_iterator last; 2634 | Reader(Stream&& stream) 2635 | : stream(std::forward(stream)), first(this->stream) {} 2636 | }; 2637 | return generator(Reader(std::forward(stream)), 2638 | [](auto&& reader) mutable -> optional { 2639 | if (reader.first == reader.last) { 2640 | return nullopt; 2641 | } 2642 | decltype(auto) val = *reader.first; 2643 | ++reader.first; 2644 | return val; 2645 | }); 2646 | } 2647 | 2648 | /* 2649 | * return a generator that reads lines from the given stream. The generator 2650 | * yields a new string for each line. If an lvalue is given, only a reference 2651 | * to the stream is held. If a rvalue is given, the generator takes ownership, 2652 | * the stream is moved into the generator.*/ 2653 | template 2654 | auto readLines(Stream&& stream) { 2655 | return generator(detail::wrapIfRef(std::forward(stream)), 2656 | [](auto&& stream) mutable -> optional { 2657 | if (static_cast(stream)) { 2658 | std::string s; 2659 | std::getline(stream, s); 2660 | return s; 2661 | } else { 2662 | return nullopt; 2663 | } 2664 | }); 2665 | } 2666 | 2667 | } // namespace LazyCode 2668 | #endif /* LAZYCODE_BASICGENERATORS_H_*/ 2669 | 2670 | #endif /* LAZYCODE_LAZYCODE_H_*/ 2671 | 2672 | -------------------------------------------------------------------------------- /single_header/makeSingleHeader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | from os.path import * 4 | import re 5 | import sys 6 | 7 | 8 | 9 | seenFiles = set() 10 | includePattern = re.compile(r'#include[ ]*"([^"]+)"') 11 | currentDir = os.getcwd() 12 | 13 | def resolvePath(path): 14 | global currentDir 15 | testPath = currentDir + "/" + path 16 | if exists(testPath): 17 | return realpath(testPath) 18 | for p in alternativePaths: 19 | testPath = p + "/" + path 20 | if exists(testPath): 21 | return realpath(testPath) 22 | print("path not found:", path, file=sys.stderr) 23 | sys.exit(1) 24 | 25 | 26 | def readFile(path): 27 | global currentDir 28 | path = resolvePath(path) 29 | if path in seenFiles: 30 | return "" 31 | with open(path) as file: 32 | currentDirBackup = currentDir 33 | currentDir = dirname(path) 34 | seenFiles.add(path) 35 | src = file.read() 36 | src = re.sub(includePattern,lambda m: readFile(m.group(1)),src) 37 | currentDir = currentDirBackup 38 | return src 39 | 40 | 41 | 42 | alternativePaths = set(sys.argv[2:]) 43 | print(readFile(sys.argv[1])) -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required (VERSION 3.6) 3 | 4 | 5 | 6 | add_library (lazyCode INTERFACE) 7 | target_include_directories (lazyCode INTERFACE 8 | $ 9 | $) 10 | target_link_libraries (lazyCode INTERFACE optional-lite) 11 | target_compile_features (lazyCode INTERFACE ${CXX_FEATURES_USED}) 12 | target_compile_definitions (lazyCode INTERFACE) 13 | -------------------------------------------------------------------------------- /vendor/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(NOT TARGET optional-lite) 2 | add_subdirectory(optional-lite) 3 | endif() --------------------------------------------------------------------------------