2 * Copyright 2016, 2017 Tobias Grosser. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''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 TOBIAS GROSSER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * The views and conclusions contained in the software and documentation
29 * are those of the authors and should not be interpreted as
30 * representing official policies, either expressed or implied, of
39 #include "isl_config.h"
41 /* Determine the isl types from which the given class can be implicitly
42 * constructed using a unary constructor.
44 * Look through all constructors for implicit conversion constructors that take
45 * an isl type and add those types, along with the corresponding
46 * constructor argument.
48 void cpp_generator::set_class_construction_types(isl_class
&clazz
)
50 for (const auto &cons
: clazz
.constructors
) {
55 if (!is_implicit_conversion(Method(clazz
, cons
)))
58 param
= cons
->getParamDecl(0);
59 type
= param
->getOriginalType();
60 arg_type
= extract_type(type
);
61 clazz
.construction_types
.emplace(arg_type
, param
);
65 /* Determine the isl types from which any (proper) class can be constructed
66 * using a unary constructor.
68 void cpp_generator::set_construction_types()
70 for (auto &kvp
: classes
) {
71 auto &clazz
= kvp
.second
;
72 set_class_construction_types(clazz
);
76 /* Construct a generator for C++ bindings.
78 * The classes and methods are extracted by the constructor
79 * of the generator superclass.
81 * Additionally extract information about types
82 * that can be converted to a class and copy all methods
83 * from superclasses that can be converted to a given class
86 cpp_generator::cpp_generator(SourceManager
&SM
,
87 set
<RecordDecl
*> &exported_types
,
88 set
<FunctionDecl
*> exported_functions
, set
<FunctionDecl
*> functions
) :
89 generator(SM
, exported_types
, exported_functions
, functions
)
91 set_construction_types();
95 /* Copy the method called "name" described by "fd" from "super" to "clazz"
96 * with the distance to the original ancestor given by "depth".
98 * In particular, keep track of "fd" as well as the superclass
99 * from which it was copied and the distance to the original ancestor.
101 static void copy_method(isl_class
&clazz
, const isl_class
&super
,
102 const std::string
&name
, FunctionDecl
*fd
, int depth
)
104 clazz
.methods
[name
].insert(fd
);
105 clazz
.copied_from
.emplace(fd
, super
);
106 clazz
.copy_depth
.emplace(fd
, depth
);
109 /* Do "fd1" and "fd2" have the same signature (ignoring the first argument
110 * which represents the object class on which the corresponding method
113 static bool same_signature(FunctionDecl
*fd1
, FunctionDecl
*fd2
)
115 int n1
= fd1
->getNumParams();
116 int n2
= fd2
->getNumParams();
121 for (int i
= 1; i
< n1
; ++i
) {
122 ParmVarDecl
*p1
= fd1
->getParamDecl(i
);
123 ParmVarDecl
*p2
= fd2
->getParamDecl(i
);
125 if (p1
->getOriginalType() != p2
->getOriginalType())
132 /* Return the distance between "clazz" and the ancestor
133 * from which "fd" got copied.
134 * If no distance was recorded, then the method has not been copied
135 * but appears in "clazz" itself and so the distance is zero.
137 static int copy_depth(const isl_class
&clazz
, FunctionDecl
*fd
)
139 if (clazz
.copy_depth
.count(fd
) == 0)
141 return clazz
.copy_depth
.at(fd
);
144 /* Is the method derived from "fd", with method name "name" and
145 * with distance to the original ancestor "depth",
146 * overridden by a method already in "clazz"?
148 * A method is considered to have been overridden if there
149 * is a method with the same name in "clazz" that has the same signature and
150 * that comes from an ancestor closer to "clazz",
151 * where an ancestor is closer if the distance in the class hierarchy
152 * is smaller or the distance is the same and the ancestor appears
153 * closer in the declaration of the type (in which case it gets added first).
155 * If a method with the same signature has already been added,
156 * but it does not override the method derived from "fd",
157 * then this method is removed since it is overridden by "fd".
159 static bool is_overridden(FunctionDecl
*fd
, isl_class
&clazz
,
160 const std::string
&name
, int depth
)
162 if (clazz
.methods
.count(name
) == 0)
165 for (const auto &m
: clazz
.methods
.at(name
)) {
166 if (!same_signature(fd
, m
))
168 if (copy_depth(clazz
, m
) <= depth
)
170 clazz
.methods
[name
].erase(m
);
176 /* Add the methods "methods" with method name "name" from "super" to "clazz"
177 * provided they have not been overridden by a method already in "clazz".
179 * Methods that are static in their original class are not copied.
181 void cpp_generator::copy_methods(isl_class
&clazz
, const std::string
&name
,
182 const isl_class
&super
, const function_set
&methods
)
184 for (auto fd
: methods
) {
187 if (method2class(fd
)->is_static(fd
))
189 depth
= copy_depth(super
, fd
) + 1;
190 if (is_overridden(fd
, clazz
, name
, depth
))
192 copy_method(clazz
, super
, name
, fd
, depth
);
196 /* Add all methods from "super" to "clazz" that have not been overridden
197 * by a method already in "clazz".
199 * Look through all groups of methods with the same name.
201 void cpp_generator::copy_super_methods(isl_class
&clazz
, const isl_class
&super
)
203 for (const auto &kvp
: super
.methods
) {
204 const auto &name
= kvp
.first
;
205 const auto &methods
= kvp
.second
;
207 copy_methods(clazz
, name
, super
, methods
);
211 /* Copy methods from the superclasses of "clazz"
212 * if an object of this class can be implicitly converted to an object
213 * from the superclass, keeping track
214 * of the classes that have already been handled in "done".
216 * Make sure the superclasses have copied methods from their superclasses first
217 * since those methods could be copied further down to this class.
219 * Consider the superclass that appears closest to the subclass first.
221 void cpp_generator::copy_super_methods(isl_class
&clazz
, set
<string
> &done
)
223 auto supers
= find_superclasses(clazz
.type
);
225 for (const auto &super
: supers
)
226 if (done
.count(super
) == 0)
227 copy_super_methods(classes
[super
], done
);
228 done
.insert(clazz
.name
);
230 for (const auto &super_name
: supers
) {
231 const auto &super
= classes
[super_name
];
233 if (super
.construction_types
.count(clazz
.name
) == 0)
235 copy_super_methods(clazz
, super
);
239 /* For each (proper) class, copy methods from its superclasses,
240 * if an object from the class can be converted to an object
241 * from the superclass.
243 * Type based subclasses are not considered for now since
244 * they do not have any explicit superclasses.
246 * Iterate through all (proper) classes and copy methods
247 * from their superclasses,
248 * unless they have already been determined by a recursive call.
250 void cpp_generator::copy_super_methods()
254 for (auto &kvp
: classes
) {
255 auto &clazz
= kvp
.second
;
257 if (clazz
.is_type_subclass())
259 if (done
.count(clazz
.name
) != 0)
261 copy_super_methods(clazz
, done
);
265 /* Print declarations or implementations of constructors.
267 * For each isl function that is marked as __isl_constructor,
268 * add a corresponding C++ constructor.
270 * Example of declarations:
272 * inline /\* implicit *\/ union_set(basic_set bset);
273 * inline /\* implicit *\/ union_set(set set);
274 * inline explicit val(ctx ctx, long i);
275 * inline explicit val(ctx ctx, const std::string &str);
277 void cpp_generator::class_printer::print_constructors()
279 for (const auto &cons
: clazz
.constructors
)
280 print_method(Method(clazz
, cons
));
283 /* Print declarations or definitions for methods in the class.
285 void cpp_generator::class_printer::print_methods()
287 for (const auto &kvp
: clazz
.methods
)
288 print_method_group(kvp
.second
, kvp
.first
);
291 /* Print declarations or implementations for the methods derived from "fd",
292 * which sets an enum.
294 * A method is generated for each value in the enum, setting
295 * the enum to that value.
297 void cpp_generator::class_printer::print_set_enums(FunctionDecl
*fd
)
299 for (const auto &set
: clazz
.set_enums
.at(fd
)) {
300 EnumMethod
method(clazz
, fd
, set
.method_name
, set
.name
);
302 print_method(method
);
306 /* Print declarations or implementations for methods derived from functions
309 void cpp_generator::class_printer::print_set_enums()
311 for (const auto &kvp
: clazz
.set_enums
)
312 print_set_enums(kvp
.first
);
315 /* Update "convert" to reflect the next combination of automatic conversions
316 * for the arguments of "fd",
317 * returning false if there are no more combinations.
319 * In particular, find the last argument for which an automatic
320 * conversion function is available mapping to the type of this argument and
321 * that is not already marked for conversion.
322 * Mark this argument, if any, for conversion and clear the markings
323 * of all subsequent arguments.
324 * Repeated calls to this method therefore run through
325 * all possible combinations.
327 * Note that the first function argument is never considered
328 * for automatic conversion since this is the argument
329 * from which the isl_ctx used in the conversion is extracted.
331 bool cpp_generator::class_printer::next_variant(FunctionDecl
*fd
,
332 std::vector
<bool> &convert
)
334 size_t n
= convert
.size();
336 for (int i
= n
- 1; i
>= 1; --i
) {
337 ParmVarDecl
*param
= fd
->getParamDecl(i
);
338 const Type
*type
= param
->getOriginalType().getTypePtr();
340 if (generator
.conversions
.count(type
) == 0)
345 for (size_t j
= i
+ 1; j
< n
; ++j
)
353 /* Print a declaration or definition for a method called "name"
356 * If the method was copied from a superclass, then print a definition
357 * that calls the corresponding method in the superclass.
358 * Otherwise, for methods that are identified as "get" methods, also
359 * print a declaration or definition for the method
360 * using a name that includes the "get_" prefix.
362 * If the generated method is an object method, then check
363 * whether any of its arguments can be automatically converted
364 * from something else, and, if so, generate a method
365 * for each combination of converted arguments.
366 * Do so by constructing a ConversionMethod that changes the converted arguments
367 * to those of the sources of the conversions.
369 * Note that a method may be both copied from a superclass and
370 * have arguments that can be automatically converted.
371 * In this case, the conversion methods for the arguments
372 * call the corresponding method in this class, which
373 * in turn will call the method in the superclass.
375 void cpp_generator::class_printer::print_method_variants(FunctionDecl
*fd
,
376 const std::string
&name
)
378 Method
method(clazz
, fd
, name
);
379 std::vector
<bool> convert(method
.num_params());
381 if (method
.clazz
.copied_from
.count(method
.fd
) == 0) {
382 print_method(method
);
383 if (clazz
.is_get_method(fd
))
384 print_get_method(fd
);
386 auto super
= method
.clazz
.copied_from
.at(method
.fd
);
387 print_method(ConversionMethod(method
, super
.name
));
389 if (method
.kind
!= Method::Kind::member_method
)
391 while (next_variant(fd
, convert
)) {
392 print_method(ConversionMethod(method
, [&] (int pos
) {
393 return get_param(fd
, pos
, convert
);
398 /* Given a function declaration representing a method,
399 * does this method have a single argument (beyond the object
400 * on which the method is called) that corresponds to
403 static bool has_single_isl_argument(FunctionDecl
*fd
)
407 if (fd
->getNumParams() != 2)
410 param
= fd
->getParamDecl(1);
411 return generator::is_isl_type(param
->getOriginalType());
414 /* Does the set "methods" contain exactly one function declaration
415 * that corresponds to a method of "clazz" itself (i.e., that
416 * was not copied from an ancestor)?
418 static FunctionDecl
*single_local(const isl_class
&clazz
,
419 const function_set
&methods
)
424 for (const auto &fn
: methods
) {
425 if (!clazz
.first_arg_matches_class(fn
))
431 return count
== 1 ? local
: NULL
;
434 /* Given a function declaration "fd" for a method called "name"
435 * with a single argument representing an isl object,
436 * generate declarations or definitions for methods with the same name,
437 * but with as argument an isl object of a class that can be implicitly
438 * converted to that of the original argument.
439 * In particular, generate methods for converting this argument.
441 void cpp_generator::class_printer::print_descendent_overloads(
442 FunctionDecl
*fd
, const std::string
&name
)
444 Method
method(clazz
, fd
, name
);
445 ParmVarDecl
*param
= fd
->getParamDecl(1);
446 QualType type
= param
->getOriginalType();
447 std::string arg
= type
->getPointeeType().getAsString();
449 for (const auto &kvp
: generator
.classes
[arg
].construction_types
) {
450 const auto sub
= kvp
.second
;
451 print_method(ConversionMethod(method
, [&] (int pos
) {
457 /* Print declarations or definitions for methods called "name"
458 * derived from "methods".
460 * If want_descendent_overloads signals that variants should be added that take
461 * as arguments those types that can be converted to the original argument type
462 * through a unary constructor and if only one of the methods in the group
463 * was originally defined in "clazz", then effectively add those variants.
464 * Only do this for methods with a single (isl object) argument.
466 void cpp_generator::class_printer::print_method_group(
467 const function_set
&methods
, const std::string
&name
)
471 for (const auto &fd
: methods
)
472 print_method_variants(fd
, name
);
473 if (!want_descendent_overloads(methods
))
475 local
= single_local(clazz
, methods
);
478 if (!has_single_isl_argument(local
))
480 print_descendent_overloads(local
, name
);
483 /* Print the use of the argument at position "pos" to "os".
485 * Member methods pass the isl object corresponding to "this"
486 * as first argument (at position 0).
487 * Any other arguments are passed along from the method arguments.
489 * If the argument value is loaded from a this pointer, the original
490 * value must be preserved and must consequently be copied. Values that are
491 * loaded from method parameters do not need to be preserved, as such values
492 * will already be copies of the actual parameters. It is consequently possible
493 * to directly take the pointer from these values, which saves
494 * an unnecessary copy.
496 * In case the parameter is a callback function, two parameters get printed,
497 * a wrapper for the callback function and a pointer to the actual
498 * callback function. The wrapper is expected to be available
499 * in a previously declared variable <name>_lambda, while
500 * the actual callback function is expected to be stored
501 * in a structure called <name>_data.
502 * The caller of this function must ensure that these variables exist.
504 void Method::print_param_use(ostream
&os
, int pos
) const
506 ParmVarDecl
*param
= fd
->getParamDecl(pos
);
507 bool load_from_this_ptr
= pos
== 0 && kind
== member_method
;
508 string name
= param
->getName().str();
509 QualType type
= param
->getOriginalType();
511 if (type
->isIntegerType()) {
516 if (generator::is_string(type
)) {
517 os
<< name
<< ".c_str()";
521 if (generator::is_callback(type
)) {
522 os
<< name
<< "_lambda, ";
523 os
<< "&" << name
<< "_data";
527 if (!load_from_this_ptr
)
530 if (generator::keeps(param
)) {
533 if (load_from_this_ptr
)
540 /* Does the isl function from which this method is derived
541 * modify an object of a subclass based on a type function?
543 bool Method::is_subclass_mutator() const
545 return clazz
.is_type_subclass() && generator::is_mutator(clazz
, fd
);
548 /* Return the C++ return type of the method "method".
550 * If the corresponding function modifies an object of a subclass, then return
551 * the type of this subclass.
552 * Otherwise, return the C++ counterpart of the actual return type.
554 std::string
cpp_type_printer::return_type(const Method
&method
) const
556 if (method
.is_subclass_mutator())
557 return cpp_generator::type2cpp(method
.clazz
);
559 return param(-1, method
.fd
->getReturnType());
562 /* Return the formal parameter at position "pos" of "fd".
563 * However, if this parameter should be converted, as indicated
564 * by "convert", then return the second formal parameter
565 * of the conversion function instead.
567 ParmVarDecl
*cpp_generator::class_printer::get_param(FunctionDecl
*fd
,
568 int pos
, const std::vector
<bool> &convert
)
570 ParmVarDecl
*param
= fd
->getParamDecl(pos
);
574 return generator
.conversions
[param
->getOriginalType().getTypePtr()];
577 /* Print the header for "method", without newline or semicolon,
578 * using "type_printer" to print argument and return types.
580 * Print the header of a declaration if this->declarations is set,
581 * otherwise print the header of a method definition.
583 * This function prints headers for member methods, static methods, and
584 * constructors, either for their declaration or definition.
586 * Member functions are declared as "const", as they do not change the current
587 * object, but instead create a new object. They always retrieve the first
588 * parameter of the original isl function from the this-pointer of the object,
589 * such that only starting at the second parameter the parameters of the
590 * original function become part of the method's interface.
594 * __isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1,
595 * __isl_take isl_set *s2);
597 * is translated into:
599 * inline set intersect(set set2) const
601 * For static functions and constructors all parameters of the original isl
602 * function are exposed.
604 * Parameters of which no copy is required, are passed
605 * as const reference, which allows the compiler to optimize the parameter
608 * Constructors are marked as explicit using the C++ keyword 'explicit' or as
609 * implicit using a comment in place of the explicit keyword. By annotating
610 * implicit constructors with a comment, users of the interface are made
611 * aware of the potential danger that implicit construction is possible
612 * for these constructors, whereas without a comment not every user would
613 * know that implicit construction is allowed in absence of an explicit keyword.
615 * Note that in case "method" is a ConversionMethod, the argument returned
616 * by Method::get_param may be different from the original argument.
617 * The name of the argument is, however, derived from the original
620 void cpp_generator::class_printer::print_method_header(
621 const Method
&method
, const cpp_type_printer
&type_printer
)
623 string rettype_str
= type_printer
.return_type(method
);
628 if (method
.kind
== Method::Kind::static_method
)
633 if (method
.kind
== Method::Kind::constructor
) {
634 if (generator
.is_implicit_conversion(method
))
635 os
<< "/* implicit */ ";
641 if (method
.kind
!= Method::Kind::constructor
)
642 os
<< rettype_str
<< " ";
645 os
<< type_printer
.class_type(cppstring
) << "::";
647 if (method
.kind
!= Method::Kind::constructor
)
652 method
.print_cpp_arg_list(os
, [&] (int i
, int arg
) {
653 std::string name
= method
.fd
->getParamDecl(i
)->getName().str();
654 ParmVarDecl
*param
= method
.get_param(i
);
655 QualType type
= param
->getOriginalType();
656 string cpptype
= type_printer
.param(arg
, type
);
658 if (!method
.param_needs_copy(i
))
659 os
<< "const " << cpptype
<< " &" << name
;
661 os
<< cpptype
<< " " << name
;
664 if (method
.kind
== Method::Kind::member_method
)
668 /* Generate the list of argument types for a callback function of
669 * type "type", appearing in argument position "arg".
670 * If "cpp" is set, then generate the C++ type list, otherwise
673 * For a callback of type
675 * isl_stat (*)(__isl_take isl_map *map, void *user)
677 * the following C++ argument list is generated:
681 * The arguments of the callback are considered to appear
682 * after the position of the callback itself.
684 std::string
cpp_type_printer::generate_callback_args(int arg
, QualType type
,
687 std::string type_str
;
688 const FunctionProtoType
*callback
;
691 callback
= generator::extract_prototype(type
);
692 num_params
= callback
->getNumArgs();
696 for (long i
= 0; i
< num_params
; i
++) {
697 QualType type
= callback
->getArgType(i
);
700 type_str
+= param(arg
+ 1 + i
, type
);
702 type_str
+= type
.getAsString();
705 type_str
+= "arg_" + ::to_string(i
);
707 if (i
!= num_params
- 1)
714 /* Generate the full cpp type of a callback function of type "type",
715 * appearing in argument position "arg".
717 * For a callback of type
719 * isl_stat (*)(__isl_take isl_map *map, void *user)
721 * the following type is generated:
723 * std::function<stat(map)>
725 std::string
cpp_type_printer::generate_callback_type(int arg
, QualType type
)
728 std::string type_str
;
729 const FunctionProtoType
*callback
= generator::extract_prototype(type
);
730 QualType return_type
= callback
->getReturnType();
731 string rettype_str
= param(arg
, return_type
);
733 type_str
= "std::function<";
734 type_str
+= rettype_str
;
736 type_str
+= generate_callback_args(arg
, type
, true);
742 /* An array listing functions that must be renamed and the function name they
743 * should be renamed to. We currently rename functions in case their name would
744 * match a reserved C++ keyword, which is not allowed in C++.
746 static const char *rename_map
[][2] = {
747 { "union", "unite" },
750 /* Rename method "name" in case the method name in the C++ bindings should not
751 * match the name in the C bindings. We do this for example to avoid
754 static std::string
rename_method(std::string name
)
756 for (size_t i
= 0; i
< sizeof(rename_map
) / sizeof(rename_map
[0]); i
++)
757 if (name
.compare(rename_map
[i
][0]) == 0)
758 return rename_map
[i
][1];
763 /* Translate isl class "clazz" to its corresponding C++ type.
764 * Use the name of the type based subclass, if any.
766 string
cpp_generator::type2cpp(const isl_class
&clazz
)
768 return type2cpp(clazz
.subclass_name
);
771 /* Translate type string "type_str" to its C++ name counterpart.
773 string
cpp_generator::type2cpp(string type_str
)
775 return type_str
.substr(4);
778 /* Return the C++ counterpart to the isl_bool type.
780 * By default, this is simply "bool" since
781 * the exceptional case is handled through exceptions.
783 std::string
cpp_type_printer::isl_bool() const
788 /* Return the C++ counterpart to the isl_stat type.
790 * By default, this is simply "void" since
791 * the exceptional case is handled through exceptions.
793 string
cpp_type_printer::isl_stat() const
798 /* Return the C++ counterpart to the isl_size type.
800 * By default, this is simply "unsigned" since
801 * the exceptional case is handled through exceptions.
803 string
cpp_type_printer::isl_size() const
808 /* Return the namespace of the generated C++ bindings.
810 * By default, this is "isl::".
812 std::string
cpp_type_printer::isl_namespace() const
817 /* Return the class type given the C++ name.
819 * By default, directly use the C++ name.
821 std::string
cpp_type_printer::class_type(const std::string
&cpp_name
) const
826 /* Return the qualified form of the given C++ isl type name appearing
827 * in argument position "arg" (-1 for return type).
829 * By default, the argument position is ignored.
831 std::string
cpp_type_printer::qualified(int arg
, const std::string
&cpp_type
)
834 return isl_namespace() + cpp_type
;
837 /* Return the C++ counterpart to the given isl type appearing
838 * in argument position "arg" (-1 for return type).
840 std::string
cpp_type_printer::isl_type(int arg
, QualType type
) const
842 auto name
= type
->getPointeeType().getAsString();
843 return qualified(arg
, cpp_generator::type2cpp(name
));
846 /* Translate parameter or return type "type" to its C++ name counterpart.
847 * "arg" is the position of the argument, or -1 in case of the return type.
848 * If any callback is involved, then the return type and arguments types
849 * of the callback are considered to start at the position of the callback.
851 std::string
cpp_type_printer::param(int arg
, QualType type
) const
853 if (cpp_generator::is_isl_type(type
))
854 return isl_type(arg
, type
);
856 if (cpp_generator::is_isl_bool(type
))
859 if (cpp_generator::is_isl_stat(type
))
862 if (cpp_generator::is_isl_size(type
))
865 if (type
->isIntegerType())
866 return type
.getAsString();
868 if (cpp_generator::is_string(type
))
869 return "std::string";
871 if (cpp_generator::is_callback(type
))
872 return generate_callback_type(arg
, type
);
874 generator::die("Cannot convert type to C++ type");
877 /* Check if "subclass_type" is a subclass of "class_type".
879 bool cpp_generator::is_subclass(QualType subclass_type
,
880 const isl_class
&class_type
)
882 std::string type_str
= subclass_type
->getPointeeType().getAsString();
883 std::vector
<std::string
> superclasses
;
884 std::vector
<const isl_class
*> parents
;
885 std::vector
<std::string
>::iterator ci
;
887 superclasses
= generator::find_superclasses(classes
[type_str
].type
);
889 for (ci
= superclasses
.begin(); ci
< superclasses
.end(); ci
++)
890 parents
.push_back(&classes
[*ci
]);
892 while (!parents
.empty()) {
893 const isl_class
*candidate
= parents
.back();
897 if (&class_type
== candidate
)
900 superclasses
= generator::find_superclasses(candidate
->type
);
902 for (ci
= superclasses
.begin(); ci
< superclasses
.end(); ci
++)
903 parents
.push_back(&classes
[*ci
]);
909 /* Check if "cons" is an implicit conversion constructor of class "clazz".
911 * An implicit conversion constructor is generated in case "cons" has a single
912 * parameter, where the parameter type is a subclass of the class that is
913 * currently being generated.
915 bool cpp_generator::is_implicit_conversion(const Method
&cons
)
917 const auto &clazz
= cons
.clazz
;
918 ParmVarDecl
*param
= cons
.fd
->getParamDecl(0);
919 QualType type
= param
->getOriginalType();
921 int num_params
= cons
.fd
->getNumParams();
925 if (is_isl_type(type
) && !is_isl_ctx(type
) && is_subclass(type
, clazz
))
931 /* Construct a list combiner for printing a list.
933 Method::list_combiner
Method::print_combiner(std::ostream
&os
)
936 [&] () { os
<< "("; },
937 [&] () { os
<< ", "; },
938 [&] () { os
<< ")"; }
942 /* Construct a list combiner for simply iterating over a list.
944 Method::list_combiner
Method::empty_combiner()
946 return { [&] () { }, [&] () { }, [&] () { } };
949 /* Get kind of "method" in "clazz".
951 * Given the declaration of a static or member method, returns its kind.
953 static Method::Kind
get_kind(const isl_class
&clazz
, FunctionDecl
*method
)
955 if (generator::is_constructor(method
))
956 return Method::Kind::constructor
;
957 else if (generator::is_static(clazz
, method
))
958 return Method::Kind::static_method
;
960 return Method::Kind::member_method
;
963 /* Return the callback arguments of "fd".
965 static std::vector
<ParmVarDecl
*> find_callback_args(FunctionDecl
*fd
)
967 std::vector
<ParmVarDecl
*> callbacks
;
968 int num_params
= fd
->getNumParams();
970 for (int i
= 0; i
< num_params
; ++i
) {
971 ParmVarDecl
*param
= fd
->getParamDecl(i
);
972 if (generator::is_callback(param
->getType()))
973 callbacks
.emplace_back(param
);
979 /* Construct a C++ method object from the class to which is belongs,
980 * the isl function from which it is derived and the method name.
982 * Perform any renaming of the method that may be required and
983 * determine the type of the method.
985 Method::Method(const isl_class
&clazz
, FunctionDecl
*fd
,
986 const std::string
&name
) :
987 clazz(clazz
), fd(fd
), name(rename_method(name
)),
988 kind(get_kind(clazz
, fd
)),
989 callbacks(find_callback_args(fd
))
993 /* Construct a C++ method object from the class to which is belongs and
994 * the isl function from which it is derived.
996 * Obtain the default method name and continue
997 * with the generic constructor.
999 Method::Method(const isl_class
&clazz
, FunctionDecl
*fd
) :
1000 Method(clazz
, fd
, clazz
.method_name(fd
))
1004 /* Return the number of parameters of the corresponding C function.
1006 * This number includes any possible user pointers that follow callback
1007 * arguments. These are skipped by Method::print_fd_arg_list
1008 * during the actual argument printing.
1010 int Method::c_num_params() const
1012 return fd
->getNumParams();
1015 /* Return the number of parameters of the method
1016 * (including the implicit "this").
1018 * By default, it is the same as the number of parameters
1019 * of the corresponding C function.
1021 int Method::num_params() const
1023 return c_num_params();
1026 /* Call "on_arg_skip_next" on the arguments from "start" (inclusive)
1027 * to "end" (exclusive), calling the methods of "combiner"
1028 * before, between and after the arguments.
1029 * If "on_arg_skip_next" returns true then the next argument is skipped.
1031 void Method::on_arg_list(int start
, int end
,
1032 const Method::list_combiner
&combiner
,
1033 const std::function
<bool(int i
)> &on_arg_skip_next
)
1036 for (int i
= start
; i
< end
; ++i
) {
1039 if (on_arg_skip_next(i
))
1045 /* Print the arguments from "start" (inclusive) to "end" (exclusive)
1046 * as arguments to a method of C function call, using "print_arg_skip_next"
1047 * to print each individual argument. If this callback return true
1048 * then the next argument is skipped.
1050 void Method::print_arg_list(std::ostream
&os
, int start
, int end
,
1051 const std::function
<bool(int i
)> &print_arg_skip_next
)
1053 on_arg_list(start
, end
, print_combiner(os
), [&] (int i
) {
1054 return print_arg_skip_next(i
);
1058 /* Call "on_arg" on the arguments from "start" (inclusive) to "end" (exclusive),
1059 * calling the methods of "combiner" before, between and after the arguments.
1060 * The first argument to "on_arg" is the position of the argument
1062 * The second argument is the (first) position in the list of arguments
1063 * with all callback arguments spliced in.
1065 * Call on_arg_list to do the actual iteration over the arguments, skipping
1066 * the user argument that comes after every callback argument.
1067 * On the C++ side no user pointer is needed, as arguments can be forwarded
1068 * as part of the std::function argument which specifies the callback function.
1069 * The user pointer is also removed from the number of parameters
1070 * of the C function because the pair of callback and user pointer
1071 * is considered as a single argument that is printed as a whole
1072 * by Method::print_param_use.
1074 * In case of a callback argument, the second argument to "print_arg"
1075 * is also adjusted to account for the spliced-in arguments of the callback.
1076 * The return value takes the place of the callback itself,
1077 * while the arguments (excluding the final user pointer)
1078 * take the following positions.
1080 void Method::on_fd_arg_list(int start
, int end
,
1081 const Method::list_combiner
&combiner
,
1082 const std::function
<void(int i
, int arg
)> &on_arg
) const
1086 on_arg_list(start
, end
, combiner
, [this, &on_arg
, &arg
] (int i
) {
1087 auto type
= fd
->getParamDecl(i
)->getType();
1090 if (!generator::is_callback(type
))
1092 arg
+= generator::prototype_n_args(type
) - 1;
1097 /* Print the arguments from "start" (inclusive) to "end" (exclusive)
1098 * as arguments to a method of C function call, using "print_arg"
1099 * to print each individual argument.
1100 * The first argument to this callback is the position of the argument
1102 * The second argument is the (first) position in the list of arguments
1103 * with all callback arguments spliced in.
1105 void Method::print_fd_arg_list(std::ostream
&os
, int start
, int end
,
1106 const std::function
<void(int i
, int arg
)> &print_arg
) const
1108 on_fd_arg_list(start
, end
, print_combiner(os
), print_arg
);
1111 /* Call "on_arg" on the arguments to the method call,
1112 * calling the methods of "combiner" before, between and after the arguments.
1113 * The first argument to "on_arg" is the position of the argument
1115 * The second argument is the (first) position in the list of arguments
1116 * with all callback arguments spliced in.
1118 void Method::on_cpp_arg_list(const Method::list_combiner
&combiner
,
1119 const std::function
<void(int i
, int arg
)> &on_arg
) const
1121 int first_param
= kind
== member_method
? 1 : 0;
1122 on_fd_arg_list(first_param
, num_params(), combiner
, on_arg
);
1125 /* Call "on_arg" on the arguments to the method call.
1126 * The first argument to "on_arg" is the position of the argument
1128 * The second argument is the (first) position in the list of arguments
1129 * with all callback arguments spliced in.
1131 void Method::on_cpp_arg_list(
1132 const std::function
<void(int i
, int arg
)> &on_arg
) const
1134 on_cpp_arg_list(empty_combiner(), on_arg
);
1137 /* Print the arguments to the method call, using "print_arg"
1138 * to print each individual argument.
1139 * The first argument to this callback is the position of the argument
1141 * The second argument is the (first) position in the list of arguments
1142 * with all callback arguments spliced in.
1144 void Method::print_cpp_arg_list(std::ostream
&os
,
1145 const std::function
<void(int i
, int arg
)> &print_arg
) const
1147 on_cpp_arg_list(print_combiner(os
), print_arg
);
1150 /* Should the parameter at position "pos" be a copy (rather than
1151 * a const reference)?
1153 * Strictly speaking, a copy is only needed on isl types that are
1154 * not marked __isl_keep, since those will be release()'d
1155 * by code printed by Method::print_param_use.
1157 * However, there may be other arguments such as integer types
1158 * that are more naturally passed as a copy.
1159 * The default is therefore to require a copy, except for
1160 * arguments marked __isl_keep, string arguments or callback arguments.
1162 bool Method::param_needs_copy(int pos
) const
1164 ParmVarDecl
*param
= get_param(pos
);
1165 QualType type
= param
->getOriginalType();
1167 if (generator::keeps(param
))
1169 if (generator::is_string(type
) || generator::is_callback(type
))
1174 /* Return the method argument at position "pos".
1176 clang::ParmVarDecl
*Method::get_param(int pos
) const
1178 return fd
->getParamDecl(pos
);
1181 /* Construct a method that performs one or more conversions
1182 * from the original Method (without conversions),
1183 * the name of the type to which "this" should be converted and
1184 * a function for determining the arguments of the constructed method.
1186 ConversionMethod::ConversionMethod(const Method
&method
,
1187 const std::string
&this_type
,
1188 const std::function
<clang::ParmVarDecl
*(int pos
)> &get_param
) :
1189 NoCopyMethod(method
), this_type(this_type
),
1190 get_param_fn(get_param
)
1194 /* Construct a method that only performs a conversion on "this"
1195 * from the original Method (without conversions) and
1196 * the name of the type to which "this" should be converted.
1198 * Call the generic constructor with
1199 * a function for determining the arguments of the constructed method
1200 * that performs no conversion.
1202 ConversionMethod::ConversionMethod(const Method
&method
,
1203 const std::string
&this_type
) :
1204 ConversionMethod(method
, this_type
, [this] (int pos
) {
1205 return Method::get_param(pos
);
1210 /* Construct a method that performs one or more argument conversions
1211 * from the original Method (without conversions) and
1212 * a function for determining the arguments of the constructed method.
1214 * Call the generic constructor with method.clazz.name as "this" type,
1215 * indicating that "this" should not be converted.
1217 ConversionMethod::ConversionMethod(const Method
&method
,
1218 const std::function
<clang::ParmVarDecl
*(int pos
)> &get_param
) :
1219 ConversionMethod(method
, method
.clazz
.name
, get_param
)
1223 /* Should the parameter at position "pos" be a copy (rather than
1224 * a const reference)?
1226 * Parameters of isl type do not need to be a copy.
1227 * For other types, use the same defaults as Method.
1229 bool NoCopyMethod::param_needs_copy(int pos
) const
1231 ParmVarDecl
*param
= get_param(pos
);
1232 QualType type
= param
->getOriginalType();
1234 if (generator::is_isl_type(type
))
1237 return Method::param_needs_copy(pos
);
1240 /* Return the method argument at position "pos".
1242 * Call get_param_fn to determine this argument.
1244 clang::ParmVarDecl
*ConversionMethod::get_param(int pos
) const
1246 return get_param_fn(pos
);
1249 /* Print a call to the method (without the arguments),
1250 * with "ns" the namespace of the generated C++ bindings.
1252 * If "this_type" is different from the name of the class of the method,
1253 * then "this" needs to be converted to that type before
1254 * the call is performed.
1256 void ConversionMethod::print_call(std::ostream
&os
, const std::string
&ns
) const
1258 if (clazz
.name
== this_type
) {
1261 auto cpp_type
= ns
+ cpp_generator::type2cpp(this_type
);
1262 os
<< cpp_type
<< "(*this).";
1267 /* Construct an object representing a C++ method for setting an enum
1268 * from the class to which is belongs,
1269 * the isl function from which it is derived and the method and enum names.
1271 EnumMethod::EnumMethod(const isl_class
&clazz
, FunctionDecl
*fd
,
1272 const std::string
&method_name
, const std::string
&enum_name
) :
1273 Method(clazz
, fd
, method_name
), enum_name(enum_name
)
1277 /* Print the use of the argument at position "pos" to "os".
1279 * If the position is beyond the number of method arguments,
1280 * then it corresponds to the enum value corresponding to this EnumMethod.
1281 * Otherwise, delegate to Method::print_param_use.
1283 void EnumMethod::print_param_use(ostream
&os
, int pos
) const
1285 if (pos
== num_params())
1288 Method::print_param_use(os
, pos
);
1291 /* Return the number of parameters of the method
1292 * (including the implicit "this").
1294 * The last argument of the C function does not appear in the method call,
1295 * because it is replaced by a break-up into several methods.
1297 int EnumMethod::num_params() const
1299 return Method::num_params() - 1;
1302 /* Initialize a class method printer from the stream onto which the methods
1303 * are printed, the class method description and the C++ interface generator.
1305 cpp_generator::class_printer::class_printer(std::ostream
&os
,
1306 const isl_class
&clazz
, cpp_generator
&generator
,
1307 bool declarations
) :
1308 os(os
), clazz(clazz
), cppstring(type2cpp(clazz
)), generator(generator
),
1309 declarations(declarations
)