cpp: generate C++ wrapper classes
[isl.git] / interface / cpp.cc
blobea0f7f9d9ae9f67e132356f759b9b090b23a9c8f
1 /*
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
6 * are met:
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
31 * Tobias Grosser.
34 #include <cstdarg>
35 #include <cstdio>
36 #include <iostream>
37 #include <map>
38 #include <vector>
40 #include "cpp.h"
41 #include "isl_config.h"
43 /* Print string formatted according to "fmt" to ostream "os".
45 * This osprintf method allows us to use printf style formatting constructs when
46 * writing to an ostream.
48 static void osprintf(ostream &os, const char *format, ...)
50 va_list arguments;
51 FILE *string_stream;
52 char *string_pointer;
53 size_t size;
55 va_start(arguments, format);
57 string_stream = open_memstream(&string_pointer, &size);
59 if (!string_stream) {
60 fprintf(stderr, "open_memstream failed -- aborting!\n");
61 exit(1);
64 vfprintf(string_stream, format, arguments);
65 fclose(string_stream);
66 os << string_pointer;
67 free(string_pointer);
70 /* Generate a cpp interface based on the extracted types and functions.
72 * Print first a set of forward declarations for all isl wrapper
73 * classes, then the declarations of the classes, and at the end all
74 * implementations.
76 void cpp_generator::generate()
78 ostream &os = cout;
80 osprintf(os, "\n");
81 osprintf(os, "namespace isl {\n\n");
82 osprintf(os, "inline namespace noexceptions {\n\n");
84 print_forward_declarations(os);
85 osprintf(os, "\n");
86 print_declarations(os);
87 osprintf(os, "\n");
88 print_implementations(os);
90 osprintf(os, "} // namespace noexceptions\n");
91 osprintf(os, "} // namespace isl\n\n");
92 osprintf(os, "#endif /* ISL_CPP_NOEXCEPTIONS */\n");
95 /* Print forward declarations for all classes to "os".
97 void cpp_generator::print_forward_declarations(ostream &os)
99 map<string, isl_class>::iterator ci;
101 osprintf(os, "// forward declarations\n");
103 for (ci = classes.begin(); ci != classes.end(); ++ci)
104 print_class_forward_decl(os, ci->second);
107 /* Print all declarations to "os".
109 void cpp_generator::print_declarations(ostream &os)
111 map<string, isl_class>::iterator ci;
112 bool first = true;
114 for (ci = classes.begin(); ci != classes.end(); ++ci) {
115 if (first)
116 first = false;
117 else
118 osprintf(os, "\n");
120 print_class(os, ci->second);
124 /* Print all implementations to "os".
126 void cpp_generator::print_implementations(ostream &os)
128 map<string, isl_class>::iterator ci;
129 bool first = true;
131 for (ci = classes.begin(); ci != classes.end(); ++ci) {
132 if (first)
133 first = false;
134 else
135 osprintf(os, "\n");
137 print_class_impl(os, ci->second);
141 /* Print declarations for class "clazz" to "os".
143 void cpp_generator::print_class(ostream &os, const isl_class &clazz)
145 const char *name = clazz.name.c_str();
146 std::string cppstring = type2cpp(clazz);
147 const char *cppname = cppstring.c_str();
149 osprintf(os, "// declarations for isl::%s\n", cppname);
151 print_class_factory_decl(os, clazz);
152 osprintf(os, "\n");
153 osprintf(os, "class %s {\n", cppname);
154 osprintf(os, " friend ");
155 print_class_factory_decl(os, clazz);
156 osprintf(os, "\n");
157 osprintf(os, " %s *ptr = nullptr;\n", name);
158 osprintf(os, "\n");
159 print_private_constructors_decl(os, clazz);
160 osprintf(os, "\n");
161 osprintf(os, "public:\n");
162 print_public_constructors_decl(os, clazz);
163 print_copy_assignment_decl(os, clazz);
164 print_destructor_decl(os, clazz);
165 print_ptr_decl(os, clazz);
167 osprintf(os, "};\n");
170 /* Print forward declaration of class "clazz" to "os".
172 void cpp_generator::print_class_forward_decl(ostream &os,
173 const isl_class &clazz)
175 std::string cppstring = type2cpp(clazz);
176 const char *cppname = cppstring.c_str();
178 osprintf(os, "class %s;\n", cppname);
181 /* Print global factory function to "os".
183 * Each class has one global factory function:
185 * isl::set manage(__isl_take isl_set *ptr);
187 * The only public way to construct isl C++ objects from a raw pointer is
188 * through this global factory function. This ensures isl object creation
189 * is very explicit and pointers are not converted by accident. Due to
190 * overloading, manage() can be called on any isl raw pointer and the
191 * corresponding object is automatically created, without the user having
192 * to choose the right isl object type.
194 void cpp_generator::print_class_factory_decl(ostream &os,
195 const isl_class &clazz)
197 const char *name = clazz.name.c_str();
198 std::string cppstring = type2cpp(clazz);
199 const char *cppname = cppstring.c_str();
201 osprintf(os, "inline isl::%s manage(__isl_take %s *ptr);\n", cppname,
202 name);
205 /* Print declarations of private constructors for class "clazz" to "os".
207 * Each class has currently one private constructor:
209 * 1) Constructor from a plain isl_* C pointer
211 * Example:
213 * set(__isl_take isl_set *ptr);
215 * The raw pointer constructor is kept private. Object creation is only
216 * possible through isl::manage().
218 void cpp_generator::print_private_constructors_decl(ostream &os,
219 const isl_class &clazz)
221 const char *name = clazz.name.c_str();
222 std::string cppstring = type2cpp(clazz);
223 const char *cppname = cppstring.c_str();
225 osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname,
226 name);
229 /* Print declarations of public constructors for class "clazz" to "os".
231 * Each class currently has two public constructors:
233 * 1) A default constructor
234 * 2) A copy constructor
236 * Example:
238 * set();
239 * set(const isl::set &set);
241 void cpp_generator::print_public_constructors_decl(ostream &os,
242 const isl_class &clazz)
244 std::string cppstring = type2cpp(clazz);
245 const char *cppname = cppstring.c_str();
246 osprintf(os, " inline /* implicit */ %s();\n", cppname);
248 osprintf(os, " inline /* implicit */ %s(const isl::%s &obj);\n",
249 cppname, cppname);
252 /* Print declarations of copy assignment operator for class "clazz"
253 * to "os".
255 * Each class has one assignment operator.
257 * isl:set &set::operator=(isl::set obj)
260 void cpp_generator::print_copy_assignment_decl(ostream &os,
261 const isl_class &clazz)
263 std::string cppstring = type2cpp(clazz);
264 const char *cppname = cppstring.c_str();
266 osprintf(os, " inline isl::%s &operator=(isl::%s obj);\n", cppname,
267 cppname);
270 /* Print declaration of destructor for class "clazz" to "os".
272 void cpp_generator::print_destructor_decl(ostream &os, const isl_class &clazz)
274 std::string cppstring = type2cpp(clazz);
275 const char *cppname = cppstring.c_str();
277 osprintf(os, " inline ~%s();\n", cppname);
280 /* Print declaration of pointer functions for class "clazz" to "os".
282 * To obtain a raw pointer three functions are provided:
284 * 1) __isl_give isl_set *copy()
286 * Returns a pointer to a _copy_ of the internal object
288 * 2) __isl_keep isl_set *get()
290 * Returns a pointer to the internal object
292 * 3) __isl_give isl_set *release()
294 * Returns a pointer to the internal object and resets the
295 * internal pointer to nullptr.
297 * We also provide functionality to explicitly check if a pointer is
298 * currently managed by this object.
300 * 4) bool is_null()
302 * Check if the current object is a null pointer.
304 * The functions get() and release() model the value_ptr proposed in
305 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
306 * The copy() function is an extension to allow the user to explicitly
307 * copy the underlying object.
309 * Also generate a declaration to delete copy() for r-values, for
310 * r-values release() should be used to avoid unnecessary copies.
312 void cpp_generator::print_ptr_decl(ostream &os, const isl_class &clazz)
314 const char *name = clazz.name.c_str();
316 osprintf(os, " inline __isl_give %s *copy() const &;\n", name);
317 osprintf(os, " inline __isl_give %s *copy() && = delete;\n", name);
318 osprintf(os, " inline __isl_keep %s *get() const;\n", name);
319 osprintf(os, " inline __isl_give %s *release();\n", name);
320 osprintf(os, " inline bool is_null() const;\n");
323 /* Print implementations for class "clazz" to "os".
325 void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
327 std::string cppstring = type2cpp(clazz);
328 const char *cppname = cppstring.c_str();
330 osprintf(os, "// implementations for isl::%s\n", cppname);
332 print_class_factory_impl(os, clazz);
333 osprintf(os, "\n");
334 print_public_constructors_impl(os, clazz);
335 osprintf(os, "\n");
336 print_private_constructors_impl(os, clazz);
337 osprintf(os, "\n");
338 print_copy_assignment_impl(os, clazz);
339 osprintf(os, "\n");
340 print_destructor_impl(os, clazz);
341 osprintf(os, "\n");
342 print_ptr_impl(os, clazz);
345 /* Print implementation of global factory function to "os".
347 void cpp_generator::print_class_factory_impl(ostream &os,
348 const isl_class &clazz)
350 const char *name = clazz.name.c_str();
351 std::string cppstring = type2cpp(clazz);
352 const char *cppname = cppstring.c_str();
354 osprintf(os, "isl::%s manage(__isl_take %s *ptr) {\n", cppname, name);
355 osprintf(os, " return %s(ptr);\n", cppname);
356 osprintf(os, "}\n");
359 /* Print implementations of private constructors for class "clazz" to "os".
361 void cpp_generator::print_private_constructors_impl(ostream &os,
362 const isl_class &clazz)
364 const char *name = clazz.name.c_str();
365 std::string cppstring = type2cpp(clazz);
366 const char *cppname = cppstring.c_str();
368 osprintf(os, "%s::%s(__isl_take %s *ptr)\n : ptr(ptr) {}\n",
369 cppname, cppname, name);
372 /* Print implementations of public constructors for class "clazz" to "os".
374 void cpp_generator::print_public_constructors_impl(ostream &os,
375 const isl_class &clazz)
377 const char *name = clazz.name.c_str();
378 std::string cppstring = type2cpp(clazz);
379 const char *cppname = cppstring.c_str();
381 osprintf(os, "%s::%s()\n : ptr(nullptr) {}\n\n", cppname, cppname);
382 osprintf(os, "%s::%s(const isl::%s &obj)\n : ptr(obj.copy()) {}\n",
383 cppname, cppname, cppname, name);
386 /* Print implementation of copy assignment operator for class "clazz" to "os".
388 void cpp_generator::print_copy_assignment_impl(ostream &os,
389 const isl_class &clazz)
391 const char *name = clazz.name.c_str();
392 std::string cppstring = type2cpp(clazz);
393 const char *cppname = cppstring.c_str();
395 osprintf(os, "%s &%s::operator=(isl::%s obj) {\n", cppname,
396 cppname, cppname);
397 osprintf(os, " std::swap(this->ptr, obj.ptr);\n", name);
398 osprintf(os, " return *this;\n");
399 osprintf(os, "}\n");
402 /* Print implementation of destructor for class "clazz" to "os".
404 void cpp_generator::print_destructor_impl(ostream &os,
405 const isl_class &clazz)
407 const char *name = clazz.name.c_str();
408 std::string cppstring = type2cpp(clazz);
409 const char *cppname = cppstring.c_str();
411 osprintf(os, "%s::~%s() {\n", cppname, cppname);
412 osprintf(os, " if (ptr)\n");
413 osprintf(os, " %s_free(ptr);\n", name);
414 osprintf(os, "}\n");
417 /* Print implementation of ptr() functions for class "clazz" to "os".
419 void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz)
421 const char *name = clazz.name.c_str();
422 std::string cppstring = type2cpp(clazz);
423 const char *cppname = cppstring.c_str();
425 osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
426 osprintf(os, " return %s_copy(ptr);\n", name);
427 osprintf(os, "}\n\n");
428 osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
429 osprintf(os, " return ptr;\n");
430 osprintf(os, "}\n\n");
431 osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
432 osprintf(os, " %s *tmp = ptr;\n", name);
433 osprintf(os, " ptr = nullptr;\n");
434 osprintf(os, " return tmp;\n");
435 osprintf(os, "}\n\n");
436 osprintf(os, "bool %s::is_null() const {\n", cppname);
437 osprintf(os, " return ptr == nullptr;\n");
438 osprintf(os, "}\n");
441 /* Translate isl class "clazz" to its corresponding C++ type.
443 string cpp_generator::type2cpp(const isl_class &clazz)
445 return type2cpp(clazz.name);
448 /* Translate type string "type_str" to its C++ name counterpart.
450 string cpp_generator::type2cpp(string type_str)
452 return type_str.substr(4);