├── CMakeLists.txt ├── LICENSE ├── README.md ├── include └── generators │ ├── gen_factory.h │ ├── gen_iterator.h │ ├── generator.h │ ├── msft_gen_mod.h │ └── type_generator.h ├── test └── driver.cxx └── win32 ├── generator.sln ├── generator.vcxproj └── generator.vcxproj.filters /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.12) 2 | 3 | set(MY_VCPKG_DIR $ENV{HOMEDRIVE}$ENV{HOMEPATH}\\vcpkg) 4 | 5 | if(NOT EXISTS ${MY_VCPKG_DIR}) 6 | message("Cloning vcpkg in ${MY_VCPKG_DIR}") 7 | execute_process(COMMAND git clone https://github.com/Microsoft/vcpkg.git ${MY_VCPKG_DIR}) 8 | endif() 9 | 10 | if(NOT EXISTS ${MY_VCPKG_DIR}\\README.md) 11 | message(FATAL_ERROR "***** FATAL ERROR: Could not clone vcpkg *****") 12 | endif() 13 | 14 | if(NOT EXISTS ${MY_VCPKG_DIR}\\vcpkg.exe) 15 | message("Bootstrapping vcpkg in ${MY_VCPKG_DIR}") 16 | execute_process(COMMAND ${MY_VCPKG_DIR}\\bootstrap-vcpkg.bat WORKING_DIRECTORY ${MY_VCPKG_DIR}) 17 | endif() 18 | 19 | if(NOT EXISTS ${MY_VCPKG_DIR}\\vcpkg.exe) 20 | message(FATAL_ERROR "***** FATAL ERROR: Could not bootstrap vcpkg *****") 21 | endif() 22 | 23 | set(MY_PROJECT_DEPENDENCIES boost-core boost-optional) 24 | message(STATUS "***** Checking project third party dependencies in ${MY_VCPKG_DIR} *****") 25 | execute_process(COMMAND ${MY_VCPKG_DIR}\\vcpkg.exe install ${MY_PROJECT_DEPENDENCIES} WORKING_DIRECTORY ${MY_VCPKG_DIR}) 26 | set(CMAKE_TOOLCHAIN_FILE ${MY_VCPKG_DIR}\\scripts\\buildsystems\\vcpkg.cmake) 27 | set(Boost_INCLUDE_DIR ${MY_VCPKG_DIR}\\installed\\x86-windows\\include) 28 | project (CppGenerators) 29 | find_package(Boost 1.67 REQUIRED) 30 | 31 | message("***** VCPKG INCLUDE DIRS: ${Boost_INCLUDE_DIR} *****") 32 | 33 | include_directories(${PROJECT_SOURCE_DIR}/include ${Boost_INCLUDE_DIR}) 34 | add_executable(driver test/driver.cxx) 35 | set_property(TARGET driver PROPERTY CXX_STANDARD 17) 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Sumant Tambe 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of generators nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # generators 2 | Composable Data and Type Generators in C++14 3 | -------------------------------------------------------------------------------- /include/generators/gen_factory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace gen { 4 | 5 | template <> 6 | auto GenFactory::make() 7 | { 8 | return make_gen_from([]() { 9 | return (random_int32() % 2)? true : false; 10 | }); 11 | } 12 | 13 | template <> 14 | auto GenFactory::make() 15 | { 16 | return make_printable_gen(); 17 | } 18 | 19 | template <> 20 | auto GenFactory::make() 21 | { 22 | return make_gen_from([]() { 23 | return static_cast(random_int32() % std::numeric_limits::max()); 24 | }); 25 | } 26 | 27 | template <> 28 | auto GenFactory::make() 29 | { 30 | return make_gen_from([]() { 31 | return static_cast(random_int32() % std::numeric_limits::max()); 32 | }); 33 | } 34 | 35 | template <> 36 | auto GenFactory::make() 37 | { 38 | return make_gen_from([]() { 39 | return static_cast(random_int32()); 40 | }); 41 | } 42 | 43 | template <> 44 | auto GenFactory::make() 45 | { 46 | return make_gen_from([]() { 47 | return (static_cast(random_int32()) << 32) + random_int32(); 48 | }); 49 | } 50 | 51 | template <> 52 | auto GenFactory::make() 53 | { 54 | return make_gen_from([]() { 55 | return static_cast(random_int32() % std::numeric_limits::max()); 56 | }); 57 | } 58 | 59 | template <> 60 | auto GenFactory::make() 61 | { 62 | return make_gen_from([]() { 63 | return static_cast(random_int32() % std::numeric_limits::max()); 64 | }); 65 | } 66 | 67 | template <> 68 | auto GenFactory::make() 69 | { 70 | return make_gen_from([]() { 71 | return static_cast(random_int32()); 72 | }); 73 | } 74 | 75 | template <> 76 | auto GenFactory::make() 77 | { 78 | return make_gen_from([]() { 79 | return (static_cast(random_int32()) << 32) + random_int32(); 80 | }); 81 | } 82 | 83 | template <> 84 | auto GenFactory::make() 85 | { 86 | return make_gen_from([]() { 87 | return static_cast(random_int32()) / random_int32(); 88 | //std::numeric_limits::max() * 89 | //std::numeric_limits::max(); 90 | }); 91 | } 92 | 93 | template <> 94 | auto GenFactory::make() 95 | { 96 | return make_gen_from([]() { 97 | return static_cast((random_int32()) / 98 | std::numeric_limits::max() * 99 | std::numeric_limits::max()); 100 | }); 101 | } 102 | 103 | template <> 104 | auto GenFactory::make() 105 | { 106 | return make_gen_from([]() { 107 | return static_cast(random_int32()) / 108 | std::numeric_limits::max() * 109 | std::numeric_limits::max(); 110 | }); 111 | } 112 | 113 | template 114 | struct GenFactory> 115 | { 116 | template 117 | static auto make(TGen&& tgen, 118 | unsigned int maxlen = DEFAULT_MAX_SEQ_LEN, 119 | bool possibly_empty = false) 120 | { 121 | typedef typename std::remove_reference::type::value_type TGenType; 122 | static_assert(std::is_same::value, "Types don't match"); 123 | return make_seq_gen(std::forward(tgen), maxlen, possibly_empty); 124 | } 125 | 126 | static auto make() 127 | { 128 | return make_seq_gen(GenFactory::make()); 129 | } 130 | 131 | }; 132 | 133 | template 134 | struct GenFactory> 135 | { 136 | template 137 | static auto make(TGen&& tgen, 138 | unsigned int maxlen = DEFAULT_MAX_SEQ_LEN, 139 | bool possibly_empty = false) 140 | { 141 | typedef typename std::remove_reference::type::value_type TGenType; 142 | static_assert(std::is_same::value, "Types don't match"); 143 | return make_seq_gen(std::forward(tgen), maxlen, possibly_empty); 144 | } 145 | 146 | static auto make() 147 | { 148 | return make_seq_gen(GenFactory::make()); 149 | } 150 | 151 | }; 152 | 153 | template 154 | struct GenFactory> 155 | { 156 | static auto make() 157 | { 158 | return make_optional_gen(GenFactory::make()); 159 | } 160 | 161 | template 162 | static auto make(TGen&& tgen) 163 | { 164 | return make_optional_gen(std::forward(tgen)); 165 | } 166 | }; 167 | 168 | template 169 | struct GenFactory> 170 | { 171 | static auto make() 172 | { 173 | return make_array_gen(GenFactory::make(), dim_list()); 174 | } 175 | 176 | template 177 | static auto make(TGen&& tgen) 178 | { 179 | return make_array_gen(std::forward(tgen), dim_list()); 180 | } 181 | }; 182 | 183 | template 184 | struct GenFactory> 185 | { 186 | static auto make() 187 | { 188 | auto tgen = GenFactory::make(); 189 | return make_gen_from([tgen]() mutable { 190 | return std::make_shared(tgen.generate()); 191 | }); 192 | } 193 | }; 194 | 195 | template 196 | struct GenFactory 197 | { 198 | static auto make() 199 | { 200 | auto tgen = GenFactory::make(); 201 | return make_gen_from([tgen]() mutable { 202 | return new T(tgen.generate()); 203 | }); 204 | } 205 | }; 206 | 207 | template 208 | struct GenFactory> 209 | { 210 | static auto make() 211 | { 212 | return make_tuple_gen>(); 213 | } 214 | }; 215 | 216 | template <> 217 | struct GenFactory 218 | { 219 | auto make() 220 | { 221 | return make_string_gen(make_printable_gen(), 256); 222 | } 223 | }; 224 | 225 | } // namespace gen 226 | -------------------------------------------------------------------------------- /include/generators/gen_iterator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace gen { 6 | 7 | template 8 | class gen_iterator : 9 | public std::iterator 10 | { 11 | Gen * gen_; 12 | bool end_; 13 | T current_; 14 | 15 | public: 16 | 17 | typedef T value_type; 18 | typedef const T & reference; 19 | typedef const T * pointer; 20 | 21 | gen_iterator(Gen & gen, bool end = false) 22 | : gen_(&gen), 23 | end_(end) 24 | { 25 | if(!end_) 26 | ++(*this); 27 | } 28 | 29 | reference operator *() const { 30 | return current_; 31 | } 32 | 33 | pointer operator ->() const { 34 | return ¤t_; 35 | } 36 | 37 | gen_iterator & operator ++ () { 38 | if (end_) 39 | throw std::out_of_range("gen_iterator incremented beyond the end"); 40 | 41 | try { 42 | current_ = gen_->generate(); 43 | } 44 | catch (std::out_of_range &) { 45 | end_ = true; 46 | } 47 | return *this; 48 | } 49 | 50 | gen_iterator operator ++ (int) { 51 | gen_iterator temp(*this); 52 | ++(*this); 53 | return temp; 54 | } 55 | 56 | bool operator == (gen_iterator const & gi) const { 57 | if ((this->gen_ == gi.gen_) && 58 | (this->end_ == gi.end_)) 59 | return true; 60 | else 61 | return false; 62 | } 63 | 64 | bool operator != (gen_iterator const & gi) const { 65 | return !(*this == gi); 66 | } 67 | }; 68 | 69 | } // namespace gen -------------------------------------------------------------------------------- /include/generators/generator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | namespace gen { 18 | 19 | constexpr unsigned int DEFAULT_MAX_STR_LEN = 10; 20 | constexpr unsigned int DEFAULT_MAX_SEQ_LEN = 10; 21 | 22 | template 23 | class gen_iterator; 24 | 25 | #ifdef WIN32 26 | void initialize(unsigned int seed = 0) 27 | { 28 | if (seed == 0) 29 | seed = (unsigned) time(NULL); 30 | 31 | srand(seed); 32 | } 33 | 34 | int32_t random_int32() 35 | { 36 | return rand(); 37 | } 38 | 39 | #else 40 | void initialize(unsigned int seed = 0) 41 | { 42 | if (seed == 0) 43 | seed = (unsigned) time(NULL); 44 | 45 | srandom(seed); 46 | } 47 | 48 | int random_int32() 49 | { 50 | return static_cast(random()); 51 | } 52 | #endif // WIN32 53 | 54 | template 55 | auto make_gen_from(GenFunc&& func); 56 | 57 | template 58 | struct GenFactory 59 | { 60 | static auto make(); 61 | }; 62 | 63 | template 64 | class Gen : GenFunc 65 | { 66 | public: 67 | typedef T value_type; 68 | 69 | explicit Gen(GenFunc& func) 70 | : GenFunc(func) 71 | { } 72 | 73 | explicit Gen(GenFunc&& func) 74 | : GenFunc(std::move(func)) 75 | { } 76 | 77 | T generate() 78 | { 79 | return GenFunc::operator()(); 80 | } 81 | 82 | gen_iterator begin() 83 | { 84 | return gen_iterator(*this, false); 85 | } 86 | 87 | gen_iterator end() 88 | { 89 | return gen_iterator(*this, true); 90 | } 91 | 92 | template 93 | auto map(Func&& func) 94 | { 95 | return make_gen_from( 96 | [self = std::move(*this), 97 | func = std::forward(func)]() mutable { 98 | return func(self.generate()); 99 | }); 100 | } 101 | 102 | template 103 | auto zip_with(Zipper&& func, GenList&&... genlist) 104 | { 105 | return make_gen_from( 106 | [self = std::move(*this), 107 | genlist..., 108 | func = std::forward(func)]() mutable { 109 | return func(self.generate(), genlist.generate()...); 110 | }); 111 | } 112 | 113 | template 114 | auto amb(UGen&& ugen) 115 | { 116 | return make_gen_from( 117 | [self = std::move(*this), 118 | ugen = std::forward(ugen)]() mutable { 119 | return (random_int32() % 2) ? self.generate() : ugen.generate(); 120 | }); 121 | } 122 | 123 | auto take(size_t count) 124 | { 125 | return make_gen_from( 126 | [self = std::move(*this), count]() mutable { 127 | if(count-- > 0) 128 | { 129 | return self.generate(); 130 | } 131 | else 132 | throw std::out_of_range("take: generate exceeded take"); 133 | }); 134 | } 135 | 136 | template 137 | auto reduce(ReducerFunc&& reducer, Seed&& seed) 138 | { 139 | return make_gen_from( 140 | [self = std::move(*this), 141 | reducer = std::forward(reducer), 142 | seed = std::forward(seed), 143 | done = false]() mutable { 144 | try { 145 | while(!done) 146 | seed = reducer(seed, self.generate()); 147 | } 148 | catch(std::out_of_range &) { 149 | done = true; 150 | return seed; 151 | } 152 | throw std::out_of_range("reduction completed"); 153 | return seed; 154 | }); 155 | } 156 | 157 | template 158 | auto append(UGen&& ugen) 159 | { 160 | return concat(std::forward(ugen)); 161 | } 162 | 163 | template 164 | auto concat(UGen&& ugen) 165 | { 166 | return make_gen_from( 167 | [tgen = std::move(*this), 168 | ugen = std::forward(ugen), 169 | tdone = false, 170 | udone = false]() mutable { 171 | if(!tdone) 172 | { 173 | try { 174 | return tgen.generate(); 175 | } 176 | catch(std::out_of_range &) { 177 | tdone = true; 178 | } 179 | } 180 | 181 | if(!udone) 182 | { 183 | try { 184 | return ugen.generate(); 185 | } 186 | catch(std::out_of_range &) { 187 | udone = true; 188 | } 189 | } 190 | 191 | throw std::out_of_range("concat: both generators completed!"); 192 | }); 193 | } 194 | 195 | template 196 | auto concat_map(UGenFunc&& ugenfunc) 197 | { 198 | typedef decltype(ugenfunc(std::declval())) UGenType; 199 | return make_gen_from( 200 | [tgen = std::move(*this), 201 | ugenfunc = std::forward(ugenfunc), 202 | //ugenopt = boost::optional(), 203 | ugenvec = std::vector(), 204 | tdone = false, 205 | udone = true]() mutable { 206 | if(!udone) 207 | { 208 | try { 209 | return ugenvec[0].generate(); 210 | //return ugenopt->generate(); 211 | } 212 | catch(std::out_of_range &) { 213 | udone = true; 214 | } 215 | } 216 | while(!tdone && udone) 217 | { 218 | try { 219 | //ugenopt.emplace(ugenfunc(tgen.generate())); 220 | ugenvec.clear(); 221 | ugenvec.emplace_back(ugenfunc(tgen.generate())); 222 | udone = false; 223 | } 224 | catch(std::out_of_range &) { 225 | tdone = true; 226 | throw; 227 | } 228 | 229 | if(!udone) 230 | { 231 | try { 232 | return ugenvec[0].generate(); 233 | //return ugenopt->generate(); 234 | } 235 | catch(std::out_of_range &) { 236 | udone = true; 237 | } 238 | } 239 | } 240 | throw std::out_of_range("concat_map completed"); 241 | }); 242 | } 243 | 244 | std::vector to_vector() 245 | { 246 | std::vector v; 247 | try { 248 | while(true) 249 | v.push_back(this->generate()); 250 | } 251 | catch(std::out_of_range &) 252 | { 253 | return v; 254 | } 255 | return v; 256 | } 257 | 258 | }; 259 | 260 | template 261 | auto make_gen_from(GenFunc&& func) 262 | { 263 | return Gen(std::forward(func)); 264 | } 265 | 266 | template 267 | auto make_constant_gen(T&& t) 268 | { 269 | return make_gen_from([t = std::forward(t)]() { return t; }); 270 | } 271 | 272 | template 273 | auto make_empty_gen() 274 | { 275 | return make_gen_from([]() -> T { 276 | throw std::out_of_range("empty generator!"); 277 | //return std::declval(); //did not work for int!! 278 | return *static_cast(nullptr); 279 | }); 280 | } 281 | 282 | template 283 | auto make_single_gen(T&& t) 284 | { 285 | return make_gen_from([t = std::forward(t), done = false]() mutable { 286 | if(!done) 287 | { 288 | done = true; 289 | return t; 290 | } 291 | else 292 | throw std::out_of_range("single generator completed!"); 293 | }); 294 | } 295 | 296 | template 297 | auto make_range_gen(Integer lo, Integer hi) 298 | { 299 | return make_gen_from([lo, hi]() { 300 | return static_cast(lo + random_int32() % (hi - lo)); 301 | }); 302 | } 303 | 304 | auto make_printable_gen() 305 | { 306 | return make_gen_from([]() { 307 | auto space = 32; 308 | auto tilde = 126; 309 | return static_cast(space + random_int32() % (tilde + 1 - space)); 310 | }); 311 | } 312 | 313 | auto make_ascii_gen() 314 | { 315 | return make_gen_from([]() { 316 | return static_cast(random_int32() % 128); 317 | }); 318 | } 319 | 320 | auto make_lowercase_gen() 321 | { 322 | return make_gen_from([]() { 323 | return static_cast('a' + random_int32() % ('z' + 1 - 'a')); 324 | }); 325 | } 326 | 327 | auto make_uppercase_gen() 328 | { 329 | return make_gen_from([]() { 330 | return static_cast('A' + random_int32() % ('Z' + 1 - 'A')); 331 | }); 332 | } 333 | 334 | auto make_alpha_gen() 335 | { 336 | return make_gen_from([]() { 337 | return (random_int32() % 2) ? 338 | static_cast('a' + random_int32() % ('z' + 1 - 'a')) : 339 | static_cast('A' + random_int32() % ('Z' + 1 - 'A')); 340 | }); 341 | } 342 | 343 | auto make_digit_gen() 344 | { 345 | return make_gen_from([]() { 346 | return static_cast('0' + random_int32() % ('9' + 1 - '0')); 347 | }); 348 | } 349 | 350 | auto make_alphanum_gen() 351 | { 352 | return make_gen_from([]() { 353 | if (random_int32() % 2) 354 | { 355 | return (random_int32() % 2) ? 356 | static_cast('a' + random_int32() % ('z' + 1 - 'a')) : 357 | static_cast('A' + random_int32() % ('Z' + 1 - 'A')); 358 | } 359 | else 360 | return static_cast('0' + random_int32() % ('9' + 1 - '0')); 361 | }); 362 | } 363 | 364 | template 365 | auto make_string_gen(CharGen&& chargen = make_printable_gen(), 366 | unsigned int maxlen = DEFAULT_MAX_STR_LEN, 367 | bool possibly_empty = false) 368 | { 369 | return make_gen_from( 370 | [chargen=std::forward(chargen), 371 | maxlen, 372 | possibly_empty]() mutable { 373 | std::string str; 374 | int length = 375 | possibly_empty ? (random_int32() % (maxlen+1)) : 376 | (random_int32() % maxlen) + 1; 377 | str.reserve(length); 378 | for (int i = 0; i < length; ++i) 379 | str.push_back(chargen.generate()); 380 | 381 | return str; 382 | }); 383 | } 384 | 385 | template