1 /* 2 * Copyright 2020 Cerebras Systems. 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 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following 13 * disclaimer in the documentation and/or other materials provided 14 * with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY CEREBRAS SYSTEMS ''AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CEREBRAS SYSTEMS OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * The views and conclusions contained in the software and documentation 29 * are those of the authors and should not be interpreted as 30 * representing official policies, either expressed or implied, of 31 * Cerebras Systems. 32 */ 33 34 #include <ctype.h> 35 36 #include <algorithm> 37 #include <iostream> 38 #include <set> 39 #include <sstream> 40 #include <string> 41 #include <unordered_map> 42 #include <unordered_set> 43 44 #include "template_cpp.h" 45 #include "isl_config.h" 46 47 /* The textual representation of this tuple kind. 48 * 49 * By default, the textual representation is just the name. 50 */ 51 std::string TupleKind::to_string() const 52 { 53 return name; 54 } 55 56 /* Return the parameters of this tuple kind. 57 * 58 * By default, there are no parameters. 59 */ 60 std::vector<std::string> TupleKind::params() const 61 { 62 return { }; 63 } 64 65 /* Apply the substitution "subs" to this tuple kind and return the result. 66 * "self" is a shared pointer to this. 67 * 68 * If the name of this tuple kind appears in the substitution, 69 * then return the corresponding tuple kind pointer. 70 * Otherwise, return "self". 71 */ 72 TupleKindPtr TupleKind::apply(const Substitution &subs, 73 const TupleKindPtr &self) const 74 { 75 if (subs.count(name) != 0) 76 return subs.at(name); 77 return self; 78 } 79 80 /* Apply the substitution "subs" to "tuple" and return the result. 81 */ 82 static TupleKindPtr apply(const TupleKindPtr tuple, const Substitution &subs) 83 { 84 return tuple->apply(subs, tuple); 85 } 86 87 /* Return the left child of this tuple kind. 88 * 89 * Since this is not a pair, there is no left child. 90 */ 91 TupleKindPtr TupleKind::left() const 92 { 93 return TupleKindPtr(); 94 } 95 96 /* Return the right child of this tuple kind. 97 * 98 * Since this is not a pair, there is no right child. 99 */ 100 TupleKindPtr TupleKind::right() const 101 { 102 return TupleKindPtr(); 103 } 104 105 /* Helper class used to construct a pointer to a tuple kind 106 * that refers to a non-template type. 107 */ 108 struct Fixed { 109 }; 110 111 /* Construct a pointer to a tuple kind that refers to a non-template type. 112 * 113 * Use an empty string as name. Since this is a non-template type, 114 * the kind name will never appear in the generated code. 115 */ 116 TupleKindPtr::TupleKindPtr(Fixed) : Base(std::make_shared<TupleKind>("")) 117 { 118 } 119 120 /* Tuple pointers for non-template types. 121 */ 122 static TupleKindPtr Ctx{Fixed()}; 123 static TupleKindPtr Integer{Fixed()}; 124 static TupleKindPtr Str{Fixed()}; 125 static TupleKindPtr Res{Fixed()}; 126 127 /* Special tuple pointers. 128 * Anonymous appears in the generated code but cannot be unified 129 * with anything else since it is a predefined template argument. 130 * Leaf can only be unified with something that is not a pair and 131 * does not appear in the generated code. 132 */ 133 static TupleKindPtr Anonymous("Anonymous"); 134 static TupleKindPtr Leaf("Leaf"); 135 136 /* Placeholder tuple pointers that refer to (part of) the domain or range. 137 */ 138 static TupleKindPtr Domain("Domain"); 139 static TupleKindPtr Domain2("Domain2"); 140 static TupleKindPtr Domain3("Domain3"); 141 static TupleKindPtr Range("Range"); 142 static TupleKindPtr Range2("Range2"); 143 static TupleKindPtr Range3("Range3"); 144 145 /* A representation of a proper tuple kind that is used as a template 146 * parameter or a template argument. 147 */ 148 struct ProperTupleKind : public TupleKind { 149 ProperTupleKind(const std::string &name) : TupleKind(name) {} 150 151 virtual std::vector<std::string> params() const override; 152 }; 153 154 /* Return the parameters of this tuple kind. 155 * 156 * Return the name of this tuple kind, unless it is the special Anonymous 157 * predefined template argument. 158 */ 159 std::vector<std::string> ProperTupleKind::params() const 160 { 161 if (Anonymous.get() == this) 162 return { }; 163 return { name }; 164 } 165 166 /* Construct a pointer to a tuple kind that refers 167 * to a proper tuple kind with the given name. 168 */ 169 TupleKindPtr::TupleKindPtr(const std::string &name) : 170 Base(std::make_shared<ProperTupleKind>(name)) 171 { 172 } 173 174 /* A tuple kind that represents an anonymous pair of nested tuple kinds. 175 */ 176 struct Pair : public TupleKind { 177 Pair(const TupleKindPtr &tuple1, const TupleKindPtr &tuple2) : 178 TupleKind(""), tuple1(tuple1), tuple2(tuple2) {} 179 180 virtual std::string to_string() const override; 181 virtual std::vector<std::string> params() const override; 182 virtual TupleKindPtr apply(const Substitution &match, 183 const TupleKindPtr &self) const override; 184 virtual TupleKindPtr left() const override; 185 virtual TupleKindPtr right() const override; 186 187 const TupleKindPtr tuple1; 188 const TupleKindPtr tuple2; 189 }; 190 191 /* The textual representation of this tuple kind. 192 * 193 * The textual representation of a pair is of the form "pair<tuple1, tuple2>". 194 */ 195 std::string Pair::to_string() const 196 { 197 return std::string("pair<") + tuple1->to_string() + ", " + 198 tuple2->to_string() + ">"; 199 } 200 201 /* Add the elements of "vec2" that do not already appear in "vec1" 202 * at the end of "vec1". 203 * 204 * The two vectors are assumed not to have any repeated elements. 205 * The updated vector will then also not have repeated elements. 206 */ 207 static void combine(std::vector<std::string> &vec1, 208 const std::vector<std::string> &vec2) 209 { 210 for (const auto &s : vec2) 211 if (std::find(vec1.begin(), vec1.end(), s) == vec1.end()) 212 vec1.emplace_back(s); 213 } 214 215 /* Return the parameters of this tuple kind. 216 * 217 * Combine the parameters of the two nested tuple kinds. 218 */ 219 std::vector<std::string> Pair::params() const 220 { 221 auto names1 = tuple1->params(); 222 auto names2 = tuple2->params(); 223 224 combine(names1, names2); 225 226 return names1; 227 } 228 229 /* Apply the substitution "subs" to this tuple kind and return the result. 230 * "self" is a shared pointer to this. 231 * 232 * Construct a new tuple kind consisting of the result of applying 233 * the substitution to the two nested tuple kinds. 234 */ 235 TupleKindPtr Pair::apply(const Substitution &subs, const TupleKindPtr &self) 236 const 237 { 238 return TupleKindPtr(::apply(tuple1, subs), ::apply(tuple2, subs)); 239 } 240 241 /* Return the left child of this tuple kind. 242 */ 243 TupleKindPtr Pair::left() const 244 { 245 return tuple1; 246 } 247 248 /* Return the right child of this tuple kind. 249 */ 250 TupleKindPtr Pair::right() const 251 { 252 return tuple2; 253 } 254 255 /* Construct a pointer to a tuple kind that refers 256 * to the given pair of nested tuple kinds. 257 */ 258 TupleKindPtr::TupleKindPtr(const TupleKindPtr &left, const TupleKindPtr &right) 259 : Base(std::make_shared<Pair>(left, right)) 260 { 261 } 262 263 /* Is this a kind of object representing an anonymous function? 264 */ 265 bool Kind::is_anon() const 266 { 267 return size() != 0 && back() == Anonymous; 268 } 269 270 /* Is this a kind of object with a single tuple? 271 */ 272 bool Kind::is_set() const 273 { 274 return size() == 1; 275 } 276 277 /* Is this a kind of object with a single, anonymous tuple? 278 */ 279 bool Kind::is_anon_set() const 280 { 281 return is_set() && is_anon(); 282 } 283 284 /* Return the parameters of this kind. 285 * 286 * Collect the parameters of the tuple kinds in the sequence. 287 */ 288 std::vector<std::string> Kind::params() const 289 { 290 std::vector<std::string> params; 291 292 for (const auto &tuple : *this) 293 combine(params, tuple->params()); 294 295 return params; 296 } 297 298 /* Apply the substitution "subs" to this kind and return the result. 299 * 300 * Apply the substitution to each of the tuple kinds in the sequence. 301 */ 302 Kind Kind::apply(const Substitution &subs) const 303 { 304 Kind applied; 305 306 for (const auto &tuple : *this) 307 applied.emplace_back(::apply(tuple, subs)); 308 309 return applied; 310 } 311 312 /* A signature of a method in terms of kinds, 313 * consisting of a return kind and a sequence of argument kinds. 314 */ 315 struct Signature { 316 Kind ret; 317 std::vector<Kind> args; 318 319 std::vector<std::string> params() const; 320 Signature apply(const Substitution &match) const; 321 }; 322 323 /* Return the parameters of this signature. 324 * 325 * Collect the parameters of the argument kinds and the return kind. 326 */ 327 std::vector<std::string> Signature::params() const 328 { 329 std::vector<std::string> params; 330 331 for (const auto &arg : args) 332 combine(params, arg.params()); 333 combine(params, ret.params()); 334 335 return params; 336 } 337 338 /* Apply the substitution "subs" to this kind and return the result. 339 * 340 * Apply the substitution to the argument kinds and the return kind. 341 */ 342 Signature Signature::apply(const Substitution &subs) const 343 { 344 std::vector<Kind> applied_args; 345 346 for (const auto &arg : args) 347 applied_args.emplace_back(arg.apply(subs)); 348 349 return { ret.apply(subs), applied_args }; 350 } 351 352 /* Return a renaming substitution that renames the elements of "params" 353 * using names starting with "prefix". 354 */ 355 static Substitution param_renamer(const std::vector<std::string> ¶ms, 356 const std::string &prefix) 357 { 358 Substitution renamer; 359 int n = 0; 360 361 for (const auto &name : params) { 362 auto suffix = std::to_string(++n); 363 auto arg_name = prefix + suffix; 364 auto arg = TupleKindPtr(arg_name); 365 366 if (name == Leaf->name) 367 generator::die("Leaf cannot be renamed"); 368 369 renamer.emplace(name, arg); 370 } 371 372 return renamer; 373 } 374 375 /* Does the vector "v" contain the element "el"? 376 */ 377 static bool contains(const std::vector<std::string> &v, const std::string &el) 378 { 379 return find(v.begin(), v.end(), el) != v.end(); 380 } 381 382 383 /* Return the shared elements of "v1" and "v2", preserving the order 384 * of those elements in "v1". 385 */ 386 static std::vector<std::string> intersect(const std::vector<std::string> &v1, 387 const std::vector<std::string> &v2) 388 { 389 std::vector<std::string> intersection; 390 391 for (const auto &el : v1) 392 if (contains(v2, el)) 393 intersection.push_back(el); 394 395 return intersection; 396 } 397 398 /* Return a renaming substitution that renames 399 * any parameters that appears in both "sig" and "kind". 400 */ 401 static Substitution shared_param_renamer(const Signature &sig, const Kind &kind) 402 { 403 return param_renamer(intersect(sig.params(), kind.params()), "Arg"); 404 } 405 406 /* Signatures for unary operations. 407 * Functions have at least one tuple. 408 */ 409 static Signature un_params = { { }, { { } } }; 410 static Signature un_set = { { Domain }, { { Domain } } }; 411 static Signature un_map = { { Domain, Range }, { { Domain, Range } } }; 412 static std::vector<Signature> un_op = { un_params, un_set, un_map }; 413 static std::vector<Signature> fn_un_op = { un_set, un_map }; 414 415 /* Signatures for binary operations, with the second argument 416 * possibly referring to part of the first argument. 417 * Functions have at least one tuple. 418 */ 419 static Signature bin_params = { { }, { { }, { } } }; 420 static Signature bin_set = { { Domain }, { { Domain }, { Domain } } }; 421 static Signature bin_map = 422 { { Domain, Range }, { { Domain, Range }, { Domain, Range } } }; 423 static std::vector<Signature> bin_op = { bin_params, bin_set, bin_map }; 424 static std::vector<Signature> fn_bin_op = { bin_set, bin_map }; 425 static Signature bin_set_params = { { Domain }, { { Domain }, { } } }; 426 static Signature bin_map_params = 427 { { Domain, Range }, { { Domain, Range }, { } } }; 428 static Signature bin_map_domain = 429 { { Domain, Range }, { { Domain, Range }, { Domain } } }; 430 static Signature bin_map_range = 431 { { Domain, Range }, { { Domain, Range }, { Range } } }; 432 433 /* Signatures for binary operations, where the second argument 434 * is an identifier (with an anonymous tuple). 435 */ 436 static Signature bin_params_anon = { { }, { { }, { Anonymous } } }; 437 static Signature bin_set_anon = { { Domain }, { { Domain }, { Anonymous } } }; 438 static Signature bin_map_anon = 439 { { Domain, Range }, { { Domain, Range }, { Anonymous } } }; 440 static std::vector<Signature> bin_op_anon = 441 { bin_params_anon, bin_set_anon, bin_map_anon }; 442 443 /* Signatures for ternary operations, where the last two arguments are integers. 444 */ 445 static Signature ter_params_int_int = 446 { { }, { { }, { Integer }, { Integer } } }; 447 static Signature ter_set_int_int = 448 { { Domain }, { { Domain }, { Integer }, { Integer } } }; 449 static Signature ter_map_int_int = 450 { { Domain, Range }, { { Domain, Range }, { Integer }, { Integer } } }; 451 static std::vector<Signature> ter_int_int = 452 { ter_params_int_int, ter_set_int_int, ter_map_int_int }; 453 454 /* Signatures for ternary operations. 455 * Functions have at least one tuple. 456 */ 457 static Signature ter_set = 458 { { Domain }, { { Domain }, { Domain }, { Domain } } }; 459 static Signature ter_map = 460 { { Domain, Range }, 461 { { Domain, Range }, { Domain, Range }, { Domain, Range } } }; 462 static std::vector<Signature> fn_ter_op = { ter_set, ter_map }; 463 464 /* Signatures for naming a leaf tuple using an identifier (with an anonymous 465 * tuple). 466 */ 467 static Signature update_set = { { Domain2 }, { { Leaf }, { Anonymous } } }; 468 static Signature update_domain = 469 { { Domain2, Range }, { { Leaf, Range }, { Anonymous } } }; 470 static Signature update_range = 471 { { Domain, Range2 }, { { Domain, Leaf }, { Anonymous } } }; 472 473 /* Signatures for the functions "min" and "max", which can be either 474 * unary or binary operations. 475 */ 476 static std::vector<Signature> min_max = { un_set, bin_set, un_map, bin_map }; 477 478 /* Signatures for adding an unnamed tuple to an object with zero or one tuple. 479 */ 480 static Signature to_set = { { Domain }, { { }, { Integer } } }; 481 static Signature add_range = { { Domain, Range }, { { Domain }, { Integer } } }; 482 /* Signatures for adding a named tuple to an object with zero or one tuple. 483 */ 484 static Signature to_set_named = 485 { { Domain }, { { }, { Anonymous }, { Integer } } }; 486 static Signature add_range_named = 487 { { Domain, Range }, { { Domain }, { Anonymous }, { Integer } } }; 488 489 /* Signatures for methods applying a map to a set, a function or 490 * part of a map. 491 */ 492 static Signature set_forward = { { Range }, { { Domain }, { Domain, Range } } }; 493 static Signature domain_forward = 494 { { Domain2, Range }, { { Domain, Range }, { Domain, Domain2 } } }; 495 static Signature range_forward = 496 { { Domain, Range2 }, { { Domain, Range }, { Range, Range2 } } }; 497 498 /* Signatures for methods plugging in a function into a set, a function or 499 * part of a map. 500 */ 501 static Signature set_backward = 502 { { Domain2 }, { { Domain }, { Domain2, Domain } } }; 503 static Signature domain_backward = 504 { { Domain2, Range }, { { Domain, Range }, { Domain2, Domain } } }; 505 static Signature range_backward = 506 { { Domain, Range2 }, { { Domain, Range }, { Range2, Range } } }; 507 static Signature domain_wrapped_domain_backward = 508 { { { Domain3, Domain2 }, Range }, 509 { { { Domain, Domain2 }, Range }, { Domain3, Domain } } }; 510 511 /* Signatures for methods binding a set, a function, 512 * or (part of) a map to parameters or an object of the same kind. 513 */ 514 static Signature bind_set = { { }, { { Domain }, { Domain } } }; 515 static Signature bind_domain = { { Range }, { { Domain, Range }, { Domain } } }; 516 static Signature bind_range = { { Domain }, { { Domain, Range }, { Range } } }; 517 static Signature bind_domain_wrapped_domain = 518 { { Range2, Range }, { { { Domain2, Range2 }, Range }, { Domain2 } } }; 519 520 /* Signatures for functions that take a callback accepting 521 * objects of the same kind (but a different type). 522 * 523 * The return and argument kinds of the callback appear 524 * at the position of the callback. 525 */ 526 static Signature each_params = { { Res }, { { }, { Res }, { } } }; 527 static Signature each_set = { { Res }, { { Domain }, { Res }, { Domain } } }; 528 static Signature each_map = 529 { { Res }, { { Domain, Range }, { Res }, { Domain, Range } } }; 530 static std::vector<Signature> each = { each_params, each_set, each_map }; 531 532 /* Signature for creating a map from a range, 533 * where the domain is given by an extra argument. 534 */ 535 static Signature map_from_range_and_domain = 536 { { Domain, Range }, { { Range }, { Domain } } }; 537 538 /* Signature for creating a map from a domain, 539 * where the range is given by an extra argument. 540 */ 541 static Signature map_from_domain_and_range = 542 { { Domain, Range }, { { Domain }, { Range } } }; 543 544 /* Signatures for creating an anonymous set from a parameter set 545 * or a map from a domain, where the range is anonymous. 546 */ 547 static Signature anonymous_set_from_params = { { Anonymous }, { { } } }; 548 static Signature anonymous_map_from_domain = 549 { { Domain, Anonymous }, { { Domain } } }; 550 static std::vector<Signature> anonymous_from_domain = 551 { anonymous_set_from_params, anonymous_map_from_domain }; 552 553 /* Signature for creating a set from a parameter set, 554 * where the domain is given by an extra argument. 555 */ 556 static Signature set_from_params = { { Domain }, { { }, { Domain } } }; 557 558 /* Signatures for creating an anonymous function from a domain, 559 * where the second argument is an identifier (with an anonymous tuple). 560 */ 561 static Signature anonymous_set_from_params_bin_anon = 562 { { Anonymous }, { { }, { Anonymous } } }; 563 static Signature anonymous_map_from_domain_bin_anon = 564 { { Domain, Anonymous }, { { Domain }, { Anonymous } } }; 565 static std::vector<Signature> anonymous_from_domain_bin_anon = { 566 anonymous_set_from_params_bin_anon, 567 anonymous_map_from_domain_bin_anon 568 }; 569 570 /* Signature for creating a map from a domain, 571 * where the range tuple is equal to the domain tuple. 572 */ 573 static Signature set_to_map = { { Domain, Domain }, { { Domain } } }; 574 575 /* Signatures for obtaining the range or the domain of a map. 576 * In case of a transformation, the domain and range are the same. 577 */ 578 static Signature domain = { { Domain }, { { Domain, Range } } }; 579 static Signature range = { { Range }, { { Domain, Range } } }; 580 static Signature transformation_domain = { { Domain }, { { Domain, Domain } } }; 581 582 /* Signatures for obtaining the parameter domain of a set or map. 583 */ 584 static Signature set_params = { { }, { { Domain } } }; 585 static Signature map_params = { { }, { { Domain, Range } } }; 586 587 /* Signatures for obtaining the domain of a function. 588 */ 589 static std::vector<Signature> fn_domain = { domain, set_params }; 590 591 /* Signatures for interchanging (wrapped) domain and range. 592 */ 593 static Signature map_reverse = { { Range, Domain }, { { Domain, Range } } }; 594 static Signature map_range_reverse = 595 { { Domain, { Range2, Range } }, { { Domain, { Range, Range2 } } } }; 596 597 /* Signatures for constructing products. 598 */ 599 static Signature set_product = 600 { { { Domain, Range } }, { { Domain }, { Range } } }; 601 static Signature map_product = 602 { { { Domain, Domain2 }, { Range, Range2 } }, 603 { { Domain, Range }, { Domain2, Range2 } } }; 604 static Signature domain_product = 605 { { { Domain, Domain2 }, Range }, 606 { { Domain, Range }, { Domain2, Range } } }; 607 static Signature range_product = 608 { { Domain, { Range, Range2 } }, 609 { { Domain, Range }, { Domain, Range2 } } }; 610 611 /* Signatures for obtaining factors from a product. 612 */ 613 static Signature domain_factor_domain = 614 { { Domain, Range }, { { { Domain, Domain2 }, Range } } }; 615 static Signature domain_factor_range = 616 { { Domain2, Range }, { { { Domain, Domain2 }, Range } } }; 617 static Signature range_factor_domain = 618 { { Domain, Range }, { { Domain, { Range, Range2 } } } }; 619 static Signature range_factor_range = 620 { { Domain, Range2 }, { { Domain, { Range, Range2 } } } }; 621 622 /* Signatures for (un)currying. 623 */ 624 static Signature curry = 625 { { Domain, { Range, Range2 } }, 626 { { { Domain, Range }, Range2 } } }; 627 static Signature uncurry = 628 { { { Domain, Range }, Range2 }, 629 { { Domain, { Range, Range2 } } } }; 630 631 /* Signatures for (un)wrapping. 632 */ 633 static Signature wrap = { { { Domain, Range } }, { { Domain, Range } } }; 634 static Signature unwrap = { { Domain, Range }, { { { Domain, Range } } } }; 635 636 /* Signatures for constructing objects that map to the domain or range 637 * of a map. 638 */ 639 static Signature domain_map = 640 { { { Domain, Range }, Domain }, { { Domain, Range } } }; 641 static Signature range_map = 642 { { { Domain, Range }, Range }, { { Domain, Range } } }; 643 644 /* Signature for applying a comparison between the domain and the range 645 * of a map. 646 */ 647 static Signature map_cmp = 648 { { Domain, Domain }, { { Domain, Domain }, { Domain, Range } } }; 649 650 /* Signature for creating a set corresponding to the domains 651 * of two functions. 652 */ 653 static Signature set_join = 654 { { Domain }, { { Domain, Range }, { Domain, Range } } }; 655 656 /* Signatures for flattening the domain or range of a map, 657 * replacing it with either an anonymous tuple or a tuple with a given name. 658 */ 659 static Signature anonymize_nested_domain = 660 { { Anonymous, Range2 }, { { { Domain, Range }, Range2 } } }; 661 static Signature anonymize_nested_range = 662 { { Domain, Anonymous }, { { Domain, { Range, Range2 } } } }; 663 static Signature replace_nested_domain = 664 { { Domain2, Range2 }, 665 { { { Domain, Range }, Range2 }, { Anonymous} } }; 666 static Signature replace_nested_range = 667 { { Domain, Range3 }, { { Domain, { Range, Range2 } }, { Anonymous} } }; 668 static std::vector<Signature> flatten_domain = 669 { anonymize_nested_domain, replace_nested_domain }; 670 static std::vector<Signature> flatten_range = 671 { anonymize_nested_range, replace_nested_range }; 672 673 /* Signatures for "set_at" methods. 674 */ 675 static Signature set_at_set = 676 { { Domain }, { { Domain }, { Integer }, { Anonymous } } }; 677 static Signature set_at_map = 678 { { Domain, Range }, 679 { { Domain, Range }, { Integer }, { Domain, Anonymous } } }; 680 static std::vector<Signature> set_at = { set_at_set, set_at_map }; 681 682 /* Signatures for "list" methods, extracting a list 683 * from a multi-expression. 684 */ 685 static Signature to_list_set = { { Anonymous }, { { Domain } } }; 686 static Signature to_list_map = { { Domain, Anonymous }, { { Domain, Range } } }; 687 688 /* Signatures for functions constructing an object from only an isl::ctx. 689 */ 690 static Signature ctx_params = { { }, { { Ctx } } }; 691 static Signature ctx_set = { { Domain }, { { Ctx } } }; 692 static Signature ctx_map = { { Domain, Range }, { { Ctx } } }; 693 694 /* Helper structure for sorting the keys of static_methods and 695 * special_member_methods such that the larger keys appear first. 696 * In particular, a key should appear before any key that appears 697 * as a substring in the key. 698 * Note that this sorting is currently only important 699 * for special_member_methods. 700 */ 701 struct larger_infix { 702 bool operator()(const std::string &x, const std::string &y) const { 703 if (x.length() > y. length()) 704 return true; 705 return x < y; 706 } 707 }; 708 709 /* A map from part of a type name to a sequence of signatures. 710 */ 711 typedef std::map<std::string, std::vector<Signature>, larger_infix> infix_map; 712 713 /* A map from a method name to a map from part of a type name 714 * to a sequence of signatures. 715 */ 716 typedef std::map<std::string, infix_map> infix_map_map; 717 718 /* Signatures for static methods. 719 * 720 * The "unit" static method is only available in a 0-tuple space. 721 * 722 * The "empty" static method creates union objects with the relevant 723 * number of tuples. 724 * 725 * The "universe" static methods create objects from the corresponding spaces. 726 */ 727 static const infix_map_map static_methods { 728 { "unit", 729 { { "space", { ctx_params } } } 730 }, 731 { "empty", 732 { 733 { "union_set", { ctx_params, ctx_set } }, 734 { "union_map", { ctx_map } }, 735 { "union_pw_multi_aff", { ctx_set, ctx_map } }, 736 } 737 }, 738 { "universe", 739 { 740 { "set", { un_params, un_set } }, 741 { "map", { un_map } }, 742 } 743 }, 744 }; 745 746 /* Signatures for unary operations that either take something in a set space 747 * and return something in the same space or take something in a map space 748 * and return something in the range of that space. 749 */ 750 static std::vector<Signature> range_op = { un_set, range }; 751 752 /* Signatures for binary operations where the second argument 753 * is a (multi-)value. 754 */ 755 static std::vector<Signature> bin_val = { bin_set, bin_map_range }; 756 757 /* The (default) signatures for methods with a given name. 758 * Some of these are overridden by special_member_methods. 759 */ 760 static const std::unordered_map<std::string, std::vector<Signature>> 761 member_methods { 762 { "add", bin_op }, 763 { "add_constant", bin_val }, 764 { "add_named_tuple", { to_set_named, add_range_named } }, 765 { "add_param", bin_op_anon }, 766 { "add_unnamed_tuple", { to_set, add_range } }, 767 { "apply", { set_forward, range_forward } }, 768 { "apply_domain", { domain_forward } }, 769 { "apply_range", { range_forward } }, 770 { "as", un_op }, 771 { "as_map", { un_map } }, 772 { "as_union_map", { un_map } }, 773 { "as_set", { un_set } }, 774 { "bind", { bind_set, bind_range } }, 775 { "bind_domain", { bind_domain } }, 776 { "bind_range", { bind_range } }, 777 { "bind_domain_wrapped_domain", 778 { bind_domain_wrapped_domain } }, 779 { "ceil", fn_un_op }, 780 { "coalesce", un_op }, 781 { "cond", fn_ter_op }, 782 { "constant_multi_val", range_op }, 783 { "curry", { curry } }, 784 { "deltas", { transformation_domain } }, 785 { "detect_equalities", un_op }, 786 { "domain", fn_domain }, 787 { "domain_factor_domain", 788 { domain_factor_domain } }, 789 { "domain_factor_range", 790 { domain_factor_range } }, 791 { "domain_map", { domain_map } }, 792 { "domain_product", { domain_product } }, 793 { "drop", ter_int_int }, 794 { "eq_at", { map_cmp } }, 795 { "every", each }, 796 { "extract", bin_op }, 797 { "flatten_domain", flatten_domain }, 798 { "flatten_range", flatten_range }, 799 { "floor", fn_un_op }, 800 { "foreach", each }, 801 { "ge_set", { set_join } }, 802 { "gt_set", { set_join } }, 803 { "gist", bin_op }, 804 { "gist_domain", { bin_map_domain } }, 805 { "identity", { un_map, set_to_map } }, 806 { "identity_on_domain", { set_to_map } }, 807 { "indicator_function", anonymous_from_domain }, 808 { "insert_domain", { map_from_range_and_domain } }, 809 { "intersect", bin_op }, 810 { "intersect_params", { bin_set_params, bin_map_params } }, 811 { "intersect_domain", { bin_map_domain } }, 812 { "intersect_range", { bin_map_range } }, 813 { "le_set", { set_join } }, 814 { "lt_set", { set_join } }, 815 { "lex_le_at", { map_cmp } }, 816 { "lex_lt_at", { map_cmp } }, 817 { "lex_ge_at", { map_cmp } }, 818 { "lex_gt_at", { map_cmp } }, 819 { "lexmin", fn_un_op }, 820 { "lexmax", fn_un_op }, 821 { "list", { to_list_set, to_list_map } }, 822 { "lower_bound", fn_bin_op }, 823 { "map_from_set", { set_to_map } }, 824 { "max", min_max }, 825 { "max_multi_val", range_op }, 826 { "min", min_max }, 827 { "min_multi_val", range_op }, 828 { "mod", bin_val }, 829 { "on_domain", { map_from_domain_and_range } }, 830 { "neg", fn_un_op }, 831 { "offset", fn_un_op }, 832 { "param_on_domain", anonymous_from_domain_bin_anon }, 833 { "params", { set_params, map_params } }, 834 { "plain_multi_val_if_fixed", 835 { un_set } }, 836 { "preimage", { set_backward } }, 837 { "preimage_domain", { domain_backward } }, 838 { "preimage_domain_wrapped_domain", 839 { domain_wrapped_domain_backward } }, 840 { "preimage_range", { range_backward } }, 841 { "product", { set_product, map_product } }, 842 { "project_out_param", bin_op_anon }, 843 { "project_out_all_params", 844 un_op }, 845 { "pullback", { domain_backward, bind_domain } }, 846 { "range", { range } }, 847 { "range_factor_domain", 848 { range_factor_domain } }, 849 { "range_factor_range", { range_factor_range } }, 850 { "range_lattice_tile", { un_map } }, 851 { "range_map", { range_map } }, 852 { "range_product", { range_product } }, 853 { "range_reverse", { map_range_reverse } }, 854 { "range_simple_fixed_box_hull", 855 { un_map } }, 856 { "reverse", { map_reverse } }, 857 { "scale", bin_val }, 858 { "scale_down", bin_val }, 859 { "set_at", set_at }, 860 { "set_domain_tuple", { update_domain } }, 861 { "set_range_tuple", { update_set, update_range } }, 862 { "simple_fixed_box_hull", 863 { un_set } }, 864 { "sub", fn_bin_op }, 865 { "subtract", bin_op }, 866 { "subtract_domain", { bin_map_domain } }, 867 { "subtract_range", { bin_map_range } }, 868 { "translation", { set_to_map } }, 869 { "to", un_op }, 870 { "unbind_params", { set_from_params } }, 871 { "unbind_params_insert_domain", 872 { map_from_range_and_domain } }, 873 { "uncurry", { uncurry } }, 874 { "union_add", fn_bin_op }, 875 { "unite", bin_op }, 876 { "universe", un_op }, 877 { "unwrap", { unwrap } }, 878 { "upper_bound", fn_bin_op }, 879 { "wrap", { wrap } }, 880 { "zero", fn_un_op }, 881 { "zero_on_domain", { anonymous_map_from_domain } }, 882 }; 883 884 /* Signatures for methods of types containing a given substring 885 * that override the default signatures, where larger substrings 886 * appear first. 887 * 888 * In particular, "gist" is usually a regular binary operation, 889 * but for any type derived from "aff", the argument refers 890 * to the domain of the function. 891 * 892 * The "size" method can usually simply be inherited from 893 * the corresponding plain C++ type, but for a "fixed_box", 894 * the size lives in the space of the box or its range. 895 * 896 * The "space" method is usually a regular unary operation 897 * that returns the single space of the elements in the object, 898 * with the same number of tuples. 899 * However, a "union" object may contain elements from many spaces and 900 * therefore its space only refers to the symbolic constants and 901 * has zero tuples, except if it is also a "multi_union" object, 902 * in which case it has a fixed range space and the space of the object 903 * has a single tuple. 904 * Note that since "space' is also the name of a template class, 905 * the default space method is handled by print_type_named_member_method. 906 */ 907 static const infix_map_map special_member_methods { 908 { "gist", 909 { { "aff", { bin_set_params, bin_map_domain } } } 910 }, 911 { "size", 912 { { "fixed_box", range_op } }, 913 }, 914 { "space", 915 { 916 { "multi_union", range_op }, 917 { "union", { un_params, set_params, map_params } }, 918 } 919 }, 920 }; 921 922 /* Generic kinds for objects with zero, one or two tuples, 923 * the last of which may be anonymous. 924 */ 925 static Kind params{}; 926 static Kind set_type{ Domain }; 927 static Kind set_anon{ Anonymous }; 928 static Kind map_type{ Domain, Range }; 929 static Kind map_anon{ Domain, Anonymous }; 930 931 /* The initial sequence of specialization kinds for base types. 932 * The specialization kinds for other types are derived 933 * from the corresponding base types. 934 * 935 * In particular, this sequence specifies how many tuples 936 * a given type can have and whether it is anonymous. 937 * 938 * "space" can have any number of tuples. 939 * "set" and "point" can have zero or one tuple. 940 * "map" can only have two tuples. 941 * "aff" can have one or two tuples, the last of which is anonymous. 942 * "fixed_box" can represent a (proper) set) or a map. 943 * "val" and "id" are treated as anonymous sets so that 944 * they can form the basis of "multi_val" and "multi_id". 945 */ 946 static const std::unordered_map<std::string, std::vector<Kind>> base_kinds { 947 { "space", { params, set_type, map_type } }, 948 { "set", { params, set_type } }, 949 { "point", { params, set_type } }, 950 { "map", { map_type } }, 951 { "aff", { set_anon, map_anon } }, 952 { "fixed_box", { set_type, map_type } }, 953 { "val", { set_anon } }, 954 { "id", { set_anon } }, 955 }; 956 957 /* Prefixes introduced by type constructors. 958 */ 959 static const std::unordered_set<std::string> type_prefixes { 960 "basic", 961 "multi", 962 "pw", 963 "union", 964 }; 965 966 /* If "type" has a "_list" suffix, then return "type" with this suffix removed. 967 * Otherwise, simply return "type". 968 */ 969 static std::string drop_list(const std::string &type) 970 { 971 size_t pos = type.rfind('_'); 972 973 if (pos == std::string::npos) 974 return type; 975 if (type.substr(pos + 1) == "list") 976 return type.substr(0, pos); 977 return type; 978 } 979 980 /* Given the name of a plain C++ type, return the base type 981 * from which it was derived using type constructors. 982 * 983 * In particular, drop any "list" suffix and 984 * drop any prefixes from type_prefixes, stopping 985 * as soon as a base type is found for which kinds have been registered 986 * in base_kinds. 987 */ 988 static std::string base_type(const std::string &type) 989 { 990 auto base = type; 991 size_t pos; 992 993 base = drop_list(base); 994 while (base_kinds.count(base) == 0 && 995 (pos = base.find('_')) != std::string::npos && 996 type_prefixes.count(base.substr(0, pos)) != 0) { 997 base = base.substr(pos + 1); 998 } 999 1000 return base; 1001 } 1002 1003 /* A mapping from anonymous kinds to named kinds. 1004 */ 1005 static std::map<Kind, Kind> anon_to_named { 1006 { set_anon, set_type }, 1007 { map_anon, map_type }, 1008 }; 1009 1010 /* Given a sequence of anonymous kinds, replace them 1011 * by the corresponding named kinds. 1012 */ 1013 static std::vector<Kind> add_name(const std::vector<Kind> &tuples) 1014 { 1015 std::vector<Kind> named; 1016 1017 for (const auto &tuple : tuples) 1018 named.emplace_back(anon_to_named.at(tuple)); 1019 1020 return named; 1021 } 1022 1023 /* Add a template class called "name", of which the methods are described 1024 * by "clazz" and where the corresponding base type has kinds "base_kinds". 1025 * 1026 * If this template class is a multi-expression, then it was derived 1027 * from an anonymous function type. Replace the final Anonymous 1028 * tuple kind by a placeholder in this case. 1029 */ 1030 void template_cpp_generator::add_template_class(const isl_class &clazz, 1031 const std::string &name, const std::vector<Kind> &base_kinds) 1032 { 1033 auto isl_namespace = cpp_type_printer().isl_namespace(); 1034 auto super = isl_namespace + name; 1035 auto class_tuples = base_kinds; 1036 1037 if (name.find("multi_") != std::string::npos) 1038 class_tuples = add_name(class_tuples); 1039 template_classes.emplace(name, 1040 template_class{name, super, clazz, class_tuples}); 1041 } 1042 1043 /* Construct a templated C++ bindings generator from 1044 * the exported types and functions and the set of all declared functions. 1045 * 1046 * On top of the initialization of the shared parts 1047 * of C++ bindings generators, add a template class 1048 * for each plain C++ class for which template kinds 1049 * have been defined. 1050 * In particular, determine the base type from which the plain C++ class 1051 * was derived using type constructors and check if any template kinds 1052 * have been registered for this base type. 1053 */ 1054 template_cpp_generator::template_cpp_generator(clang::SourceManager &SM, 1055 std::set<clang::RecordDecl *> &exported_types, 1056 std::set<clang::FunctionDecl *> exported_functions, 1057 std::set<clang::FunctionDecl *> functions) : 1058 cpp_generator(SM, exported_types, exported_functions, 1059 functions) 1060 { 1061 for (const auto &kvp : classes) { 1062 const auto &clazz = kvp.second; 1063 std::string name = type2cpp(clazz); 1064 std::string base = base_type(name); 1065 1066 if (base_kinds.count(base) == 0) 1067 continue; 1068 add_template_class(clazz, name, base_kinds.at(base)); 1069 } 1070 } 1071 1072 /* Call "fn" on each template class. 1073 */ 1074 void template_cpp_generator::foreach_template_class( 1075 const std::function<void(const template_class &)> &fn) const 1076 { 1077 for (const auto &kvp : template_classes) 1078 fn(kvp.second); 1079 } 1080 1081 /* Print forward declarations for all template classes to "os". 1082 * 1083 * For template classes that represent an anonymous function 1084 * that can also have a domain tuple, provide an <name>_on alias 1085 * that adds the fixed Anonymous tuple kind. 1086 */ 1087 void template_cpp_generator::print_forward_declarations(std::ostream &os) 1088 { 1089 foreach_template_class([&os] (const template_class &template_class) { 1090 auto name = template_class.class_name; 1091 1092 os << "\n"; 1093 os << "template <typename...>\n"; 1094 os << "struct " << name << ";\n"; 1095 1096 if (!template_class.is_anon()) 1097 return; 1098 if (template_class.is_anon_set()) 1099 return; 1100 1101 os << "\n"; 1102 os << "template <typename...Ts>\n"; 1103 os << "using " << name << "_on = " 1104 << name << "<Ts..., Anonymous>;\n"; 1105 }); 1106 } 1107 1108 /* Print friend declarations for all template classes to "os". 1109 */ 1110 void template_cpp_generator::print_friends(std::ostream &os) 1111 { 1112 foreach_template_class([&os] (const template_class &template_class) { 1113 os << " template <typename...>\n"; 1114 os << " friend struct " << template_class.class_name << ";\n"; 1115 }); 1116 } 1117 1118 /* Print a template parameter or argument. 1119 * In case of a std::string, it's a template parameter 1120 * that needs to be declared. 1121 */ 1122 static void print_template_arg(std::ostream &os, const std::string &arg) 1123 { 1124 os << "typename " << arg; 1125 } 1126 1127 /* Print a template parameter or argument. 1128 * In case of a TupleKindPtr, it's a template argument. 1129 */ 1130 static void print_template_arg(std::ostream &os, const TupleKindPtr &kind) 1131 { 1132 os << kind->to_string(); 1133 } 1134 1135 /* Print a sequence of template parameters (std::string) or 1136 * arguments (TupleKindPtr) "args", without the enclosing angle brackets. 1137 */ 1138 template <typename List> 1139 static void print_pure_template_args(std::ostream &os, const List &args) 1140 { 1141 for (size_t i = 0; i < args.size(); ++i) { 1142 if (i != 0) 1143 os << ", "; 1144 print_template_arg(os, args[i]); 1145 } 1146 } 1147 1148 /* Print a sequence of template parameters (std::string) or 1149 * arguments (TupleKindPtr) "args". 1150 */ 1151 template <typename List> 1152 static void print_template_args(std::ostream &os, const List &args) 1153 { 1154 os << "<"; 1155 print_pure_template_args(os, args); 1156 os << ">"; 1157 } 1158 1159 /* Print a declaration of the template parameters "params". 1160 */ 1161 static void print_template(std::ostream &os, 1162 const std::vector<std::string> ¶ms) 1163 { 1164 os << "template "; 1165 print_template_args(os, params); 1166 os << "\n"; 1167 } 1168 1169 /* Print a declaration of the template parameters "params", 1170 * if there are any. 1171 */ 1172 static void print_non_empty_template(std::ostream &os, 1173 const std::vector<std::string> ¶ms) 1174 { 1175 if (params.size() > 0) 1176 print_template(os, params); 1177 } 1178 1179 /* Print a bare template type, i.e., without namespace, 1180 * consisting of the type "type" and the kind "kind" to "os". 1181 * 1182 * In particular, print "type" followed by the template arguments 1183 * as specified by "kind". 1184 */ 1185 static void print_bare_template_type(std::ostream &os, const std::string &type, 1186 const Kind &kind) 1187 { 1188 os << type; 1189 print_template_args(os, kind); 1190 } 1191 1192 /* A specific instance of "template_class", with tuple kinds given by "kind". 1193 */ 1194 struct specialization { 1195 struct template_class &template_class; 1196 Kind kind; 1197 1198 const std::string &base_name() const; 1199 const std::string &class_name() const; 1200 }; 1201 1202 /* The name of the plain C++ interface class 1203 * from which this template class (instance) derives. 1204 */ 1205 const std::string &specialization::base_name() const 1206 { 1207 return template_class.super_name; 1208 } 1209 1210 /* The name of the template class. 1211 */ 1212 const std::string &specialization::class_name() const 1213 { 1214 return template_class.class_name; 1215 } 1216 1217 /* Helper class for printing the specializations of template classes 1218 * that is used to print both the class declarations and the class definitions. 1219 * 1220 * "os" is the stream onto which the classes should be printed. 1221 * "generator" is the templated C++ interface generator printing the classes. 1222 */ 1223 struct specialization_printer { 1224 specialization_printer(std::ostream &os, 1225 template_cpp_generator &generator) : 1226 os(os), generator(generator) {} 1227 1228 virtual void print_class(const specialization &instance) const = 0; 1229 void print_classes() const; 1230 1231 std::ostream &os; 1232 template_cpp_generator &generator; 1233 }; 1234 1235 /* Print all specializations of all template classes. 1236 * 1237 * Each class has a predefined set of initial specializations, 1238 * but while such a specialization is being printed, 1239 * the need for other specializations may arise and 1240 * these are added at the end of the list of specializations. 1241 * That is, class_tuples.size() may change during the execution 1242 * of the loop. 1243 * 1244 * For each specialization of a template class, call 1245 * the print_class virtual method. 1246 */ 1247 void specialization_printer::print_classes() const 1248 { 1249 for (auto &kvp : generator.template_classes) { 1250 auto &template_class = kvp.second; 1251 const auto &class_tuples = template_class.class_tuples; 1252 1253 for (size_t i = 0; i < class_tuples.size(); ++i) 1254 print_class({ template_class, class_tuples[i] }); 1255 } 1256 } 1257 1258 /* A helper class for printing method declarations and definitions 1259 * of a template class specialization. 1260 * 1261 * "instance" is the template class specialization for which methods 1262 * are printed. 1263 * "generator" is the templated C++ interface generator printing the classes. 1264 */ 1265 struct template_cpp_generator::class_printer : 1266 public cpp_generator::class_printer { 1267 class_printer(const specialization &instance, 1268 const specialization_printer &instance_printer, 1269 bool is_declaration); 1270 1271 void print_return_type(const Method &method, const Kind &kind) 1272 const; 1273 void print_method_template_arguments(const Signature &sig); 1274 void print_method_header(const Method &method, const Signature &sig); 1275 bool print_special_method(const Method &method, 1276 const infix_map_map &special_methods); 1277 void print_static_method(const Method &method); 1278 void print_constructor(const Method &method); 1279 bool is_return_kind(const Method &method, const Kind &return_kind); 1280 void add_specialization(const Kind &kind); 1281 bool print_matching_method(const Method &method, const Signature &sig, 1282 const Kind &match_arg); 1283 bool print_matching_method(const Method &method, const Signature &sig); 1284 void print_matching_method(const Method &method, 1285 const std::vector<Signature> &signatures); 1286 void print_at_method(const Method &method); 1287 bool print_special_member_method(const Method &method); 1288 bool print_type_named_member_method(const Method &method); 1289 bool print_member_method_with_name(const Method &method, 1290 const std::string &name); 1291 void print_member_method(const Method &method); 1292 void print_any_method(const Method &method); 1293 virtual void print_method(const Method &method) override; 1294 virtual void print_method(const ConversionMethod &method) override; 1295 virtual void print_method_sig(const Method &method, 1296 const Signature &sig, bool deleted) = 0; 1297 virtual bool want_descendent_overloads(const function_set &methods) 1298 override; 1299 void print_all_methods(); 1300 1301 const specialization &instance; 1302 template_cpp_generator &generator; 1303 }; 1304 1305 /* Construct a class_printer from the template class specialization 1306 * for which methods are printed and 1307 * the printer of the template class. 1308 * 1309 * The template class printer is only used to obtain the output stream and 1310 * the templated C++ interface generator printing the classes. 1311 */ 1312 template_cpp_generator::class_printer::class_printer( 1313 const specialization &instance, 1314 const specialization_printer &instance_printer, 1315 bool is_declaration) : 1316 cpp_generator::class_printer(instance_printer.os, 1317 instance.template_class.clazz, instance_printer.generator, 1318 is_declaration), 1319 instance(instance), generator(instance_printer.generator) 1320 { 1321 } 1322 1323 /* An abstract template type printer, where the way of obtaining 1324 * the argument kind is specified by the subclasses. 1325 */ 1326 struct template_cpp_type_printer : public cpp_type_printer { 1327 template_cpp_type_printer() {} 1328 1329 std::string base(const std::string &type, const Kind &kind) const; 1330 virtual Kind kind(int arg) const = 0; 1331 virtual std::string qualified(int arg, const std::string &cpp_type) 1332 const override; 1333 }; 1334 1335 /* Print a template type consisting of the type "type" and the kind "kind", 1336 * including the "typed::" namespace specifier. 1337 */ 1338 std::string template_cpp_type_printer::base(const std::string &type, 1339 const Kind &kind) const 1340 { 1341 std::ostringstream ss; 1342 1343 ss << "typed::"; 1344 print_bare_template_type(ss, type, kind); 1345 return ss.str(); 1346 } 1347 1348 /* Return the qualified form of the given C++ isl type name appearing 1349 * in argument position "arg" (-1 for return type). 1350 * 1351 * isl::ctx is not templated, so if "cpp_type" is "ctx", 1352 * then print a non-templated version. 1353 * Otherwise, look up the kind of the argument and print 1354 * the corresponding template type. 1355 */ 1356 std::string template_cpp_type_printer::qualified(int arg, 1357 const std::string &cpp_type) const 1358 { 1359 if (cpp_type == "ctx") 1360 return cpp_type_printer::qualified(arg, cpp_type); 1361 1362 return base(cpp_type, kind(arg)); 1363 } 1364 1365 /* A template type printer for printing types with a fixed kind. 1366 * 1367 * "fixed_kind" is the fixed kind. 1368 */ 1369 struct template_cpp_kind_type_printer : public template_cpp_type_printer { 1370 template_cpp_kind_type_printer(const Kind &kind) : 1371 template_cpp_type_printer(), fixed_kind(kind) {} 1372 1373 virtual Kind kind(int arg) const override; 1374 1375 const Kind &fixed_kind; 1376 }; 1377 1378 /* Return the kind of the argument at position "arg", 1379 * where position -1 refers to the return type. 1380 * 1381 * Always use the fixed kind. 1382 */ 1383 Kind template_cpp_kind_type_printer::kind(int arg) const 1384 { 1385 return fixed_kind; 1386 } 1387 1388 /* A template type printer for printing a method with a given signature. 1389 * 1390 * "sig" is the signature of the method being printed. 1391 */ 1392 struct template_cpp_arg_type_printer : public template_cpp_type_printer { 1393 template_cpp_arg_type_printer(const Signature &sig) : 1394 template_cpp_type_printer(), sig(sig) {} 1395 1396 virtual Kind kind(int arg) const override; 1397 1398 const Signature &sig; 1399 }; 1400 1401 /* Return the kind of the argument at position "arg", 1402 * where position -1 refers to the return type. 1403 * 1404 * Look up the kind in the signature. 1405 */ 1406 Kind template_cpp_arg_type_printer::kind(int arg) const 1407 { 1408 int n_args = sig.args.size(); 1409 1410 if (arg < 0) 1411 return sig.ret; 1412 if (arg >= n_args) 1413 generator::die("argument out of bounds"); 1414 return sig.args[arg]; 1415 } 1416 1417 /* A template type printer for printing a method with a given signature 1418 * as part of a template class specialization of a given kind. 1419 * 1420 * "class_kind" is the template class specialization kind. 1421 */ 1422 struct template_method_type_printer : public template_cpp_arg_type_printer { 1423 template_method_type_printer(const Signature &sig, 1424 const Kind &class_kind) : 1425 template_cpp_arg_type_printer(sig), 1426 class_kind(class_kind) {} 1427 1428 virtual std::string class_type(const std::string &cpp_name) 1429 const override; 1430 1431 const Kind &class_kind; 1432 }; 1433 1434 /* Print the class type "cpp_name". 1435 * 1436 * Print the templated version using the template class specialization kind. 1437 */ 1438 std::string template_method_type_printer::class_type( 1439 const std::string &cpp_name) const 1440 { 1441 return base(cpp_name, class_kind); 1442 } 1443 1444 /* Print the templated return type of "method" of the kind "return_kind". 1445 * 1446 * Construct a type printer with "return_kind" as fixed kind and 1447 * use it to print the return type. 1448 */ 1449 void template_cpp_generator::class_printer::print_return_type( 1450 const Method &method, const Kind &return_kind) const 1451 { 1452 template_cpp_kind_type_printer printer(return_kind); 1453 1454 os << printer.return_type(method); 1455 } 1456 1457 /* Remove the initial "n" elements from "v". 1458 */ 1459 template <typename T> 1460 static void drop_initial(std::vector<T> &v, size_t n) 1461 { 1462 v.erase(v.begin(), v.begin() + n); 1463 } 1464 1465 /* If a method with signature "sig" requires additional template parameters 1466 * compared to those of the class, then print a declaration for them. 1467 * If this->declarations is set, then this will be part of a method declaration, 1468 * requiring extra indentation. 1469 * 1470 * Construct the sequence of all required template parameters 1471 * with those of the template class appearing first. 1472 * If this sequence has any parameters not induced by the template class itself, 1473 * then print a declaration for these extra parameters. 1474 */ 1475 void template_cpp_generator::class_printer::print_method_template_arguments( 1476 const Signature &sig) 1477 { 1478 std::vector<std::string> class_params, method_params; 1479 1480 class_params = instance.kind.params(); 1481 method_params = class_params; 1482 combine(method_params, sig.params()); 1483 1484 if (class_params.size() == method_params.size()) 1485 return; 1486 1487 drop_initial(method_params, class_params.size()); 1488 1489 if (declarations) 1490 os << " "; 1491 print_template(os, method_params); 1492 } 1493 1494 /* Print the header for "method" with signature "sig". 1495 * 1496 * First print any additional template parameters that may be required and 1497 * then print a regular method header, using a template type printer. 1498 */ 1499 void template_cpp_generator::class_printer::print_method_header( 1500 const Method &method, const Signature &sig) 1501 { 1502 template_method_type_printer type_printer(sig, instance.kind); 1503 1504 print_method_template_arguments(sig); 1505 cpp_generator::class_printer::print_method_header(method, 1506 type_printer); 1507 } 1508 1509 /* Given a group of methods with the same name, 1510 * should extra methods be added that take as arguments 1511 * those types that can be converted to the original argument type 1512 * through a unary constructor? 1513 * 1514 * Since type deduction does not consider implicit conversions, 1515 * these extra methods should always be printed. 1516 */ 1517 bool template_cpp_generator::class_printer::want_descendent_overloads( 1518 const function_set &methods) 1519 { 1520 return true; 1521 } 1522 1523 /* Print all constructors and methods that forward 1524 * to the corresponding methods in the plain C++ interface class. 1525 */ 1526 void template_cpp_generator::class_printer::print_all_methods() 1527 { 1528 print_constructors(); 1529 print_methods(); 1530 } 1531 1532 /* A helper class for printing method declarations 1533 * of a template class specialization. 1534 */ 1535 struct template_cpp_generator::method_decl_printer : 1536 public template_cpp_generator::class_printer { 1537 method_decl_printer(const specialization &instance, 1538 const struct specialization_printer &instance_printer) : 1539 class_printer(instance, instance_printer, true) {} 1540 1541 virtual void print_method_sig(const Method &method, 1542 const Signature &sig, bool deleted) override; 1543 virtual void print_get_method(FunctionDecl *fd) override; 1544 }; 1545 1546 /* Print a declaration of the method "method" with signature "sig". 1547 * Mark is "delete" if "deleted" is set. 1548 */ 1549 void template_cpp_generator::method_decl_printer::print_method_sig( 1550 const Method &method, const Signature &sig, bool deleted) 1551 { 1552 print_method_header(method, sig); 1553 if (deleted) 1554 os << " = delete"; 1555 os << ";\n"; 1556 } 1557 1558 /* Return the total number of arguments in the signature for "method", 1559 * taking into account a possible callback argument. 1560 * 1561 * In particular, if the method has a callback argument, 1562 * then the return kind of the callback appears at the position 1563 * of the callback and the kinds of the arguments (except 1564 * the user pointer argument) appear in the following positions. 1565 */ 1566 static int total_params(const Method &method) 1567 { 1568 int n = method.num_params(); 1569 1570 if (method.callback) { 1571 auto callback_type = method.callback->getType(); 1572 auto callback = generator::extract_prototype(callback_type); 1573 1574 n += callback->getNumArgs() - 1; 1575 } 1576 1577 return n; 1578 } 1579 1580 /* Return a signature for "method" that matches "instance". 1581 */ 1582 static Signature instance_sig(const Method &method, 1583 const specialization &instance) 1584 { 1585 std::vector<Kind> args(total_params(method)); 1586 1587 args[0] = instance.kind; 1588 return { instance.kind, args }; 1589 } 1590 1591 /* Print a declaration for the "get" method "fd", 1592 * using a name that includes the "get_" prefix. 1593 * 1594 * These methods are only included in the plain interface. 1595 * Explicitly delete them from the templated interface. 1596 */ 1597 void template_cpp_generator::method_decl_printer::print_get_method( 1598 FunctionDecl *fd) 1599 { 1600 Method method(clazz, fd, clazz.base_method_name(fd)); 1601 1602 print_method_sig(method, instance_sig(method, instance), true); 1603 } 1604 1605 /* A helper class for printing method definitions 1606 * of a template class specialization. 1607 */ 1608 struct template_cpp_generator::method_impl_printer : 1609 public template_cpp_generator::class_printer { 1610 method_impl_printer(const specialization &instance, 1611 const struct specialization_printer &instance_printer) : 1612 class_printer(instance, instance_printer, false) {} 1613 1614 void print_callback_method_body(const Method &method, 1615 const Signature &sig); 1616 void print_method_body(const Method &method, const Signature &sig); 1617 void print_constructor_body(const Method &method, const Signature &sig); 1618 virtual void print_method_sig(const Method &method, 1619 const Signature &sig, bool deleted) override; 1620 virtual void print_get_method(FunctionDecl *fd) override; 1621 }; 1622 1623 /* Print a definition of the constructor "method" with signature "sig". 1624 * 1625 * Simply pass all arguments to the constructor of the corresponding 1626 * plain type. 1627 */ 1628 void template_cpp_generator::method_impl_printer::print_constructor_body( 1629 const Method &method, const Signature &sig) 1630 { 1631 const auto &base_name = instance.base_name(); 1632 1633 os << " : " << base_name; 1634 method.print_cpp_arg_list(os, [&] (int i) { 1635 os << method.fd->getParamDecl(i)->getName().str(); 1636 }); 1637 os << "\n"; 1638 1639 os << "{\n"; 1640 os << "}\n"; 1641 } 1642 1643 /* Print the arguments of the callback function "callback" to "os", 1644 * calling "print_arg" with the type and the name of the arguments, 1645 * where the type is obtained from "type_printer" with argument positions 1646 * shifted by "shift". 1647 */ 1648 static void print_callback_args(std::ostream &os, 1649 const FunctionProtoType *callback, const cpp_type_printer &type_printer, 1650 int shift, 1651 const std::function<void(const std::string &type, 1652 const std::string &name)> &print_arg) 1653 { 1654 auto n_arg = callback->getNumArgs() - 1; 1655 1656 Method::print_arg_list(os, 0, n_arg, [&] (int i) { 1657 auto type = callback->getArgType(i); 1658 auto name = "arg" + std::to_string(i); 1659 auto cpptype = type_printer.param(shift + i, type); 1660 1661 print_arg(cpptype, name); 1662 }); 1663 } 1664 1665 /* Print a lambda for passing to the plain method corresponding to "method" 1666 * with signature "sig". 1667 * 1668 * The method is assumed to have only the callback as argument, 1669 * which means the arguments of the callback are shifted by 2 1670 * with respect to the arguments of the signature 1671 * (one for the position of the callback argument plus 1672 * one for the return kind of the callback). 1673 * 1674 * The lambda takes arguments with plain isl types and 1675 * calls the callback of "method" with templated arguments. 1676 */ 1677 static void print_callback_lambda(std::ostream &os, const Method &method, 1678 const Signature &sig) 1679 { 1680 auto callback_type = method.callback->getType(); 1681 auto callback_name = method.callback->getName().str(); 1682 auto callback = generator::extract_prototype(callback_type); 1683 1684 if (method.num_params() != 2) 1685 generator::die("callback is assumed to be single argument"); 1686 1687 os << " auto lambda = [&] "; 1688 print_callback_args(os, callback, cpp_type_printer(), 2, 1689 [&] (const std::string &type, const std::string &name) { 1690 os << type << " " << name; 1691 }); 1692 os << " {\n"; 1693 1694 os << " return " << callback_name; 1695 print_callback_args(os, callback, template_cpp_arg_type_printer(sig), 2, 1696 [&] (const std::string &type, const std::string &name) { 1697 os << type << "(" << name << ")"; 1698 }); 1699 os << ";\n"; 1700 1701 os << " };\n"; 1702 } 1703 1704 /* Print a definition of the member method "method", which is known 1705 * to have a callback argument, with signature "sig". 1706 * 1707 * First print a lambda for passing to the corresponding plain method and 1708 * calling the callback of "method" with templated arguments. 1709 * Then call the plain method, replacing the original callback 1710 * by the lambda. 1711 * 1712 * The return value is assumed to be isl_bool or isl_stat 1713 * so that no conversion to a template type is required. 1714 */ 1715 void template_cpp_generator::method_impl_printer::print_callback_method_body( 1716 const Method &method, const Signature &sig) 1717 { 1718 const auto &base_name = instance.base_name(); 1719 auto return_type = method.fd->getReturnType(); 1720 1721 if (!is_isl_bool(return_type) && !is_isl_stat(return_type)) 1722 die("only isl_bool and isl_stat return types are supported"); 1723 1724 os << "{\n"; 1725 1726 print_callback_lambda(os, method, sig); 1727 1728 os << " return "; 1729 os << base_name << "::" << method.name; 1730 method.print_cpp_arg_list(os, [&] (int i) { 1731 auto param = method.fd->getParamDecl(i); 1732 1733 if (param == method.callback) 1734 os << "lambda"; 1735 else 1736 os << param->getName().str(); 1737 }); 1738 os << ";\n"; 1739 1740 os << "}\n"; 1741 } 1742 1743 /* Print a definition of the member or static method "method" 1744 * with signature "sig". 1745 * 1746 * The body calls the corresponding method of the base class 1747 * in the plain interface and 1748 * then casts the result to the templated result type. 1749 */ 1750 void template_cpp_generator::method_impl_printer::print_method_body( 1751 const Method &method, const Signature &sig) 1752 { 1753 const auto &base_name = instance.base_name(); 1754 1755 os << "{\n"; 1756 os << " auto res = "; 1757 os << base_name << "::" << method.name; 1758 method.print_cpp_arg_list(os, [&] (int i) { 1759 os << method.fd->getParamDecl(i)->getName().str(); 1760 }); 1761 os << ";\n"; 1762 1763 os << " return "; 1764 print_return_type(method, sig.ret); 1765 os << "(res);\n"; 1766 os << "}\n"; 1767 } 1768 1769 /* Print a definition of the method "method" with signature "sig", 1770 * if "deleted" is not set. 1771 * 1772 * If "deleted" is set, then the corresponding declaration 1773 * is marked "delete" and no definition needs to be printed. 1774 * 1775 * Otherwise print the method header, preceded by the template parameters, 1776 * if needed. 1777 * The body depends on whether the method is a constructor or 1778 * takes a callback. 1779 */ 1780 void template_cpp_generator::method_impl_printer::print_method_sig( 1781 const Method &method, const Signature &sig, bool deleted) 1782 { 1783 if (deleted) 1784 return; 1785 1786 os << "\n"; 1787 print_non_empty_template(os, instance.kind.params()); 1788 print_method_header(method, sig); 1789 os << "\n"; 1790 if (method.kind == Method::Kind::constructor) 1791 print_constructor_body(method, sig); 1792 else if (method.callback) 1793 print_callback_method_body(method, sig); 1794 else 1795 print_method_body(method, sig); 1796 } 1797 1798 /* Print a definition for the "get" method "fd" in class "clazz", 1799 * using a name that includes the "get_" prefix, to "os". 1800 * 1801 * The declarations of these methods are explicitly delete'd 1802 * so no definition needs to be printed. 1803 */ 1804 void template_cpp_generator::method_impl_printer::print_get_method( 1805 FunctionDecl *fd) 1806 { 1807 } 1808 1809 /* Print a declaration or definition of the static method "method", 1810 * if it has a signature specified by static_methods. 1811 */ 1812 void template_cpp_generator::class_printer::print_static_method( 1813 const Method &method) 1814 { 1815 print_special_method(method, static_methods); 1816 } 1817 1818 /* Signatures for constructors of multi-expressions 1819 * from a space and a list. 1820 */ 1821 static Signature from_list_set = { { Domain }, { { Domain }, { Anonymous } } }; 1822 static Signature from_list_map = 1823 { { Domain, Range }, { { Domain, Range }, { Domain, Anonymous } } }; 1824 1825 /* Signatures for constructors from a string. 1826 */ 1827 static Signature params_from_str = { { }, { { Ctx }, { Str } } }; 1828 static Signature set_from_str = { { Domain }, { { Ctx }, { Str } } }; 1829 static Signature map_from_str = { { Domain, Range }, { { Ctx }, { Str } } }; 1830 static std::vector<Signature> from_str = 1831 { params_from_str, set_from_str, map_from_str }; 1832 1833 /* Signature for a constructor from an integer. 1834 */ 1835 static Signature int_from_si = { { Anonymous }, { { Ctx }, { Integer } } }; 1836 1837 /* Signatures for constructors of lists from the initial number 1838 * of elements. 1839 */ 1840 static Signature alloc_params = { { }, { { Ctx }, { Integer } } }; 1841 static Signature alloc_set = { { Domain }, { { Ctx }, { Integer } } }; 1842 static Signature alloc_map = { { Domain, Range }, { { Ctx }, { Integer } } }; 1843 1844 /* Signatures for constructors and methods named after some other class. 1845 * 1846 * Two forms of constructors are handled 1847 * - conversion from another object 1848 * - construction of a multi-expression from a space and a list 1849 * 1850 * Methods named after some other class also come in two forms 1851 * - extraction of information such as the space or a list 1852 * - construction of a multi-expression from a space and a list 1853 * 1854 * In both cases, the first form is a unary operation and 1855 * the second has an extra argument with a kind that is equal 1856 * to that of the first argument, except that the final tuple is anonymous. 1857 */ 1858 static std::vector<Signature> constructor_sig = { 1859 un_params, 1860 un_set, 1861 un_map, 1862 from_list_set, 1863 from_list_map, 1864 }; 1865 1866 /* Signatures for constructors derived from methods 1867 * with the given names that override the default signatures. 1868 */ 1869 static const std::unordered_map<std::string, std::vector<Signature>> 1870 special_constructors { 1871 { "alloc", { alloc_params, alloc_set, alloc_map } }, 1872 { "int_from_si", { int_from_si } }, 1873 { "read_from_str", from_str }, 1874 }; 1875 1876 /* Print a declaration or definition of the constructor "method". 1877 */ 1878 void template_cpp_generator::class_printer::print_constructor( 1879 const Method &method) 1880 { 1881 if (special_constructors.count(method.name) != 0) { 1882 const auto &sigs = special_constructors.at(method.name); 1883 return print_matching_method(method, sigs); 1884 } 1885 print_matching_method(method, constructor_sig); 1886 } 1887 1888 /* Does this template class represent an anonymous function? 1889 * 1890 * If any specialization represents an anonymous function, 1891 * then every specialization does, so simply check 1892 * the first specialization. 1893 */ 1894 bool template_class::is_anon() const 1895 { 1896 return class_tuples[0].is_anon(); 1897 } 1898 1899 /* Does this template class represent an anonymous value? 1900 * 1901 * That is, is there only a single specialization that moreover 1902 * has a single, anonymous tuple? 1903 */ 1904 bool template_class::is_anon_set() const 1905 { 1906 return class_tuples.size() == 1 && class_tuples[0].is_anon_set(); 1907 } 1908 1909 /* Update the substitution "sub" to map "general" to "specific" 1910 * if "specific" is a special case of "general" consistent with "sub", 1911 * given that "general" is not a pair and can be assigned "specific". 1912 * Return true if successful. 1913 * Otherwise, return false. 1914 * 1915 * Check whether "general" is already assigned something in "sub". 1916 * If so, it must be assigned "specific". 1917 * Otherwise, there is a conflict. 1918 */ 1919 static bool update_sub_base(Substitution &sub, const TupleKindPtr &general, 1920 const TupleKindPtr &specific) 1921 { 1922 auto name = general->name; 1923 1924 if (sub.count(name) != 0 && sub.at(name) != specific) 1925 return false; 1926 sub.emplace(name, specific); 1927 return true; 1928 } 1929 1930 /* Update the substitution "sub" to map "general" to "specific" 1931 * if "specific" is a special case of "general" consistent with "sub". 1932 * Return true if successful. 1933 * Otherwise, return false. 1934 * 1935 * If "general" is a pair and "specific" is not, 1936 * then "specific" cannot be a special case. 1937 * If both are pairs, then update the substitution based 1938 * on both sides. 1939 * If "general" is Anonymous, then "specific" must be Anonymous as well. 1940 * If "general" is Leaf, then "specific" cannot be a pair. 1941 * 1942 * Otherwise, assign "specific" to "general", if possible. 1943 */ 1944 static bool update_sub(Substitution &sub, const TupleKindPtr &general, 1945 const TupleKindPtr &specific) 1946 { 1947 if (general->left() && !specific->left()) 1948 return false; 1949 if (general->left()) 1950 return update_sub(sub, general->left(), specific->left()) && 1951 update_sub(sub, general->right(), specific->right()); 1952 if (general == Anonymous && specific != Anonymous) 1953 return false; 1954 if (general == Leaf && specific->left()) 1955 return false; 1956 1957 return update_sub_base(sub, general, specific); 1958 } 1959 1960 /* Check if "specific" is a special case of "general" and, 1961 * if so, return true along with a substitution 1962 * that maps "general" to "specific". 1963 * Otherwise return false. 1964 * 1965 * This can only happen if the number of tuple kinds is the same. 1966 * If so, start with an empty substitution and update it 1967 * for each pair of tuple kinds, checking that each update succeeds. 1968 */ 1969 static std::pair<bool, Substitution> specializer(const Kind &general, 1970 const Kind &specific) 1971 { 1972 Substitution specializer; 1973 1974 if (general.size() != specific.size()) 1975 return { false, Substitution() }; 1976 1977 for (size_t i = 0; i < general.size(); ++i) { 1978 auto general_tuple = general[i]; 1979 1980 if (!update_sub(specializer, general[i], specific[i])) 1981 return { false, Substitution() }; 1982 } 1983 1984 return { true, specializer }; 1985 } 1986 1987 /* Is "kind1" equivalent to "kind2"? 1988 * That is, is each a special case of the other? 1989 */ 1990 static bool equivalent(const Kind &kind1, const Kind &kind2) 1991 { 1992 return specializer(kind1, kind2).first && 1993 specializer(kind2, kind1).first; 1994 } 1995 1996 /* Add the specialization "kind" to the sequence of specializations, 1997 * provided there is no equivalent specialization already in there. 1998 */ 1999 void template_class::add_specialization(const Kind &kind) 2000 { 2001 for (const auto &special : class_tuples) 2002 if (equivalent(special, kind)) 2003 return; 2004 class_tuples.emplace_back(kind); 2005 } 2006 2007 /* A type printer that prints the plain interface type, 2008 * without namespace. 2009 */ 2010 struct plain_cpp_type_printer : public cpp_type_printer { 2011 plain_cpp_type_printer() {} 2012 2013 virtual std::string qualified(int arg, const std::string &cpp_type) 2014 const override; 2015 }; 2016 2017 /* Return the qualified form of the given C++ isl type name appearing 2018 * in argument position "arg" (-1 for return type). 2019 * 2020 * For printing the plain type without namespace, no modifications 2021 * are required. 2022 */ 2023 std::string plain_cpp_type_printer::qualified(int arg, 2024 const std::string &cpp_type) const 2025 { 2026 return cpp_type; 2027 } 2028 2029 /* Return a string representation of the plain type "type". 2030 * 2031 * For the plain printer, the argument position is irrelevant, 2032 * so simply pass in -1. 2033 */ 2034 static std::string plain_type(QualType type) 2035 { 2036 return plain_cpp_type_printer().param(-1, type); 2037 } 2038 2039 /* Return a string representation of the plain return type of "method". 2040 */ 2041 static std::string plain_return_type(const Method &method) 2042 { 2043 return plain_type(method.fd->getReturnType()); 2044 } 2045 2046 /* Return that part of the signature "sig" that should match 2047 * the template class specialization for the given method. 2048 * 2049 * In particular, if the method is a regular member method, 2050 * then the instance should match the first argument. 2051 * Otherwise, it should match the return kind. 2052 */ 2053 static const Kind &matching_kind(const Method &method, const Signature &sig) 2054 { 2055 if (method.kind == Method::Kind::member_method) 2056 return sig.args[0]; 2057 else 2058 return sig.ret; 2059 } 2060 2061 /* Is it possible for "template_class" to have the given kind? 2062 * 2063 * If the template class represents an anonymous function, 2064 * then so must the given kind. 2065 * There should also be specialization with the same number of tuple kinds. 2066 */ 2067 static bool has_kind(const template_class &template_class, const Kind &kind) 2068 { 2069 if (template_class.is_anon() && !kind.is_anon()) 2070 return false; 2071 for (const auto &class_tuple : template_class.class_tuples) 2072 if (class_tuple.size() == kind.size()) 2073 return true; 2074 return false; 2075 } 2076 2077 /* Is "return_kind" a possible kind for the return type of "method"? 2078 * 2079 * If the return type is not a template class, 2080 * then "return_kind" should not have any template parameters. 2081 * Otherwise, "return_kind" should be a valid kind for the template class. 2082 */ 2083 bool template_cpp_generator::class_printer::is_return_kind( 2084 const Method &method, const Kind &return_kind) 2085 { 2086 const auto &template_classes = generator.template_classes; 2087 auto return_type = plain_return_type(method); 2088 2089 if (template_classes.count(return_type) == 0) 2090 return return_kind.params().size() == 0; 2091 return has_kind(template_classes.at(return_type), return_kind); 2092 } 2093 2094 /* Is "kind" a placeholder that can be assigned something else 2095 * in a substitution? 2096 * 2097 * Anonymous can only be mapped to itself. This is taken care of 2098 * by assign(). 2099 * Leaf can only be assigned a placeholder, but there is no need 2100 * to handle this specifically since Leaf can still be assigned 2101 * to the placeholder. 2102 */ 2103 static bool assignable(const TupleKindPtr &kind) 2104 { 2105 return kind != Anonymous && kind != Leaf; 2106 } 2107 2108 /* Return a substitution that maps "kind1" to "kind2", if possible. 2109 * Otherwise return an empty substitution. 2110 * 2111 * Check if "kind1" can be assigned anything or 2112 * if "kind1" and "kind2" are identical. 2113 * The latter case handles mapping Anonymous to itself. 2114 */ 2115 static Substitution assign(const TupleKindPtr &kind1, const TupleKindPtr &kind2) 2116 { 2117 Substitution res; 2118 2119 if (assignable(kind1) || kind1 == kind2) 2120 res.emplace(kind1->name, kind2); 2121 return res; 2122 } 2123 2124 /* Return a substitution that first applies "first" and then "second". 2125 * 2126 * The result consists of "second" and of "second" applied to "first". 2127 */ 2128 static Substitution compose(const Substitution &first, 2129 const Substitution &second) 2130 { 2131 Substitution res = second; 2132 2133 for (const auto &kvp : first) 2134 res.emplace(kvp.first, apply(kvp.second, second)); 2135 2136 return res; 2137 } 2138 2139 static Substitution compute_unifier(const TupleKindPtr &kind1, 2140 const TupleKindPtr &kind2); 2141 2142 /* Try and extend "unifier" with a unifier for "kind1" and "kind2". 2143 * Return the resulting unifier if successful. 2144 * Otherwise, return an empty substitution. 2145 * 2146 * First apply "unifier" to "kind1" and "kind2". 2147 * Then compute a unifier for the resulting tuple kinds and 2148 * combine it with "unifier". 2149 */ 2150 static Substitution combine_unifiers(const TupleKindPtr &kind1, 2151 const TupleKindPtr &kind2, const Substitution &unifier) 2152 { 2153 auto k1 = apply(kind1, unifier); 2154 auto k2 = apply(kind2, unifier); 2155 auto u = compute_unifier(k1, k2); 2156 if (u.size() == 0) 2157 return Substitution(); 2158 return compose(unifier, u); 2159 } 2160 2161 /* Try and compute a unifier of "kind1" and "kind2", 2162 * i.e., a substitution that produces the same result when 2163 * applied to both "kind1" and "kind2", 2164 * for the case where both "kind1" and "kind2" are pairs. 2165 * Return this unifier if it was found. 2166 * Return an empty substitution if no unifier can be found. 2167 * 2168 * First compute a unifier for the left parts of the pairs and, 2169 * if successful, combine it with a unifier for the right parts. 2170 */ 2171 static Substitution compute_pair_unifier(const TupleKindPtr &kind1, 2172 const TupleKindPtr &kind2) 2173 { 2174 auto unifier_left = compute_unifier(kind1->left(), kind2->left()); 2175 if (unifier_left.size() == 0) 2176 return Substitution(); 2177 return combine_unifiers(kind1->right(), kind2->right(), unifier_left); 2178 } 2179 2180 /* Try and compute a unifier of "kind1" and "kind2", 2181 * i.e., a substitution that produces the same result when 2182 * applied to both "kind1" and "kind2". 2183 * Return this unifier if it was found. 2184 * Return an empty substitution if no unifier can be found. 2185 * 2186 * If one of the tuple kinds is a pair then assign it 2187 * to the other tuple kind, if possible. 2188 * If neither is a pair, then try and assign one to the other. 2189 * Otherwise, let compute_pair_unifier compute a unifier. 2190 * 2191 * Note that an assignment is added to the unifier even 2192 * if "kind1" and "kind2" are identical. 2193 * This ensures that a successful substitution is never empty. 2194 */ 2195 static Substitution compute_unifier(const TupleKindPtr &kind1, 2196 const TupleKindPtr &kind2) 2197 { 2198 if (kind1->left() && !kind2->left()) 2199 return assign(kind2, kind1); 2200 if (!kind1->left() && kind2->left()) 2201 return assign(kind1, kind2); 2202 if (!kind1->left() && !kind2->left()) { 2203 if (assignable(kind1)) 2204 return assign(kind1, kind2); 2205 else 2206 return assign(kind2, kind1); 2207 } 2208 2209 return compute_pair_unifier(kind1, kind2); 2210 } 2211 2212 /* Try and compute a unifier of "kind1" and "kind2", 2213 * i.e., a substitution that produces the same result when 2214 * applied to both "kind1" and "kind2". 2215 * Return this unifier if it was found. 2216 * Return an empty substitution if no unifier can be found. 2217 * 2218 * Start with an empty substitution and compute a unifier for 2219 * each pair of tuple kinds, combining the results. 2220 * If no combined unifier can be found or 2221 * if the numbers of tuple kinds are different, then return 2222 * an empty substitution. 2223 * This assumes that the number of tuples is greater than zero, 2224 * as otherwise an empty substitution would be returned as well. 2225 */ 2226 static Substitution compute_unifier(const Kind &kind1, const Kind &kind2) 2227 { 2228 Substitution unifier; 2229 2230 if (kind1.size() != kind2.size()) 2231 return Substitution(); 2232 2233 for (size_t i = 0; i < kind1.size(); ++i) 2234 unifier = combine_unifiers(kind1[i], kind2[i], unifier); 2235 2236 return unifier; 2237 } 2238 2239 /* Try and construct a Kind that is a specialization of both "general" and 2240 * "specific", where "specific" is known _not_ to be a specialization 2241 * of "general" and not to contain any Leaf. 2242 * 2243 * First check whether "general" is a specialization of "specific". 2244 * If so, simply return "general". 2245 * Otherwise, rename the placeholders in the two kinds apart and 2246 * try and compute a unifier. 2247 * If this succeeds, then return the result of applying the unifier. 2248 */ 2249 static std::pair<bool, Kind> unify(const Kind &general, const Kind &specific) 2250 { 2251 if (specializer(specific, general).first) { 2252 return { true, general }; 2253 } else { 2254 auto rename = param_renamer(specific.params(), "T"); 2255 auto renamed = specific.apply(rename); 2256 auto unifier = compute_unifier(general, renamed); 2257 2258 if (unifier.size() == 0) 2259 return { false, { } }; 2260 2261 return { true, general.apply(unifier) }; 2262 } 2263 } 2264 2265 /* Try and add a template class specialization corresponding to "kind". 2266 * The new specialization needs to be a specialization of both 2267 * the current specialization and "kind". 2268 * 2269 * The current template class specialization is known not to be a special case 2270 * of "kind". 2271 * 2272 * Try and unify the two kinds and, if this succeeds, add the result 2273 * to this list of template class specializations. 2274 */ 2275 void template_cpp_generator::class_printer::add_specialization( 2276 const Kind &kind) 2277 { 2278 auto maybe_unified = unify(kind, instance.kind); 2279 2280 if (!maybe_unified.first) 2281 return; 2282 instance.template_class.add_specialization(maybe_unified.second); 2283 } 2284 2285 /* Print a declaration or definition of the method "method" 2286 * if the template class specialization matches "match_arg". 2287 * Return true if so. 2288 * "sig" is the complete signature, of which "match_arg" refers 2289 * to the first argument or the return type. 2290 * 2291 * Since "sig" may have parameters with the same names as 2292 * those in instance.kind, rename them apart first. 2293 * 2294 * If the template class specialization is a special case of 2295 * (the renamed) "match_arg" 2296 * then apply the specializer to the complete (renamed) signature, 2297 * check that the return kind is allowed and, if so, 2298 * print the declaration or definition using the specialized signature. 2299 * 2300 * If the template class specialization is not a special case of "match_arg" 2301 * then add a further specialization to the list of specializations 2302 * of the template class. 2303 */ 2304 bool template_cpp_generator::class_printer::print_matching_method( 2305 const Method &method, const Signature &sig, const Kind &match_arg) 2306 { 2307 auto rename = shared_param_renamer(sig, instance.kind); 2308 auto renamed_arg = match_arg.apply(rename); 2309 auto maybe_specializer = specializer(renamed_arg, instance.kind); 2310 if (maybe_specializer.first) { 2311 const auto &specializer = maybe_specializer.second; 2312 auto specialized_sig = sig.apply(rename).apply(specializer); 2313 if (!is_return_kind(method, specialized_sig.ret)) 2314 return false; 2315 2316 print_method_sig(method, specialized_sig, false); 2317 } else { 2318 add_specialization(match_arg); 2319 } 2320 return maybe_specializer.first; 2321 } 2322 2323 /* Is the first argument of "method" of type "isl_ctx *"? 2324 */ 2325 static bool first_arg_is_ctx(const Method &method) 2326 { 2327 return generator::first_arg_is_isl_ctx(method.fd); 2328 } 2329 2330 /* Is the first signature argument set to { Ctx }? 2331 */ 2332 static bool first_kind_is_ctx(const Signature &sig) 2333 { 2334 return sig.args[0].size() > 0 && sig.args[0][0] == Ctx; 2335 } 2336 2337 /* Print a declaration or definition of the member method "method" 2338 * if it matches the signature "sig". 2339 * Return true if so. 2340 * 2341 * First determine the part of the signature that needs to match 2342 * the template class specialization and 2343 * check that it has the same number of template arguments. 2344 * Also check that the number of arguments of the signature 2345 * matches that of the method. 2346 * If there is at least one argument, then check that the first method argument 2347 * is an isl_ctx if and only if the first signature argument is Ctx. 2348 * 2349 * If these tests succeed, proceed with the actual matching. 2350 */ 2351 bool template_cpp_generator::class_printer::print_matching_method( 2352 const Method &method, const Signature &sig) 2353 { 2354 auto match_arg = matching_kind(method, sig); 2355 int n_args = sig.args.size(); 2356 2357 if (match_arg.size() != instance.kind.size()) 2358 return false; 2359 if (n_args != total_params(method)) 2360 return false; 2361 if (n_args > 0 && first_arg_is_ctx(method) != first_kind_is_ctx(sig)) 2362 return false; 2363 2364 return print_matching_method(method, sig, match_arg); 2365 } 2366 2367 /* Print a declaration or definition of the member method "method" 2368 * for each matching signature in "signatures". 2369 * 2370 * If there is no matching signature in "signatures", 2371 * then explicitly delete the method (using a signature based on 2372 * the specialization) so that it is not inherited from the base class. 2373 */ 2374 void template_cpp_generator::class_printer::print_matching_method( 2375 const Method &method, const std::vector<Signature> &signatures) 2376 { 2377 auto any = false; 2378 2379 for (const auto &sig : signatures) 2380 if (print_matching_method(method, sig)) 2381 any = true; 2382 2383 if (!any) 2384 print_method_sig(method, instance_sig(method, instance), true); 2385 } 2386 2387 /* Signatures for "at" methods applied to a multi-expression, 2388 * which make the final tuple anonymous. 2389 */ 2390 static Signature select_set = { { Anonymous }, { { Domain }, { Integer } } }; 2391 static Signature select_map = 2392 { { Domain, Anonymous }, { { Domain, Range }, { Integer } } }; 2393 static std::vector<Signature> at_select = { select_set, select_map }; 2394 2395 /* Signatures for other "at" methods applied to a list, 2396 * which do not modify the tuple kind. 2397 */ 2398 static Signature bin_set_int = { { Domain }, { { Domain }, { Integer } } }; 2399 static Signature bin_map_int = 2400 { { Domain, Range }, { { Domain, Range }, { Integer } } }; 2401 static std::vector<Signature> at_keep = { bin_set_int, bin_map_int }; 2402 2403 /* Print a declaration or definition of the "at" member method "method". 2404 * 2405 * There are two types of methods called "at". 2406 * One type extracts an element from a multi-expression and 2407 * the other extracts an element from a list. 2408 * 2409 * In the first case, the return type is an anonymous function 2410 * while the object type is not. In this case, the return kind 2411 * should have a final Anonymous tuple. 2412 * Otherwise, the return kind should be the same as the object kind. 2413 */ 2414 void template_cpp_generator::class_printer::print_at_method( 2415 const Method &method) 2416 { 2417 auto anon = instance.template_class.is_anon(); 2418 auto return_type = plain_return_type(method); 2419 auto return_class = generator.template_classes.at(return_type); 2420 2421 if (!anon && return_class.is_anon()) 2422 return print_matching_method(method, at_select); 2423 else 2424 return print_matching_method(method, at_keep); 2425 } 2426 2427 /* Does the string "s" contain "sub" as a substring? 2428 */ 2429 static bool contains(const std::string &s, const std::string &sub) 2430 { 2431 return s.find(sub) != std::string::npos; 2432 } 2433 2434 /* Print a declaration or definition of the member method "method", 2435 * if it has a special signature in "special_methods". 2436 * Return true if this is the case. 2437 * 2438 * Check if any special signatures are specified for this method and 2439 * if the class name matches any of those with special signatures. 2440 * If so, pick the one with the best match, i.e., the first match 2441 * since the largest keys appear first. 2442 */ 2443 bool template_cpp_generator::class_printer::print_special_method( 2444 const Method &method, const infix_map_map &special_methods) 2445 { 2446 if (special_methods.count(method.name) == 0) 2447 return false; 2448 2449 for (const auto &kvp : special_methods.at(method.name)) { 2450 if (!contains(instance.template_class.class_name, kvp.first)) 2451 continue; 2452 print_matching_method(method, kvp.second); 2453 return true; 2454 } 2455 2456 return false; 2457 } 2458 2459 /* Print a declaration or definition of the member method "method", 2460 * if it has a special signature specified by special_member_methods. 2461 * Return true if this is the case. 2462 */ 2463 bool template_cpp_generator::class_printer::print_special_member_method( 2464 const Method &method) 2465 { 2466 return print_special_method(method, special_member_methods); 2467 } 2468 2469 /* Print a declaration or definition of the member method "method", 2470 * if it is named after a template class. Return true if this is the case. 2471 */ 2472 bool template_cpp_generator::class_printer::print_type_named_member_method( 2473 const Method &method) 2474 { 2475 if (generator.template_classes.count(method.name) == 0) 2476 return false; 2477 2478 print_matching_method(method, constructor_sig); 2479 2480 return true; 2481 } 2482 2483 /* Print a declaration or definition of the member method "method" 2484 * using a signature associated to method name "name", if there is any. 2485 * Return true if this is the case. 2486 */ 2487 bool template_cpp_generator::class_printer::print_member_method_with_name( 2488 const Method &method, const std::string &name) 2489 { 2490 if (member_methods.count(name) == 0) 2491 return false; 2492 2493 print_matching_method(method, member_methods.at(name)); 2494 return true; 2495 } 2496 2497 /* If "sub" appears inside "str", then remove the first occurrence and 2498 * return the result. Otherwise, simply return "str". 2499 */ 2500 static std::string drop_occurrence(const std::string &str, 2501 const std::string &sub) 2502 { 2503 auto res = str; 2504 auto pos = str.find(sub); 2505 2506 if (pos != std::string::npos) 2507 res.erase(pos, sub.length()); 2508 2509 return res; 2510 } 2511 2512 /* If "sub" appears in "str" next to an underscore, then remove the combination. 2513 * Otherwise, simply return "str". 2514 */ 2515 static std::string drop_underscore_occurrence(const std::string &str, 2516 const std::string &sub) 2517 { 2518 auto res = drop_occurrence(str, sub + "_"); 2519 if (res != str) 2520 return res; 2521 return drop_occurrence(res, std::string("_") + sub); 2522 } 2523 2524 /* Return the name of "method", with the name of the return type, 2525 * along with an underscore, removed, if this combination appears in the name. 2526 * Otherwise, simply return the name. 2527 */ 2528 const std::string name_without_return(const Method &method) 2529 { 2530 auto return_infix = plain_return_type(method); 2531 return drop_underscore_occurrence(method.name, return_infix); 2532 } 2533 2534 /* If this method has a callback, then remove the type 2535 * of the first argument of the callback from the name of the method. 2536 * Otherwise, simply return the name of the method. 2537 */ 2538 const std::string callback_name(const Method &method) 2539 { 2540 if (!method.callback) 2541 return method.name; 2542 2543 auto type = method.callback->getType(); 2544 auto callback = cpp_generator::extract_prototype(type); 2545 auto arg_type = plain_type(callback->getArgType(0)); 2546 return generator::drop_suffix(method.name, "_" + arg_type); 2547 } 2548 2549 /* Print a declaration or definition of the member method "method". 2550 * 2551 * If the method is called "at", then it requires special treatment. 2552 * Otherwise, check if the signature is overridden for this class or 2553 * if the method is named after some other type. 2554 * Otherwise look for an appropriate signature using different variations 2555 * of the method name. First try the method name itself, 2556 * then the method name with the return type removed and 2557 * finally the method name with the callback argument type removed. 2558 */ 2559 void template_cpp_generator::class_printer::print_member_method( 2560 const Method &method) 2561 { 2562 if (method.name == "at") 2563 return print_at_method(method); 2564 if (print_special_member_method(method)) 2565 return; 2566 if (print_type_named_member_method(method)) 2567 return; 2568 if (print_member_method_with_name(method, method.name)) 2569 return; 2570 if (print_member_method_with_name(method, name_without_return(method))) 2571 return; 2572 if (print_member_method_with_name(method, callback_name(method))) 2573 return; 2574 } 2575 2576 /* Print a declaration or definition of "method" based on its type. 2577 */ 2578 void template_cpp_generator::class_printer::print_any_method( 2579 const Method &method) 2580 { 2581 switch (method.kind) { 2582 case Method::Kind::static_method: 2583 print_static_method(method); 2584 break; 2585 case Method::Kind::constructor: 2586 print_constructor(method); 2587 break; 2588 case Method::Kind::member_method: 2589 print_member_method(method); 2590 break; 2591 } 2592 } 2593 2594 /* Print a declaration or definition of "method". 2595 * 2596 * Mark the method as not requiring copies of the arguments. 2597 */ 2598 void template_cpp_generator::class_printer::print_method(const Method &method) 2599 { 2600 print_any_method(NoCopyMethod(method)); 2601 } 2602 2603 /* Print a declaration or definition of "method". 2604 * 2605 * Note that a ConversionMethod is already marked 2606 * as not requiring copies of the arguments. 2607 */ 2608 void template_cpp_generator::class_printer::print_method( 2609 const ConversionMethod &method) 2610 { 2611 print_any_method(method); 2612 } 2613 2614 /* Helper class for printing the declarations for 2615 * template class specializations. 2616 */ 2617 struct template_cpp_generator::class_decl_printer : 2618 public specialization_printer 2619 { 2620 class_decl_printer(std::ostream &os, 2621 template_cpp_generator &generator) : 2622 specialization_printer(os, generator) {} 2623 2624 void print_arg_subclass_constructor(const specialization &instance, 2625 const std::vector<std::string> ¶ms) const; 2626 void print_super_constructor(const specialization &instance) const; 2627 virtual void print_class(const specialization &instance) const override; 2628 }; 2629 2630 /* Print the declaration and definition of a constructor 2631 * for the template class specialization "instance" taking 2632 * an instance with more specialized template arguments, 2633 * where "params" holds the template parameters of "instance". 2634 * It is assumed that there is at least one template parameter as otherwise 2635 * there are no template arguments to be specialized and 2636 * no constructor needs to be printed. 2637 * 2638 * In particular, the constructor takes an object of the same instance where 2639 * for each template parameter, the corresponding template argument 2640 * of the input object is a subclass of the template argument 2641 * of the constructed object. 2642 * 2643 * Pick fresh names for all template parameters and 2644 * add a constructor with these fresh names as extra template parameters and 2645 * a constraint requiring that each of them is a subclass 2646 * of the corresponding class template parameter. 2647 * The plain C++ interface object of the constructed object is initialized with 2648 * the plain C++ interface object of the constructor argument. 2649 */ 2650 void template_cpp_generator::class_decl_printer::print_arg_subclass_constructor( 2651 const specialization &instance, 2652 const std::vector<std::string> ¶ms) const 2653 { 2654 const auto &class_name = instance.class_name(); 2655 auto rename = param_renamer(params, "Arg"); 2656 auto derived = instance.kind.apply(rename); 2657 2658 os << " template "; 2659 os << "<"; 2660 print_pure_template_args(os, derived.params()); 2661 os << ",\n"; 2662 os << " typename std::enable_if<\n"; 2663 for (size_t i = 0; i < params.size(); ++i) { 2664 if (i != 0) 2665 os << " &&\n"; 2666 os << " std::is_base_of<" 2667 << params[i] << ", " 2668 << rename.at(params[i])->params()[0] << ">{}"; 2669 } 2670 os << ",\n"; 2671 os << " bool>::type = true>"; 2672 os << "\n"; 2673 os << " " << class_name << "(const "; 2674 print_bare_template_type(os, class_name, derived); 2675 os << " &obj) : " << instance.base_name() << "(obj) {}\n"; 2676 } 2677 2678 /* Print the declaration and definition of a constructor 2679 * for the template class specialization "instance" taking 2680 * an instance of the base class. 2681 * 2682 * If the instance kind is that of an anonymous set 2683 * (i.e., it has a single tuple that is set to Anonymous), 2684 * then allow the constructor to be called externally. 2685 * This is mostly useful for being able to use isl::val and 2686 * isl::typed::val<Anonymous> interchangeably and similarly for isl::id. 2687 * 2688 * If the instance is of any other kind, then make this constructor private 2689 * to avoid objects of the plain interface being converted automatically. 2690 * Also make sure that it does not apply to any type derived 2691 * from the base class. In particular, this makes sure it does 2692 * not apply to any other specializations of this template class as 2693 * otherwise any conflict in specializations would simply point 2694 * to the private constructor. 2695 * 2696 * A factory method is added to be able to perform the conversion explicitly, 2697 * with an explicit specification of the template arguments. 2698 */ 2699 void template_cpp_generator::class_decl_printer::print_super_constructor( 2700 const specialization &instance) const 2701 { 2702 bool hide = !instance.kind.is_anon_set(); 2703 const auto &base_name = instance.base_name(); 2704 const auto &arg_name = hide ? "base" : base_name; 2705 2706 if (hide) { 2707 os << " private:\n"; 2708 os << " template <typename base,\n"; 2709 os << " typename std::enable_if<\n"; 2710 os << " std::is_same<base, " << base_name 2711 << ">{}, bool>::type = true>\n"; 2712 } 2713 os << " " << instance.class_name() 2714 << "(const " << arg_name << " &obj) : " 2715 << base_name << "(obj) {}\n"; 2716 if (hide) 2717 os << " public:\n"; 2718 os << " static " << instance.class_name() << " from" 2719 << "(const " << base_name << " &obj) {\n"; 2720 os << " return " << instance.class_name() << "(obj);\n"; 2721 os << " }\n"; 2722 } 2723 2724 /* Print a "declaration" for the given template class specialization. 2725 * In particular, print the class definition and the method declarations. 2726 * 2727 * The template parameters are the distinct variable names 2728 * in the instance kind. 2729 * 2730 * Each instance of the template class derives from the corresponding 2731 * plain C++ interface class. 2732 * 2733 * All (other) template classes are made friends of this template class 2734 * to allow them to call the private constructor taking an object 2735 * of the plain interface. 2736 * 2737 * Besides the constructors and methods that forward 2738 * to the corresponding methods in the plain C++ interface class, 2739 * some extra constructors are defined. 2740 * The default zero-argument constructor is useful for declaring 2741 * a variable that only gets assigned a value at a later stage. 2742 * The constructor taking an instance with more specialized 2743 * template arguments is useful for lifting the class hierarchy 2744 * of the template arguments to the template class. 2745 * The constructor taking an instance of the base class 2746 * is useful for (explicitly) constructing a template type 2747 * from a plain type. 2748 */ 2749 void template_cpp_generator::class_decl_printer::print_class( 2750 const specialization &instance) const 2751 { 2752 const auto &class_name = instance.class_name(); 2753 auto params = instance.kind.params(); 2754 2755 os << "\n"; 2756 2757 print_template(os, params); 2758 2759 os << "struct "; 2760 print_bare_template_type(os, class_name, instance.kind); 2761 os << " : public " << instance.base_name() << " {\n"; 2762 2763 generator.print_friends(os); 2764 os << "\n"; 2765 2766 os << " " << class_name << "() = default;\n"; 2767 if (params.size() != 0) 2768 print_arg_subclass_constructor(instance, params); 2769 print_super_constructor(instance); 2770 method_decl_printer(instance, *this).print_all_methods(); 2771 2772 os << "};\n"; 2773 } 2774 2775 /* Helper class for printing the definitions of template class specializations. 2776 */ 2777 struct template_cpp_generator::class_impl_printer : 2778 public specialization_printer 2779 { 2780 class_impl_printer(std::ostream &os, 2781 template_cpp_generator &generator) : 2782 specialization_printer(os, generator) {} 2783 2784 virtual void print_class(const specialization &instance) const override; 2785 }; 2786 2787 /* Print a definition for the given template class specialization. 2788 * 2789 * In particular, print definitions 2790 * for the constructors and methods that forward 2791 * to the corresponding methods in the plain C++ interface class. 2792 * The extra constructors declared in the class definition 2793 * are defined inline. 2794 */ 2795 void template_cpp_generator::class_impl_printer::print_class( 2796 const specialization &instance) const 2797 { 2798 method_impl_printer(instance, *this).print_all_methods(); 2799 } 2800 2801 /* Generate a templated cpp interface 2802 * based on the extracted types and functions. 2803 * 2804 * First print forward declarations for all template classes, 2805 * then the declarations of the classes, and at the end all 2806 * method implementations. 2807 */ 2808 void template_cpp_generator::generate() 2809 { 2810 ostream &os = std::cout; 2811 2812 os << "\n"; 2813 2814 print_forward_declarations(os); 2815 class_decl_printer(os, *this).print_classes(); 2816 class_impl_printer(os, *this).print_classes(); 2817 } 2818