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