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
, ...)
56 va_start(arguments
, format
);
57 size
= vsnprintf(NULL
, 0, format
, arguments
);
58 string_pointer
= new char[size
+ 1];
60 va_start(arguments
, format
);
61 vsnprintf(string_pointer
, size
+ 1, format
, arguments
);
64 delete[] string_pointer
;
67 /* Convert "l" to a string.
69 static std::string
to_string(long l
)
71 std::ostringstream strm
;
76 /* Generate a cpp interface based on the extracted types and functions.
78 * Print first a set of forward declarations for all isl wrapper
79 * classes, then the declarations of the classes, and at the end all
82 void cpp_generator::generate()
87 osprintf(os
, "namespace isl {\n\n");
88 osprintf(os
, "inline namespace noexceptions {\n\n");
90 print_forward_declarations(os
);
92 print_declarations(os
);
94 print_implementations(os
);
96 osprintf(os
, "} // namespace noexceptions\n");
97 osprintf(os
, "} // namespace isl\n");
100 /* Print forward declarations for all classes to "os".
102 void cpp_generator::print_forward_declarations(ostream
&os
)
104 map
<string
, isl_class
>::iterator ci
;
106 osprintf(os
, "// forward declarations\n");
108 for (ci
= classes
.begin(); ci
!= classes
.end(); ++ci
)
109 print_class_forward_decl(os
, ci
->second
);
112 /* Print all declarations to "os".
114 void cpp_generator::print_declarations(ostream
&os
)
116 map
<string
, isl_class
>::iterator ci
;
119 for (ci
= classes
.begin(); ci
!= classes
.end(); ++ci
) {
125 print_class(os
, ci
->second
);
129 /* Print all implementations to "os".
131 void cpp_generator::print_implementations(ostream
&os
)
133 map
<string
, isl_class
>::iterator ci
;
136 for (ci
= classes
.begin(); ci
!= classes
.end(); ++ci
) {
142 print_class_impl(os
, ci
->second
);
146 /* Print declarations for class "clazz" to "os".
148 void cpp_generator::print_class(ostream
&os
, const isl_class
&clazz
)
150 const char *name
= clazz
.name
.c_str();
151 std::string cppstring
= type2cpp(clazz
);
152 const char *cppname
= cppstring
.c_str();
154 osprintf(os
, "// declarations for isl::%s\n", cppname
);
156 print_class_factory_decl(os
, clazz
);
158 osprintf(os
, "class %s {\n", cppname
);
159 print_class_factory_decl(os
, clazz
, " friend ");
161 osprintf(os
, " %s *ptr = nullptr;\n", name
);
163 print_private_constructors_decl(os
, clazz
);
165 osprintf(os
, "public:\n");
166 print_public_constructors_decl(os
, clazz
);
167 print_constructors_decl(os
, clazz
);
168 print_copy_assignment_decl(os
, clazz
);
169 print_destructor_decl(os
, clazz
);
170 print_ptr_decl(os
, clazz
);
171 print_get_ctx_decl(os
);
173 print_methods_decl(os
, clazz
);
175 osprintf(os
, "};\n");
178 /* Print forward declaration of class "clazz" to "os".
180 void cpp_generator::print_class_forward_decl(ostream
&os
,
181 const isl_class
&clazz
)
183 std::string cppstring
= type2cpp(clazz
);
184 const char *cppname
= cppstring
.c_str();
186 osprintf(os
, "class %s;\n", cppname
);
189 /* Print global factory functions to "os".
191 * Each class has two global factory functions:
193 * isl::set manage(__isl_take isl_set *ptr);
194 * isl::set manage_copy(__isl_keep isl_set *ptr);
196 * A user can construct isl C++ objects from a raw pointer and indicate whether
197 * they intend to take the ownership of the object or not through these global
198 * factory functions. This ensures isl object creation is very explicit and
199 * pointers are not converted by accident. Thanks to overloading, manage() and
200 * manage_copy() can be called on any isl raw pointer and the corresponding
201 * object is automatically created, without the user having to choose the right
204 void cpp_generator::print_class_factory_decl(ostream
&os
,
205 const isl_class
&clazz
, const std::string
&prefix
)
207 const char *name
= clazz
.name
.c_str();
208 std::string cppstring
= type2cpp(clazz
);
209 const char *cppname
= cppstring
.c_str();
212 osprintf(os
, "inline isl::%s manage(__isl_take %s *ptr);\n", cppname
,
215 osprintf(os
, "inline isl::%s manage_copy(__isl_keep %s *ptr);\n",
219 /* Print declarations of private constructors for class "clazz" to "os".
221 * Each class has currently one private constructor:
223 * 1) Constructor from a plain isl_* C pointer
227 * set(__isl_take isl_set *ptr);
229 * The raw pointer constructor is kept private. Object creation is only
230 * possible through isl::manage() or isl::manage_copy().
232 void cpp_generator::print_private_constructors_decl(ostream
&os
,
233 const isl_class
&clazz
)
235 const char *name
= clazz
.name
.c_str();
236 std::string cppstring
= type2cpp(clazz
);
237 const char *cppname
= cppstring
.c_str();
239 osprintf(os
, " inline explicit %s(__isl_take %s *ptr);\n", cppname
,
243 /* Print declarations of public constructors for class "clazz" to "os".
245 * Each class currently has two public constructors:
247 * 1) A default constructor
248 * 2) A copy constructor
253 * set(const isl::set &set);
255 void cpp_generator::print_public_constructors_decl(ostream
&os
,
256 const isl_class
&clazz
)
258 std::string cppstring
= type2cpp(clazz
);
259 const char *cppname
= cppstring
.c_str();
260 osprintf(os
, " inline /* implicit */ %s();\n", cppname
);
262 osprintf(os
, " inline /* implicit */ %s(const isl::%s &obj);\n",
266 /* Print declarations for constructors for class "class" to "os".
268 * For each isl function that is marked as __isl_constructor,
269 * add a corresponding C++ constructor.
273 * inline /\* implicit *\/ union_set(isl::basic_set bset);
274 * inline /\* implicit *\/ union_set(isl::set set);
275 * inline explicit val(isl::ctx ctx, long i);
276 * inline explicit val(isl::ctx ctx, const std::string &str);
278 void cpp_generator::print_constructors_decl(ostream
&os
,
279 const isl_class
&clazz
)
281 set
<FunctionDecl
*>::const_iterator in
;
282 const set
<FunctionDecl
*> &constructors
= clazz
.constructors
;
284 for (in
= constructors
.begin(); in
!= constructors
.end(); ++in
) {
285 FunctionDecl
*cons
= *in
;
286 string fullname
= cons
->getName();
287 function_kind kind
= function_kind_constructor
;
289 print_method_decl(os
, clazz
, fullname
, cons
, kind
);
293 /* Print declarations of copy assignment operator for class "clazz"
296 * Each class has one assignment operator.
298 * isl:set &set::operator=(isl::set obj)
301 void cpp_generator::print_copy_assignment_decl(ostream
&os
,
302 const isl_class
&clazz
)
304 std::string cppstring
= type2cpp(clazz
);
305 const char *cppname
= cppstring
.c_str();
307 osprintf(os
, " inline isl::%s &operator=(isl::%s obj);\n", cppname
,
311 /* Print declaration of destructor for class "clazz" to "os".
313 void cpp_generator::print_destructor_decl(ostream
&os
, const isl_class
&clazz
)
315 std::string cppstring
= type2cpp(clazz
);
316 const char *cppname
= cppstring
.c_str();
318 osprintf(os
, " inline ~%s();\n", cppname
);
321 /* Print declaration of pointer functions for class "clazz" to "os".
323 * To obtain a raw pointer three functions are provided:
325 * 1) __isl_give isl_set *copy()
327 * Returns a pointer to a _copy_ of the internal object
329 * 2) __isl_keep isl_set *get()
331 * Returns a pointer to the internal object
333 * 3) __isl_give isl_set *release()
335 * Returns a pointer to the internal object and resets the
336 * internal pointer to nullptr.
338 * We also provide functionality to explicitly check if a pointer is
339 * currently managed by this object.
343 * Check if the current object is a null pointer.
345 * The functions get() and release() model the value_ptr proposed in
346 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
347 * The copy() function is an extension to allow the user to explicitly
348 * copy the underlying object.
350 * Also generate a declaration to delete copy() for r-values, for
351 * r-values release() should be used to avoid unnecessary copies.
353 void cpp_generator::print_ptr_decl(ostream
&os
, const isl_class
&clazz
)
355 const char *name
= clazz
.name
.c_str();
357 osprintf(os
, " inline __isl_give %s *copy() const &;\n", name
);
358 osprintf(os
, " inline __isl_give %s *copy() && = delete;\n", name
);
359 osprintf(os
, " inline __isl_keep %s *get() const;\n", name
);
360 osprintf(os
, " inline __isl_give %s *release();\n", name
);
361 osprintf(os
, " inline bool is_null() const;\n");
364 /* Print the declaration of the get_ctx method.
366 void cpp_generator::print_get_ctx_decl(ostream
&os
)
368 osprintf(os
, " inline isl::ctx get_ctx() const;\n");
371 /* Print declarations for methods in class "clazz" to "os".
373 void cpp_generator::print_methods_decl(ostream
&os
, const isl_class
&clazz
)
375 map
<string
, set
<FunctionDecl
*> >::const_iterator it
;
377 for (it
= clazz
.methods
.begin(); it
!= clazz
.methods
.end(); ++it
)
378 print_method_group_decl(os
, clazz
, it
->first
, it
->second
);
381 /* Print declarations for methods "methods" of name "fullname" in class "clazz"
384 * "fullname" is the name of the generated C++ method. It commonly corresponds
385 * to the isl name, with the object type prefix dropped.
386 * In case of overloaded methods, the result type suffix has also been removed.
388 void cpp_generator::print_method_group_decl(ostream
&os
, const isl_class
&clazz
,
389 const string
&fullname
, const set
<FunctionDecl
*> &methods
)
391 set
<FunctionDecl
*>::const_iterator it
;
393 for (it
= methods
.begin(); it
!= methods
.end(); ++it
) {
394 function_kind kind
= get_method_kind(clazz
, *it
);
395 print_method_decl(os
, clazz
, fullname
, *it
, kind
);
399 /* Print declarations for "method" in class "clazz" to "os".
401 * "fullname" is the name of the generated C++ method. It commonly corresponds
402 * to the isl name, with the object type prefix dropped.
403 * In case of overloaded methods, the result type suffix has also been removed.
405 * "kind" specifies the kind of method that should be generated.
407 void cpp_generator::print_method_decl(ostream
&os
, const isl_class
&clazz
,
408 const string
&fullname
, FunctionDecl
*method
, function_kind kind
)
410 print_method_header(os
, clazz
, method
, fullname
, true, kind
);
413 /* Print implementations for class "clazz" to "os".
415 void cpp_generator::print_class_impl(ostream
&os
, const isl_class
&clazz
)
417 std::string cppstring
= type2cpp(clazz
);
418 const char *cppname
= cppstring
.c_str();
420 osprintf(os
, "// implementations for isl::%s\n", cppname
);
422 print_class_factory_impl(os
, clazz
);
424 print_public_constructors_impl(os
, clazz
);
426 print_private_constructors_impl(os
, clazz
);
428 print_constructors_impl(os
, clazz
);
430 print_copy_assignment_impl(os
, clazz
);
432 print_destructor_impl(os
, clazz
);
434 print_ptr_impl(os
, clazz
);
436 print_get_ctx_impl(os
, clazz
);
438 print_methods_impl(os
, clazz
);
441 /* Print implementation of global factory function to "os".
443 void cpp_generator::print_class_factory_impl(ostream
&os
,
444 const isl_class
&clazz
)
446 const char *name
= clazz
.name
.c_str();
447 std::string cppstring
= type2cpp(clazz
);
448 const char *cppname
= cppstring
.c_str();
450 osprintf(os
, "isl::%s manage(__isl_take %s *ptr) {\n", cppname
, name
);
451 osprintf(os
, " return %s(ptr);\n", cppname
);
454 osprintf(os
, "isl::%s manage_copy(__isl_keep %s *ptr) {\n", cppname
,
456 osprintf(os
, " return %s(%s_copy(ptr));\n", cppname
, name
);
460 /* Print implementations of private constructors for class "clazz" to "os".
462 void cpp_generator::print_private_constructors_impl(ostream
&os
,
463 const isl_class
&clazz
)
465 const char *name
= clazz
.name
.c_str();
466 std::string cppstring
= type2cpp(clazz
);
467 const char *cppname
= cppstring
.c_str();
469 osprintf(os
, "%s::%s(__isl_take %s *ptr)\n : ptr(ptr) {}\n",
470 cppname
, cppname
, name
);
473 /* Print implementations of public constructors for class "clazz" to "os".
475 void cpp_generator::print_public_constructors_impl(ostream
&os
,
476 const isl_class
&clazz
)
478 const char *name
= clazz
.name
.c_str();
479 std::string cppstring
= type2cpp(clazz
);
480 const char *cppname
= cppstring
.c_str();
482 osprintf(os
, "%s::%s()\n : ptr(nullptr) {}\n\n", cppname
, cppname
);
483 osprintf(os
, "%s::%s(const isl::%s &obj)\n : ptr(obj.copy()) {}\n",
484 cppname
, cppname
, cppname
, name
);
487 /* Print implementations of constructors for class "clazz" to "os".
489 void cpp_generator::print_constructors_impl(ostream
&os
,
490 const isl_class
&clazz
)
492 set
<FunctionDecl
*>::const_iterator in
;
493 const set
<FunctionDecl
*> constructors
= clazz
.constructors
;
495 for (in
= constructors
.begin(); in
!= constructors
.end(); ++in
) {
496 FunctionDecl
*cons
= *in
;
497 string fullname
= cons
->getName();
498 function_kind kind
= function_kind_constructor
;
500 print_method_impl(os
, clazz
, fullname
, cons
, kind
);
504 /* Print implementation of copy assignment operator for class "clazz" to "os".
506 void cpp_generator::print_copy_assignment_impl(ostream
&os
,
507 const isl_class
&clazz
)
509 const char *name
= clazz
.name
.c_str();
510 std::string cppstring
= type2cpp(clazz
);
511 const char *cppname
= cppstring
.c_str();
513 osprintf(os
, "%s &%s::operator=(isl::%s obj) {\n", cppname
,
515 osprintf(os
, " std::swap(this->ptr, obj.ptr);\n", name
);
516 osprintf(os
, " return *this;\n");
520 /* Print implementation of destructor for class "clazz" to "os".
522 void cpp_generator::print_destructor_impl(ostream
&os
,
523 const isl_class
&clazz
)
525 const char *name
= clazz
.name
.c_str();
526 std::string cppstring
= type2cpp(clazz
);
527 const char *cppname
= cppstring
.c_str();
529 osprintf(os
, "%s::~%s() {\n", cppname
, cppname
);
530 osprintf(os
, " if (ptr)\n");
531 osprintf(os
, " %s_free(ptr);\n", name
);
535 /* Print implementation of ptr() functions for class "clazz" to "os".
537 void cpp_generator::print_ptr_impl(ostream
&os
, const isl_class
&clazz
)
539 const char *name
= clazz
.name
.c_str();
540 std::string cppstring
= type2cpp(clazz
);
541 const char *cppname
= cppstring
.c_str();
543 osprintf(os
, "__isl_give %s *%s::copy() const & {\n", name
, cppname
);
544 osprintf(os
, " return %s_copy(ptr);\n", name
);
545 osprintf(os
, "}\n\n");
546 osprintf(os
, "__isl_keep %s *%s::get() const {\n", name
, cppname
);
547 osprintf(os
, " return ptr;\n");
548 osprintf(os
, "}\n\n");
549 osprintf(os
, "__isl_give %s *%s::release() {\n", name
, cppname
);
550 osprintf(os
, " %s *tmp = ptr;\n", name
);
551 osprintf(os
, " ptr = nullptr;\n");
552 osprintf(os
, " return tmp;\n");
553 osprintf(os
, "}\n\n");
554 osprintf(os
, "bool %s::is_null() const {\n", cppname
);
555 osprintf(os
, " return ptr == nullptr;\n");
559 /* Print the implementation of the get_ctx method.
561 void cpp_generator::print_get_ctx_impl(ostream
&os
, const isl_class
&clazz
)
563 const char *name
= clazz
.name
.c_str();
564 std::string cppstring
= type2cpp(clazz
);
565 const char *cppname
= cppstring
.c_str();
567 osprintf(os
, "isl::ctx %s::get_ctx() const {\n", cppname
);
568 osprintf(os
, " return isl::ctx(%s_get_ctx(ptr));\n", name
);
572 /* Print definitions for methods of class "clazz" to "os".
574 void cpp_generator::print_methods_impl(ostream
&os
, const isl_class
&clazz
)
576 map
<string
, set
<FunctionDecl
*> >::const_iterator it
;
579 for (it
= clazz
.methods
.begin(); it
!= clazz
.methods
.end(); ++it
) {
584 print_method_group_impl(os
, clazz
, it
->first
, it
->second
);
588 /* Print definitions for methods "methods" of name "fullname" in class "clazz"
591 * "fullname" is the name of the generated C++ method. It commonly corresponds
592 * to the isl name, with the object type prefix dropped.
593 * In case of overloaded methods, the result type suffix has also been removed.
595 * "kind" specifies the kind of method that should be generated.
597 void cpp_generator::print_method_group_impl(ostream
&os
, const isl_class
&clazz
,
598 const string
&fullname
, const set
<FunctionDecl
*> &methods
)
600 set
<FunctionDecl
*>::const_iterator it
;
603 for (it
= methods
.begin(); it
!= methods
.end(); ++it
) {
609 kind
= get_method_kind(clazz
, *it
);
610 print_method_impl(os
, clazz
, fullname
, *it
, kind
);
614 /* Print the use of "param" to "os".
616 * "load_from_this_ptr" specifies whether the parameter should be loaded from
617 * the this-ptr. In case a value is loaded from a this pointer, the original
618 * value must be preserved and must consequently be copied. Values that are
619 * loaded from parameters do not need to be preserved, as such values will
620 * already be copies of the actual parameters. It is consequently possible
621 * to directly take the pointer from these values, which saves
622 * an unnecessary copy.
624 * In case the parameter is a callback function, two parameters get printed,
625 * a wrapper for the callback function and a pointer to the actual
626 * callback function. The wrapper is expected to be available
627 * in a previously declared variable <name>_lambda, while
628 * the actual callback function is expected in <name>_p.
629 * The caller of this function must ensure that these variables exist.
631 void cpp_generator::print_method_param_use(ostream
&os
, ParmVarDecl
*param
,
632 bool load_from_this_ptr
)
634 string name
= param
->getName().str();
635 const char *name_str
= name
.c_str();
636 QualType type
= param
->getOriginalType();
638 if (type
->isIntegerType()) {
639 osprintf(os
, "%s", name_str
);
643 if (is_string(type
)) {
644 osprintf(os
, "%s.c_str()", name_str
);
648 if (is_callback(type
)) {
649 osprintf(os
, "%s_lambda, ", name_str
);
650 osprintf(os
, "&%s_p", name_str
);
654 if (!load_from_this_ptr
&& !is_callback(type
))
655 osprintf(os
, "%s.", name_str
);
658 osprintf(os
, "get()");
660 if (load_from_this_ptr
)
661 osprintf(os
, "copy()");
663 osprintf(os
, "release()");
667 /* Print definition for "method" in class "clazz" to "os".
669 * "fullname" is the name of the generated C++ method. It commonly corresponds
670 * to the isl name, with the object type prefix dropped.
671 * In case of overloaded methods, the result type suffix has also been removed.
673 * "kind" specifies the kind of method that should be generated.
675 * This method distinguishes three kinds of methods: member methods, static
676 * methods, and constructors.
678 * Member methods call "method" by passing to the underlying isl function the
679 * isl object belonging to "this" as first argument and the remaining arguments
680 * as subsequent arguments. The result of the isl function is returned as a new
681 * object if the underlying isl function returns an isl_* ptr or an isl_bool
682 * value, as std::string if the isl function returns 'const char *', and as
683 * unmodified return value otherwise.
685 * Static methods call "method" by passing all arguments to the underlying isl
686 * function, as no this-pointer is available. The result is a newly managed
689 * Constructors create a new object from a given set of input parameters. They
690 * do not return a value, but instead update the pointer stored inside the
691 * newly created object.
693 * If the method has a callback argument, we reduce the number of parameters
694 * that are exposed by one to hide the user pointer from the interface. On
695 * the C++ side no user pointer is needed, as arguments can be forwarded
696 * as part of the std::function argument which specifies the callback function.
698 void cpp_generator::print_method_impl(ostream
&os
, const isl_class
&clazz
,
699 const string
&fullname
, FunctionDecl
*method
, function_kind kind
)
701 string cname
= fullname
.substr(clazz
.name
.length() + 1);
702 string methodname
= method
->getName();
703 int num_params
= method
->getNumParams();
704 QualType return_type
= method
->getReturnType();
705 string rettype_str
= type2cpp(return_type
);
706 bool has_callback
= false;
708 print_method_header(os
, clazz
, method
, fullname
, false, kind
);
710 for (int i
= 0; i
< num_params
; ++i
) {
711 ParmVarDecl
*param
= method
->getParamDecl(i
);
712 if (is_callback(param
->getType())) {
715 print_callback_local(os
, param
);
719 osprintf(os
, " auto res = %s(", methodname
.c_str());
721 for (int i
= 0; i
< num_params
; ++i
) {
722 ParmVarDecl
*param
= method
->getParamDecl(i
);
723 bool load_from_this_ptr
= false;
725 if (i
== 0 && kind
== function_kind_member_method
)
726 load_from_this_ptr
= true;
728 print_method_param_use(os
, param
, load_from_this_ptr
);
730 if (i
!= num_params
- 1)
733 osprintf(os
, ");\n");
735 if (kind
== function_kind_constructor
) {
736 osprintf(os
, " ptr = res;\n");
737 } else if (is_isl_type(return_type
) || is_isl_bool(return_type
)) {
738 osprintf(os
, " return manage(res);\n");
739 } else if (has_callback
) {
740 osprintf(os
, " return %s(res);\n", rettype_str
.c_str());
741 } else if (is_string(return_type
)) {
742 osprintf(os
, " std::string tmp(res);\n");
744 osprintf(os
, " free(res);\n");
745 osprintf(os
, " return tmp;\n");
747 osprintf(os
, " return res;\n");
753 /* Print the header for "method" in class "clazz" to "os".
755 * Print the header of a declaration if "is_declaration" is set, otherwise print
756 * the header of a method definition.
758 * "fullname" is the name of the generated C++ method. It commonly corresponds
759 * to the isl name, with the object type prefix dropped.
760 * In case of overloaded methods, the result type suffix has also been removed.
762 * "kind" specifies the kind of method that should be generated.
764 * This function prints headers for member methods, static methods, and
765 * constructors, either for their declaration or definition.
767 * Member functions are declared as "const", as they do not change the current
768 * object, but instead create a new object. They always retrieve the first
769 * parameter of the original isl function from the this-pointer of the object,
770 * such that only starting at the second parameter the parameters of the
771 * original function become part of the method's interface.
775 * __isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1,
776 * __isl_take isl_set *s2);
778 * is translated into:
780 * inline isl::set intersect(isl::set set2) const;
782 * For static functions and constructors all parameters of the original isl
783 * function are exposed.
785 * Parameters that are defined as __isl_keep or are of type string, are passed
786 * as const reference, which allows the compiler to optimize the parameter
789 * Constructors are marked as explicit using the C++ keyword 'explicit' or as
790 * implicit using a comment in place of the explicit keyword. By annotating
791 * implicit constructors with a comment, users of the interface are made
792 * aware of the potential danger that implicit construction is possible
793 * for these constructors, whereas without a comment not every user would
794 * know that implicit construction is allowed in absence of an explicit keyword.
796 void cpp_generator::print_method_header(ostream
&os
, const isl_class
&clazz
,
797 FunctionDecl
*method
, const string
&fullname
, bool is_declaration
,
800 string cname
= fullname
.substr(clazz
.name
.length() + 1);
801 string rettype_str
= type2cpp(method
->getReturnType());
802 string classname
= type2cpp(clazz
);
803 int num_params
= method
->getNumParams();
806 cname
= rename_method(cname
);
807 if (kind
== function_kind_member_method
)
810 if (is_declaration
) {
813 if (kind
== function_kind_static_method
)
814 osprintf(os
, "static ");
816 osprintf(os
, "inline ");
818 if (kind
== function_kind_constructor
) {
819 if (is_implicit_conversion(clazz
, method
))
820 osprintf(os
, "/* implicit */ ");
822 osprintf(os
, "explicit ");
826 if (kind
!= function_kind_constructor
)
827 osprintf(os
, "%s ", rettype_str
.c_str());
830 osprintf(os
, "%s::", classname
.c_str());
832 if (kind
!= function_kind_constructor
)
833 osprintf(os
, "%s", cname
.c_str());
835 osprintf(os
, "%s", classname
.c_str());
839 for (int i
= first_param
; i
< num_params
; ++i
) {
840 ParmVarDecl
*param
= method
->getParamDecl(i
);
841 QualType type
= param
->getOriginalType();
842 string cpptype
= type2cpp(type
);
844 if (is_callback(type
))
847 if (keeps(param
) || is_string(type
) || is_callback(type
))
848 osprintf(os
, "const %s &%s", cpptype
.c_str(),
849 param
->getName().str().c_str());
851 osprintf(os
, "%s %s", cpptype
.c_str(),
852 param
->getName().str().c_str());
854 if (i
!= num_params
- 1)
860 if (kind
== function_kind_member_method
)
861 osprintf(os
, " const");
866 osprintf(os
, " {\n");
869 /* Generate the list of argument types for a callback function of
870 * type "type". If "cpp" is set, then generate the C++ type list, otherwise
873 * For a callback of type
875 * isl_stat (*)(__isl_take isl_map *map, void *user)
877 * the following C++ argument list is generated:
881 string
cpp_generator::generate_callback_args(QualType type
, bool cpp
)
883 std::string type_str
;
884 const FunctionProtoType
*callback
;
887 callback
= type
->getPointeeType()->getAs
<FunctionProtoType
>();
888 num_params
= callback
->getNumArgs();
892 for (long i
= 0; i
< num_params
; i
++) {
893 QualType type
= callback
->getArgType(i
);
896 type_str
+= type2cpp(type
);
898 type_str
+= type
.getAsString();
901 type_str
+= "arg_" + ::to_string(i
);
903 if (i
!= num_params
- 1)
910 /* Generate the full cpp type of a callback function of type "type".
912 * For a callback of type
914 * isl_stat (*)(__isl_take isl_map *map, void *user)
916 * the following type is generated:
918 * std::function<isl::stat(isl::map)>
920 string
cpp_generator::generate_callback_type(QualType type
)
922 std::string type_str
;
923 const FunctionProtoType
*callback
= type
->getPointeeType()->getAs
<FunctionProtoType
>();
924 QualType return_type
= callback
->getReturnType();
925 string rettype_str
= type2cpp(return_type
);
927 type_str
= "std::function<";
928 type_str
+= rettype_str
;
930 type_str
+= generate_callback_args(type
, true);
936 /* Print the local variables that are needed for a callback argument,
937 * in particular, print a lambda function that wraps the callback and
938 * a pointer to the actual C++ callback function.
940 * For a callback of the form
942 * isl_stat (*fn)(__isl_take isl_map *map, void *user)
944 * the following lambda function is generated:
946 * auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
947 * auto *func = *static_cast<const std::function<stat(map)> **>(arg_1);
948 * stat ret = (*func)(isl::manage(arg_0));
949 * return isl_stat(ret);
952 * The pointer to the std::function C++ callback function is stored in fn_p.
953 * This std::function object represents the actual user
954 * callback function together with the locally captured state at the caller.
956 * The lambda function is expected to be used as a C callback function
957 * where the lambda itself is provided as the function pointer and
958 * where the user void pointer is a pointer to fn_p.
959 * The std::function object is extracted from the pointer to fn_p
960 * inside the lambda function.
961 * The double indirection is used to avoid having to worry about
964 void cpp_generator::print_callback_local(ostream
&os
, ParmVarDecl
*param
)
968 string call_args
, c_args
, cpp_args
, rettype
, last_idx
;
969 const FunctionProtoType
*callback
;
972 pname
= param
->getName().str();
973 ptype
= param
->getType();
975 c_args
= generate_callback_args(ptype
, false);
976 cpp_args
= generate_callback_type(ptype
);
978 callback
= ptype
->getPointeeType()->getAs
<FunctionProtoType
>();
979 rettype
= callback
->getReturnType().getAsString();
980 num_params
= callback
->getNumArgs();
982 last_idx
= ::to_string(num_params
- 1);
984 for (long i
= 0; i
< num_params
- 1; i
++) {
985 call_args
+= "isl::manage(arg_" + ::to_string(i
) + ")";
986 if (i
!= num_params
- 2)
990 osprintf(os
, " auto %s_p = &%s;\n", pname
.c_str(), pname
.c_str());
992 " auto %s_lambda = [](%s) -> %s {\n"
993 " auto *func = *static_cast<const %s **>(arg_%s);\n"
994 " stat ret = (*func)(%s);\n"
995 " return isl_stat(ret);\n"
997 pname
.c_str(), c_args
.c_str(), rettype
.c_str(),
998 cpp_args
.c_str(), last_idx
.c_str(), call_args
.c_str());
1001 /* An array listing functions that must be renamed and the function name they
1002 * should be renamed to. We currently rename functions in case their name would
1003 * match a reserved C++ keyword, which is not allowed in C++.
1005 static const char *rename_map
[][2] = {
1006 { "union", "unite" },
1009 /* Rename method "name" in case the method name in the C++ bindings should not
1010 * match the name in the C bindings. We do this for example to avoid
1013 std::string
cpp_generator::rename_method(std::string name
)
1015 for (size_t i
= 0; i
< sizeof(rename_map
) / sizeof(rename_map
[0]); i
++)
1016 if (name
.compare(rename_map
[i
][0]) == 0)
1017 return rename_map
[i
][1];
1022 /* Translate isl class "clazz" to its corresponding C++ type.
1024 string
cpp_generator::type2cpp(const isl_class
&clazz
)
1026 return type2cpp(clazz
.name
);
1029 /* Translate type string "type_str" to its C++ name counterpart.
1031 string
cpp_generator::type2cpp(string type_str
)
1033 return type_str
.substr(4);
1036 /* Translate QualType "type" to its C++ name counterpart.
1038 string
cpp_generator::type2cpp(QualType type
)
1040 if (is_isl_type(type
))
1041 return "isl::" + type2cpp(type
->getPointeeType().getAsString());
1043 if (is_isl_bool(type
))
1044 return "isl::boolean";
1046 if (is_isl_stat(type
))
1049 if (type
->isIntegerType())
1050 return type
.getAsString();
1052 if (is_string(type
))
1053 return "std::string";
1055 if (is_callback(type
))
1056 return generate_callback_type(type
);
1058 die("Cannot convert type to C++ type");
1061 /* Check if "subclass_type" is a subclass of "class_type".
1063 bool cpp_generator::is_subclass(QualType subclass_type
,
1064 const isl_class
&class_type
)
1066 std::string type_str
= subclass_type
->getPointeeType().getAsString();
1067 std::vector
<std::string
> superclasses
;
1068 std::vector
<const isl_class
*> parents
;
1069 std::vector
<std::string
>::iterator ci
;
1071 superclasses
= generator::find_superclasses(classes
[type_str
].type
);
1073 for (ci
= superclasses
.begin(); ci
< superclasses
.end(); ci
++)
1074 parents
.push_back(&classes
[*ci
]);
1076 while (!parents
.empty()) {
1077 const isl_class
*candidate
= parents
.back();
1081 if (&class_type
== candidate
)
1084 superclasses
= generator::find_superclasses(candidate
->type
);
1086 for (ci
= superclasses
.begin(); ci
< superclasses
.end(); ci
++)
1087 parents
.push_back(&classes
[*ci
]);
1093 /* Check if "cons" is an implicit conversion constructor of class "clazz".
1095 * An implicit conversion constructor is generated in case "cons" has a single
1096 * parameter, where the parameter type is a subclass of the class that is
1097 * currently being generated.
1099 bool cpp_generator::is_implicit_conversion(const isl_class
&clazz
,
1102 ParmVarDecl
*param
= cons
->getParamDecl(0);
1103 QualType type
= param
->getOriginalType();
1105 int num_params
= cons
->getNumParams();
1106 if (num_params
!= 1)
1109 if (is_isl_type(type
) && !is_isl_ctx(type
) && is_subclass(type
, clazz
))
1115 /* Get kind of "method" in "clazz".
1117 * Given the declaration of a static or member method, returns its kind.
1119 cpp_generator::function_kind
cpp_generator::get_method_kind(
1120 const isl_class
&clazz
, FunctionDecl
*method
)
1122 if (is_static(clazz
, method
))
1123 return function_kind_static_method
;
1125 return function_kind_member_method
;