add exported isl_space_wrapped_reverse
[isl.git] / interface / template_cpp.cc
blobde4762b78148500ef458ae0846aad57ccd874fe9
1 /*
2 * Copyright 2020 Cerebras Systems. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include <ctype.h>
36 #include <algorithm>
37 #include <iostream>
38 #include <set>
39 #include <sstream>
40 #include <string>
41 #include <unordered_map>
42 #include <unordered_set>
44 #include "template_cpp.h"
45 #include "isl_config.h"
47 /* The textual representation of this tuple kind.
49 * By default, the textual representation is just the name.
51 std::string TupleKind::to_string() const
53 return name;
56 /* Return the parameters of this tuple kind.
58 * By default, there are no parameters.
60 std::vector<std::string> TupleKind::params() const
62 return { };
65 /* Apply the substitution "subs" to this tuple kind and return the result.
66 * "self" is a shared pointer to this.
68 * If the name of this tuple kind appears in the substitution,
69 * then return the corresponding tuple kind pointer.
70 * Otherwise, return "self".
72 TupleKindPtr TupleKind::apply(const Substitution &subs,
73 const TupleKindPtr &self) const
75 if (subs.count(name) != 0)
76 return subs.at(name);
77 return self;
80 /* Apply the substitution "subs" to "tuple" and return the result.
82 static TupleKindPtr apply(const TupleKindPtr tuple, const Substitution &subs)
84 return tuple->apply(subs, tuple);
87 /* Return the left child of this tuple kind.
89 * Since this is not a pair, there is no left child.
91 TupleKindPtr TupleKind::left() const
93 return TupleKindPtr();
96 /* Return the right child of this tuple kind.
98 * Since this is not a pair, there is no right child.
100 TupleKindPtr TupleKind::right() const
102 return TupleKindPtr();
105 /* Helper class used to construct a pointer to a tuple kind
106 * that refers to a non-template type.
108 struct Fixed {
111 /* Construct a pointer to a tuple kind that refers to a non-template type.
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.
116 TupleKindPtr::TupleKindPtr(Fixed) : Base(std::make_shared<TupleKind>(""))
120 /* Tuple pointers for non-template types.
122 static TupleKindPtr Ctx{Fixed()};
123 static TupleKindPtr Integer{Fixed()};
124 static TupleKindPtr Str{Fixed()};
125 static TupleKindPtr Res{Fixed()};
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.
133 static TupleKindPtr Anonymous("Anonymous");
134 static TupleKindPtr Leaf("Leaf");
136 /* Placeholder tuple pointers that refer to (part of) the domain or range.
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");
145 /* A representation of a proper tuple kind that is used as a template
146 * parameter or a template argument.
148 struct ProperTupleKind : public TupleKind {
149 ProperTupleKind(const std::string &name) : TupleKind(name) {}
151 virtual std::vector<std::string> params() const override;
154 /* Return the parameters of this tuple kind.
156 * Return the name of this tuple kind, unless it is the special Anonymous
157 * predefined template argument.
159 std::vector<std::string> ProperTupleKind::params() const
161 if (Anonymous.get() == this)
162 return { };
163 return { name };
166 /* Construct a pointer to a tuple kind that refers
167 * to a proper tuple kind with the given name.
169 TupleKindPtr::TupleKindPtr(const std::string &name) :
170 Base(std::make_shared<ProperTupleKind>(name))
174 /* A tuple kind that represents an anonymous pair of nested tuple kinds.
176 struct Pair : public TupleKind {
177 Pair(const TupleKindPtr &tuple1, const TupleKindPtr &tuple2) :
178 TupleKind(""), tuple1(tuple1), tuple2(tuple2) {}
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;
187 const TupleKindPtr tuple1;
188 const TupleKindPtr tuple2;
191 /* The textual representation of this tuple kind.
193 * The textual representation of a pair is of the form "pair<tuple1, tuple2>".
195 std::string Pair::to_string() const
197 return std::string("pair<") + tuple1->to_string() + ", " +
198 tuple2->to_string() + ">";
201 /* Add the elements of "vec2" that do not already appear in "vec1"
202 * at the end of "vec1".
204 * The two vectors are assumed not to have any repeated elements.
205 * The updated vector will then also not have repeated elements.
207 static void combine(std::vector<std::string> &vec1,
208 const std::vector<std::string> &vec2)
210 for (const auto &s : vec2)
211 if (std::find(vec1.begin(), vec1.end(), s) == vec1.end())
212 vec1.emplace_back(s);
215 /* Return the parameters of this tuple kind.
217 * Combine the parameters of the two nested tuple kinds.
219 std::vector<std::string> Pair::params() const
221 auto names1 = tuple1->params();
222 auto names2 = tuple2->params();
224 combine(names1, names2);
226 return names1;
229 /* Apply the substitution "subs" to this tuple kind and return the result.
230 * "self" is a shared pointer to this.
232 * Construct a new tuple kind consisting of the result of applying
233 * the substitution to the two nested tuple kinds.
235 TupleKindPtr Pair::apply(const Substitution &subs, const TupleKindPtr &self)
236 const
238 return TupleKindPtr(::apply(tuple1, subs), ::apply(tuple2, subs));
241 /* Return the left child of this tuple kind.
243 TupleKindPtr Pair::left() const
245 return tuple1;
248 /* Return the right child of this tuple kind.
250 TupleKindPtr Pair::right() const
252 return tuple2;
255 /* Construct a pointer to a tuple kind that refers
256 * to the given pair of nested tuple kinds.
258 TupleKindPtr::TupleKindPtr(const TupleKindPtr &left, const TupleKindPtr &right)
259 : Base(std::make_shared<Pair>(left, right))
263 /* Is this a kind of object representing an anonymous function?
265 bool Kind::is_anon() const
267 return size() != 0 && back() == Anonymous;
270 /* Is this a kind of object with a single tuple?
272 bool Kind::is_set() const
274 return size() == 1;
277 /* Is this a kind of object with a single, anonymous tuple?
279 bool Kind::is_anon_set() const
281 return is_set() && is_anon();
284 /* Return the parameters of this kind.
286 * Collect the parameters of the tuple kinds in the sequence.
288 std::vector<std::string> Kind::params() const
290 std::vector<std::string> params;
292 for (const auto &tuple : *this)
293 combine(params, tuple->params());
295 return params;
298 /* Apply the substitution "subs" to this kind and return the result.
300 * Apply the substitution to each of the tuple kinds in the sequence.
302 Kind Kind::apply(const Substitution &subs) const
304 Kind applied;
306 for (const auto &tuple : *this)
307 applied.emplace_back(::apply(tuple, subs));
309 return applied;
312 /* A signature of a method in terms of kinds,
313 * consisting of a return kind and a sequence of argument kinds.
315 struct Signature {
316 Kind ret;
317 std::vector<Kind> args;
319 std::vector<std::string> params() const;
320 Signature apply(const Substitution &match) const;
323 /* Return the parameters of this signature.
325 * Collect the parameters of the argument kinds and the return kind.
327 std::vector<std::string> Signature::params() const
329 std::vector<std::string> params;
331 for (const auto &arg : args)
332 combine(params, arg.params());
333 combine(params, ret.params());
335 return params;
338 /* Apply the substitution "subs" to this kind and return the result.
340 * Apply the substitution to the argument kinds and the return kind.
342 Signature Signature::apply(const Substitution &subs) const
344 std::vector<Kind> applied_args;
346 for (const auto &arg : args)
347 applied_args.emplace_back(arg.apply(subs));
349 return { ret.apply(subs), applied_args };
352 /* Return a renaming substitution that renames the elements of "params"
353 * using names starting with "prefix".
355 static Substitution param_renamer(const std::vector<std::string> &params,
356 const std::string &prefix)
358 Substitution renamer;
359 int n = 0;
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);
366 if (name == Leaf->name)
367 generator::die("Leaf cannot be renamed");
369 renamer.emplace(name, arg);
372 return renamer;
375 /* Does the vector "v" contain the element "el"?
377 static bool contains(const std::vector<std::string> &v, const std::string &el)
379 return find(v.begin(), v.end(), el) != v.end();
383 /* Return the shared elements of "v1" and "v2", preserving the order
384 * of those elements in "v1".
386 static std::vector<std::string> intersect(const std::vector<std::string> &v1,
387 const std::vector<std::string> &v2)
389 std::vector<std::string> intersection;
391 for (const auto &el : v1)
392 if (contains(v2, el))
393 intersection.push_back(el);
395 return intersection;
398 /* Return a renaming substitution that renames
399 * any parameters that appears in both "sig" and "kind".
401 static Substitution shared_param_renamer(const Signature &sig, const Kind &kind)
403 return param_renamer(intersect(sig.params(), kind.params()), "Arg");
406 /* Signatures for unary operations.
407 * Functions have at least one tuple.
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 };
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.
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 static Signature bin_map_domain_wrapped_domain =
433 { { { Domain, Domain2 }, Range },
434 { { { Domain, Domain2 }, Range }, { Domain } } };
435 static Signature bin_map_range_wrapped_domain =
436 { { Domain, { Range, Range2 } },
437 { { Domain, { Range, Range2 } }, { Range } } };
439 /* Signatures for binary operations, where the second argument
440 * is an identifier (with an anonymous tuple).
442 static Signature bin_params_anon = { { }, { { }, { Anonymous } } };
443 static Signature bin_set_anon = { { Domain }, { { Domain }, { Anonymous } } };
444 static Signature bin_map_anon =
445 { { Domain, Range }, { { Domain, Range }, { Anonymous } } };
446 static std::vector<Signature> bin_op_anon =
447 { bin_params_anon, bin_set_anon, bin_map_anon };
449 /* Signatures for ternary operations, where the last two arguments are integers.
451 static Signature ter_params_int_int =
452 { { }, { { }, { Integer }, { Integer } } };
453 static Signature ter_set_int_int =
454 { { Domain }, { { Domain }, { Integer }, { Integer } } };
455 static Signature ter_map_int_int =
456 { { Domain, Range }, { { Domain, Range }, { Integer }, { Integer } } };
457 static std::vector<Signature> ter_int_int =
458 { ter_params_int_int, ter_set_int_int, ter_map_int_int };
460 /* Signatures for ternary operations.
461 * Functions have at least one tuple.
463 static Signature ter_set =
464 { { Domain }, { { Domain }, { Domain }, { Domain } } };
465 static Signature ter_map =
466 { { Domain, Range },
467 { { Domain, Range }, { Domain, Range }, { Domain, Range } } };
468 static std::vector<Signature> fn_ter_op = { ter_set, ter_map };
470 /* Signatures for naming a leaf tuple using an identifier (with an anonymous
471 * tuple).
473 static Signature update_set = { { Domain2 }, { { Leaf }, { Anonymous } } };
474 static Signature update_domain =
475 { { Domain2, Range }, { { Leaf, Range }, { Anonymous } } };
476 static Signature update_range =
477 { { Domain, Range2 }, { { Domain, Leaf }, { Anonymous } } };
479 /* Signatures for the functions "min" and "max", which can be either
480 * unary or binary operations.
482 static std::vector<Signature> min_max = { un_set, bin_set, un_map, bin_map };
484 /* Signatures for adding an unnamed tuple to an object with zero or one tuple.
486 static Signature to_set = { { Domain }, { { }, { Integer } } };
487 static Signature add_range = { { Domain, Range }, { { Domain }, { Integer } } };
488 /* Signatures for adding a named tuple to an object with zero or one tuple.
490 static Signature to_set_named =
491 { { Domain }, { { }, { Anonymous }, { Integer } } };
492 static Signature add_range_named =
493 { { Domain, Range }, { { Domain }, { Anonymous }, { Integer } } };
495 /* Signatures for methods applying a map to a set, a function or
496 * part of a map.
498 static Signature set_forward = { { Range }, { { Domain }, { Domain, Range } } };
499 static Signature domain_forward =
500 { { Domain2, Range }, { { Domain, Range }, { Domain, Domain2 } } };
501 static Signature range_forward =
502 { { Domain, Range2 }, { { Domain, Range }, { Range, Range2 } } };
504 /* Signatures for methods plugging in a function into a set, a function or
505 * part of a map.
507 static Signature set_backward =
508 { { Domain2 }, { { Domain }, { Domain2, Domain } } };
509 static Signature domain_backward =
510 { { Domain2, Range }, { { Domain, Range }, { Domain2, Domain } } };
511 static Signature range_backward =
512 { { Domain, Range2 }, { { Domain, Range }, { Range2, Range } } };
513 static Signature domain_wrapped_domain_backward =
514 { { { Domain3, Domain2 }, Range },
515 { { { Domain, Domain2 }, Range }, { Domain3, Domain } } };
517 /* Signatures for methods binding a set, a function,
518 * or (part of) a map to parameters or an object of the same kind.
520 static Signature bind_set = { { }, { { Domain }, { Domain } } };
521 static Signature bind_domain = { { Range }, { { Domain, Range }, { Domain } } };
522 static Signature bind_range = { { Domain }, { { Domain, Range }, { Range } } };
523 static Signature bind_domain_wrapped_domain =
524 { { Range2, Range }, { { { Domain2, Range2 }, Range }, { Domain2 } } };
526 /* Signatures for functions that take a callback accepting
527 * objects of the same kind (but a different type).
529 * The return and argument kinds of the callback appear
530 * at the position of the callback.
532 static Signature each_params = { { Res }, { { }, { Res }, { } } };
533 static Signature each_set = { { Res }, { { Domain }, { Res }, { Domain } } };
534 static Signature each_map =
535 { { Res }, { { Domain, Range }, { Res }, { Domain, Range } } };
536 static std::vector<Signature> each = { each_params, each_set, each_map };
538 /* Signatures for isl_*_list_foreach_scc.
540 * The first callback takes two elements with the same tuple kinds.
541 * The second callback takes a list with the same tuple kinds.
543 static Signature each_scc_params =
544 { { Res }, { { }, { Res }, { }, { }, { Res }, { } } };
545 static Signature each_scc_set =
546 { { Res }, { { Domain },
547 { Res }, { Domain }, { Domain },
548 { Res }, { Domain } } };
549 static Signature each_scc_map =
550 { { Res }, { { Domain, Range },
551 { Res }, { Domain, Range }, { Domain, Range },
552 { Res }, { Domain, Range } } };
553 static std::vector<Signature> each_scc =
554 { each_scc_params, each_scc_set, each_scc_map };
556 /* Signature for creating a map from a range,
557 * where the domain is given by an extra argument.
559 static Signature map_from_range_and_domain =
560 { { Domain, Range }, { { Range }, { Domain } } };
563 /* Signatures for creating a set from a parameter set or
564 * a map from a domain,
565 * where the domain/range is given by an extra argument.
567 static Signature set_from_params = { { Domain }, { { }, { Domain } } };
568 static Signature map_from_domain_and_range =
569 { { Domain, Range }, { { Domain }, { Range } } };
570 static std::vector<Signature> from_domain =
571 { set_from_params, map_from_domain_and_range };
573 /* Signatures for creating an anonymous set from a parameter set
574 * or a map from a domain, where the range is anonymous.
576 static Signature anonymous_set_from_params = { { Anonymous }, { { } } };
577 static Signature anonymous_map_from_domain =
578 { { Domain, Anonymous }, { { Domain } } };
579 static std::vector<Signature> anonymous_from_domain =
580 { anonymous_set_from_params, anonymous_map_from_domain };
582 /* Signatures for creating an anonymous function from a domain,
583 * where the second argument is an identifier (with an anonymous tuple).
585 static Signature anonymous_set_from_params_bin_anon =
586 { { Anonymous }, { { }, { Anonymous } } };
587 static Signature anonymous_map_from_domain_bin_anon =
588 { { Domain, Anonymous }, { { Domain }, { Anonymous } } };
589 static std::vector<Signature> anonymous_from_domain_bin_anon = {
590 anonymous_set_from_params_bin_anon,
591 anonymous_map_from_domain_bin_anon
594 /* Signature for creating a map from a domain,
595 * where the range tuple is equal to the domain tuple.
597 static Signature set_to_map = { { Domain, Domain }, { { Domain } } };
599 /* Signatures for obtaining the range or the domain of a map.
600 * In case of a transformation, the domain and range are the same.
602 static Signature domain = { { Domain }, { { Domain, Range } } };
603 static Signature range = { { Range }, { { Domain, Range } } };
604 static Signature transformation_domain = { { Domain }, { { Domain, Domain } } };
606 /* Signatures for obtaining the parameter domain of a set or map.
608 static Signature set_params = { { }, { { Domain } } };
609 static Signature map_params = { { }, { { Domain, Range } } };
611 /* Signatures for obtaining the domain of a function.
613 static std::vector<Signature> fn_domain = { domain, set_params };
615 /* Signatures for interchanging (wrapped) domain and range.
617 static Signature set_reverse =
618 { { { Range, Domain } }, { { { Domain, Range } } } };
619 static Signature map_reverse = { { Range, Domain }, { { Domain, Range } } };
620 static Signature map_domain_reverse =
621 { { { Domain2, Domain }, Range }, { { { Domain, Domain2 }, Range } } };
622 static Signature map_range_reverse =
623 { { Domain, { Range2, Range } }, { { Domain, { Range, Range2 } } } };
625 /* Signatures for constructing products.
627 static Signature set_product =
628 { { { Domain, Range } }, { { Domain }, { Range } } };
629 static Signature map_product =
630 { { { Domain, Domain2 }, { Range, Range2 } },
631 { { Domain, Range }, { Domain2, Range2 } } };
632 static Signature domain_product =
633 { { { Domain, Domain2 }, Range },
634 { { Domain, Range }, { Domain2, Range } } };
635 static Signature range_product =
636 { { Domain, { Range, Range2 } },
637 { { Domain, Range }, { Domain, Range2 } } };
639 /* Signatures for obtaining factors from a product.
641 static Signature domain_factor_domain =
642 { { Domain, Range }, { { { Domain, Domain2 }, Range } } };
643 static Signature domain_factor_range =
644 { { Domain2, Range }, { { { Domain, Domain2 }, Range } } };
645 static Signature range_factor_domain =
646 { { Domain, Range }, { { Domain, { Range, Range2 } } } };
647 static Signature range_factor_range =
648 { { Domain, Range2 }, { { Domain, { Range, Range2 } } } };
650 /* Signatures for (un)currying.
652 static Signature curry =
653 { { Domain, { Range, Range2 } },
654 { { { Domain, Range }, Range2 } } };
655 static Signature uncurry =
656 { { { Domain, Range }, Range2 },
657 { { Domain, { Range, Range2 } } } };
659 /* Signatures for (un)wrapping.
661 static Signature wrap = { { { Domain, Range } }, { { Domain, Range } } };
662 static Signature unwrap = { { Domain, Range }, { { { Domain, Range } } } };
664 /* Signatures for constructing objects that map to the domain or range
665 * of a map.
667 static Signature domain_map =
668 { { { Domain, Range }, Domain }, { { Domain, Range } } };
669 static Signature range_map =
670 { { { Domain, Range }, Range }, { { Domain, Range } } };
672 /* Signature for applying a comparison between the domain and the range
673 * of a map.
675 static Signature map_cmp =
676 { { Domain, Domain }, { { Domain, Domain }, { Domain, Range } } };
678 /* Signature for creating a set corresponding to the domains
679 * of two functions.
681 static Signature set_join =
682 { { Domain }, { { Domain, Range }, { Domain, Range } } };
684 /* Signatures for flattening the domain or range of a map,
685 * replacing it with either an anonymous tuple or a tuple with a given name.
687 static Signature anonymize_nested_domain =
688 { { Anonymous, Range2 }, { { { Domain, Range }, Range2 } } };
689 static Signature anonymize_nested_range =
690 { { Domain, Anonymous }, { { Domain, { Range, Range2 } } } };
691 static Signature replace_nested_domain =
692 { { Domain2, Range2 },
693 { { { Domain, Range }, Range2 }, { Anonymous} } };
694 static Signature replace_nested_range =
695 { { Domain, Range3 }, { { Domain, { Range, Range2 } }, { Anonymous} } };
696 static std::vector<Signature> flatten_domain =
697 { anonymize_nested_domain, replace_nested_domain };
698 static std::vector<Signature> flatten_range =
699 { anonymize_nested_range, replace_nested_range };
701 /* Signatures for "set_at" methods.
703 static Signature set_at_set =
704 { { Domain }, { { Domain }, { Integer }, { Anonymous } } };
705 static Signature set_at_map =
706 { { Domain, Range },
707 { { Domain, Range }, { Integer }, { Domain, Anonymous } } };
708 static std::vector<Signature> set_at = { set_at_set, set_at_map };
710 /* Signatures for "list" methods, extracting a list
711 * from a multi-expression.
713 static Signature to_list_set = { { Anonymous }, { { Domain } } };
714 static Signature to_list_map = { { Domain, Anonymous }, { { Domain, Range } } };
716 /* Signatures for functions constructing an object from only an isl::ctx.
718 static Signature ctx_params = { { }, { { Ctx } } };
719 static Signature ctx_set = { { Domain }, { { Ctx } } };
720 static Signature ctx_map = { { Domain, Range }, { { Ctx } } };
722 /* Helper structure for sorting the keys of static_methods and
723 * special_member_methods such that the larger keys appear first.
724 * In particular, a key should appear before any key that appears
725 * as a substring in the key.
726 * Note that this sorting is currently only important
727 * for special_member_methods.
729 struct larger_infix {
730 bool operator()(const std::string &x, const std::string &y) const {
731 if (x.length() > y. length())
732 return true;
733 return x < y;
737 /* A map from part of a type name to a sequence of signatures.
739 typedef std::map<std::string, std::vector<Signature>, larger_infix> infix_map;
741 /* A map from a method name to a map from part of a type name
742 * to a sequence of signatures.
744 typedef std::map<std::string, infix_map> infix_map_map;
746 /* Signatures for static methods.
748 * The "unit" static method is only available in a 0-tuple space.
750 * The "empty" static method creates union objects with the relevant
751 * number of tuples.
753 * The "universe" static methods create objects from the corresponding spaces.
755 static const infix_map_map static_methods {
756 { "unit",
757 { { "space", { ctx_params } } }
759 { "empty",
761 { "union_set", { ctx_params, ctx_set } },
762 { "union_map", { ctx_map } },
763 { "union_pw_multi_aff", { ctx_set, ctx_map } },
766 { "universe",
768 { "set", { un_params, un_set } },
769 { "map", { un_map } },
774 /* Signatures for unary operations that either take something in a set space
775 * and return something in the same space or take something in a map space
776 * and return something in the range of that space.
778 static std::vector<Signature> range_op = { un_set, range };
780 /* Signatures for binary operations where the second argument
781 * is a (multi-)value.
783 static std::vector<Signature> bin_val = { bin_set, bin_map_range };
785 /* The (default) signatures for methods with a given name.
786 * Some of these are overridden by special_member_methods.
788 static const std::unordered_map<std::string, std::vector<Signature>>
789 member_methods {
790 { "add", bin_op },
791 { "add_constant", bin_val },
792 { "add_named_tuple", { to_set_named, add_range_named } },
793 { "add_param", bin_op_anon },
794 { "add_unnamed_tuple", { to_set, add_range } },
795 { "apply", { set_forward, range_forward } },
796 { "apply_domain", { domain_forward } },
797 { "apply_range", { range_forward } },
798 { "as", un_op },
799 { "as_map", { un_map } },
800 { "as_union_map", { un_map } },
801 { "as_set", { un_set } },
802 { "bind", { bind_set, bind_range } },
803 { "bind_domain", { bind_domain } },
804 { "bind_range", { bind_range } },
805 { "bind_domain_wrapped_domain",
806 { bind_domain_wrapped_domain } },
807 { "ceil", fn_un_op },
808 { "coalesce", un_op },
809 { "cond", fn_ter_op },
810 { "constant", range_op },
811 { "curry", { curry } },
812 { "deltas", { transformation_domain } },
813 { "detect_equalities", un_op },
814 { "domain", fn_domain },
815 { "domain_factor_domain",
816 { domain_factor_domain } },
817 { "domain_factor_range",
818 { domain_factor_range } },
819 { "domain_map", { domain_map } },
820 { "domain_product", { domain_product } },
821 { "domain_reverse", { map_domain_reverse } },
822 { "drop", ter_int_int },
823 { "drop_all_params", un_op },
824 { "drop_unused_params", un_op },
825 { "eq_at", { map_cmp } },
826 { "every", each },
827 { "extract", bin_op },
828 { "flatten_domain", flatten_domain },
829 { "flatten_range", flatten_range },
830 { "floor", fn_un_op },
831 { "foreach", each },
832 { "foreach_scc", each_scc },
833 { "ge_set", { set_join } },
834 { "gt_set", { set_join } },
835 { "gist", bin_op },
836 { "gist_domain", { bin_map_domain } },
837 { "gist_params", { bin_set_params, bin_map_params } },
838 { "identity", { un_map, set_to_map } },
839 { "identity_on_domain", { set_to_map } },
840 { "indicator_function", anonymous_from_domain },
841 { "insert_domain", { map_from_range_and_domain } },
842 { "intersect", bin_op },
843 { "intersect_params", { bin_set_params, bin_map_params } },
844 { "intersect_domain", { bin_map_domain } },
845 { "intersect_domain_wrapped_domain",
846 { bin_map_domain_wrapped_domain } },
847 { "intersect_range", { bin_map_range } },
848 { "intersect_range_wrapped_domain",
849 { bin_map_range_wrapped_domain } },
850 { "lattice_tile", { un_set } },
851 { "le_set", { set_join } },
852 { "lt_set", { set_join } },
853 { "lex_le_at", { map_cmp } },
854 { "lex_lt_at", { map_cmp } },
855 { "lex_ge_at", { map_cmp } },
856 { "lex_gt_at", { map_cmp } },
857 { "lexmin", fn_un_op },
858 { "lexmax", fn_un_op },
859 { "list", { to_list_set, to_list_map } },
860 { "lower_bound", fn_bin_op },
861 { "map_from_set", { set_to_map } },
862 { "max", min_max },
863 { "max_val", range_op },
864 { "max_multi_val", range_op },
865 { "min", min_max },
866 { "min_val", range_op },
867 { "min_multi_val", range_op },
868 { "mod", bin_val },
869 { "on_domain", from_domain },
870 { "neg", fn_un_op },
871 { "offset", fn_un_op },
872 { "param_on_domain", anonymous_from_domain_bin_anon },
873 { "params", { set_params, map_params } },
874 { "plain_multi_val_if_fixed",
875 { un_set } },
876 { "preimage", { set_backward } },
877 { "preimage_domain", { domain_backward } },
878 { "preimage_domain_wrapped_domain",
879 { domain_wrapped_domain_backward } },
880 { "preimage_range", { range_backward } },
881 { "product", { set_product, map_product } },
882 { "project_out_param", bin_op_anon },
883 { "project_out_all_params",
884 un_op },
885 { "pullback", { domain_backward, bind_domain } },
886 { "range", { range } },
887 { "range_factor_domain",
888 { range_factor_domain } },
889 { "range_factor_range", { range_factor_range } },
890 { "range_lattice_tile", { un_map } },
891 { "range_map", { range_map } },
892 { "range_product", { range_product } },
893 { "range_reverse", { map_range_reverse } },
894 { "range_simple_fixed_box_hull",
895 { un_map } },
896 { "reverse", { map_reverse } },
897 { "scale", bin_val },
898 { "scale_down", bin_val },
899 { "set_at", set_at },
900 { "set_domain_tuple", { update_domain } },
901 { "set_range_tuple", { update_set, update_range } },
902 { "simple_fixed_box_hull",
903 { un_set } },
904 { "sub", fn_bin_op },
905 { "subtract", bin_op },
906 { "subtract_domain", { bin_map_domain } },
907 { "subtract_range", { bin_map_range } },
908 { "translation", { set_to_map } },
909 { "to", un_op },
910 { "unbind_params", { set_from_params } },
911 { "unbind_params_insert_domain",
912 { map_from_range_and_domain } },
913 { "uncurry", { uncurry } },
914 { "union_add", fn_bin_op },
915 { "unite", bin_op },
916 { "universe", un_op },
917 { "unwrap", { unwrap } },
918 { "upper_bound", fn_bin_op },
919 { "wrap", { wrap } },
920 { "wrapped_reverse", { set_reverse } },
921 { "zero", fn_un_op },
922 { "zero_on_domain", { anonymous_map_from_domain } },
925 /* Signatures for methods of types containing a given substring
926 * that override the default signatures, where larger substrings
927 * appear first.
929 * In particular, "gist" is usually a regular binary operation,
930 * but for any type derived from "aff", the argument refers
931 * to the domain of the function.
933 * The "size" method can usually simply be inherited from
934 * the corresponding plain C++ type, but for a "fixed_box",
935 * the size lives in the space of the box or its range.
937 * The "space" method is usually a regular unary operation
938 * that returns the single space of the elements in the object,
939 * with the same number of tuples.
940 * However, a "union" object may contain elements from many spaces and
941 * therefore its space only refers to the symbolic constants and
942 * has zero tuples, except if it is also a "multi_union" object,
943 * in which case it has a fixed range space and the space of the object
944 * has a single tuple.
945 * Note that since "space' is also the name of a template class,
946 * the default space method is handled by print_type_named_member_method.
948 static const infix_map_map special_member_methods {
949 { "gist",
950 { { "aff", { bin_set_params, bin_map_domain } } }
952 { "size",
953 { { "fixed_box", range_op } },
955 { "space",
957 { "multi_union", range_op },
958 { "union", { un_params, set_params, map_params } },
963 /* Generic kinds for objects with zero, one or two tuples,
964 * the last of which may be anonymous.
966 static Kind params{};
967 static Kind set_type{ Domain };
968 static Kind set_anon{ Anonymous };
969 static Kind map_type{ Domain, Range };
970 static Kind map_anon{ Domain, Anonymous };
972 /* The initial sequence of specialization kinds for base types.
973 * The specialization kinds for other types are derived
974 * from the corresponding base types.
976 * In particular, this sequence specifies how many tuples
977 * a given type can have and whether it is anonymous.
979 * "space" can have any number of tuples.
980 * "set" and "point" can have zero or one tuple.
981 * "map" can only have two tuples.
982 * "aff" can have one or two tuples, the last of which is anonymous.
983 * "fixed_box" can represent a (proper) set) or a map.
984 * "val" and "id" are treated as anonymous sets so that
985 * they can form the basis of "multi_val" and "multi_id".
987 static const std::unordered_map<std::string, std::vector<Kind>> base_kinds {
988 { "space", { params, set_type, map_type } },
989 { "set", { params, set_type } },
990 { "point", { params, set_type } },
991 { "map", { map_type } },
992 { "aff", { set_anon, map_anon } },
993 { "fixed_box", { set_type, map_type } },
994 { "val", { set_anon } },
995 { "id", { set_anon } },
998 /* Prefixes introduced by type constructors.
1000 static const std::unordered_set<std::string> type_prefixes {
1001 "basic",
1002 "multi",
1003 "pw",
1004 "union",
1007 /* If "type" has a "_list" suffix, then return "type" with this suffix removed.
1008 * Otherwise, simply return "type".
1010 static std::string drop_list(const std::string &type)
1012 size_t pos = type.rfind('_');
1014 if (pos == std::string::npos)
1015 return type;
1016 if (type.substr(pos + 1) == "list")
1017 return type.substr(0, pos);
1018 return type;
1021 /* Given the name of a plain C++ type, return the base type
1022 * from which it was derived using type constructors.
1024 * In particular, drop any "list" suffix and
1025 * drop any prefixes from type_prefixes, stopping
1026 * as soon as a base type is found for which kinds have been registered
1027 * in base_kinds.
1029 static std::string base_type(const std::string &type)
1031 auto base = type;
1032 size_t pos;
1034 base = drop_list(base);
1035 while (base_kinds.count(base) == 0 &&
1036 (pos = base.find('_')) != std::string::npos &&
1037 type_prefixes.count(base.substr(0, pos)) != 0) {
1038 base = base.substr(pos + 1);
1041 return base;
1044 /* A mapping from anonymous kinds to named kinds.
1046 static std::map<Kind, Kind> anon_to_named {
1047 { set_anon, set_type },
1048 { map_anon, map_type },
1051 /* Given a sequence of anonymous kinds, replace them
1052 * by the corresponding named kinds.
1054 static std::vector<Kind> add_name(const std::vector<Kind> &tuples)
1056 std::vector<Kind> named;
1058 for (const auto &tuple : tuples)
1059 named.emplace_back(anon_to_named.at(tuple));
1061 return named;
1064 /* Look up the (initial) specializations of the class called "name".
1065 * If no specializations have been defined, then return an empty vector.
1067 * Start from the initial specializations of the corresponding base type.
1068 * If this template class is a multi-expression, then it was derived
1069 * from an anonymous function type. Replace the final Anonymous
1070 * tuple kind by a placeholder in this case.
1072 static std::vector<Kind> lookup_class_tuples(const std::string &name)
1074 std::string base = base_type(name);
1076 if (base_kinds.count(base) == 0)
1077 return { };
1078 if (name.find("multi_") != std::string::npos)
1079 return add_name(base_kinds.at(base));
1080 return base_kinds.at(base);
1083 /* Add a template class called "name", of which the methods are described
1084 * by "clazz" and the initial specializations by "class_tuples".
1086 void template_cpp_generator::add_template_class(const isl_class &clazz,
1087 const std::string &name, const std::vector<Kind> &class_tuples)
1089 auto isl_namespace = cpp_type_printer().isl_namespace();
1090 auto super = isl_namespace + name;
1092 template_classes.emplace(name,
1093 template_class{name, super, clazz, class_tuples});
1096 /* Construct a templated C++ bindings generator from
1097 * the exported types and functions and the set of all declared functions.
1099 * On top of the initialization of the shared parts
1100 * of C++ bindings generators, add a template class
1101 * for each plain C++ class for which template kinds
1102 * have been defined.
1103 * In particular, determine the base type from which the plain C++ class
1104 * was derived using type constructors and check if any template kinds
1105 * have been registered for this base type.
1107 template_cpp_generator::template_cpp_generator(clang::SourceManager &SM,
1108 std::set<clang::RecordDecl *> &exported_types,
1109 std::set<clang::FunctionDecl *> exported_functions,
1110 std::set<clang::FunctionDecl *> functions) :
1111 cpp_generator(SM, exported_types, exported_functions,
1112 functions)
1114 for (const auto &kvp : classes) {
1115 const auto &clazz = kvp.second;
1116 std::string name = type2cpp(clazz);
1117 const auto &class_tuples = lookup_class_tuples(name);
1119 if (class_tuples.empty())
1120 continue;
1121 add_template_class(clazz, name, class_tuples);
1125 /* Call "fn" on each template class.
1127 void template_cpp_generator::foreach_template_class(
1128 const std::function<void(const template_class &)> &fn) const
1130 for (const auto &kvp : template_classes)
1131 fn(kvp.second);
1134 /* Print forward declarations for all template classes to "os".
1136 * For template classes that represent an anonymous function
1137 * that can also have a domain tuple, provide an <name>_on alias
1138 * that adds the fixed Anonymous tuple kind.
1140 void template_cpp_generator::print_forward_declarations(std::ostream &os)
1142 foreach_template_class([&os] (const template_class &template_class) {
1143 auto name = template_class.class_name;
1145 os << "\n";
1146 os << "template <typename...>\n";
1147 os << "struct " << name << ";\n";
1149 if (!template_class.is_anon())
1150 return;
1151 if (template_class.is_anon_set())
1152 return;
1154 os << "\n";
1155 os << "template <typename...Ts>\n";
1156 os << "using " << name << "_on = "
1157 << name << "<Ts..., Anonymous>;\n";
1161 /* Print friend declarations for all template classes to "os".
1163 void template_cpp_generator::print_friends(std::ostream &os)
1165 foreach_template_class([&os] (const template_class &template_class) {
1166 os << " template <typename...>\n";
1167 os << " friend struct " << template_class.class_name << ";\n";
1171 /* Print a template parameter or argument.
1172 * In case of a std::string, it's a template parameter
1173 * that needs to be declared.
1175 static void print_template_arg(std::ostream &os, const std::string &arg)
1177 os << "typename " << arg;
1180 /* Print a template parameter or argument.
1181 * In case of a TupleKindPtr, it's a template argument.
1183 static void print_template_arg(std::ostream &os, const TupleKindPtr &kind)
1185 os << kind->to_string();
1188 /* Print a sequence of template parameters (std::string) or
1189 * arguments (TupleKindPtr) "args", without the enclosing angle brackets.
1191 template <typename List>
1192 static void print_pure_template_args(std::ostream &os, const List &args)
1194 for (size_t i = 0; i < args.size(); ++i) {
1195 if (i != 0)
1196 os << ", ";
1197 print_template_arg(os, args[i]);
1201 /* Print a sequence of template parameters (std::string) or
1202 * arguments (TupleKindPtr) "args".
1204 template <typename List>
1205 static void print_template_args(std::ostream &os, const List &args)
1207 os << "<";
1208 print_pure_template_args(os, args);
1209 os << ">";
1212 /* Print a declaration of the template parameters "params".
1214 static void print_template(std::ostream &os,
1215 const std::vector<std::string> &params)
1217 os << "template ";
1218 print_template_args(os, params);
1219 os << "\n";
1222 /* Print a declaration of the template parameters "params",
1223 * if there are any.
1225 static void print_non_empty_template(std::ostream &os,
1226 const std::vector<std::string> &params)
1228 if (params.size() > 0)
1229 print_template(os, params);
1232 /* Print a bare template type, i.e., without namespace,
1233 * consisting of the type "type" and the kind "kind" to "os".
1235 * In particular, print "type" followed by the template arguments
1236 * as specified by "kind".
1238 static void print_bare_template_type(std::ostream &os, const std::string &type,
1239 const Kind &kind)
1241 os << type;
1242 print_template_args(os, kind);
1245 /* A specific instance of "template_class", with tuple kinds given by "kind".
1247 struct specialization {
1248 struct template_class &template_class;
1249 Kind kind;
1251 const std::string &base_name() const;
1252 const std::string &class_name() const;
1255 /* The name of the plain C++ interface class
1256 * from which this template class (instance) derives.
1258 const std::string &specialization::base_name() const
1260 return template_class.super_name;
1263 /* The name of the template class.
1265 const std::string &specialization::class_name() const
1267 return template_class.class_name;
1270 /* Helper class for printing the specializations of template classes
1271 * that is used to print both the class declarations and the class definitions.
1273 * "os" is the stream onto which the classes should be printed.
1274 * "generator" is the templated C++ interface generator printing the classes.
1276 struct specialization_printer {
1277 specialization_printer(std::ostream &os,
1278 template_cpp_generator &generator) :
1279 os(os), generator(generator) {}
1281 virtual void print_class(const specialization &instance) const = 0;
1282 void print_classes() const;
1284 std::ostream &os;
1285 template_cpp_generator &generator;
1288 /* Print all specializations of all template classes.
1290 * Each class has a predefined set of initial specializations,
1291 * but while such a specialization is being printed,
1292 * the need for other specializations may arise and
1293 * these are added at the end of the list of specializations.
1294 * That is, class_tuples.size() may change during the execution
1295 * of the loop.
1297 * For each specialization of a template class, call
1298 * the print_class virtual method.
1300 void specialization_printer::print_classes() const
1302 for (auto &kvp : generator.template_classes) {
1303 auto &template_class = kvp.second;
1304 const auto &class_tuples = template_class.class_tuples;
1306 for (size_t i = 0; i < class_tuples.size(); ++i)
1307 print_class({ template_class, class_tuples[i] });
1311 /* A helper class for printing method declarations and definitions
1312 * of a template class specialization.
1314 * "instance" is the template class specialization for which methods
1315 * are printed.
1316 * "generator" is the templated C++ interface generator printing the classes.
1318 struct template_cpp_generator::class_printer :
1319 public cpp_generator::class_printer {
1320 class_printer(const specialization &instance,
1321 const specialization_printer &instance_printer,
1322 bool is_declaration);
1324 void print_return_type(const Method &method, const Kind &kind)
1325 const;
1326 void print_method_template_arguments(const Signature &sig);
1327 void print_method_header(const Method &method, const Signature &sig);
1328 bool print_special_method(const Method &method,
1329 const infix_map_map &special_methods);
1330 void print_static_method(const Method &method);
1331 void print_constructor(const Method &method);
1332 bool is_return_kind(const Method &method, const Kind &return_kind);
1333 void add_specialization(const Kind &kind);
1334 bool print_matching_method(const Method &method, const Signature &sig,
1335 const Kind &match_arg);
1336 bool print_matching_method(const Method &method, const Signature &sig);
1337 void print_matching_method(const Method &method,
1338 const std::vector<Signature> &signatures);
1339 void print_at_method(const Method &method);
1340 bool print_special_member_method(const Method &method);
1341 bool print_type_named_member_method(const Method &method);
1342 bool print_member_method_with_name(const Method &method,
1343 const std::string &name);
1344 void print_member_method(const Method &method);
1345 void print_any_method(const Method &method);
1346 virtual void print_method(const Method &method) override;
1347 virtual void print_method(const ConversionMethod &method) override;
1348 virtual void print_method_sig(const Method &method,
1349 const Signature &sig, bool deleted) = 0;
1350 virtual bool want_descendent_overloads(const function_set &methods)
1351 override;
1352 void print_all_methods();
1354 const specialization &instance;
1355 template_cpp_generator &generator;
1358 /* Construct a class_printer from the template class specialization
1359 * for which methods are printed and
1360 * the printer of the template class.
1362 * The template class printer is only used to obtain the output stream and
1363 * the templated C++ interface generator printing the classes.
1365 template_cpp_generator::class_printer::class_printer(
1366 const specialization &instance,
1367 const specialization_printer &instance_printer,
1368 bool is_declaration) :
1369 cpp_generator::class_printer(instance_printer.os,
1370 instance.template_class.clazz, instance_printer.generator,
1371 is_declaration),
1372 instance(instance), generator(instance_printer.generator)
1376 /* An abstract template type printer, where the way of obtaining
1377 * the argument kind is specified by the subclasses.
1379 struct template_cpp_type_printer : public cpp_type_printer {
1380 template_cpp_type_printer() {}
1382 std::string base(const std::string &type, const Kind &kind) const;
1383 virtual Kind kind(int arg) const = 0;
1384 virtual std::string qualified(int arg, const std::string &cpp_type)
1385 const override;
1388 /* Print a template type consisting of the type "type" and the kind "kind",
1389 * including the "typed::" namespace specifier.
1391 std::string template_cpp_type_printer::base(const std::string &type,
1392 const Kind &kind) const
1394 std::ostringstream ss;
1396 ss << "typed::";
1397 print_bare_template_type(ss, type, kind);
1398 return ss.str();
1401 /* Return the qualified form of the given C++ isl type name appearing
1402 * in argument position "arg" (-1 for return type).
1404 * isl::ctx is not templated, so if "cpp_type" is "ctx",
1405 * then print a non-templated version.
1406 * Otherwise, look up the kind of the argument and print
1407 * the corresponding template type.
1409 std::string template_cpp_type_printer::qualified(int arg,
1410 const std::string &cpp_type) const
1412 if (cpp_type == "ctx")
1413 return cpp_type_printer::qualified(arg, cpp_type);
1415 return base(cpp_type, kind(arg));
1418 /* A template type printer for printing types with a fixed kind.
1420 * "fixed_kind" is the fixed kind.
1422 struct template_cpp_kind_type_printer : public template_cpp_type_printer {
1423 template_cpp_kind_type_printer(const Kind &kind) :
1424 template_cpp_type_printer(), fixed_kind(kind) {}
1426 virtual Kind kind(int arg) const override;
1428 const Kind &fixed_kind;
1431 /* Return the kind of the argument at position "arg",
1432 * where position -1 refers to the return type.
1434 * Always use the fixed kind.
1436 Kind template_cpp_kind_type_printer::kind(int arg) const
1438 return fixed_kind;
1441 /* A template type printer for printing a method with a given signature.
1443 * "sig" is the signature of the method being printed.
1445 struct template_cpp_arg_type_printer : public template_cpp_type_printer {
1446 template_cpp_arg_type_printer(const Signature &sig) :
1447 template_cpp_type_printer(), sig(sig) {}
1449 virtual Kind kind(int arg) const override;
1451 const Signature &sig;
1454 /* Return the kind of the argument at position "arg",
1455 * where position -1 refers to the return type.
1457 * Look up the kind in the signature.
1459 Kind template_cpp_arg_type_printer::kind(int arg) const
1461 int n_args = sig.args.size();
1463 if (arg < 0)
1464 return sig.ret;
1465 if (arg >= n_args)
1466 generator::die("argument out of bounds");
1467 return sig.args[arg];
1470 /* A template type printer for printing a method with a given signature
1471 * as part of a template class specialization of a given kind.
1473 * "class_kind" is the template class specialization kind.
1475 struct template_method_type_printer : public template_cpp_arg_type_printer {
1476 template_method_type_printer(const Signature &sig,
1477 const Kind &class_kind) :
1478 template_cpp_arg_type_printer(sig),
1479 class_kind(class_kind) {}
1481 virtual std::string class_type(const std::string &cpp_name)
1482 const override;
1484 const Kind &class_kind;
1487 /* Print the class type "cpp_name".
1489 * Print the templated version using the template class specialization kind.
1491 std::string template_method_type_printer::class_type(
1492 const std::string &cpp_name) const
1494 return base(cpp_name, class_kind);
1497 /* Print the templated return type of "method" of the kind "return_kind".
1499 * Construct a type printer with "return_kind" as fixed kind and
1500 * use it to print the return type.
1502 void template_cpp_generator::class_printer::print_return_type(
1503 const Method &method, const Kind &return_kind) const
1505 template_cpp_kind_type_printer printer(return_kind);
1507 os << printer.return_type(method);
1510 /* Remove the initial "n" elements from "v".
1512 template <typename T>
1513 static void drop_initial(std::vector<T> &v, size_t n)
1515 v.erase(v.begin(), v.begin() + n);
1518 /* If a method with signature "sig" requires additional template parameters
1519 * compared to those of the class, then print a declaration for them.
1520 * If this->declarations is set, then this will be part of a method declaration,
1521 * requiring extra indentation.
1523 * Construct the sequence of all required template parameters
1524 * with those of the template class appearing first.
1525 * If this sequence has any parameters not induced by the template class itself,
1526 * then print a declaration for these extra parameters.
1528 void template_cpp_generator::class_printer::print_method_template_arguments(
1529 const Signature &sig)
1531 std::vector<std::string> class_params, method_params;
1533 class_params = instance.kind.params();
1534 method_params = class_params;
1535 combine(method_params, sig.params());
1537 if (class_params.size() == method_params.size())
1538 return;
1540 drop_initial(method_params, class_params.size());
1542 if (declarations)
1543 os << " ";
1544 print_template(os, method_params);
1547 /* Print the header for "method" with signature "sig".
1549 * First print any additional template parameters that may be required and
1550 * then print a regular method header, using a template type printer.
1552 void template_cpp_generator::class_printer::print_method_header(
1553 const Method &method, const Signature &sig)
1555 template_method_type_printer type_printer(sig, instance.kind);
1557 print_method_template_arguments(sig);
1558 cpp_generator::class_printer::print_method_header(method,
1559 type_printer);
1562 /* Given a group of methods with the same name,
1563 * should extra methods be added that take as arguments
1564 * those types that can be converted to the original argument type
1565 * through a unary constructor?
1567 * Since type deduction does not consider implicit conversions,
1568 * these extra methods should always be printed.
1570 bool template_cpp_generator::class_printer::want_descendent_overloads(
1571 const function_set &methods)
1573 return true;
1576 /* Print all constructors and methods that forward
1577 * to the corresponding methods in the plain C++ interface class.
1579 void template_cpp_generator::class_printer::print_all_methods()
1581 print_constructors();
1582 print_methods();
1585 /* A helper class for printing method declarations
1586 * of a template class specialization.
1588 struct template_cpp_generator::method_decl_printer :
1589 public template_cpp_generator::class_printer {
1590 method_decl_printer(const specialization &instance,
1591 const struct specialization_printer &instance_printer) :
1592 class_printer(instance, instance_printer, true) {}
1594 virtual void print_method_sig(const Method &method,
1595 const Signature &sig, bool deleted) override;
1596 virtual void print_get_method(FunctionDecl *fd) override;
1599 /* Print a declaration of the method "method" with signature "sig".
1600 * Mark is "delete" if "deleted" is set.
1602 void template_cpp_generator::method_decl_printer::print_method_sig(
1603 const Method &method, const Signature &sig, bool deleted)
1605 print_method_header(method, sig);
1606 if (deleted)
1607 os << " = delete";
1608 os << ";\n";
1611 /* Return the total number of arguments in the signature for "method",
1612 * taking into account any possible callback arguments.
1614 * In particular, if the method has a callback argument,
1615 * then the return kind of the callback appears at the position
1616 * of the callback and the kinds of the arguments (except
1617 * the user pointer argument) appear in the following positions.
1618 * The user pointer argument that follows the callback argument
1619 * is also removed.
1621 static int total_params(const Method &method)
1623 int n = method.num_params();
1625 for (const auto &callback : method.callbacks) {
1626 auto callback_type = callback->getType();
1627 auto proto = generator::extract_prototype(callback_type);
1629 n += proto->getNumArgs() - 1;
1630 n -= 1;
1633 return n;
1636 /* Return a signature for "method" that matches "instance".
1638 static Signature instance_sig(const Method &method,
1639 const specialization &instance)
1641 std::vector<Kind> args(total_params(method));
1643 args[0] = instance.kind;
1644 return { instance.kind, args };
1647 /* Print a declaration for the "get" method "fd",
1648 * using a name that includes the "get_" prefix.
1650 * These methods are only included in the plain interface.
1651 * Explicitly delete them from the templated interface.
1653 void template_cpp_generator::method_decl_printer::print_get_method(
1654 FunctionDecl *fd)
1656 Method method(clazz, fd, clazz.base_method_name(fd));
1658 print_method_sig(method, instance_sig(method, instance), true);
1661 /* A helper class for printing method definitions
1662 * of a template class specialization.
1664 struct template_cpp_generator::method_impl_printer :
1665 public template_cpp_generator::class_printer {
1666 method_impl_printer(const specialization &instance,
1667 const struct specialization_printer &instance_printer) :
1668 class_printer(instance, instance_printer, false) {}
1670 void print_callback_method_body(const Method &method,
1671 const Signature &sig);
1672 void print_method_body(const Method &method, const Signature &sig);
1673 void print_constructor_body(const Method &method, const Signature &sig);
1674 virtual void print_method_sig(const Method &method,
1675 const Signature &sig, bool deleted) override;
1676 virtual void print_get_method(FunctionDecl *fd) override;
1679 /* Print a definition of the constructor "method" with signature "sig".
1681 * Simply pass all arguments to the constructor of the corresponding
1682 * plain type.
1684 void template_cpp_generator::method_impl_printer::print_constructor_body(
1685 const Method &method, const Signature &sig)
1687 const auto &base_name = instance.base_name();
1689 os << " : " << base_name;
1690 method.print_cpp_arg_list(os, [&] (int i, int arg) {
1691 os << method.fd->getParamDecl(i)->getName().str();
1693 os << "\n";
1695 os << "{\n";
1696 os << "}\n";
1699 /* Print the arguments of the callback function "callback" to "os",
1700 * calling "print_arg" with the type and the name of the arguments,
1701 * where the type is obtained from "type_printer" with argument positions
1702 * shifted by "shift".
1703 * None of the arguments should be skipped.
1705 static void print_callback_args(std::ostream &os,
1706 const FunctionProtoType *callback, const cpp_type_printer &type_printer,
1707 int shift,
1708 const std::function<void(const std::string &type,
1709 const std::string &name)> &print_arg)
1711 auto n_arg = callback->getNumArgs() - 1;
1713 Method::print_arg_list(os, 0, n_arg, [&] (int i) {
1714 auto type = callback->getArgType(i);
1715 auto name = "arg" + std::to_string(i);
1716 auto cpptype = type_printer.param(shift + i, type);
1718 print_arg(cpptype, name);
1720 return false;
1724 /* Print a lambda corresponding to "callback"
1725 * with signature "sig" and argument positions shifted by "shift".
1727 * The lambda takes arguments with plain isl types and
1728 * calls the callback of "method" with templated arguments.
1730 static void print_callback_lambda(std::ostream &os, ParmVarDecl *callback,
1731 const Signature &sig, int shift)
1733 auto callback_type = callback->getType();
1734 auto callback_name = callback->getName().str();
1735 auto proto = generator::extract_prototype(callback_type);
1737 os << " auto lambda_" << callback_name << " = [&] ";
1738 print_callback_args(os, proto, cpp_type_printer(), shift,
1739 [&] (const std::string &type, const std::string &name) {
1740 os << type << " " << name;
1742 os << " {\n";
1744 os << " return " << callback_name;
1745 print_callback_args(os, proto, template_cpp_arg_type_printer(sig),
1746 shift,
1747 [&] (const std::string &type, const std::string &name) {
1748 os << type << "(" << name << ")";
1750 os << ";\n";
1752 os << " };\n";
1755 /* Print lambdas for passing to the plain method corresponding to "method"
1756 * with signature "sig".
1758 * The method is assumed to have only callbacks as argument,
1759 * which means the arguments of the first callback are shifted by 2
1760 * with respect to the arguments of the signature
1761 * (one for the position of the callback argument plus
1762 * one for the return kind of the callback).
1763 * The arguments of a subsequent callback are shifted by
1764 * the number of arguments of the previous callback minus one
1765 * for the user pointer plus one for the return kind.
1767 static void print_callback_lambdas(std::ostream &os, const Method &method,
1768 const Signature &sig)
1770 int shift;
1772 if (method.num_params() != 1 + 2 * method.callbacks.size())
1773 generator::die("callbacks are assumed to be only arguments");
1775 shift = 2;
1776 for (const auto &callback : method.callbacks) {
1777 print_callback_lambda(os, callback, sig, shift);
1778 shift += generator::prototype_n_args(callback->getType());
1782 /* Print a definition of the member method "method", which is known
1783 * to have a callback argument, with signature "sig".
1785 * First print lambdas for passing to the corresponding plain method and
1786 * calling the callback of "method" with templated arguments.
1787 * Then call the plain method, replacing the original callbacks
1788 * by the lambdas.
1790 * The return value is assumed to be isl_bool or isl_stat
1791 * so that no conversion to a template type is required.
1793 void template_cpp_generator::method_impl_printer::print_callback_method_body(
1794 const Method &method, const Signature &sig)
1796 const auto &base_name = instance.base_name();
1797 auto return_type = method.fd->getReturnType();
1799 if (!is_isl_bool(return_type) && !is_isl_stat(return_type))
1800 die("only isl_bool and isl_stat return types are supported");
1802 os << "{\n";
1804 print_callback_lambdas(os, method, sig);
1806 os << " return ";
1807 os << base_name << "::" << method.name;
1808 method.print_cpp_arg_list(os, [&] (int i, int arg) {
1809 auto param = method.fd->getParamDecl(i);
1811 if (generator::is_callback(param->getType()))
1812 os << "lambda_";
1813 os << param->getName().str();
1815 os << ";\n";
1817 os << "}\n";
1820 /* Print a definition of the member or static method "method"
1821 * with signature "sig".
1823 * The body calls the corresponding method of the base class
1824 * in the plain interface and
1825 * then casts the result to the templated result type.
1827 void template_cpp_generator::method_impl_printer::print_method_body(
1828 const Method &method, const Signature &sig)
1830 const auto &base_name = instance.base_name();
1832 os << "{\n";
1833 os << " auto res = ";
1834 os << base_name << "::" << method.name;
1835 method.print_cpp_arg_list(os, [&] (int i, int arg) {
1836 os << method.fd->getParamDecl(i)->getName().str();
1838 os << ";\n";
1840 os << " return ";
1841 print_return_type(method, sig.ret);
1842 os << "(res);\n";
1843 os << "}\n";
1846 /* Print a definition of the method "method" with signature "sig",
1847 * if "deleted" is not set.
1849 * If "deleted" is set, then the corresponding declaration
1850 * is marked "delete" and no definition needs to be printed.
1852 * Otherwise print the method header, preceded by the template parameters,
1853 * if needed.
1854 * The body depends on whether the method is a constructor or
1855 * takes any callbacks.
1857 void template_cpp_generator::method_impl_printer::print_method_sig(
1858 const Method &method, const Signature &sig, bool deleted)
1860 if (deleted)
1861 return;
1863 os << "\n";
1864 print_non_empty_template(os, instance.kind.params());
1865 print_method_header(method, sig);
1866 os << "\n";
1867 if (method.kind == Method::Kind::constructor)
1868 print_constructor_body(method, sig);
1869 else if (method.callbacks.size() != 0)
1870 print_callback_method_body(method, sig);
1871 else
1872 print_method_body(method, sig);
1875 /* Print a definition for the "get" method "fd" in class "clazz",
1876 * using a name that includes the "get_" prefix, to "os".
1878 * The declarations of these methods are explicitly delete'd
1879 * so no definition needs to be printed.
1881 void template_cpp_generator::method_impl_printer::print_get_method(
1882 FunctionDecl *fd)
1886 /* Print a declaration or definition of the static method "method",
1887 * if it has a signature specified by static_methods.
1889 void template_cpp_generator::class_printer::print_static_method(
1890 const Method &method)
1892 print_special_method(method, static_methods);
1895 /* Signatures for constructors of multi-expressions
1896 * from a space and a list.
1898 static Signature from_list_set = { { Domain }, { { Domain }, { Anonymous } } };
1899 static Signature from_list_map =
1900 { { Domain, Range }, { { Domain, Range }, { Domain, Anonymous } } };
1902 /* Signatures for constructors from a string.
1904 static Signature params_from_str = { { }, { { Ctx }, { Str } } };
1905 static Signature set_from_str = { { Domain }, { { Ctx }, { Str } } };
1906 static Signature map_from_str = { { Domain, Range }, { { Ctx }, { Str } } };
1907 static std::vector<Signature> from_str =
1908 { params_from_str, set_from_str, map_from_str };
1910 /* Signature for a constructor from an integer.
1912 static Signature int_from_si = { { Anonymous }, { { Ctx }, { Integer } } };
1914 /* Signatures for constructors of lists from the initial number
1915 * of elements.
1917 static Signature alloc_params = { { }, { { Ctx }, { Integer } } };
1918 static Signature alloc_set = { { Domain }, { { Ctx }, { Integer } } };
1919 static Signature alloc_map = { { Domain, Range }, { { Ctx }, { Integer } } };
1921 /* Signatures for constructors and methods named after some other class.
1923 * Two forms of constructors are handled
1924 * - conversion from another object
1925 * - construction of a multi-expression from a space and a list
1927 * Methods named after some other class also come in two forms
1928 * - extraction of information such as the space or a list
1929 * - construction of a multi-expression from a space and a list
1931 * In both cases, the first form is a unary operation and
1932 * the second has an extra argument with a kind that is equal
1933 * to that of the first argument, except that the final tuple is anonymous.
1935 static std::vector<Signature> constructor_sig = {
1936 un_params,
1937 un_set,
1938 un_map,
1939 from_list_set,
1940 from_list_map,
1943 /* Signatures for constructors derived from methods
1944 * with the given names that override the default signatures.
1946 static const std::unordered_map<std::string, std::vector<Signature>>
1947 special_constructors {
1948 { "alloc", { alloc_params, alloc_set, alloc_map } },
1949 { "int_from_si", { int_from_si } },
1950 { "read_from_str", from_str },
1953 /* Print a declaration or definition of the constructor "method".
1955 void template_cpp_generator::class_printer::print_constructor(
1956 const Method &method)
1958 if (special_constructors.count(method.name) != 0) {
1959 const auto &sigs = special_constructors.at(method.name);
1960 return print_matching_method(method, sigs);
1962 print_matching_method(method, constructor_sig);
1965 /* Does this template class represent an anonymous function?
1967 * If any specialization represents an anonymous function,
1968 * then every specialization does, so simply check
1969 * the first specialization.
1971 bool template_class::is_anon() const
1973 return class_tuples[0].is_anon();
1976 /* Does this template class represent an anonymous value?
1978 * That is, is there only a single specialization that moreover
1979 * has a single, anonymous tuple?
1981 bool template_class::is_anon_set() const
1983 return class_tuples.size() == 1 && class_tuples[0].is_anon_set();
1986 /* Update the substitution "sub" to map "general" to "specific"
1987 * if "specific" is a special case of "general" consistent with "sub",
1988 * given that "general" is not a pair and can be assigned "specific".
1989 * Return true if successful.
1990 * Otherwise, return false.
1992 * Check whether "general" is already assigned something in "sub".
1993 * If so, it must be assigned "specific".
1994 * Otherwise, there is a conflict.
1996 static bool update_sub_base(Substitution &sub, const TupleKindPtr &general,
1997 const TupleKindPtr &specific)
1999 auto name = general->name;
2001 if (sub.count(name) != 0 && sub.at(name) != specific)
2002 return false;
2003 sub.emplace(name, specific);
2004 return true;
2007 /* Update the substitution "sub" to map "general" to "specific"
2008 * if "specific" is a special case of "general" consistent with "sub".
2009 * Return true if successful.
2010 * Otherwise, return false.
2012 * If "general" is a pair and "specific" is not,
2013 * then "specific" cannot be a special case.
2014 * If both are pairs, then update the substitution based
2015 * on both sides.
2016 * If "general" is Anonymous, then "specific" must be Anonymous as well.
2017 * If "general" is Leaf, then "specific" cannot be a pair.
2019 * Otherwise, assign "specific" to "general", if possible.
2021 static bool update_sub(Substitution &sub, const TupleKindPtr &general,
2022 const TupleKindPtr &specific)
2024 if (general->left() && !specific->left())
2025 return false;
2026 if (general->left())
2027 return update_sub(sub, general->left(), specific->left()) &&
2028 update_sub(sub, general->right(), specific->right());
2029 if (general == Anonymous && specific != Anonymous)
2030 return false;
2031 if (general == Leaf && specific->left())
2032 return false;
2034 return update_sub_base(sub, general, specific);
2037 /* Check if "specific" is a special case of "general" and,
2038 * if so, return true along with a substitution
2039 * that maps "general" to "specific".
2040 * Otherwise return false.
2042 * This can only happen if the number of tuple kinds is the same.
2043 * If so, start with an empty substitution and update it
2044 * for each pair of tuple kinds, checking that each update succeeds.
2046 static std::pair<bool, Substitution> specializer(const Kind &general,
2047 const Kind &specific)
2049 Substitution specializer;
2051 if (general.size() != specific.size())
2052 return { false, Substitution() };
2054 for (size_t i = 0; i < general.size(); ++i) {
2055 auto general_tuple = general[i];
2057 if (!update_sub(specializer, general[i], specific[i]))
2058 return { false, Substitution() };
2061 return { true, specializer };
2064 /* Is "kind1" equivalent to "kind2"?
2065 * That is, is each a special case of the other?
2067 static bool equivalent(const Kind &kind1, const Kind &kind2)
2069 return specializer(kind1, kind2).first &&
2070 specializer(kind2, kind1).first;
2073 /* Add the specialization "kind" to the sequence of specializations,
2074 * provided there is no equivalent specialization already in there.
2076 void template_class::add_specialization(const Kind &kind)
2078 for (const auto &special : class_tuples)
2079 if (equivalent(special, kind))
2080 return;
2081 class_tuples.emplace_back(kind);
2084 /* A type printer that prints the plain interface type,
2085 * without namespace.
2087 struct plain_cpp_type_printer : public cpp_type_printer {
2088 plain_cpp_type_printer() {}
2090 virtual std::string qualified(int arg, const std::string &cpp_type)
2091 const override;
2094 /* Return the qualified form of the given C++ isl type name appearing
2095 * in argument position "arg" (-1 for return type).
2097 * For printing the plain type without namespace, no modifications
2098 * are required.
2100 std::string plain_cpp_type_printer::qualified(int arg,
2101 const std::string &cpp_type) const
2103 return cpp_type;
2106 /* Return a string representation of the plain type "type".
2108 * For the plain printer, the argument position is irrelevant,
2109 * so simply pass in -1.
2111 static std::string plain_type(QualType type)
2113 return plain_cpp_type_printer().param(-1, type);
2116 /* Return a string representation of the plain return type of "method".
2118 static std::string plain_return_type(const Method &method)
2120 return plain_type(method.fd->getReturnType());
2123 /* Return that part of the signature "sig" that should match
2124 * the template class specialization for the given method.
2126 * In particular, if the method is a regular member method,
2127 * then the instance should match the first argument.
2128 * Otherwise, it should match the return kind.
2130 static const Kind &matching_kind(const Method &method, const Signature &sig)
2132 if (method.kind == Method::Kind::member_method)
2133 return sig.args[0];
2134 else
2135 return sig.ret;
2138 /* Is it possible for "template_class" to have the given kind?
2140 * If the template class represents an anonymous function,
2141 * then so must the given kind.
2142 * There should also be specialization with the same number of tuple kinds.
2144 static bool has_kind(const template_class &template_class, const Kind &kind)
2146 if (template_class.is_anon() && !kind.is_anon())
2147 return false;
2148 for (const auto &class_tuple : template_class.class_tuples)
2149 if (class_tuple.size() == kind.size())
2150 return true;
2151 return false;
2154 /* Is "return_kind" a possible kind for the return type of "method"?
2156 * If the return type is not a template class,
2157 * then "return_kind" should not have any template parameters.
2158 * Otherwise, "return_kind" should be a valid kind for the template class.
2160 bool template_cpp_generator::class_printer::is_return_kind(
2161 const Method &method, const Kind &return_kind)
2163 const auto &template_classes = generator.template_classes;
2164 auto return_type = plain_return_type(method);
2166 if (template_classes.count(return_type) == 0)
2167 return return_kind.params().size() == 0;
2168 return has_kind(template_classes.at(return_type), return_kind);
2171 /* Is "kind" a placeholder that can be assigned something else
2172 * in a substitution?
2174 * Anonymous can only be mapped to itself. This is taken care of
2175 * by assign().
2176 * Leaf can only be assigned a placeholder, but there is no need
2177 * to handle this specifically since Leaf can still be assigned
2178 * to the placeholder.
2180 static bool assignable(const TupleKindPtr &kind)
2182 return kind != Anonymous && kind != Leaf;
2185 /* Return a substitution that maps "kind1" to "kind2", if possible.
2186 * Otherwise return an empty substitution.
2188 * Check if "kind1" can be assigned anything or
2189 * if "kind1" and "kind2" are identical.
2190 * The latter case handles mapping Anonymous to itself.
2192 static Substitution assign(const TupleKindPtr &kind1, const TupleKindPtr &kind2)
2194 Substitution res;
2196 if (assignable(kind1) || kind1 == kind2)
2197 res.emplace(kind1->name, kind2);
2198 return res;
2201 /* Return a substitution that first applies "first" and then "second".
2203 * The result consists of "second" and of "second" applied to "first".
2205 static Substitution compose(const Substitution &first,
2206 const Substitution &second)
2208 Substitution res = second;
2210 for (const auto &kvp : first)
2211 res.emplace(kvp.first, apply(kvp.second, second));
2213 return res;
2216 static Substitution compute_unifier(const TupleKindPtr &kind1,
2217 const TupleKindPtr &kind2);
2219 /* Try and extend "unifier" with a unifier for "kind1" and "kind2".
2220 * Return the resulting unifier if successful.
2221 * Otherwise, return an empty substitution.
2223 * First apply "unifier" to "kind1" and "kind2".
2224 * Then compute a unifier for the resulting tuple kinds and
2225 * combine it with "unifier".
2227 static Substitution combine_unifiers(const TupleKindPtr &kind1,
2228 const TupleKindPtr &kind2, const Substitution &unifier)
2230 auto k1 = apply(kind1, unifier);
2231 auto k2 = apply(kind2, unifier);
2232 auto u = compute_unifier(k1, k2);
2233 if (u.size() == 0)
2234 return Substitution();
2235 return compose(unifier, u);
2238 /* Try and compute a unifier of "kind1" and "kind2",
2239 * i.e., a substitution that produces the same result when
2240 * applied to both "kind1" and "kind2",
2241 * for the case where both "kind1" and "kind2" are pairs.
2242 * Return this unifier if it was found.
2243 * Return an empty substitution if no unifier can be found.
2245 * First compute a unifier for the left parts of the pairs and,
2246 * if successful, combine it with a unifier for the right parts.
2248 static Substitution compute_pair_unifier(const TupleKindPtr &kind1,
2249 const TupleKindPtr &kind2)
2251 auto unifier_left = compute_unifier(kind1->left(), kind2->left());
2252 if (unifier_left.size() == 0)
2253 return Substitution();
2254 return combine_unifiers(kind1->right(), kind2->right(), unifier_left);
2257 /* Try and compute a unifier of "kind1" and "kind2",
2258 * i.e., a substitution that produces the same result when
2259 * applied to both "kind1" and "kind2".
2260 * Return this unifier if it was found.
2261 * Return an empty substitution if no unifier can be found.
2263 * If one of the tuple kinds is a pair then assign it
2264 * to the other tuple kind, if possible.
2265 * If neither is a pair, then try and assign one to the other.
2266 * Otherwise, let compute_pair_unifier compute a unifier.
2268 * Note that an assignment is added to the unifier even
2269 * if "kind1" and "kind2" are identical.
2270 * This ensures that a successful substitution is never empty.
2272 static Substitution compute_unifier(const TupleKindPtr &kind1,
2273 const TupleKindPtr &kind2)
2275 if (kind1->left() && !kind2->left())
2276 return assign(kind2, kind1);
2277 if (!kind1->left() && kind2->left())
2278 return assign(kind1, kind2);
2279 if (!kind1->left() && !kind2->left()) {
2280 if (assignable(kind1))
2281 return assign(kind1, kind2);
2282 else
2283 return assign(kind2, kind1);
2286 return compute_pair_unifier(kind1, kind2);
2289 /* Try and compute a unifier of "kind1" and "kind2",
2290 * i.e., a substitution that produces the same result when
2291 * applied to both "kind1" and "kind2".
2292 * Return this unifier if it was found.
2293 * Return an empty substitution if no unifier can be found.
2295 * Start with an empty substitution and compute a unifier for
2296 * each pair of tuple kinds, combining the results.
2297 * If no combined unifier can be found or
2298 * if the numbers of tuple kinds are different, then return
2299 * an empty substitution.
2300 * This assumes that the number of tuples is greater than zero,
2301 * as otherwise an empty substitution would be returned as well.
2303 static Substitution compute_unifier(const Kind &kind1, const Kind &kind2)
2305 Substitution unifier;
2307 if (kind1.size() != kind2.size())
2308 return Substitution();
2310 for (size_t i = 0; i < kind1.size(); ++i)
2311 unifier = combine_unifiers(kind1[i], kind2[i], unifier);
2313 return unifier;
2316 /* Try and construct a Kind that is a specialization of both "general" and
2317 * "specific", where "specific" is known _not_ to be a specialization
2318 * of "general" and not to contain any Leaf.
2320 * First check whether "general" is a specialization of "specific".
2321 * If so, simply return "general".
2322 * Otherwise, rename the placeholders in the two kinds apart and
2323 * try and compute a unifier.
2324 * If this succeeds, then return the result of applying the unifier.
2326 static std::pair<bool, Kind> unify(const Kind &general, const Kind &specific)
2328 if (specializer(specific, general).first) {
2329 return { true, general };
2330 } else {
2331 auto rename = param_renamer(specific.params(), "T");
2332 auto renamed = specific.apply(rename);
2333 auto unifier = compute_unifier(general, renamed);
2335 if (unifier.size() == 0)
2336 return { false, { } };
2338 return { true, general.apply(unifier) };
2342 /* Try and add a template class specialization corresponding to "kind".
2343 * The new specialization needs to be a specialization of both
2344 * the current specialization and "kind".
2346 * The current template class specialization is known not to be a special case
2347 * of "kind".
2349 * Try and unify the two kinds and, if this succeeds, add the result
2350 * to this list of template class specializations.
2352 void template_cpp_generator::class_printer::add_specialization(
2353 const Kind &kind)
2355 auto maybe_unified = unify(kind, instance.kind);
2357 if (!maybe_unified.first)
2358 return;
2359 instance.template_class.add_specialization(maybe_unified.second);
2362 /* Does the type of the parameter at position "i" of "method" necessarily
2363 * have a final Anonymous tuple?
2365 * If the parameter is not of an isl type or if no specializations
2366 * have been defined for the type, then it can be considered anonymous.
2367 * Otherwise, if any specialization represents an anonymous function,
2368 * then every specialization does, so simply check
2369 * the first specialization.
2371 static bool param_is_anon(const Method &method, int i)
2373 ParmVarDecl *param = method.get_param(i);
2374 QualType type = param->getOriginalType();
2376 if (cpp_generator::is_isl_type(type)) {
2377 const auto &name = type->getPointeeType().getAsString();
2378 const auto &cpp = cpp_generator::type2cpp(name);
2379 const auto &tuples = lookup_class_tuples(cpp);
2381 if (tuples.empty())
2382 return true;
2383 return tuples[0].is_anon();
2386 return true;
2389 /* Replace the final tuple of "arg_kind" by Anonymous in "sig" and
2390 * return the update signature,
2391 * unless this would affect the class instance "instance_kind".
2393 * If the original "instance_kind" is a special case
2394 * of the result of the substitution, then "instance_kind"
2395 * is not affected and the substitution can be applied
2396 * to the entire signature.
2398 static Signature specialize_anonymous_arg(const Signature &sig,
2399 const Kind &arg_kind, const Kind &instance_kind)
2401 const auto &subs = compute_unifier(arg_kind.back(), Anonymous);
2402 const auto &specialized_instance = instance_kind.apply(subs);
2404 if (!specializer(specialized_instance, instance_kind).first)
2405 return sig;
2407 return sig.apply(subs);
2410 /* If any of the arguments of "method" is of a type that necessarily
2411 * has a final Anonymous tuple, but the corresponding entry
2412 * in the signature "sig" is not Anonymous, then replace
2413 * that entry by Anonymous and return the updated signature,
2414 * unless this would affect the class instance "instance_kind".
2416 static Signature specialize_anonymous_args(const Signature &sig,
2417 const Method &method, const Kind &instance_kind)
2419 auto specialized_sig = sig;
2421 method.on_cpp_arg_list([&] (int i, int arg) {
2422 const auto &arg_kind = sig.args[arg];
2424 if (arg_kind.is_anon())
2425 return;
2426 if (!param_is_anon(method, i))
2427 return;
2428 specialized_sig = specialize_anonymous_arg(specialized_sig,
2429 arg_kind, instance_kind);
2432 return specialized_sig;
2435 /* Print a declaration or definition of the method "method"
2436 * if the template class specialization matches "match_arg".
2437 * Return true if so.
2438 * "sig" is the complete signature, of which "match_arg" refers
2439 * to the first argument or the return type.
2441 * Since "sig" may have parameters with the same names as
2442 * those in instance.kind, rename them apart first.
2444 * If the template class specialization is a special case of
2445 * (the renamed) "match_arg"
2446 * then apply the specializer to the complete (renamed) signature,
2447 * specialize any anonymous arguments,
2448 * check that the return kind is allowed and, if so,
2449 * print the declaration or definition using the specialized signature.
2451 * If the template class specialization is not a special case of "match_arg"
2452 * then add a further specialization to the list of specializations
2453 * of the template class.
2455 bool template_cpp_generator::class_printer::print_matching_method(
2456 const Method &method, const Signature &sig, const Kind &match_arg)
2458 auto rename = shared_param_renamer(sig, instance.kind);
2459 auto renamed_arg = match_arg.apply(rename);
2460 auto maybe_specializer = specializer(renamed_arg, instance.kind);
2461 if (maybe_specializer.first) {
2462 const auto &specializer = maybe_specializer.second;
2463 auto specialized_sig = sig.apply(rename).apply(specializer);
2464 specialized_sig = specialize_anonymous_args(specialized_sig,
2465 method, instance.kind);
2466 if (!is_return_kind(method, specialized_sig.ret))
2467 return false;
2469 print_method_sig(method, specialized_sig, false);
2470 } else {
2471 add_specialization(match_arg);
2473 return maybe_specializer.first;
2476 /* Is the first argument of "method" of type "isl_ctx *"?
2478 static bool first_arg_is_ctx(const Method &method)
2480 return generator::first_arg_is_isl_ctx(method.fd);
2483 /* Is the first signature argument set to { Ctx }?
2485 static bool first_kind_is_ctx(const Signature &sig)
2487 return sig.args[0].size() > 0 && sig.args[0][0] == Ctx;
2490 /* Print a declaration or definition of the member method "method"
2491 * if it matches the signature "sig".
2492 * Return true if so.
2494 * First determine the part of the signature that needs to match
2495 * the template class specialization and
2496 * check that it has the same number of template arguments.
2497 * Also check that the number of arguments of the signature
2498 * matches that of the method.
2499 * If there is at least one argument, then check that the first method argument
2500 * is an isl_ctx if and only if the first signature argument is Ctx.
2502 * If these tests succeed, proceed with the actual matching.
2504 bool template_cpp_generator::class_printer::print_matching_method(
2505 const Method &method, const Signature &sig)
2507 auto match_arg = matching_kind(method, sig);
2508 int n_args = sig.args.size();
2510 if (match_arg.size() != instance.kind.size())
2511 return false;
2512 if (n_args != total_params(method))
2513 return false;
2514 if (n_args > 0 && first_arg_is_ctx(method) != first_kind_is_ctx(sig))
2515 return false;
2517 return print_matching_method(method, sig, match_arg);
2520 /* Print a declaration or definition of the member method "method"
2521 * for each matching signature in "signatures".
2523 * If there is no matching signature in "signatures",
2524 * then explicitly delete the method (using a signature based on
2525 * the specialization) so that it is not inherited from the base class.
2527 void template_cpp_generator::class_printer::print_matching_method(
2528 const Method &method, const std::vector<Signature> &signatures)
2530 auto any = false;
2532 for (const auto &sig : signatures)
2533 if (print_matching_method(method, sig))
2534 any = true;
2536 if (!any)
2537 print_method_sig(method, instance_sig(method, instance), true);
2540 /* Signatures for "at" methods applied to a multi-expression,
2541 * which make the final tuple anonymous.
2543 static Signature select_set = { { Anonymous }, { { Domain }, { Integer } } };
2544 static Signature select_map =
2545 { { Domain, Anonymous }, { { Domain, Range }, { Integer } } };
2546 static std::vector<Signature> at_select = { select_set, select_map };
2548 /* Signatures for other "at" methods applied to a list,
2549 * which do not modify the tuple kind.
2551 static Signature bin_set_int = { { Domain }, { { Domain }, { Integer } } };
2552 static Signature bin_map_int =
2553 { { Domain, Range }, { { Domain, Range }, { Integer } } };
2554 static std::vector<Signature> at_keep = { bin_set_int, bin_map_int };
2556 /* Print a declaration or definition of the "at" member method "method".
2558 * There are two types of methods called "at".
2559 * One type extracts an element from a multi-expression and
2560 * the other extracts an element from a list.
2562 * In the first case, the return type is an anonymous function
2563 * while the object type is not. In this case, the return kind
2564 * should have a final Anonymous tuple.
2565 * Otherwise, the return kind should be the same as the object kind.
2567 void template_cpp_generator::class_printer::print_at_method(
2568 const Method &method)
2570 auto anon = instance.template_class.is_anon();
2571 auto return_type = plain_return_type(method);
2572 auto return_class = generator.template_classes.at(return_type);
2574 if (!anon && return_class.is_anon())
2575 return print_matching_method(method, at_select);
2576 else
2577 return print_matching_method(method, at_keep);
2580 /* Does the string "s" contain "sub" as a substring?
2582 static bool contains(const std::string &s, const std::string &sub)
2584 return s.find(sub) != std::string::npos;
2587 /* Print a declaration or definition of the member method "method",
2588 * if it has a special signature in "special_methods".
2589 * Return true if this is the case.
2591 * Check if any special signatures are specified for this method and
2592 * if the class name matches any of those with special signatures.
2593 * If so, pick the one with the best match, i.e., the first match
2594 * since the largest keys appear first.
2596 bool template_cpp_generator::class_printer::print_special_method(
2597 const Method &method, const infix_map_map &special_methods)
2599 if (special_methods.count(method.name) == 0)
2600 return false;
2602 for (const auto &kvp : special_methods.at(method.name)) {
2603 if (!contains(instance.template_class.class_name, kvp.first))
2604 continue;
2605 print_matching_method(method, kvp.second);
2606 return true;
2609 return false;
2612 /* Print a declaration or definition of the member method "method",
2613 * if it has a special signature specified by special_member_methods.
2614 * Return true if this is the case.
2616 bool template_cpp_generator::class_printer::print_special_member_method(
2617 const Method &method)
2619 return print_special_method(method, special_member_methods);
2622 /* Print a declaration or definition of the member method "method",
2623 * if it is named after a template class. Return true if this is the case.
2625 bool template_cpp_generator::class_printer::print_type_named_member_method(
2626 const Method &method)
2628 if (generator.template_classes.count(method.name) == 0)
2629 return false;
2631 print_matching_method(method, constructor_sig);
2633 return true;
2636 /* Print a declaration or definition of the member method "method"
2637 * using a signature associated to method name "name", if there is any.
2638 * Return true if this is the case.
2640 bool template_cpp_generator::class_printer::print_member_method_with_name(
2641 const Method &method, const std::string &name)
2643 if (member_methods.count(name) == 0)
2644 return false;
2646 print_matching_method(method, member_methods.at(name));
2647 return true;
2650 /* If "sub" appears inside "str", then remove the first occurrence and
2651 * return the result. Otherwise, simply return "str".
2653 static std::string drop_occurrence(const std::string &str,
2654 const std::string &sub)
2656 auto res = str;
2657 auto pos = str.find(sub);
2659 if (pos != std::string::npos)
2660 res.erase(pos, sub.length());
2662 return res;
2665 /* If "sub" appears in "str" next to an underscore, then remove the combination.
2666 * Otherwise, simply return "str".
2668 static std::string drop_underscore_occurrence(const std::string &str,
2669 const std::string &sub)
2671 auto res = drop_occurrence(str, sub + "_");
2672 if (res != str)
2673 return res;
2674 return drop_occurrence(res, std::string("_") + sub);
2677 /* Return the name of "method", with the name of the return type,
2678 * along with an underscore, removed, if this combination appears in the name.
2679 * Otherwise, simply return the name.
2681 const std::string name_without_return(const Method &method)
2683 auto return_infix = plain_return_type(method);
2684 return drop_underscore_occurrence(method.name, return_infix);
2687 /* If this method has a callback, then remove the type
2688 * of the first argument of the first callback from the name of the method.
2689 * Otherwise, simply return the name of the method.
2691 const std::string callback_name(const Method &method)
2693 if (method.callbacks.size() == 0)
2694 return method.name;
2696 auto type = method.callbacks.at(0)->getType();
2697 auto callback = cpp_generator::extract_prototype(type);
2698 auto arg_type = plain_type(callback->getArgType(0));
2699 return generator::drop_suffix(method.name, "_" + arg_type);
2702 /* Print a declaration or definition of the member method "method".
2704 * If the method is called "at", then it requires special treatment.
2705 * Otherwise, check if the signature is overridden for this class or
2706 * if the method is named after some other type.
2707 * Otherwise look for an appropriate signature using different variations
2708 * of the method name. First try the method name itself,
2709 * then the method name with the return type removed and
2710 * finally the method name with the callback argument type removed.
2712 void template_cpp_generator::class_printer::print_member_method(
2713 const Method &method)
2715 if (method.name == "at")
2716 return print_at_method(method);
2717 if (print_special_member_method(method))
2718 return;
2719 if (print_type_named_member_method(method))
2720 return;
2721 if (print_member_method_with_name(method, method.name))
2722 return;
2723 if (print_member_method_with_name(method, name_without_return(method)))
2724 return;
2725 if (print_member_method_with_name(method, callback_name(method)))
2726 return;
2729 /* Print a declaration or definition of "method" based on its type.
2731 void template_cpp_generator::class_printer::print_any_method(
2732 const Method &method)
2734 switch (method.kind) {
2735 case Method::Kind::static_method:
2736 print_static_method(method);
2737 break;
2738 case Method::Kind::constructor:
2739 print_constructor(method);
2740 break;
2741 case Method::Kind::member_method:
2742 print_member_method(method);
2743 break;
2747 /* Print a declaration or definition of "method".
2749 * Mark the method as not requiring copies of the arguments.
2751 void template_cpp_generator::class_printer::print_method(const Method &method)
2753 print_any_method(NoCopyMethod(method));
2756 /* Print a declaration or definition of "method".
2758 * Note that a ConversionMethod is already marked
2759 * as not requiring copies of the arguments.
2761 void template_cpp_generator::class_printer::print_method(
2762 const ConversionMethod &method)
2764 print_any_method(method);
2767 /* Helper class for printing the declarations for
2768 * template class specializations.
2770 struct template_cpp_generator::class_decl_printer :
2771 public specialization_printer
2773 class_decl_printer(std::ostream &os,
2774 template_cpp_generator &generator) :
2775 specialization_printer(os, generator) {}
2777 void print_arg_subclass_constructor(const specialization &instance,
2778 const std::vector<std::string> &params) const;
2779 void print_super_constructor(const specialization &instance) const;
2780 virtual void print_class(const specialization &instance) const override;
2783 /* Print the declaration and definition of a constructor
2784 * for the template class specialization "instance" taking
2785 * an instance with more specialized template arguments,
2786 * where "params" holds the template parameters of "instance".
2787 * It is assumed that there is at least one template parameter as otherwise
2788 * there are no template arguments to be specialized and
2789 * no constructor needs to be printed.
2791 * In particular, the constructor takes an object of the same instance where
2792 * for each template parameter, the corresponding template argument
2793 * of the input object is a subclass of the template argument
2794 * of the constructed object.
2796 * Pick fresh names for all template parameters and
2797 * add a constructor with these fresh names as extra template parameters and
2798 * a constraint requiring that each of them is a subclass
2799 * of the corresponding class template parameter.
2800 * The plain C++ interface object of the constructed object is initialized with
2801 * the plain C++ interface object of the constructor argument.
2803 void template_cpp_generator::class_decl_printer::print_arg_subclass_constructor(
2804 const specialization &instance,
2805 const std::vector<std::string> &params) const
2807 const auto &class_name = instance.class_name();
2808 auto rename = param_renamer(params, "Arg");
2809 auto derived = instance.kind.apply(rename);
2811 os << " template ";
2812 os << "<";
2813 print_pure_template_args(os, derived.params());
2814 os << ",\n";
2815 os << " typename std::enable_if<\n";
2816 for (size_t i = 0; i < params.size(); ++i) {
2817 if (i != 0)
2818 os << " &&\n";
2819 os << " std::is_base_of<"
2820 << params[i] << ", "
2821 << rename.at(params[i])->params()[0] << ">{}";
2823 os << ",\n";
2824 os << " bool>::type = true>";
2825 os << "\n";
2826 os << " " << class_name << "(const ";
2827 print_bare_template_type(os, class_name, derived);
2828 os << " &obj) : " << instance.base_name() << "(obj) {}\n";
2831 /* Print the declaration and definition of a constructor
2832 * for the template class specialization "instance" taking
2833 * an instance of the base class.
2835 * If the instance kind is that of an anonymous set
2836 * (i.e., it has a single tuple that is set to Anonymous),
2837 * then allow the constructor to be called externally.
2838 * This is mostly useful for being able to use isl::val and
2839 * isl::typed::val<Anonymous> interchangeably and similarly for isl::id.
2841 * If the instance is of any other kind, then make this constructor private
2842 * to avoid objects of the plain interface being converted automatically.
2843 * Also make sure that it does not apply to any type derived
2844 * from the base class. In particular, this makes sure it does
2845 * not apply to any other specializations of this template class as
2846 * otherwise any conflict in specializations would simply point
2847 * to the private constructor.
2849 * A factory method is added to be able to perform the conversion explicitly,
2850 * with an explicit specification of the template arguments.
2852 void template_cpp_generator::class_decl_printer::print_super_constructor(
2853 const specialization &instance) const
2855 bool hide = !instance.kind.is_anon_set();
2856 const auto &base_name = instance.base_name();
2857 const auto &arg_name = hide ? "base" : base_name;
2859 if (hide) {
2860 os << " private:\n";
2861 os << " template <typename base,\n";
2862 os << " typename std::enable_if<\n";
2863 os << " std::is_same<base, " << base_name
2864 << ">{}, bool>::type = true>\n";
2866 os << " " << instance.class_name()
2867 << "(const " << arg_name << " &obj) : "
2868 << base_name << "(obj) {}\n";
2869 if (hide)
2870 os << " public:\n";
2871 os << " static " << instance.class_name() << " from"
2872 << "(const " << base_name << " &obj) {\n";
2873 os << " return " << instance.class_name() << "(obj);\n";
2874 os << " }\n";
2877 /* Print a "declaration" for the given template class specialization.
2878 * In particular, print the class definition and the method declarations.
2880 * The template parameters are the distinct variable names
2881 * in the instance kind.
2883 * Each instance of the template class derives from the corresponding
2884 * plain C++ interface class.
2886 * All (other) template classes are made friends of this template class
2887 * to allow them to call the private constructor taking an object
2888 * of the plain interface.
2890 * Besides the constructors and methods that forward
2891 * to the corresponding methods in the plain C++ interface class,
2892 * some extra constructors are defined.
2893 * The default zero-argument constructor is useful for declaring
2894 * a variable that only gets assigned a value at a later stage.
2895 * The constructor taking an instance with more specialized
2896 * template arguments is useful for lifting the class hierarchy
2897 * of the template arguments to the template class.
2898 * The constructor taking an instance of the base class
2899 * is useful for (explicitly) constructing a template type
2900 * from a plain type.
2902 void template_cpp_generator::class_decl_printer::print_class(
2903 const specialization &instance) const
2905 const auto &class_name = instance.class_name();
2906 auto params = instance.kind.params();
2908 os << "\n";
2910 print_template(os, params);
2912 os << "struct ";
2913 print_bare_template_type(os, class_name, instance.kind);
2914 os << " : public " << instance.base_name() << " {\n";
2916 generator.print_friends(os);
2917 os << "\n";
2919 os << " " << class_name << "() = default;\n";
2920 if (params.size() != 0)
2921 print_arg_subclass_constructor(instance, params);
2922 print_super_constructor(instance);
2923 method_decl_printer(instance, *this).print_all_methods();
2925 os << "};\n";
2928 /* Helper class for printing the definitions of template class specializations.
2930 struct template_cpp_generator::class_impl_printer :
2931 public specialization_printer
2933 class_impl_printer(std::ostream &os,
2934 template_cpp_generator &generator) :
2935 specialization_printer(os, generator) {}
2937 virtual void print_class(const specialization &instance) const override;
2940 /* Print a definition for the given template class specialization.
2942 * In particular, print definitions
2943 * for the constructors and methods that forward
2944 * to the corresponding methods in the plain C++ interface class.
2945 * The extra constructors declared in the class definition
2946 * are defined inline.
2948 void template_cpp_generator::class_impl_printer::print_class(
2949 const specialization &instance) const
2951 method_impl_printer(instance, *this).print_all_methods();
2954 /* Generate a templated cpp interface
2955 * based on the extracted types and functions.
2957 * First print forward declarations for all template classes,
2958 * then the declarations of the classes, and at the end all
2959 * method implementations.
2961 void template_cpp_generator::generate()
2963 ostream &os = std::cout;
2965 os << "\n";
2967 print_forward_declarations(os);
2968 class_decl_printer(os, *this).print_classes();
2969 class_impl_printer(os, *this).print_classes();