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 SVEN VERDOOLAEGE 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
43 #include "isl_config.h"
45 /* Print string formatted according to "fmt" to ostream "os".
47 * This osprintf method allows us to use printf style formatting constructs when
48 * writing to an ostream.
50 static void osprintf(ostream
&os
, const char *format
, va_list arguments
)
56 va_copy(copy
, arguments
);
57 size
= vsnprintf(NULL
, 0, format
, copy
);
58 string_pointer
= new char[size
+ 1];
60 vsnprintf(string_pointer
, size
+ 1, format
, arguments
);
62 delete[] string_pointer
;
65 /* Print string formatted according to "fmt" to ostream "os".
67 * This osprintf method allows us to use printf style formatting constructs when
68 * writing to an ostream.
70 static void osprintf(ostream
&os
, const char *format
, ...)
74 va_start(arguments
, format
);
75 osprintf(os
, format
, arguments
);
79 /* Print string formatted according to "fmt" to ostream "os"
80 * with the given indentation.
82 * This osprintf method allows us to use printf style formatting constructs when
83 * writing to an ostream.
85 static void osprintf(ostream
&os
, int indent
, const char *format
, ...)
89 osprintf(os
, "%*s", indent
, " ");
90 va_start(arguments
, format
);
91 osprintf(os
, format
, arguments
);
95 /* Convert "l" to a string.
97 static std::string
to_string(long l
)
99 std::ostringstream strm
;
104 /* Generate a cpp interface based on the extracted types and functions.
106 * Print first a set of forward declarations for all isl wrapper
107 * classes, then the declarations of the classes, and at the end all
110 * If checked C++ bindings are being generated,
111 * then wrap them in a namespace to avoid conflicts
112 * with the default C++ bindings (with automatic checks using exceptions).
114 void cpp_generator::generate()
119 osprintf(os
, "namespace isl {\n\n");
121 osprintf(os
, "namespace checked {\n\n");
123 print_forward_declarations(os
);
125 print_declarations(os
);
127 print_implementations(os
);
130 osprintf(os
, "} // namespace checked\n");
131 osprintf(os
, "} // namespace isl\n");
134 /* Print forward declarations for all classes to "os".
136 void cpp_generator::print_forward_declarations(ostream
&os
)
138 map
<string
, isl_class
>::iterator ci
;
140 osprintf(os
, "// forward declarations\n");
142 for (ci
= classes
.begin(); ci
!= classes
.end(); ++ci
)
143 print_class_forward_decl(os
, ci
->second
);
146 /* Print all declarations to "os".
148 void cpp_generator::print_declarations(ostream
&os
)
150 map
<string
, isl_class
>::iterator ci
;
153 for (ci
= classes
.begin(); ci
!= classes
.end(); ++ci
) {
159 print_class(os
, ci
->second
);
163 /* Print all implementations to "os".
165 void cpp_generator::print_implementations(ostream
&os
)
167 map
<string
, isl_class
>::iterator ci
;
170 for (ci
= classes
.begin(); ci
!= classes
.end(); ++ci
) {
176 print_class_impl(os
, ci
->second
);
180 /* If "clazz" is a subclass that is based on a type function,
181 * then introduce a "type" field that holds the value of the type
182 * corresponding to the subclass and make the fields of the class
183 * accessible to the "isa" and "as" methods of the (immediate) superclass.
184 * In particular, "isa" needs access to the type field itself,
185 * while "as" needs access to the private constructor.
186 * In case of the "isa" method, all instances are made friends
187 * to avoid access right confusion.
189 void cpp_generator::print_subclass_type(ostream
&os
, const isl_class
&clazz
)
191 std::string cppstring
= type2cpp(clazz
);
193 const char *cppname
= cppstring
.c_str();
194 const char *supername
;
196 if (!clazz
.is_type_subclass())
199 super
= type2cpp(clazz
.superclass_name
);
200 supername
= super
.c_str();
201 osprintf(os
, " template <class T>\n");
202 osprintf(os
, " friend %s %s::isa() const;\n",
203 isl_bool2cpp().c_str(), supername
);
204 osprintf(os
, " friend %s %s::as<%s>() const;\n",
205 cppname
, supername
, cppname
);
206 osprintf(os
, " static const auto type = %s;\n",
207 clazz
.subclass_name
.c_str());
210 /* Print declarations for class "clazz" to "os".
212 * If "clazz" is a subclass based on a type function,
213 * then it is made to inherit from the (immediate) superclass and
214 * a "type" attribute is added for use in the "as" and "isa"
215 * methods of the superclass.
217 * Conversely, if "clazz" is a superclass with a type function,
218 * then declare those "as" and "isa" methods.
220 * The pointer to the isl object is only added for classes that
221 * are not subclasses, since subclasses refer to the same isl object.
223 void cpp_generator::print_class(ostream
&os
, const isl_class
&clazz
)
225 const char *name
= clazz
.name
.c_str();
226 std::string cppstring
= type2cpp(clazz
);
227 const char *cppname
= cppstring
.c_str();
229 osprintf(os
, "// declarations for isl::%s\n", cppname
);
231 print_class_factory_decl(os
, clazz
);
233 osprintf(os
, "class %s ", cppname
);
234 if (clazz
.is_type_subclass())
235 osprintf(os
, ": public %s ",
236 type2cpp(clazz
.superclass_name
).c_str());
238 print_subclass_type(os
, clazz
);
239 print_class_factory_decl(os
, clazz
, " friend ");
241 osprintf(os
, "protected:\n");
242 if (!clazz
.is_type_subclass()) {
243 osprintf(os
, " %s *ptr = nullptr;\n", name
);
246 print_protected_constructors_decl(os
, clazz
);
248 osprintf(os
, "public:\n");
249 print_public_constructors_decl(os
, clazz
);
250 print_constructors_decl(os
, clazz
);
251 print_copy_assignment_decl(os
, clazz
);
252 print_destructor_decl(os
, clazz
);
253 print_ptr_decl(os
, clazz
);
254 print_downcast_decl(os
, clazz
);
255 print_get_ctx_decl(os
);
257 print_persistent_callbacks_decl(os
, clazz
);
258 print_methods_decl(os
, clazz
);
259 print_set_enums_decl(os
, clazz
);
261 osprintf(os
, "};\n");
264 /* Print forward declaration of class "clazz" to "os".
266 void cpp_generator::print_class_forward_decl(ostream
&os
,
267 const isl_class
&clazz
)
269 std::string cppstring
= type2cpp(clazz
);
270 const char *cppname
= cppstring
.c_str();
272 osprintf(os
, "class %s;\n", cppname
);
275 /* Print global factory functions to "os".
277 * Each class has two global factory functions:
279 * set manage(__isl_take isl_set *ptr);
280 * set manage_copy(__isl_keep isl_set *ptr);
282 * A user can construct isl C++ objects from a raw pointer and indicate whether
283 * they intend to take the ownership of the object or not through these global
284 * factory functions. This ensures isl object creation is very explicit and
285 * pointers are not converted by accident. Thanks to overloading, manage() and
286 * manage_copy() can be called on any isl raw pointer and the corresponding
287 * object is automatically created, without the user having to choose the right
290 * For a subclass based on a type function, no factory functions
291 * are introduced because they share the C object type with
294 void cpp_generator::print_class_factory_decl(ostream
&os
,
295 const isl_class
&clazz
, const std::string
&prefix
)
297 const char *name
= clazz
.name
.c_str();
298 std::string cppstring
= type2cpp(clazz
);
299 const char *cppname
= cppstring
.c_str();
301 if (clazz
.is_type_subclass())
305 osprintf(os
, "inline %s manage(__isl_take %s *ptr);\n", cppname
, name
);
307 osprintf(os
, "inline %s manage_copy(__isl_keep %s *ptr);\n",
311 /* Print declarations of protected constructors for class "clazz" to "os".
313 * Each class has currently one protected constructor:
315 * 1) Constructor from a plain isl_* C pointer
319 * set(__isl_take isl_set *ptr);
321 * The raw pointer constructor is kept protected. Object creation is only
322 * possible through manage() or manage_copy().
324 void cpp_generator::print_protected_constructors_decl(ostream
&os
,
325 const isl_class
&clazz
)
327 const char *name
= clazz
.name
.c_str();
328 std::string cppstring
= type2cpp(clazz
);
329 const char *cppname
= cppstring
.c_str();
331 osprintf(os
, " inline explicit %s(__isl_take %s *ptr);\n", cppname
,
335 /* Print declarations of public constructors for class "clazz" to "os".
337 * Each class currently has two public constructors:
339 * 1) A default constructor
340 * 2) A copy constructor
345 * set(const set &set);
347 void cpp_generator::print_public_constructors_decl(ostream
&os
,
348 const isl_class
&clazz
)
350 std::string cppstring
= type2cpp(clazz
);
351 const char *cppname
= cppstring
.c_str();
352 osprintf(os
, " inline /* implicit */ %s();\n", cppname
);
354 osprintf(os
, " inline /* implicit */ %s(const %s &obj);\n",
358 /* Print declarations for constructors for class "class" to "os".
360 * For each isl function that is marked as __isl_constructor,
361 * add a corresponding C++ constructor.
365 * inline /\* implicit *\/ union_set(basic_set bset);
366 * inline /\* implicit *\/ union_set(set set);
367 * inline explicit val(ctx ctx, long i);
368 * inline explicit val(ctx ctx, const std::string &str);
370 void cpp_generator::print_constructors_decl(ostream
&os
,
371 const isl_class
&clazz
)
373 set
<FunctionDecl
*>::const_iterator in
;
374 const set
<FunctionDecl
*> &constructors
= clazz
.constructors
;
376 for (in
= constructors
.begin(); in
!= constructors
.end(); ++in
) {
377 FunctionDecl
*cons
= *in
;
379 print_method_decl(os
, clazz
, cons
, function_kind_constructor
);
383 /* Print declarations of copy assignment operator for class "clazz"
386 * Each class has one assignment operator.
388 * isl:set &set::operator=(set obj)
391 void cpp_generator::print_copy_assignment_decl(ostream
&os
,
392 const isl_class
&clazz
)
394 std::string cppstring
= type2cpp(clazz
);
395 const char *cppname
= cppstring
.c_str();
397 osprintf(os
, " inline %s &operator=(%s obj);\n", cppname
, cppname
);
400 /* Print declaration of destructor for class "clazz" to "os".
402 * No explicit destructor is needed for type based subclasses.
404 void cpp_generator::print_destructor_decl(ostream
&os
, const isl_class
&clazz
)
406 std::string cppstring
= type2cpp(clazz
);
407 const char *cppname
= cppstring
.c_str();
409 if (clazz
.is_type_subclass())
412 osprintf(os
, " inline ~%s();\n", cppname
);
415 /* Print declaration of pointer functions for class "clazz" to "os".
416 * Since type based subclasses share the pointer with their superclass,
417 * they can also reuse these functions from the superclass.
419 * To obtain a raw pointer three functions are provided:
421 * 1) __isl_give isl_set *copy()
423 * Returns a pointer to a _copy_ of the internal object
425 * 2) __isl_keep isl_set *get()
427 * Returns a pointer to the internal object
429 * 3) __isl_give isl_set *release()
431 * Returns a pointer to the internal object and resets the
432 * internal pointer to nullptr.
434 * We also provide functionality to explicitly check if a pointer is
435 * currently managed by this object.
439 * Check if the current object is a null pointer.
441 * The functions get() and release() model the value_ptr proposed in
442 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
443 * The copy() function is an extension to allow the user to explicitly
444 * copy the underlying object.
446 * Also generate a declaration to delete copy() for r-values, for
447 * r-values release() should be used to avoid unnecessary copies.
449 void cpp_generator::print_ptr_decl(ostream
&os
, const isl_class
&clazz
)
451 const char *name
= clazz
.name
.c_str();
453 if (clazz
.is_type_subclass())
456 osprintf(os
, " inline __isl_give %s *copy() const &;\n", name
);
457 osprintf(os
, " inline __isl_give %s *copy() && = delete;\n", name
);
458 osprintf(os
, " inline __isl_keep %s *get() const;\n", name
);
459 osprintf(os
, " inline __isl_give %s *release();\n", name
);
460 osprintf(os
, " inline bool is_null() const;\n");
463 /* Print a template declaration with given indentation
464 * for the "isa_type" method that ensures it is only enabled
465 * when called with a template argument
466 * that represents a type that is equal to that
467 * of the return type of the type function of "super".
468 * In particular, "isa_type" gets called from "isa"
469 * with as template argument the type of the "type" field
471 * The check ensures that this subclass is in fact a direct subclass
474 void cpp_generator::print_isa_type_template(ostream
&os
, int indent
,
475 const isl_class
&super
)
478 "template <typename T,\n");
480 " typename = typename std::enable_if<std::is_same<\n");
482 " const decltype(%s(NULL)),\n",
483 super
.fn_type
->getNameAsString().c_str());
485 " const T>::value>::type>\n");
488 /* Print declarations for the "as" and "isa" methods, if "clazz"
489 * is a superclass with a type function.
491 * "isa" checks whether an object is of a given subclass type.
492 * "isa_type" does the same, but gets passed the value of the type field
493 * of the subclass as a function argument and the type of this field
494 * as a template argument.
495 * "as" tries to cast an object to a given subclass type, returning
496 * an invalid object if the object is not of the given type.
498 void cpp_generator::print_downcast_decl(ostream
&os
, const isl_class
&clazz
)
503 osprintf(os
, "private:\n");
504 print_isa_type_template(os
, 2, clazz
);
505 osprintf(os
, " inline %s isa_type(T subtype) const;\n",
506 isl_bool2cpp().c_str());
507 osprintf(os
, "public:\n");
508 osprintf(os
, " template <class T> inline %s isa() const;\n",
509 isl_bool2cpp().c_str());
510 osprintf(os
, " template <class T> inline T as() const;\n");
513 /* Print the declaration of the get_ctx method.
515 void cpp_generator::print_get_ctx_decl(ostream
&os
)
517 std::string ns
= isl_namespace();
519 osprintf(os
, " inline %sctx get_ctx() const;\n", ns
.c_str());
522 /* Add a space to the return type "type" if needed,
523 * i.e., if it is not the type of a pointer.
525 static string
add_space_to_return_type(const string
&type
)
527 if (type
[type
.size() - 1] == '*')
532 /* Print the prototype of the static inline method that is used
533 * as the C callback of "clazz" set by "method" to "os".
535 void cpp_generator::print_persistent_callback_prototype(ostream
&os
,
536 const isl_class
&clazz
, FunctionDecl
*method
, bool is_declaration
)
538 string callback_name
, rettype
, c_args
;
539 ParmVarDecl
*param
= persistent_callback_arg(method
);
540 const FunctionProtoType
*callback
;
544 ptype
= param
->getType();
545 callback
= extract_prototype(ptype
);
547 rettype
= callback
->getReturnType().getAsString();
548 rettype
= add_space_to_return_type(rettype
);
549 callback_name
= clazz
.persistent_callback_name(method
);
550 c_args
= generate_callback_args(ptype
, false);
553 classname
= type2cpp(clazz
) + "::";
555 osprintf(os
, "%s%s%s(%s)",
556 rettype
.c_str(), classname
.c_str(),
557 callback_name
.c_str(), c_args
.c_str());
560 /* Print the prototype of the method for setting the callback function
561 * of "clazz" set by "method" to "os".
563 void cpp_generator::print_persistent_callback_setter_prototype(ostream
&os
,
564 const isl_class
&clazz
, FunctionDecl
*method
, bool is_declaration
)
566 string classname
, callback_name
, cpptype
;
567 ParmVarDecl
*param
= persistent_callback_arg(method
);
570 classname
= type2cpp(clazz
) + "::";
572 cpptype
= type2cpp(param
->getOriginalType());
573 callback_name
= clazz
.persistent_callback_name(method
);
574 osprintf(os
, "void %sset_%s_data(const %s &%s)",
575 classname
.c_str(), callback_name
.c_str(), cpptype
.c_str(),
576 param
->getName().str().c_str());
579 /* Given a function "method" for setting a "clazz" persistent callback,
580 * print the fields that are needed for marshalling the callback to "os".
582 * In particular, print
583 * - the declaration of a data structure for storing the C++ callback function
584 * - a shared pointer to such a data structure
585 * - the declaration of a static inline method
586 * for use as the C callback function
587 * - the declaration of a private method for setting the callback function
589 void cpp_generator::print_persistent_callback_data(ostream
&os
,
590 const isl_class
&clazz
, FunctionDecl
*method
)
592 string callback_name
;
593 ParmVarDecl
*param
= persistent_callback_arg(method
);
595 callback_name
= clazz
.persistent_callback_name(method
);
596 print_callback_data_decl(os
, param
, callback_name
);
598 osprintf(os
, " std::shared_ptr<%s_data> %s_data;\n",
599 callback_name
.c_str(), callback_name
.c_str());
600 osprintf(os
, " static inline ");
601 print_persistent_callback_prototype(os
, clazz
, method
, true);
603 osprintf(os
, " inline ");
604 print_persistent_callback_setter_prototype(os
, clazz
, method
, true);
608 /* Print declarations needed for the persistent callbacks of "clazz".
610 * In particular, if there are any persistent callbacks, then
611 * print a private method for copying callback data from
612 * one object to another,
613 * private data for keeping track of the persistent callbacks and
614 * public methods for setting the persistent callbacks.
616 void cpp_generator::print_persistent_callbacks_decl(ostream
&os
,
617 const isl_class
&clazz
)
619 std::string cppstring
= type2cpp(clazz
);
620 const char *cppname
= cppstring
.c_str();
621 set
<FunctionDecl
*>::const_iterator in
;
622 const set
<FunctionDecl
*> &callbacks
= clazz
.persistent_callbacks
;
624 if (!clazz
.has_persistent_callbacks())
627 osprintf(os
, "private:\n");
628 osprintf(os
, " inline %s ©_callbacks(const %s &obj);\n",
630 for (in
= callbacks
.begin(); in
!= callbacks
.end(); ++in
)
631 print_persistent_callback_data(os
, clazz
, *in
);
633 osprintf(os
, "public:\n");
634 for (in
= callbacks
.begin(); in
!= callbacks
.end(); ++in
)
635 print_method_decl(os
, clazz
, *in
, function_kind_member_method
);
638 /* Print declarations for methods in class "clazz" to "os".
640 void cpp_generator::print_methods_decl(ostream
&os
, const isl_class
&clazz
)
642 map
<string
, set
<FunctionDecl
*> >::const_iterator it
;
644 for (it
= clazz
.methods
.begin(); it
!= clazz
.methods
.end(); ++it
)
645 print_method_group_decl(os
, clazz
, it
->second
);
648 /* Print a declaration for a method "name" in "clazz" derived
649 * from "fd", which sets an enum, to "os".
651 * The last argument is removed because it is replaced by
652 * a break-up into several methods.
654 void cpp_generator::print_set_enum_decl(ostream
&os
, const isl_class
&clazz
,
655 FunctionDecl
*fd
, const string
&name
)
657 int n
= fd
->getNumParams();
659 print_method_header(os
, clazz
, fd
, name
, n
- 1, true,
660 function_kind_member_method
);
663 /* Print declarations for the methods in "clazz" derived from "fd",
664 * which sets an enum, to "os".
666 * A method is generated for each value in the enum, setting
667 * the enum to that value.
669 void cpp_generator::print_set_enums_decl(ostream
&os
, const isl_class
&clazz
,
672 vector
<set_enum
>::const_iterator it
;
673 const vector
<set_enum
> &set_enums
= clazz
.set_enums
.at(fd
);
675 for (it
= set_enums
.begin(); it
!= set_enums
.end(); ++it
)
676 print_set_enum_decl(os
, clazz
, fd
, it
->method_name
);
679 /* Print declarations for methods in "clazz" derived from functions
680 * that set an enum, to "os".
682 void cpp_generator::print_set_enums_decl(ostream
&os
, const isl_class
&clazz
)
684 map
<FunctionDecl
*, vector
<set_enum
> >::const_iterator it
;
686 for (it
= clazz
.set_enums
.begin(); it
!= clazz
.set_enums
.end(); ++it
)
687 print_set_enums_decl(os
, clazz
, it
->first
);
690 /* Print declarations for methods "methods" in class "clazz" to "os".
692 void cpp_generator::print_method_group_decl(ostream
&os
, const isl_class
&clazz
,
693 const set
<FunctionDecl
*> &methods
)
695 set
<FunctionDecl
*>::const_iterator it
;
697 for (it
= methods
.begin(); it
!= methods
.end(); ++it
) {
698 function_kind kind
= get_method_kind(clazz
, *it
);
699 print_method_decl(os
, clazz
, *it
, kind
);
703 /* Print declarations for "method" in class "clazz" to "os".
705 * "kind" specifies the kind of method that should be generated.
707 void cpp_generator::print_method_decl(ostream
&os
, const isl_class
&clazz
,
708 FunctionDecl
*method
, function_kind kind
)
710 print_method_header(os
, clazz
, method
, true, kind
);
713 /* Print implementations for class "clazz" to "os".
715 void cpp_generator::print_class_impl(ostream
&os
, const isl_class
&clazz
)
717 std::string cppstring
= type2cpp(clazz
);
718 const char *cppname
= cppstring
.c_str();
720 osprintf(os
, "// implementations for isl::%s\n", cppname
);
722 print_class_factory_impl(os
, clazz
);
724 print_public_constructors_impl(os
, clazz
);
726 print_protected_constructors_impl(os
, clazz
);
728 print_constructors_impl(os
, clazz
);
730 print_copy_assignment_impl(os
, clazz
);
732 print_destructor_impl(os
, clazz
);
734 print_ptr_impl(os
, clazz
);
736 if (print_downcast_impl(os
, clazz
))
738 print_get_ctx_impl(os
, clazz
);
740 print_persistent_callbacks_impl(os
, clazz
);
741 print_methods_impl(os
, clazz
);
742 print_set_enums_impl(os
, clazz
);
743 print_stream_insertion(os
, clazz
);
746 /* Print code for throwing an exception corresponding to the last error
747 * that occurred on "saved_ctx".
748 * This assumes that a valid isl::ctx is available in the "saved_ctx" variable,
749 * e.g., through a prior call to print_save_ctx.
751 static void print_throw_last_error(ostream
&os
)
753 osprintf(os
, " exception::throw_last_error(saved_ctx);\n");
756 /* Print code with the given indentation
757 * for throwing an exception_invalid with the given message.
759 static void print_throw_invalid(ostream
&os
, int indent
, const char *msg
)
762 "exception::throw_invalid(\"%s\", __FILE__, __LINE__);\n", msg
);
765 /* Print code for throwing an exception on NULL input.
767 static void print_throw_NULL_input(ostream
&os
)
769 print_throw_invalid(os
, 4, "NULL input");
772 /* Print code with the given indentation
773 * for acting on an invalid error with message "msg".
774 * In particular, throw an exception_invalid.
775 * In the checked C++ bindings, isl_die is called instead with the code
778 void cpp_generator::print_invalid(ostream
&os
, int indent
, const char *msg
,
779 const char *checked_code
)
783 "isl_die(get_ctx().get(), isl_error_invalid, "
784 "\"%s\", %s);\n", msg
, checked_code
);
786 print_throw_invalid(os
, indent
, msg
);
789 /* Print an operator for inserting objects of "class"
790 * into an output stream.
792 * Unless checked C++ bindings are being generated,
793 * the operator requires its argument to be non-NULL.
794 * An exception is thrown if anything went wrong during the printing.
795 * During this printing, isl is made not to print any error message
796 * because the error message is included in the exception.
798 * If checked C++ bindings are being generated and anything went wrong,
799 * then record this failure in the output stream.
801 void cpp_generator::print_stream_insertion(ostream
&os
, const isl_class
&clazz
)
803 const char *name
= clazz
.name
.c_str();
804 std::string cppstring
= type2cpp(clazz
);
805 const char *cppname
= cppstring
.c_str();
807 if (!clazz
.fn_to_str
)
811 osprintf(os
, "inline std::ostream &operator<<(std::ostream &os, ");
812 osprintf(os
, "const %s &obj)\n", cppname
);
814 print_check_ptr_start(os
, clazz
, "obj.get()");
815 osprintf(os
, " char *str = %s_to_str(obj.get());\n", name
);
816 print_check_ptr_end(os
, "str");
818 osprintf(os
, " if (!str) {\n");
819 osprintf(os
, " os.setstate(std::ios_base::badbit);\n");
820 osprintf(os
, " return os;\n");
821 osprintf(os
, " }\n");
823 osprintf(os
, " os << str;\n");
824 osprintf(os
, " free(str);\n");
825 osprintf(os
, " return os;\n");
829 /* Print code that checks that "ptr" is not NULL at input.
831 * Omit the check if checked C++ bindings are being generated.
833 void cpp_generator::print_check_ptr(ostream
&os
, const char *ptr
)
838 osprintf(os
, " if (!%s)\n", ptr
);
839 print_throw_NULL_input(os
);
842 /* Print code that checks that "ptr" is not NULL at input and
843 * that saves a copy of the isl_ctx of "ptr" for a later check.
845 * Omit the check if checked C++ bindings are being generated.
847 void cpp_generator::print_check_ptr_start(ostream
&os
, const isl_class
&clazz
,
853 print_check_ptr(os
, ptr
);
854 osprintf(os
, " auto saved_ctx = %s_get_ctx(%s);\n",
855 clazz
.name
.c_str(), ptr
);
856 print_on_error_continue(os
);
859 /* Print code that checks that "ptr" is not NULL at the end.
860 * A copy of the isl_ctx is expected to have been saved by
861 * code generated by print_check_ptr_start.
863 * Omit the check if checked C++ bindings are being generated.
865 void cpp_generator::print_check_ptr_end(ostream
&os
, const char *ptr
)
870 osprintf(os
, " if (!%s)\n", ptr
);
871 print_throw_last_error(os
);
874 /* Print implementation of global factory functions to "os".
876 * Each class has two global factory functions:
878 * set manage(__isl_take isl_set *ptr);
879 * set manage_copy(__isl_keep isl_set *ptr);
881 * Unless checked C++ bindings are being generated,
882 * both functions require the argument to be non-NULL.
883 * An exception is thrown if anything went wrong during the copying
885 * During the copying, isl is made not to print any error message
886 * because the error message is included in the exception.
888 * For a subclass based on a type function, no factory functions
889 * are introduced because they share the C object type with
892 void cpp_generator::print_class_factory_impl(ostream
&os
,
893 const isl_class
&clazz
)
895 const char *name
= clazz
.name
.c_str();
896 std::string cppstring
= type2cpp(clazz
);
897 const char *cppname
= cppstring
.c_str();
899 if (clazz
.is_type_subclass())
902 osprintf(os
, "%s manage(__isl_take %s *ptr) {\n", cppname
, name
);
903 print_check_ptr(os
, "ptr");
904 osprintf(os
, " return %s(ptr);\n", cppname
);
907 osprintf(os
, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname
,
909 print_check_ptr_start(os
, clazz
, "ptr");
910 osprintf(os
, " ptr = %s_copy(ptr);\n", name
);
911 print_check_ptr_end(os
, "ptr");
912 osprintf(os
, " return %s(ptr);\n", cppname
);
916 /* Print implementations of protected constructors for class "clazz" to "os".
918 * The pointer to the isl object is either initialized directly or
919 * through the (immediate) superclass.
921 void cpp_generator::print_protected_constructors_impl(ostream
&os
,
922 const isl_class
&clazz
)
924 const char *name
= clazz
.name
.c_str();
925 std::string cppstring
= type2cpp(clazz
);
926 const char *cppname
= cppstring
.c_str();
927 bool subclass
= clazz
.is_type_subclass();
929 osprintf(os
, "%s::%s(__isl_take %s *ptr)\n", cppname
, cppname
, name
);
931 osprintf(os
, " : %s(ptr) {}\n",
932 type2cpp(clazz
.superclass_name
).c_str());
934 osprintf(os
, " : ptr(ptr) {}\n");
937 /* Print implementations of public constructors for class "clazz" to "os".
939 * The pointer to the isl object is either initialized directly or
940 * through the (immediate) superclass.
942 * If the class has any persistent callbacks, then copy them
943 * from the original object in the copy constructor.
944 * If the class is a subclass, then the persistent callbacks
945 * are assumed to be copied by the copy constructor of the superclass.
947 * Throw an exception from the copy constructor if anything went wrong
948 * during the copying or if the input is NULL, if any copying is performed.
949 * During the copying, isl is made not to print any error message
950 * because the error message is included in the exception.
951 * No exceptions are thrown if checked C++ bindings
952 * are being generated,
954 void cpp_generator::print_public_constructors_impl(ostream
&os
,
955 const isl_class
&clazz
)
957 std::string cppstring
= type2cpp(clazz
);
959 const char *cppname
= cppstring
.c_str();
960 bool subclass
= clazz
.is_type_subclass();
963 super
= type2cpp(clazz
.superclass_name
);
964 osprintf(os
, "%s::%s()\n", cppname
, cppname
);
966 osprintf(os
, " : %s() {}\n\n", super
.c_str());
968 osprintf(os
, " : ptr(nullptr) {}\n\n");
969 osprintf(os
, "%s::%s(const %s &obj)\n", cppname
, cppname
, cppname
);
971 osprintf(os
, " : %s(obj)\n", super
.c_str());
973 osprintf(os
, " : ptr(nullptr)\n");
976 print_check_ptr_start(os
, clazz
, "obj.ptr");
977 osprintf(os
, " ptr = obj.copy();\n");
978 if (clazz
.has_persistent_callbacks())
979 osprintf(os
, " copy_callbacks(obj);\n");
980 print_check_ptr_end(os
, "ptr");
985 /* Print implementations of constructors for class "clazz" to "os".
987 void cpp_generator::print_constructors_impl(ostream
&os
,
988 const isl_class
&clazz
)
990 set
<FunctionDecl
*>::const_iterator in
;
991 const set
<FunctionDecl
*> constructors
= clazz
.constructors
;
993 for (in
= constructors
.begin(); in
!= constructors
.end(); ++in
) {
994 FunctionDecl
*cons
= *in
;
996 print_method_impl(os
, clazz
, cons
, function_kind_constructor
);
1000 /* Print implementation of copy assignment operator for class "clazz" to "os".
1002 * If the class has any persistent callbacks, then copy them
1003 * from the original object.
1005 void cpp_generator::print_copy_assignment_impl(ostream
&os
,
1006 const isl_class
&clazz
)
1008 const char *name
= clazz
.name
.c_str();
1009 std::string cppstring
= type2cpp(clazz
);
1010 const char *cppname
= cppstring
.c_str();
1012 osprintf(os
, "%s &%s::operator=(%s obj) {\n", cppname
,
1014 osprintf(os
, " std::swap(this->ptr, obj.ptr);\n", name
);
1015 if (clazz
.has_persistent_callbacks())
1016 osprintf(os
, " copy_callbacks(obj);\n");
1017 osprintf(os
, " return *this;\n");
1018 osprintf(os
, "}\n");
1021 /* Print implementation of destructor for class "clazz" to "os".
1023 * No explicit destructor is needed for type based subclasses.
1025 void cpp_generator::print_destructor_impl(ostream
&os
,
1026 const isl_class
&clazz
)
1028 const char *name
= clazz
.name
.c_str();
1029 std::string cppstring
= type2cpp(clazz
);
1030 const char *cppname
= cppstring
.c_str();
1032 if (clazz
.is_type_subclass())
1035 osprintf(os
, "%s::~%s() {\n", cppname
, cppname
);
1036 osprintf(os
, " if (ptr)\n");
1037 osprintf(os
, " %s_free(ptr);\n", name
);
1038 osprintf(os
, "}\n");
1041 /* Print a check that the persistent callback corresponding to "fd"
1042 * is not set, throwing an exception (or printing an error message
1043 * and returning nullptr) if it is set.
1045 void cpp_generator::print_check_no_persistent_callback(ostream
&os
,
1046 const isl_class
&clazz
, FunctionDecl
*fd
)
1048 string callback_name
= clazz
.persistent_callback_name(fd
);
1050 osprintf(os
, " if (%s_data)\n", callback_name
.c_str());
1051 print_invalid(os
, 4, "cannot release object with persistent callbacks",
1055 /* Print implementation of ptr() functions for class "clazz" to "os".
1056 * Since type based subclasses share the pointer with their superclass,
1057 * they can also reuse these functions from the superclass.
1059 * If an object has persistent callbacks set, then the underlying
1060 * C object pointer cannot be released because it references data
1061 * in the C++ object.
1063 void cpp_generator::print_ptr_impl(ostream
&os
, const isl_class
&clazz
)
1065 const char *name
= clazz
.name
.c_str();
1066 std::string cppstring
= type2cpp(clazz
);
1067 const char *cppname
= cppstring
.c_str();
1068 set
<FunctionDecl
*>::const_iterator in
;
1069 const set
<FunctionDecl
*> &callbacks
= clazz
.persistent_callbacks
;
1071 if (clazz
.is_type_subclass())
1074 osprintf(os
, "__isl_give %s *%s::copy() const & {\n", name
, cppname
);
1075 osprintf(os
, " return %s_copy(ptr);\n", name
);
1076 osprintf(os
, "}\n\n");
1077 osprintf(os
, "__isl_keep %s *%s::get() const {\n", name
, cppname
);
1078 osprintf(os
, " return ptr;\n");
1079 osprintf(os
, "}\n\n");
1080 osprintf(os
, "__isl_give %s *%s::release() {\n", name
, cppname
);
1081 for (in
= callbacks
.begin(); in
!= callbacks
.end(); ++in
)
1082 print_check_no_persistent_callback(os
, clazz
, *in
);
1083 osprintf(os
, " %s *tmp = ptr;\n", name
);
1084 osprintf(os
, " ptr = nullptr;\n");
1085 osprintf(os
, " return tmp;\n");
1086 osprintf(os
, "}\n\n");
1087 osprintf(os
, "bool %s::is_null() const {\n", cppname
);
1088 osprintf(os
, " return ptr == nullptr;\n");
1089 osprintf(os
, "}\n");
1092 /* Print implementations for the "as" and "isa" methods, if "clazz"
1093 * is a superclass with a type function.
1095 * "isa" checks whether an object is of a given subclass type.
1096 * "isa_type" does the same, but gets passed the value of the type field
1097 * of the subclass as a function argument and the type of this field
1098 * as a template argument.
1099 * "as" casts an object to a given subclass type, erroring out
1100 * if the object is not of the given type.
1102 * If the input is an invalid object, then these methods raise
1104 * If checked bindings are being generated,
1105 * then an invalid boolean or object is returned instead.
1107 * Return true if anything was printed.
1109 bool cpp_generator::print_downcast_impl(ostream
&os
, const isl_class
&clazz
)
1111 std::string cppstring
= type2cpp(clazz
);
1112 const char *cppname
= cppstring
.c_str();
1117 osprintf(os
, "template <typename T, typename>\n");
1118 osprintf(os
, "%s %s::isa_type(T subtype) const\n",
1119 isl_bool2cpp().c_str(), cppname
);
1120 osprintf(os
, "{\n");
1121 osprintf(os
, " if (is_null())\n");
1123 osprintf(os
, " return boolean();\n");
1125 print_throw_NULL_input(os
);
1126 osprintf(os
, " return %s(get()) == subtype;\n",
1127 clazz
.fn_type
->getNameAsString().c_str());
1128 osprintf(os
, "}\n");
1130 osprintf(os
, "template <class T>\n");
1131 osprintf(os
, "%s %s::isa() const\n", isl_bool2cpp().c_str(), cppname
);
1132 osprintf(os
, "{\n");
1133 osprintf(os
, " return isa_type<decltype(T::type)>(T::type);\n");
1134 osprintf(os
, "}\n");
1136 osprintf(os
, "template <class T>\n");
1137 osprintf(os
, "T %s::as() const\n", cppname
);
1138 osprintf(os
, "{\n");
1140 osprintf(os
, " if (isa<T>().is_false())\n");
1142 osprintf(os
, " if (!isa<T>())\n");
1143 print_invalid(os
, 4, "not an object of the requested subtype",
1145 osprintf(os
, " return T(copy());\n");
1146 osprintf(os
, "}\n");
1151 /* Print the implementation of the get_ctx method.
1153 void cpp_generator::print_get_ctx_impl(ostream
&os
, const isl_class
&clazz
)
1155 const char *name
= clazz
.name
.c_str();
1156 std::string cppstring
= type2cpp(clazz
);
1157 const char *cppname
= cppstring
.c_str();
1158 std::string ns
= isl_namespace();
1160 osprintf(os
, "%sctx %s::get_ctx() const {\n", ns
.c_str(), cppname
);
1161 osprintf(os
, " return %sctx(%s_get_ctx(ptr));\n", ns
.c_str(), name
);
1162 osprintf(os
, "}\n");
1165 /* Print the implementations of the methods needed for the persistent callbacks
1168 void cpp_generator::print_persistent_callbacks_impl(ostream
&os
,
1169 const isl_class
&clazz
)
1171 std::string cppstring
= type2cpp(clazz
);
1172 const char *cppname
= cppstring
.c_str();
1173 string classname
= type2cpp(clazz
);
1174 set
<FunctionDecl
*>::const_iterator in
;
1175 const set
<FunctionDecl
*> &callbacks
= clazz
.persistent_callbacks
;
1177 if (!clazz
.has_persistent_callbacks())
1180 osprintf(os
, "%s &%s::copy_callbacks(const %s &obj)\n",
1181 cppname
, classname
.c_str(), cppname
);
1182 osprintf(os
, "{\n");
1183 for (in
= callbacks
.begin(); in
!= callbacks
.end(); ++in
) {
1184 string callback_name
= clazz
.persistent_callback_name(*in
);
1186 osprintf(os
, " %s_data = obj.%s_data;\n",
1187 callback_name
.c_str(), callback_name
.c_str());
1189 osprintf(os
, " return *this;\n");
1190 osprintf(os
, "}\n\n");
1192 for (in
= callbacks
.begin(); in
!= callbacks
.end(); ++in
) {
1193 function_kind kind
= function_kind_member_method
;
1195 print_set_persistent_callback(os
, clazz
, *in
, kind
);
1199 /* Print definitions for methods of class "clazz" to "os".
1201 void cpp_generator::print_methods_impl(ostream
&os
, const isl_class
&clazz
)
1203 map
<string
, set
<FunctionDecl
*> >::const_iterator it
;
1206 for (it
= clazz
.methods
.begin(); it
!= clazz
.methods
.end(); ++it
) {
1211 print_method_group_impl(os
, clazz
, it
->second
);
1215 /* Print the definition for a method "method_name" in "clazz" derived
1216 * from "fd", which sets an enum, to "os".
1217 * In particular, the method "method_name" sets the enum to "enum_name".
1219 * The last argument of the C function does not appear in the method call,
1220 * but is fixed to "enum_name" instead.
1221 * Other than that, the method printed here is similar to one
1222 * printed by cpp_generator::print_method_impl, except that
1223 * some of the special cases do not occur.
1225 void cpp_generator::print_set_enum_impl(ostream
&os
, const isl_class
&clazz
,
1226 FunctionDecl
*fd
, const string
&enum_name
, const string
&method_name
)
1228 string c_name
= fd
->getName();
1229 int n
= fd
->getNumParams();
1230 function_kind kind
= function_kind_member_method
;
1232 print_method_header(os
, clazz
, fd
, method_name
, n
- 1, false, kind
);
1233 osprintf(os
, "{\n");
1235 print_argument_validity_check(os
, fd
, kind
);
1236 print_save_ctx(os
, fd
, kind
);
1237 print_on_error_continue(os
);
1239 osprintf(os
, " auto res = %s(", c_name
.c_str());
1241 for (int i
= 0; i
< n
- 1; ++i
) {
1242 ParmVarDecl
*param
= fd
->getParamDecl(i
);
1246 print_method_param_use(os
, param
, i
== 0);
1248 osprintf(os
, ", %s", enum_name
.c_str());
1249 osprintf(os
, ");\n");
1251 print_exceptional_execution_check(os
, clazz
, fd
, kind
);
1252 print_method_return(os
, clazz
, fd
);
1254 osprintf(os
, "}\n");
1257 /* Print definitions for the methods in "clazz" derived from "fd",
1258 * which sets an enum, to "os".
1260 * A method is generated for each value in the enum, setting
1261 * the enum to that value.
1263 void cpp_generator::print_set_enums_impl(ostream
&os
, const isl_class
&clazz
,
1266 vector
<set_enum
>::const_iterator it
;
1267 const vector
<set_enum
> &set_enums
= clazz
.set_enums
.at(fd
);
1269 for (it
= set_enums
.begin(); it
!= set_enums
.end(); ++it
) {
1271 print_set_enum_impl(os
, clazz
, fd
, it
->name
, it
->method_name
);
1275 /* Print definitions for methods in "clazz" derived from functions
1276 * that set an enum, to "os".
1278 void cpp_generator::print_set_enums_impl(ostream
&os
, const isl_class
&clazz
)
1280 map
<FunctionDecl
*, vector
<set_enum
> >::const_iterator it
;
1282 for (it
= clazz
.set_enums
.begin(); it
!= clazz
.set_enums
.end(); ++it
)
1283 print_set_enums_impl(os
, clazz
, it
->first
);
1286 /* Print definitions for methods "methods" in class "clazz" to "os".
1288 * "kind" specifies the kind of method that should be generated.
1290 void cpp_generator::print_method_group_impl(ostream
&os
, const isl_class
&clazz
,
1291 const set
<FunctionDecl
*> &methods
)
1293 set
<FunctionDecl
*>::const_iterator it
;
1296 for (it
= methods
.begin(); it
!= methods
.end(); ++it
) {
1302 kind
= get_method_kind(clazz
, *it
);
1303 print_method_impl(os
, clazz
, *it
, kind
);
1307 /* Print the use of "param" to "os".
1309 * "load_from_this_ptr" specifies whether the parameter should be loaded from
1310 * the this-ptr. In case a value is loaded from a this pointer, the original
1311 * value must be preserved and must consequently be copied. Values that are
1312 * loaded from parameters do not need to be preserved, as such values will
1313 * already be copies of the actual parameters. It is consequently possible
1314 * to directly take the pointer from these values, which saves
1315 * an unnecessary copy.
1317 * In case the parameter is a callback function, two parameters get printed,
1318 * a wrapper for the callback function and a pointer to the actual
1319 * callback function. The wrapper is expected to be available
1320 * in a previously declared variable <name>_lambda, while
1321 * the actual callback function is expected to be stored
1322 * in a structure called <name>_data.
1323 * The caller of this function must ensure that these variables exist.
1325 void cpp_generator::print_method_param_use(ostream
&os
, ParmVarDecl
*param
,
1326 bool load_from_this_ptr
)
1328 string name
= param
->getName().str();
1329 const char *name_str
= name
.c_str();
1330 QualType type
= param
->getOriginalType();
1332 if (type
->isIntegerType()) {
1333 osprintf(os
, "%s", name_str
);
1337 if (is_string(type
)) {
1338 osprintf(os
, "%s.c_str()", name_str
);
1342 if (is_callback(type
)) {
1343 osprintf(os
, "%s_lambda, ", name_str
);
1344 osprintf(os
, "&%s_data", name_str
);
1348 if (!load_from_this_ptr
)
1349 osprintf(os
, "%s.", name_str
);
1352 osprintf(os
, "get()");
1354 if (load_from_this_ptr
)
1355 osprintf(os
, "copy()");
1357 osprintf(os
, "release()");
1361 /* Print code that checks that all isl object arguments to "method" are valid
1362 * (not NULL) and throws an exception if they are not.
1363 * "kind" specifies the kind of method that is being generated.
1365 * If checked bindings are being generated,
1366 * then no such check is performed.
1368 void cpp_generator::print_argument_validity_check(ostream
&os
,
1369 FunctionDecl
*method
, function_kind kind
)
1377 n
= method
->getNumParams();
1378 for (int i
= 0; i
< n
; ++i
) {
1380 ParmVarDecl
*param
= method
->getParamDecl(i
);
1381 string name
= param
->getName().str();
1382 const char *name_str
= name
.c_str();
1383 QualType type
= param
->getOriginalType();
1385 is_this
= i
== 0 && kind
== function_kind_member_method
;
1386 if (!is_this
&& (is_isl_ctx(type
) || !is_isl_type(type
)))
1390 osprintf(os
, " if (");
1392 osprintf(os
, " || ");
1395 osprintf(os
, "!ptr");
1397 osprintf(os
, "%s.is_null()", name_str
);
1403 osprintf(os
, ")\n");
1404 print_throw_NULL_input(os
);
1407 /* Print code for saving a copy of the isl::ctx available at the start
1408 * of the method "method" in a "saved_ctx" variable,
1409 * for use in exception handling.
1410 * "kind" specifies what kind of method "method" is.
1412 * If checked bindings are being generated,
1413 * then the "saved_ctx" variable is not needed.
1414 * If "method" is a member function, then obtain the isl_ctx from
1415 * the "this" object.
1416 * If the first argument of the method is an isl::ctx, then use that one.
1417 * Otherwise, save a copy of the isl::ctx associated to the first argument
1418 * of isl object type.
1420 void cpp_generator::print_save_ctx(ostream
&os
, FunctionDecl
*method
,
1424 ParmVarDecl
*param
= method
->getParamDecl(0);
1425 QualType type
= param
->getOriginalType();
1429 if (kind
== function_kind_member_method
) {
1430 osprintf(os
, " auto saved_ctx = get_ctx();\n");
1433 if (is_isl_ctx(type
)) {
1436 name
= param
->getName().str().c_str();
1437 osprintf(os
, " auto saved_ctx = %s;\n", name
);
1440 n
= method
->getNumParams();
1441 for (int i
= 0; i
< n
; ++i
) {
1442 ParmVarDecl
*param
= method
->getParamDecl(i
);
1443 QualType type
= param
->getOriginalType();
1445 if (!is_isl_type(type
))
1447 osprintf(os
, " auto saved_ctx = %s.get_ctx();\n",
1448 param
->getName().str().c_str());
1453 /* Print code to make isl not print an error message when an error occurs
1454 * within the current scope (if exceptions are available),
1455 * since the error message will be included in the exception.
1456 * If exceptions are not available, then exception::on_error
1457 * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead.
1459 * If checked bindings are being generated,
1460 * then leave it to the user to decide what isl should do on error.
1461 * Otherwise, assume that a valid isl::ctx is available
1462 * in the "saved_ctx" variable,
1463 * e.g., through a prior call to print_save_ctx.
1465 void cpp_generator::print_on_error_continue(ostream
&os
)
1469 osprintf(os
, " options_scoped_set_on_error saved_on_error(saved_ctx, "
1470 "exception::on_error);\n");
1473 /* Print code to "os" that checks whether any of the persistent callbacks
1474 * of "clazz" is set and if it failed with an exception. If so, the "eptr"
1475 * in the corresponding data structure contains the exception
1476 * that was caught and that needs to be rethrown.
1477 * This field is cleared because the callback and its data may get reused.
1479 * The check only needs to be generated for member methods since
1480 * an object is needed for any of the persistent callbacks to be set.
1482 static void print_persistent_callback_exceptional_execution_check(ostream
&os
,
1483 const isl_class
&clazz
, cpp_generator::function_kind kind
)
1485 const set
<FunctionDecl
*> &callbacks
= clazz
.persistent_callbacks
;
1486 set
<FunctionDecl
*>::const_iterator in
;
1488 if (kind
!= cpp_generator::function_kind_member_method
)
1491 for (in
= callbacks
.begin(); in
!= callbacks
.end(); ++in
) {
1492 string callback_name
= clazz
.persistent_callback_name(*in
);
1494 osprintf(os
, " if (%s_data && %s_data->eptr) {\n",
1495 callback_name
.c_str(), callback_name
.c_str());
1496 osprintf(os
, " std::exception_ptr eptr = %s_data->eptr;\n",
1497 callback_name
.c_str());
1498 osprintf(os
, " %s_data->eptr = nullptr;\n",
1499 callback_name
.c_str());
1500 osprintf(os
, " std::rethrow_exception(eptr);\n");
1501 osprintf(os
, " }\n");
1505 /* Print code that checks whether the execution of the core of "method"
1506 * of class "clazz" was successful.
1507 * "kind" specifies what kind of method "method" is.
1509 * If checked bindings are being generated,
1510 * then no checks are performed.
1512 * Otherwise, first check if any of the callbacks failed with
1513 * an exception. If so, the "eptr" in the corresponding data structure
1514 * contains the exception that was caught and that needs to be rethrown.
1515 * Then check if the function call failed in any other way and throw
1516 * the appropriate exception.
1517 * In particular, if the return type is isl_stat, isl_bool or isl_size,
1518 * then a negative value indicates a failure. If the return type
1519 * is an isl type, then a NULL value indicates a failure.
1520 * Assume print_save_ctx has made sure that a valid isl::ctx
1521 * is available in the "ctx" variable.
1523 void cpp_generator::print_exceptional_execution_check(ostream
&os
,
1524 const isl_class
&clazz
, FunctionDecl
*method
, function_kind kind
)
1527 bool check_null
, check_neg
;
1528 QualType return_type
= method
->getReturnType();
1533 print_persistent_callback_exceptional_execution_check(os
, clazz
, kind
);
1535 n
= method
->getNumParams();
1536 for (int i
= 0; i
< n
; ++i
) {
1537 ParmVarDecl
*param
= method
->getParamDecl(i
);
1540 if (!is_callback(param
->getOriginalType()))
1542 name
= param
->getName().str().c_str();
1543 osprintf(os
, " if (%s_data.eptr)\n", name
);
1544 osprintf(os
, " std::rethrow_exception(%s_data.eptr);\n",
1548 check_neg
= is_isl_neg_error(return_type
);
1549 check_null
= is_isl_type(return_type
);
1550 if (!check_null
&& !check_neg
)
1554 osprintf(os
, " if (res < 0)\n");
1556 osprintf(os
, " if (!res)\n");
1557 print_throw_last_error(os
);
1560 /* Does "fd" modify an object of a subclass based on a type function?
1562 static bool is_subclass_mutator(const isl_class
&clazz
, FunctionDecl
*fd
)
1564 return clazz
.is_type_subclass() && generator::is_mutator(clazz
, fd
);
1567 /* Return the C++ return type of the method corresponding to "fd" in "clazz".
1569 * If "fd" modifies an object of a subclass, then return
1570 * the type of this subclass.
1571 * Otherwise, return the C++ counterpart of the actual return type.
1573 std::string
cpp_generator::get_return_type(const isl_class
&clazz
,
1576 if (is_subclass_mutator(clazz
, fd
))
1577 return type2cpp(clazz
);
1579 return type2cpp(fd
->getReturnType());
1582 /* Given a function "method" for setting a "clazz" persistent callback,
1583 * print the implementations of the methods needed for that callback.
1585 * In particular, print
1586 * - the implementation of a static inline method
1587 * for use as the C callback function
1588 * - the definition of a private method for setting the callback function
1589 * - the public method for constructing a new object with the callback set.
1591 void cpp_generator::print_set_persistent_callback(ostream
&os
,
1592 const isl_class
&clazz
, FunctionDecl
*method
,
1595 string fullname
= method
->getName();
1596 ParmVarDecl
*param
= persistent_callback_arg(method
);
1597 string classname
= type2cpp(clazz
);
1599 string callback_name
= clazz
.persistent_callback_name(method
);
1601 print_persistent_callback_prototype(os
, clazz
, method
, false);
1603 osprintf(os
, "{\n");
1604 print_callback_body(os
, 2, param
, callback_name
);
1605 osprintf(os
, "}\n\n");
1607 pname
= param
->getName().str();
1608 print_persistent_callback_setter_prototype(os
, clazz
, method
, false);
1610 osprintf(os
, "{\n");
1611 print_check_ptr_start(os
, clazz
, "ptr");
1612 osprintf(os
, " %s_data = std::make_shared<struct %s_data>();\n",
1613 callback_name
.c_str(), callback_name
.c_str());
1614 osprintf(os
, " %s_data->func = %s;\n",
1615 callback_name
.c_str(), pname
.c_str());
1616 osprintf(os
, " ptr = %s(ptr, &%s, %s_data.get());\n",
1617 fullname
.c_str(), callback_name
.c_str(), callback_name
.c_str());
1618 print_check_ptr_end(os
, "ptr");
1619 osprintf(os
, "}\n\n");
1621 print_method_header(os
, clazz
, method
, false, kind
);
1622 osprintf(os
, "{\n");
1623 osprintf(os
, " auto copy = *this;\n");
1624 osprintf(os
, " copy.set_%s_data(%s);\n",
1625 callback_name
.c_str(), pname
.c_str());
1626 osprintf(os
, " return copy;\n");
1627 osprintf(os
, "}\n\n");
1630 /* Print the return statement of the C++ method corresponding
1631 * to the C function "method" in class "clazz" to "os".
1633 * The result of the isl function is returned as a new
1634 * object if the underlying isl function returns an isl_* ptr, as a bool
1635 * if the isl function returns an isl_bool, as void if the isl functions
1636 * returns an isl_stat,
1637 * as std::string if the isl function returns 'const char *', and as
1638 * unmodified return value otherwise.
1639 * If checked C++ bindings are being generated,
1640 * then an isl_bool return type is transformed into a boolean and
1641 * an isl_stat into a stat since no exceptions can be generated
1642 * on negative results from the isl function.
1643 * If the method returns a new instance of the same object type and
1644 * if the class has any persistent callbacks, then the data
1645 * for these callbacks are copied from the original to the new object.
1646 * If "clazz" is a subclass that is based on a type function and
1647 * if the return type corresponds to the superclass data type,
1648 * then it is replaced by the subclass data type.
1650 void cpp_generator::print_method_return(ostream
&os
, const isl_class
&clazz
,
1651 FunctionDecl
*method
)
1653 QualType return_type
= method
->getReturnType();
1654 string rettype_str
= get_return_type(clazz
, method
);
1655 bool returns_super
= is_subclass_mutator(clazz
, method
);
1657 if (is_isl_type(return_type
) ||
1658 (checked
&& is_isl_neg_error(return_type
))) {
1659 osprintf(os
, " return manage(res)");
1660 if (is_mutator(clazz
, method
) &&
1661 clazz
.has_persistent_callbacks())
1662 osprintf(os
, ".copy_callbacks(*this)");
1664 osprintf(os
, ".as<%s>()", rettype_str
.c_str());
1665 osprintf(os
, ";\n");
1666 } else if (is_isl_stat(return_type
)) {
1667 osprintf(os
, " return;\n");
1668 } else if (is_string(return_type
)) {
1669 osprintf(os
, " std::string tmp(res);\n");
1671 osprintf(os
, " free(res);\n");
1672 osprintf(os
, " return tmp;\n");
1674 osprintf(os
, " return res;\n");
1678 /* Print definition for "method" in class "clazz" to "os".
1680 * "kind" specifies the kind of method that should be generated.
1682 * This method distinguishes three kinds of methods: member methods, static
1683 * methods, and constructors.
1685 * Member methods call "method" by passing to the underlying isl function the
1686 * isl object belonging to "this" as first argument and the remaining arguments
1687 * as subsequent arguments.
1689 * Static methods call "method" by passing all arguments to the underlying isl
1690 * function, as no this-pointer is available. The result is a newly managed
1693 * Constructors create a new object from a given set of input parameters. They
1694 * do not return a value, but instead update the pointer stored inside the
1695 * newly created object.
1697 * If the method has a callback argument, we reduce the number of parameters
1698 * that are exposed by one to hide the user pointer from the interface. On
1699 * the C++ side no user pointer is needed, as arguments can be forwarded
1700 * as part of the std::function argument which specifies the callback function.
1702 * Unless checked C++ bindings are being generated,
1703 * the inputs of the method are first checked for being valid isl objects and
1704 * a copy of the associated isl::ctx is saved (if needed).
1705 * If any failure occurs, either during the check for the inputs or
1706 * during the isl function call, an exception is thrown.
1707 * During the function call, isl is made not to print any error message
1708 * because the error message is included in the exception.
1710 void cpp_generator::print_method_impl(ostream
&os
, const isl_class
&clazz
,
1711 FunctionDecl
*method
, function_kind kind
)
1713 string methodname
= method
->getName();
1714 int num_params
= method
->getNumParams();
1716 print_method_header(os
, clazz
, method
, false, kind
);
1717 osprintf(os
, "{\n");
1718 print_argument_validity_check(os
, method
, kind
);
1719 print_save_ctx(os
, method
, kind
);
1720 print_on_error_continue(os
);
1722 for (int i
= 0; i
< num_params
; ++i
) {
1723 ParmVarDecl
*param
= method
->getParamDecl(i
);
1724 if (is_callback(param
->getType())) {
1726 print_callback_local(os
, param
);
1730 osprintf(os
, " auto res = %s(", methodname
.c_str());
1732 for (int i
= 0; i
< num_params
; ++i
) {
1733 ParmVarDecl
*param
= method
->getParamDecl(i
);
1734 bool load_from_this_ptr
= false;
1736 if (i
== 0 && kind
== function_kind_member_method
)
1737 load_from_this_ptr
= true;
1739 print_method_param_use(os
, param
, load_from_this_ptr
);
1741 if (i
!= num_params
- 1)
1744 osprintf(os
, ");\n");
1746 print_exceptional_execution_check(os
, clazz
, method
, kind
);
1747 if (kind
== function_kind_constructor
) {
1748 osprintf(os
, " ptr = res;\n");
1750 print_method_return(os
, clazz
, method
);
1753 osprintf(os
, "}\n");
1756 /* Print the header for "method" in class "clazz", with name "cname" and
1757 * "num_params" number of arguments, to "os".
1759 * Print the header of a declaration if "is_declaration" is set, otherwise print
1760 * the header of a method definition.
1762 * "kind" specifies the kind of method that should be generated.
1764 * This function prints headers for member methods, static methods, and
1765 * constructors, either for their declaration or definition.
1767 * Member functions are declared as "const", as they do not change the current
1768 * object, but instead create a new object. They always retrieve the first
1769 * parameter of the original isl function from the this-pointer of the object,
1770 * such that only starting at the second parameter the parameters of the
1771 * original function become part of the method's interface.
1775 * __isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1,
1776 * __isl_take isl_set *s2);
1778 * is translated into:
1780 * inline set intersect(set set2) const;
1782 * For static functions and constructors all parameters of the original isl
1783 * function are exposed.
1785 * Parameters that are defined as __isl_keep or are of type string, are passed
1786 * as const reference, which allows the compiler to optimize the parameter
1789 * Constructors are marked as explicit using the C++ keyword 'explicit' or as
1790 * implicit using a comment in place of the explicit keyword. By annotating
1791 * implicit constructors with a comment, users of the interface are made
1792 * aware of the potential danger that implicit construction is possible
1793 * for these constructors, whereas without a comment not every user would
1794 * know that implicit construction is allowed in absence of an explicit keyword.
1796 void cpp_generator::print_method_header(ostream
&os
, const isl_class
&clazz
,
1797 FunctionDecl
*method
, const string
&cname
, int num_params
,
1798 bool is_declaration
, function_kind kind
)
1800 string rettype_str
= get_return_type(clazz
, method
);
1801 string classname
= type2cpp(clazz
);
1802 int first_param
= 0;
1804 if (kind
== function_kind_member_method
)
1807 if (is_declaration
) {
1810 if (kind
== function_kind_static_method
)
1811 osprintf(os
, "static ");
1813 osprintf(os
, "inline ");
1815 if (kind
== function_kind_constructor
) {
1816 if (is_implicit_conversion(clazz
, method
))
1817 osprintf(os
, "/* implicit */ ");
1819 osprintf(os
, "explicit ");
1823 if (kind
!= function_kind_constructor
)
1824 osprintf(os
, "%s ", rettype_str
.c_str());
1826 if (!is_declaration
)
1827 osprintf(os
, "%s::", classname
.c_str());
1829 if (kind
!= function_kind_constructor
)
1830 osprintf(os
, "%s", cname
.c_str());
1832 osprintf(os
, "%s", classname
.c_str());
1836 for (int i
= first_param
; i
< num_params
; ++i
) {
1837 ParmVarDecl
*param
= method
->getParamDecl(i
);
1838 QualType type
= param
->getOriginalType();
1839 string cpptype
= type2cpp(type
);
1841 if (is_callback(type
))
1844 if (keeps(param
) || is_string(type
) || is_callback(type
))
1845 osprintf(os
, "const %s &%s", cpptype
.c_str(),
1846 param
->getName().str().c_str());
1848 osprintf(os
, "%s %s", cpptype
.c_str(),
1849 param
->getName().str().c_str());
1851 if (i
!= num_params
- 1)
1857 if (kind
== function_kind_member_method
)
1858 osprintf(os
, " const");
1865 /* Print the header for "method" in class "clazz" to "os".
1867 * Print the header of a declaration if "is_declaration" is set, otherwise print
1868 * the header of a method definition.
1870 * "kind" specifies the kind of method that should be generated.
1872 void cpp_generator::print_method_header(ostream
&os
, const isl_class
&clazz
,
1873 FunctionDecl
*method
, bool is_declaration
, function_kind kind
)
1875 string cname
= clazz
.method_name(method
);
1876 int num_params
= method
->getNumParams();
1878 cname
= rename_method(cname
);
1879 print_method_header(os
, clazz
, method
, cname
, num_params
,
1880 is_declaration
, kind
);
1883 /* Generate the list of argument types for a callback function of
1884 * type "type". If "cpp" is set, then generate the C++ type list, otherwise
1887 * For a callback of type
1889 * isl_stat (*)(__isl_take isl_map *map, void *user)
1891 * the following C++ argument list is generated:
1895 string
cpp_generator::generate_callback_args(QualType type
, bool cpp
)
1897 std::string type_str
;
1898 const FunctionProtoType
*callback
;
1901 callback
= extract_prototype(type
);
1902 num_params
= callback
->getNumArgs();
1906 for (long i
= 0; i
< num_params
; i
++) {
1907 QualType type
= callback
->getArgType(i
);
1910 type_str
+= type2cpp(type
);
1912 type_str
+= type
.getAsString();
1915 type_str
+= "arg_" + ::to_string(i
);
1917 if (i
!= num_params
- 1)
1924 /* Generate the full cpp type of a callback function of type "type".
1926 * For a callback of type
1928 * isl_stat (*)(__isl_take isl_map *map, void *user)
1930 * the following type is generated:
1932 * std::function<stat(map)>
1934 string
cpp_generator::generate_callback_type(QualType type
)
1936 std::string type_str
;
1937 const FunctionProtoType
*callback
= extract_prototype(type
);
1938 QualType return_type
= callback
->getReturnType();
1939 string rettype_str
= type2cpp(return_type
);
1941 type_str
= "std::function<";
1942 type_str
+= rettype_str
;
1944 type_str
+= generate_callback_args(type
, true);
1950 /* Print the call to the C++ callback function "call",
1951 * with the given indentation, wrapped
1952 * for use inside the lambda function that is used as the C callback function,
1953 * in the case where checked C++ bindings are being generated.
1955 * In particular, print
1957 * auto ret = @call@;
1958 * return ret.release();
1960 void cpp_generator::print_wrapped_call_checked(ostream
&os
, int indent
,
1963 osprintf(os
, indent
, "auto ret = %s;\n", call
.c_str());
1964 osprintf(os
, indent
, "return ret.release();\n");
1967 /* Print the call to the C++ callback function "call",
1968 * with the given indentation and with return type "rtype", wrapped
1969 * for use inside the lambda function that is used as the C callback function.
1971 * In particular, print
1975 * return isl_stat_ok;
1976 * } ISL_CPP_CATCH_ALL {
1977 * data->eptr = std::current_exception();
1978 * return isl_stat_error;
1982 * auto ret = @call@;
1983 * return ret ? isl_bool_true : isl_bool_false;
1984 * } ISL_CPP_CATCH_ALL {
1985 * data->eptr = std::current_exception();
1986 * return isl_bool_error;
1990 * auto ret = @call@;
1991 * return ret.release();
1992 * } ISL_CPP_CATCH_ALL {
1993 * data->eptr = std::current_exception();
1997 * depending on the return type.
1999 * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)"
2000 * (if exceptions are available).
2002 * If checked C++ bindings are being generated, then
2003 * the call is wrapped differently.
2005 void cpp_generator::print_wrapped_call(ostream
&os
, int indent
,
2006 const string
&call
, QualType rtype
)
2009 return print_wrapped_call_checked(os
, indent
, call
);
2011 osprintf(os
, indent
, "ISL_CPP_TRY {\n");
2012 if (is_isl_stat(rtype
))
2013 osprintf(os
, indent
, " %s;\n", call
.c_str());
2015 osprintf(os
, indent
, " auto ret = %s;\n", call
.c_str());
2016 if (is_isl_stat(rtype
))
2017 osprintf(os
, indent
, " return isl_stat_ok;\n");
2018 else if (is_isl_bool(rtype
))
2019 osprintf(os
, indent
,
2020 " return ret ? isl_bool_true : isl_bool_false;\n");
2022 osprintf(os
, indent
, " return ret.release();\n");
2023 osprintf(os
, indent
, "} ISL_CPP_CATCH_ALL {\n");
2024 osprintf(os
, indent
, " data->eptr = std::current_exception();\n");
2025 if (is_isl_stat(rtype
))
2026 osprintf(os
, indent
, " return isl_stat_error;\n");
2027 else if (is_isl_bool(rtype
))
2028 osprintf(os
, indent
, " return isl_bool_error;\n");
2030 osprintf(os
, indent
, " return NULL;\n");
2031 osprintf(os
, indent
, "}\n");
2034 /* Print the declaration for a "prefix"_data data structure
2035 * that can be used for passing to a C callback function
2036 * containing a copy of the C++ callback function "param",
2037 * along with an std::exception_ptr that is used to store any
2038 * exceptions thrown in the C++ callback.
2040 * If the C callback is of the form
2042 * isl_stat (*fn)(__isl_take isl_map *map, void *user)
2044 * then the following declaration is printed:
2046 * struct <prefix>_data {
2047 * std::function<stat(map)> func;
2048 * std::exception_ptr eptr;
2051 * (without a newline or a semicolon).
2053 * The std::exception_ptr object is not added to "prefix"_data
2054 * if checked C++ bindings are being generated.
2056 void cpp_generator::print_callback_data_decl(ostream
&os
, ParmVarDecl
*param
,
2057 const string
&prefix
)
2061 cpp_args
= generate_callback_type(param
->getType());
2063 osprintf(os
, " struct %s_data {\n", prefix
.c_str());
2064 osprintf(os
, " %s func;\n", cpp_args
.c_str());
2066 osprintf(os
, " std::exception_ptr eptr;\n");
2070 /* Print the body of C function callback with the given indentation
2071 * that can be use as an argument to "param" for marshalling
2072 * the corresponding C++ callback.
2073 * The data structure that contains the C++ callback is of type
2076 * For a callback of the form
2078 * isl_stat (*fn)(__isl_take isl_map *map, void *user)
2080 * the following code is generated:
2082 * auto *data = static_cast<struct <prefix>_data *>(arg_1);
2084 * stat ret = (data->func)(manage(arg_0));
2085 * return isl_stat_ok;
2086 * } ISL_CPP_CATCH_ALL {
2087 * data->eptr = std::current_exception();
2088 * return isl_stat_error;
2091 * If checked C++ bindings are being generated, then
2092 * generate the following code:
2094 * auto *data = static_cast<struct <prefix>_data *>(arg_1);
2095 * stat ret = (data->func)(manage(arg_0));
2096 * return isl_stat(ret);
2098 void cpp_generator::print_callback_body(ostream
&os
, int indent
,
2099 ParmVarDecl
*param
, const string
&prefix
)
2101 QualType ptype
, rtype
;
2102 string call
, last_idx
;
2103 const FunctionProtoType
*callback
;
2106 ptype
= param
->getType();
2108 callback
= extract_prototype(ptype
);
2109 rtype
= callback
->getReturnType();
2110 num_params
= callback
->getNumArgs();
2112 last_idx
= ::to_string(num_params
- 1);
2114 call
= "(data->func)(";
2115 for (long i
= 0; i
< num_params
- 1; i
++) {
2116 if (!callback_takes_argument(param
, i
))
2117 call
+= "manage_copy";
2120 call
+= "(arg_" + ::to_string(i
) + ")";
2121 if (i
!= num_params
- 2)
2126 osprintf(os
, indent
,
2127 "auto *data = static_cast<struct %s_data *>(arg_%s);\n",
2128 prefix
.c_str(), last_idx
.c_str());
2129 print_wrapped_call(os
, indent
, call
, rtype
);
2132 /* Print the local variables that are needed for a callback argument,
2133 * in particular, print a lambda function that wraps the callback and
2134 * a pointer to the actual C++ callback function.
2136 * For a callback of the form
2138 * isl_stat (*fn)(__isl_take isl_map *map, void *user)
2140 * the following lambda function is generated:
2142 * auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
2143 * auto *data = static_cast<struct fn_data *>(arg_1);
2145 * stat ret = (data->func)(manage(arg_0));
2146 * return isl_stat_ok;
2148 * data->eptr = std::current_exception();
2149 * return isl_stat_error;
2153 * A copy of the std::function C++ callback function is stored in
2154 * a fn_data data structure for passing to the C callback function,
2155 * along with an std::exception_ptr that is used to store any
2156 * exceptions thrown in the C++ callback.
2159 * std::function<stat(map)> func;
2160 * std::exception_ptr eptr;
2161 * } fn_data = { fn };
2163 * This std::function object represents the actual user
2164 * callback function together with the locally captured state at the caller.
2166 * The lambda function is expected to be used as a C callback function
2167 * where the lambda itself is provided as the function pointer and
2168 * where the user void pointer is a pointer to fn_data.
2169 * The std::function object is extracted from the pointer to fn_data
2170 * inside the lambda function.
2172 * The std::exception_ptr object is not added to fn_data
2173 * if checked C++ bindings are being generated.
2174 * The body of the generated lambda function then is as follows:
2176 * stat ret = (data->func)(manage(arg_0));
2177 * return isl_stat(ret);
2179 * If the C callback does not take its arguments, then
2180 * manage_copy is used instead of manage.
2182 void cpp_generator::print_callback_local(ostream
&os
, ParmVarDecl
*param
)
2185 QualType ptype
, rtype
;
2186 string c_args
, cpp_args
, rettype
;
2187 const FunctionProtoType
*callback
;
2189 pname
= param
->getName().str();
2190 ptype
= param
->getType();
2192 c_args
= generate_callback_args(ptype
, false);
2194 callback
= extract_prototype(ptype
);
2195 rtype
= callback
->getReturnType();
2196 rettype
= rtype
.getAsString();
2198 print_callback_data_decl(os
, param
, pname
);
2199 osprintf(os
, " %s_data = { %s };\n", pname
.c_str(), pname
.c_str());
2200 osprintf(os
, " auto %s_lambda = [](%s) -> %s {\n",
2201 pname
.c_str(), c_args
.c_str(), rettype
.c_str());
2202 print_callback_body(os
, 4, param
, pname
);
2203 osprintf(os
, " };\n");
2206 /* An array listing functions that must be renamed and the function name they
2207 * should be renamed to. We currently rename functions in case their name would
2208 * match a reserved C++ keyword, which is not allowed in C++.
2210 static const char *rename_map
[][2] = {
2211 { "union", "unite" },
2214 /* Rename method "name" in case the method name in the C++ bindings should not
2215 * match the name in the C bindings. We do this for example to avoid
2218 std::string
cpp_generator::rename_method(std::string name
)
2220 for (size_t i
= 0; i
< sizeof(rename_map
) / sizeof(rename_map
[0]); i
++)
2221 if (name
.compare(rename_map
[i
][0]) == 0)
2222 return rename_map
[i
][1];
2227 /* Translate isl class "clazz" to its corresponding C++ type.
2228 * Use the name of the type based subclass, if any.
2230 string
cpp_generator::type2cpp(const isl_class
&clazz
)
2232 return type2cpp(clazz
.subclass_name
);
2235 /* Translate type string "type_str" to its C++ name counterpart.
2237 string
cpp_generator::type2cpp(string type_str
)
2239 return type_str
.substr(4);
2242 /* Return the C++ counterpart to the isl_bool type.
2243 * If checked C++ bindings are being generated,
2244 * then this is "boolean". Otherwise, it is simply "bool".
2246 string
cpp_generator::isl_bool2cpp()
2248 return checked
? "boolean" : "bool";
2251 /* Return the namespace of the generated C++ bindings.
2253 string
cpp_generator::isl_namespace()
2255 return checked
? "isl::checked::" : "isl::";
2258 /* Translate QualType "type" to its C++ name counterpart.
2260 * An isl_bool return type is translated into "bool",
2261 * while an isl_stat is translated into "void" and
2262 * an isl_size is translated to "unsigned".
2263 * The exceptional cases are handled through exceptions.
2264 * If checked C++ bindings are being generated, then
2265 * C++ counterparts of isl_bool, isl_stat and isl_size need to be used instead.
2267 string
cpp_generator::type2cpp(QualType type
)
2269 if (is_isl_type(type
))
2270 return isl_namespace() +
2271 type2cpp(type
->getPointeeType().getAsString());
2273 if (is_isl_bool(type
))
2274 return isl_bool2cpp();
2276 if (is_isl_stat(type
))
2277 return checked
? "stat" : "void";
2279 if (is_isl_size(type
))
2280 return checked
? "class size" : "unsigned";
2282 if (type
->isIntegerType())
2283 return type
.getAsString();
2285 if (is_string(type
))
2286 return "std::string";
2288 if (is_callback(type
))
2289 return generate_callback_type(type
);
2291 die("Cannot convert type to C++ type");
2294 /* Check if "subclass_type" is a subclass of "class_type".
2296 bool cpp_generator::is_subclass(QualType subclass_type
,
2297 const isl_class
&class_type
)
2299 std::string type_str
= subclass_type
->getPointeeType().getAsString();
2300 std::vector
<std::string
> superclasses
;
2301 std::vector
<const isl_class
*> parents
;
2302 std::vector
<std::string
>::iterator ci
;
2304 superclasses
= generator::find_superclasses(classes
[type_str
].type
);
2306 for (ci
= superclasses
.begin(); ci
< superclasses
.end(); ci
++)
2307 parents
.push_back(&classes
[*ci
]);
2309 while (!parents
.empty()) {
2310 const isl_class
*candidate
= parents
.back();
2314 if (&class_type
== candidate
)
2317 superclasses
= generator::find_superclasses(candidate
->type
);
2319 for (ci
= superclasses
.begin(); ci
< superclasses
.end(); ci
++)
2320 parents
.push_back(&classes
[*ci
]);
2326 /* Check if "cons" is an implicit conversion constructor of class "clazz".
2328 * An implicit conversion constructor is generated in case "cons" has a single
2329 * parameter, where the parameter type is a subclass of the class that is
2330 * currently being generated.
2332 bool cpp_generator::is_implicit_conversion(const isl_class
&clazz
,
2335 ParmVarDecl
*param
= cons
->getParamDecl(0);
2336 QualType type
= param
->getOriginalType();
2338 int num_params
= cons
->getNumParams();
2339 if (num_params
!= 1)
2342 if (is_isl_type(type
) && !is_isl_ctx(type
) && is_subclass(type
, clazz
))
2348 /* Get kind of "method" in "clazz".
2350 * Given the declaration of a static or member method, returns its kind.
2352 cpp_generator::function_kind
cpp_generator::get_method_kind(
2353 const isl_class
&clazz
, FunctionDecl
*method
)
2355 if (is_static(clazz
, method
))
2356 return function_kind_static_method
;
2358 return function_kind_member_method
;