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 */
51std::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 */
60std::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 */
72TupleKindPtr 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 */
82static 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 */
91TupleKindPtr 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 */
100TupleKindPtr 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 */
108struct 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 */
116TupleKindPtr::TupleKindPtr(Fixed) : Base(std::make_shared<TupleKind>(""))
117{
118}
119
120/* Tuple pointers for non-template types.
121 */
122static TupleKindPtr Ctx{Fixed()};
123static TupleKindPtr Integer{Fixed()};
124static TupleKindPtr Str{Fixed()};
125static 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 */
133static TupleKindPtr Anonymous("Anonymous");
134static TupleKindPtr Leaf("Leaf");
135
136/* Placeholder tuple pointers that refer to (part of) the domain or range.
137 */
138static TupleKindPtr Domain("Domain");
139static TupleKindPtr Domain2("Domain2");
140static TupleKindPtr Domain3("Domain3");
141static TupleKindPtr Range("Range");
142static TupleKindPtr Range2("Range2");
143static 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 */
148struct 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 */
159std::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 */
169TupleKindPtr::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 */
176struct 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 */
195std::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 */
207static 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 */
219std::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 */
235TupleKindPtr 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 */
243TupleKindPtr Pair::left() const
244{
245	return tuple1;
246}
247
248/* Return the right child of this tuple kind.
249 */
250TupleKindPtr 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 */
258TupleKindPtr::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 */
265bool 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 */
272bool Kind::is_set() const
273{
274	return size() == 1;
275}
276
277/* Is this a kind of object with a single, anonymous tuple?
278 */
279bool 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 */
288std::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 */
302Kind 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 */
315struct 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 */
327std::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 */
342Signature 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 */
355static 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 */
377static 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 */
386static 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 */
401static 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 */
409static Signature un_params = { { }, { { } } };
410static Signature un_set = { { Domain }, { { Domain } } };
411static Signature un_map = { { Domain, Range }, { { Domain, Range } } };
412static std::vector<Signature> un_op = { un_params, un_set, un_map };
413static 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 */
419static Signature bin_params = { { }, { { }, { } } };
420static Signature bin_set = { { Domain }, { { Domain }, { Domain } } };
421static Signature bin_map =
422	{ { Domain, Range }, { { Domain, Range }, { Domain, Range } } };
423static std::vector<Signature> bin_op = { bin_params, bin_set, bin_map };
424static std::vector<Signature> fn_bin_op = { bin_set, bin_map };
425static Signature bin_set_params = { { Domain }, { { Domain }, { } } };
426static Signature bin_map_params =
427	{ { Domain, Range }, { { Domain, Range }, { } } };
428static Signature bin_map_domain =
429	{ { Domain, Range }, { { Domain, Range }, { Domain } } };
430static Signature bin_map_range =
431	{ { Domain, Range }, { { Domain, Range }, { Range } } };
432static Signature bin_map_domain_wrapped_domain =
433	{ { { Domain, Domain2 }, Range },
434	  { { { Domain, Domain2 }, Range }, { Domain } } };
435static 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 */
442static Signature bin_params_anon = { { }, { { }, { Anonymous } } };
443static Signature bin_set_anon = { { Domain }, { { Domain }, { Anonymous } } };
444static Signature bin_map_anon =
445	{ { Domain, Range }, { { Domain, Range }, { Anonymous } } };
446static 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 */
451static Signature ter_params_int_int =
452	{ { }, { { }, { Integer }, { Integer } } };
453static Signature ter_set_int_int =
454	{ { Domain }, { { Domain }, { Integer }, { Integer } } };
455static Signature ter_map_int_int =
456	{ { Domain, Range }, { { Domain, Range }, { Integer }, { Integer } } };
457static 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 */
463static Signature ter_set =
464	{ { Domain }, { { Domain }, { Domain }, { Domain } } };
465static Signature ter_map =
466	{ { Domain, Range },
467	  { { Domain, Range }, { Domain, Range }, { Domain, Range } } };
468static 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 */
473static Signature update_set = { { Domain2 }, { { Leaf }, { Anonymous } } };
474static Signature update_domain =
475	{ { Domain2, Range }, { { Leaf, Range }, { Anonymous } } };
476static 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 */
482static 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 */
486static Signature to_set = { { Domain }, { { }, { Integer } } };
487static Signature add_range = { { Domain, Range }, { { Domain }, { Integer } } };
488/* Signatures for adding a named tuple to an object with zero or one tuple.
489 */
490static Signature to_set_named =
491	{ { Domain }, { { }, { Anonymous }, { Integer } } };
492static 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 */
498static Signature set_forward = { { Range }, { { Domain }, { Domain, Range } } };
499static Signature domain_forward =
500	{ { Domain2, Range }, { { Domain, Range }, { Domain, Domain2 } } };
501static 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 */
507static Signature set_backward =
508	{ { Domain2 }, { { Domain }, { Domain2, Domain } } };
509static Signature domain_backward =
510	{ { Domain2, Range }, { { Domain, Range }, { Domain2, Domain } } };
511static Signature range_backward =
512	{ { Domain, Range2 }, { { Domain, Range }, { Range2, Range } } };
513static 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 */
520static Signature bind_set = { { }, { { Domain }, { Domain } } };
521static Signature bind_domain = { { Range }, { { Domain, Range }, { Domain } } };
522static Signature bind_range = { { Domain }, { { Domain, Range }, { Range } } };
523static 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 */
532static Signature each_params = { { Res }, { { }, { Res }, { } } };
533static Signature each_set = { { Res }, { { Domain }, { Res }, { Domain } } };
534static Signature each_map =
535	{ { Res }, { { Domain, Range }, { Res }, { Domain, Range } } };
536static 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 */
543static Signature each_scc_params =
544	{ { Res }, { { }, { Res }, { }, { }, { Res }, { } } };
545static Signature each_scc_set =
546	{ { Res }, { { Domain },
547		     { Res }, { Domain }, { Domain },
548		     { Res }, { Domain } } };
549static Signature each_scc_map =
550	{ { Res }, { { Domain, Range },
551		     { Res }, { Domain, Range }, { Domain, Range },
552		     { Res }, { Domain, Range } } };
553static 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 */
559static 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 */
567static Signature set_from_params = { { Domain }, { { }, { Domain } } };
568static Signature map_from_domain_and_range =
569	{ { Domain, Range }, { { Domain }, { Range } } };
570static 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 */
576static Signature anonymous_set_from_params = { { Anonymous }, { { } } };
577static Signature anonymous_map_from_domain =
578	{ { Domain, Anonymous }, { { Domain } } };
579static 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 */
585static Signature anonymous_set_from_params_bin_anon =
586	{ { Anonymous }, { { }, { Anonymous } } };
587static Signature anonymous_map_from_domain_bin_anon =
588	{ { Domain, Anonymous }, { { Domain }, { Anonymous } } };
589static 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 */
597static 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 */
602static Signature domain = { { Domain }, { { Domain, Range } } };
603static Signature range = { { Range }, { { Domain, Range } } };
604static Signature transformation_domain = { { Domain }, { { Domain, Domain } } };
605
606/* Signatures for obtaining the parameter domain of a set or map.
607 */
608static Signature set_params = { { }, { { Domain } } };
609static Signature map_params = { { }, { { Domain, Range } } };
610
611/* Signatures for obtaining the domain of a function.
612 */
613static std::vector<Signature> fn_domain = { domain, set_params };
614
615/* Signatures for interchanging (wrapped) domain and range.
616 */
617static Signature set_reverse =
618	{ { { Range, Domain } }, { { { Domain, Range } } } };
619static Signature map_reverse = { { Range, Domain }, { { Domain, Range } } };
620static Signature map_domain_reverse =
621	{ { { Domain2, Domain }, Range }, { { { Domain, Domain2 }, Range } } };
622static Signature map_range_reverse =
623	{ { Domain, { Range2, Range } }, { { Domain, { Range, Range2 } } } };
624
625/* Signatures for constructing products.
626 */
627static Signature set_product =
628	{ { { Domain, Range } }, { { Domain }, { Range } } };
629static Signature map_product =
630	{ { { Domain, Domain2 }, { Range, Range2 } },
631	  { { Domain, Range }, { Domain2, Range2 } } };
632static Signature domain_product =
633	{ { { Domain, Domain2 }, Range },
634	  { { Domain, Range }, { Domain2, Range } } };
635static Signature range_product =
636	{ { Domain, { Range, Range2 } },
637	  { { Domain, Range }, { Domain, Range2 } } };
638
639/* Signatures for obtaining factors from a product.
640 */
641static Signature domain_factor_domain =
642	{ { Domain, Range }, { { { Domain, Domain2 }, Range } } };
643static Signature domain_factor_range =
644	{ { Domain2, Range }, { { { Domain, Domain2 }, Range } } };
645static Signature range_factor_domain =
646	{ { Domain, Range }, { { Domain, { Range, Range2 } } } };
647static Signature range_factor_range =
648	{ { Domain, Range2 }, { { Domain, { Range, Range2 } } } };
649
650/* Signatures for (un)currying.
651 */
652static Signature curry =
653	{ { Domain, { Range, Range2 } },
654	  { { { Domain, Range }, Range2 } } };
655static Signature uncurry =
656	{ { { Domain, Range }, Range2 },
657	  { { Domain, { Range, Range2 } } } };
658
659/* Signatures for (un)wrapping.
660 */
661static Signature wrap = { { { Domain, Range } }, { { Domain, Range } } };
662static Signature unwrap = { { Domain, Range }, { { { Domain, Range } } } };
663
664/* Signatures for constructing objects that map to the domain or range
665 * of a map.
666 */
667static Signature domain_map =
668	{ { { Domain, Range }, Domain }, { { Domain, Range } } };
669static 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 */
675static 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 */
681static 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 */
687static Signature anonymize_nested_domain =
688	{ { Anonymous, Range2 }, { { { Domain, Range }, Range2 } } };
689static Signature anonymize_nested_range =
690	{ { Domain, Anonymous }, { { Domain, { Range, Range2 } } } };
691static Signature replace_nested_domain =
692	{ { Domain2, Range2 },
693	  { { { Domain, Range }, Range2 }, { Anonymous} } };
694static Signature replace_nested_range =
695	{ { Domain, Range3 }, { { Domain, { Range, Range2 } }, { Anonymous} } };
696static std::vector<Signature> flatten_domain =
697	{ anonymize_nested_domain, replace_nested_domain };
698static std::vector<Signature> flatten_range =
699	{ anonymize_nested_range, replace_nested_range };
700
701/* Signatures for "set_at" methods.
702 */
703static Signature set_at_set =
704	{ { Domain }, { { Domain }, { Integer }, { Anonymous } } };
705static Signature set_at_map =
706	{ { Domain, Range },
707	  { { Domain, Range }, { Integer }, { Domain, Anonymous } } };
708static 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 */
713static Signature to_list_set = { { Anonymous }, { { Domain } } };
714static Signature to_list_map = { { Domain, Anonymous }, { { Domain, Range } } };
715
716/* Signatures for functions constructing an object from only an isl::ctx.
717 */
718static Signature ctx_params = { { }, { { Ctx } } };
719static Signature ctx_set = { { Domain }, { { Ctx } } };
720static 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 */
729struct 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 */
739typedef 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 */
744typedef 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 */
755static 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 */
778static std::vector<Signature> range_op = { un_set, range };
779
780/* Signatures for binary operations where the second argument
781 * is a (multi-)value.
782 */
783static 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 */
788static const std::unordered_map<std::string, std::vector<Signature>>
789member_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 */
928static Signature from_list_set = { { Domain }, { { Domain }, { Anonymous } } };
929static Signature from_list_map =
930	{ { Domain, Range }, { { Domain, Range }, { Domain, Anonymous } } };
931static 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 */
966static 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 */
987static Kind params{};
988static Kind set_type{ Domain };
989static Kind set_anon{ Anonymous };
990static Kind map_type{ Domain, Range };
991static 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 */
1008static 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 */
1021static 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 */
1031static 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 */
1050static 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 */
1067static 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 */
1075static 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 */
1093static 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 */
1107void 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 */
1128template_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 */
1148void 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 */
1161void 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 */
1184void 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 */
1196static 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 */
1204static 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 */
1212template <typename List>
1213static 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 */
1225template <typename List>
1226static 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 */
1235static 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 */
1246static 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 */
1259static 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 */
1268struct 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 */
1279const std::string &specialization::base_name() const
1280{
1281	return template_class.super_name;
1282}
1283
1284/* The name of the template class.
1285 */
1286const 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 */
1297struct 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 */
1321void 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 */
1339struct 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 */
1386template_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 */
1400struct 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 */
1412std::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 */
1430std::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 */
1443struct 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 */
1457Kind 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 */
1466struct 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 */
1480Kind 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 */
1496struct 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 */
1512std::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 */
1523void 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 */
1533template <typename T>
1534static 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 */
1549void 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 */
1573void 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 */
1591bool 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 */
1600void 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 */
1609struct 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 */
1623void 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 */
1642static 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 */
1659static 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 */
1674void 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 */
1685struct 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 */
1705void 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 */
1726static 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 */
1751static 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 */
1788static 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 */
1814void 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 */
1848void 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 */
1878void 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 */
1902void 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 */
1910void 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 */
1918static Signature params_from_str = { { }, { { Ctx }, { Str } } };
1919static Signature set_from_str = { { Domain }, { { Ctx }, { Str } } };
1920static Signature map_from_str = { { Domain, Range }, { { Ctx }, { Str } } };
1921static 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 */
1926static Signature int_from_si = { { Anonymous }, { { Ctx }, { Integer } } };
1927
1928/* Signatures for constructors of lists from the initial number
1929 * of elements.
1930 */
1931static Signature alloc_params = { { }, { { Ctx }, { Integer } } };
1932static Signature alloc_set = { { Domain }, { { Ctx }, { Integer } } };
1933static 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 */
1949static 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 */
1960static const std::unordered_map<std::string, std::vector<Signature>>
1961special_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 */
1969void 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 */
1985bool 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 */
1995bool 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 */
2010static 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 */
2035static 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 */
2060static 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 */
2081static 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 */
2090void 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 */
2101struct 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 */
2114std::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 */
2125static 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 */
2132static 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 */
2144static 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 */
2158static 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 */
2174bool 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 */
2194static 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 */
2206static 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 */
2219static 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
2230static 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 */
2241static 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 */
2262static 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 */
2286static 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 */
2317static 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 */
2340static 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 */
2366void 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 */
2385static 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 */
2412static 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 */
2430static 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 */
2469bool 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 */
2492static 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 */
2499static 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 */
2518bool 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 */
2541void 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 */
2557static Signature select_set = { { Anonymous }, { { Domain }, { Integer } } };
2558static Signature select_map =
2559	{ { Domain, Anonymous }, { { Domain, Range }, { Integer } } };
2560static 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 */
2565static Signature bin_set_int = { { Domain }, { { Domain }, { Integer } } };
2566static Signature bin_map_int =
2567	{ { Domain, Range }, { { Domain, Range }, { Integer } } };
2568static 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 */
2581void 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 */
2596static 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 */
2610bool 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 */
2630bool 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 */
2639bool 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 */
2654bool 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 */
2667static 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 */
2682static 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 */
2695const 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 */
2705const 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 */
2726void 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 */
2745void 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 */
2765void 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 */
2775void 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 */
2784struct 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 */
2817void 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 */
2866void 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 */
2916void 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 */
2944struct 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 */
2962void 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 */
2975void 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