cpp: generate C++ wrapper classes
commit81c38ef4ce0517aa355e2c1ca74097be39ecaec1
authorTobias Grosser <tobias@grosser.es>
Sat, 8 Apr 2017 03:12:50 +0000 (8 05:12 +0200)
committerSven Verdoolaege <skimo@kotnet.org>
Thu, 27 Apr 2017 11:55:32 +0000 (27 13:55 +0200)
tree49008e380d5ec08c2ea66b2a7a5b211fd002cce0
parent1d3f5a08069b8d0da8ea840aa72068c0216a9495
cpp: generate C++ wrapper classes

The generator creates for each exported isl object a smart pointer class
of the following form:

      class set;
      inline isl::set manage(__isl_take isl_set *set);

      class set {
        friend inline isl::set manage(__isl_take isl_set *set);

        isl_set *ptr = nullptr;

        inline explicit set(__isl_take isl_set *ptr);

      public:
        inline set();
        inline set(const isl::set &obj);
        inline set& operator=(isl::set obj);
        inline ~set();
        inline __isl_give isl_set *copy() const &;
        inline __isl_give isl_set *copy() && = delete;
        inline __isl_keep isl_set *get() const;
        inline __isl_give isl_set *release();
        inline bool is_null() const;
      };

The interface implements a smart pointer that applies value semantics to
its pointee and is inspired by the value_ptr proposed in
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
The isl smart pointer keeps unique ownership of an object. The currently
held pointer can be observed by calling get(). When calling release(),
both the current pointer is returned and ownership is released. Names
and semantics of get() and release() match the corresponding methods in
value_ptr. In addition, a copy() method is provided, which returns a
pointer to a copy of the managed object. These three methods allow the
isl C++ objects to be used together with the isl C functions. On top of
this an is_null method is provided to check if the object is currently
not holding any reference.

Example:

     void foo(Set S) {
         isl_set_is_universe(S.get());
         isl_set_free(S.copy());
         isl_set_free(S.release());
     }

The r-value version of the copy() function is not needed as copying an
object that will be freed right after is inefficient. In such a
situation, the use of release() is more efficient as it avoids the
unnecessary object copy. By deleting the r-value version of copy this
change ensures that the user does not accidentally use the copy() in
situations where it is preferable to call release().

An alternative choice to name get() and release() would have been keep()
and take(). The name 'take' is for example used in llvm::OwningPtr. For
consistency with the value_ptr proposal and other smart pointers such as
std::unique_ptr, this alternative naming has not been chosen.

isl C++ objects can be constructed either by copying existing isl
objects of the same type or by passing an isl C pointer to a global
isl::manage(isl_type *ptr) method. Constructing an isl C++ object from
an isl C pointer using an explicit class constructor is not allowed.
This interface has been chosen in correspondence with std::make_unique.
Besides making object creation and especially pointer consumption
explicit, global methods also make specifying the needed object type
unnecessary. This change also allows default construction of null isl
objects, as default-constructability is important when using isl objects
in C++ containers and especially when exploiting C++ move semantics.
Null isl objects, are not backed up by any isl object, but correspond to
a nullptr in the C interface. To complete the "Big Three", this commit
also defines the copy assignment operator. The remaining two functions
needed to complete the "Big Five", move constructor and move assignment,
are not needed for an initial implementation and are left for future
work.

Example:

  void foo (__isl_take *s1, __isl_take *s2) {
    isl::set S1 = isl::manage(s1);
    auto S = isl::manage(s2);
    auto S2 = S1;
    isl::set ZeroSet;
  }

The currently generated library is header-only, which resembles the
already existing python bindings and is the best choice for a
lightweight interface library. In the future, implementations for
larger functions or debugging methods might require the addition
of implementations as part of a compiled (not-header-only) library.

The current library is generated in a single unified header file, which
matches the generated python bindings. In the future, this might evolve
to a combination of per-class header files and a unifying header file,
as there is interest in both. However, for an initial binding a unified
header has been chosen.

No class hierarchy is constructed, as there is currently no obvious
benefit and a hierarchy can always be introduced later. However,
most conversions are probably better implemented through implicit
constructors from related isl objects. Such constructors are added
in the next commit.

All functions are declared 'inline' to not cause link errors when
included in multiple translation units.

This change does not change error handling in case of nullptrs, but
passes nullptrs directly to isl, relying on isl's ability to
transparently forward them. Several people pointed out that C++ error
handling mechanisms such as exceptions would allow for more
C++ style error handling. However, without having actual users of
exceptions, it was agreed to not support error notifications through
exceptions. In case future use cases motivate exceptions, the
isl C++ error handling approach can be improved. To clarify that this
is a 'no-exception' namespace an inline namespace isl::noexceptions is
used. C++ inline namespaces allow to introduce additional name spaces
while at the same time making the definitions in these new namespaces
available in the outer namespaces. This allows for future additions of
isl bindings with exceptions without requiring the user to type
additional namespace qualifiers.

This change intentionally only introduces a minimalistic interface. The
interface established with this commit is already sufficient to manage
isl pointers. Polly today uses an isl C++ interface that has about the
same functionality as this commit and already the simplified memory
management has proven to facilitate software development a lot. The
infrastructure established with this commit will serve as basis for a
future function call interface that makes isl C functions conveniently
accessible through the C++ interface.

File IO is performed through ostream, as this makes it easy to split
the bindings into multiple files later on. However, this commit still
uses C style string formatting as this is more readable and closer to
the python binding generator. This approach is similar to the string
generation in Armin Groesslinger's SCALA bindings.

These bindings use lower_case::method_and_class_names to match the style
of the existing python bindings as well as the style of the isl code
base. An alternative would have been to use CamelCase, which is
recommended in many modern C++ style guides (e.g., the Google style
guide) and would match well with the styles used in LLVM and Polly, but
no agreement for CamelCase could be found. Hence, this commit stays with
lower_case.

The design of the proposed isl C++ smart pointer interface is the result
of discussions with Michael Kruse, Jakob Leben, and Alexandre Isoard. It
was inspired by earlier bindings developed by Michael, Jakob, and
Alexandre, but also the C++ bindings developed by Andreas Simbuerger,
the SCALA bindings from Armin Groesslinger, as well as islpy developed
by Andreas Kloeckner. The actual code generator has been newly
developed, but relies on three enabling patches from Armin Groesslinger,
which establish an infrastructure also used in Armin's and Andreas'
bindings. As a result, this commit also will make it easier to upstream
Armin's SCALA bindings and the similar structure of this new code
generator should make it easy to port changes from Andreas' C++
generator.

Signed-off-by: Tobias Grosser <tobias@grosser.es>
Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
interface/Makefile.am
interface/cpp.cc [new file with mode: 0644]
interface/cpp.h [new file with mode: 0644]
interface/extract_interface.cc
interface/isl.h.top [new file with mode: 0644]