From 9c5f5dd347c3a38f4272accf96a57ee6401b166d Mon Sep 17 00:00:00 2001 From: Oleksandr Zinenko Date: Tue, 5 Sep 2017 13:35:58 +0200 Subject: [PATCH 1/2] isl_id: utility functions for name-only identifiers Introduce utility functions for named identifiers: "isl_id_from_name" constructs an identifier given a name and "isl_id_has_name" checks whether an identifier has a name, i.e. whether its "name" field is not NULL. These functions allow for manipulating identifiers without user pointers. In particular, they will be used to hide user pointers from C++ and Python bindings. The "isl_id_has_name" function is necessary because NULL names cannot be expressed as strings in bindings. Signed-off-by: Oleksandr Zinenko --- doc/user.pod | 3 +++ include/isl/id.h | 3 +++ isl_id.c | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/doc/user.pod b/doc/user.pod index 1bb0da48..1bf6fa67 100644 --- a/doc/user.pod +++ b/doc/user.pod @@ -896,6 +896,8 @@ using the following functions. #include __isl_give isl_id *isl_id_alloc(isl_ctx *ctx, __isl_keep const char *name, void *user); + __isl_give isl_id *isl_id_from_name(isl_ctx *ctx, + __isl_keep const char *name); __isl_give isl_id *isl_id_set_free_user( __isl_take isl_id *id, void (*free_user)(void *user)); @@ -903,6 +905,7 @@ using the following functions. __isl_null isl_id *isl_id_free(__isl_take isl_id *id); void *isl_id_get_user(__isl_keep isl_id *id); + isl_bool isl_id_has_name(__isl_keep isl_id *id); __isl_keep const char *isl_id_get_name(__isl_keep isl_id *id); __isl_give isl_printer *isl_printer_print_id( diff --git a/include/isl/id.h b/include/isl/id.h index c025d513..36d4f396 100644 --- a/include/isl/id.h +++ b/include/isl/id.h @@ -20,11 +20,14 @@ uint32_t isl_id_get_hash(__isl_keep isl_id *id); __isl_give isl_id *isl_id_alloc(isl_ctx *ctx, __isl_keep const char *name, void *user); +__isl_give isl_id *isl_id_from_name(isl_ctx *ctx, + __isl_keep const char *name); __isl_give isl_id *isl_id_copy(isl_id *id); __isl_null isl_id *isl_id_free(__isl_take isl_id *id); void *isl_id_get_user(__isl_keep isl_id *id); __isl_keep const char *isl_id_get_name(__isl_keep isl_id *id); +isl_bool isl_id_has_name(__isl_keep isl_id *id); __isl_give isl_id *isl_id_set_free_user(__isl_take isl_id *id, void (*free_user)(void *user)); diff --git a/isl_id.c b/isl_id.c index d5c7c711..4652384c 100644 --- a/isl_id.c +++ b/isl_id.c @@ -42,6 +42,14 @@ const char *isl_id_get_name(__isl_keep isl_id *id) return id ? id->name : NULL; } +isl_bool isl_id_has_name(__isl_keep isl_id *id) +{ + if (!id) + return isl_bool_error; + + return id->name ? isl_bool_true : isl_bool_false; +} + static __isl_give isl_id *id_alloc(isl_ctx *ctx, const char *name, void *user) { const char *copy = name ? strdup(name) : NULL; @@ -122,6 +130,16 @@ __isl_give isl_id *isl_id_alloc(isl_ctx *ctx, const char *name, void *user) return entry->data; } +/* Construct an isl_id with a given "name" and a NULL user field. + */ +__isl_give isl_id *isl_id_from_name(isl_ctx *ctx, const char *name) +{ + if (!name) + return NULL; + + return isl_id_alloc(ctx, name, NULL); +} + /* If the id has a negative refcount, then it is a static isl_id * which should not be changed. */ From 395d23fa5e59c033df96248449c2e4655b866d02 Mon Sep 17 00:00:00 2001 From: Oleksandr Zinenko Date: Tue, 5 Sep 2017 14:34:48 +0200 Subject: [PATCH 2/2] cpp/python: export isl_id Export isl_id allocation and name management. Disallow unnamed identifiers by construction and hide user pointers. Identifiers can have an optional name and an optional user pointer. However, identifiers without a name and a user pointer are forbidden. The user pointer is a void * pointer to a C data structure, managed and potentially deallocated within C code. It is not fully compatible with C++ objects featuring a virtual destructor and not sufficiently type-safe. The notion of pointer does not exist from the bindings. This is achieved by providing the "isl_id_from_name" (constructor) function that only takes a name of the identifier. If necessary, user pointers may be accessed through C API, but doing so should be discouraged. As an alternative, a user of C++ or Python bindings may maintain a mapping between identifier objects and arbitrary data. The equality of pointer objects is preserved. However, hiding user pointers may lead to a situation where two identifier objects in C++ or Python are not equal although their visible attributes (names) are equal. This can only happen if at least one of the pointers was obtained from C code. Signed-off-by: Oleksandr Zinenko --- include/isl/id.h | 5 ++++- interface/isl_test_cpp.cpp | 44 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/include/isl/id.h b/include/isl/id.h index 36d4f396..8314a8c9 100644 --- a/include/isl/id.h +++ b/include/isl/id.h @@ -10,7 +10,7 @@ extern "C" { #endif -struct isl_id; +struct __isl_export isl_id; typedef struct isl_id isl_id; ISL_DECLARE_LIST(id) @@ -20,13 +20,16 @@ uint32_t isl_id_get_hash(__isl_keep isl_id *id); __isl_give isl_id *isl_id_alloc(isl_ctx *ctx, __isl_keep const char *name, void *user); +__isl_constructor __isl_give isl_id *isl_id_from_name(isl_ctx *ctx, __isl_keep const char *name); __isl_give isl_id *isl_id_copy(isl_id *id); __isl_null isl_id *isl_id_free(__isl_take isl_id *id); void *isl_id_get_user(__isl_keep isl_id *id); +__isl_export __isl_keep const char *isl_id_get_name(__isl_keep isl_id *id); +__isl_export isl_bool isl_id_has_name(__isl_keep isl_id *id); __isl_give isl_id *isl_id_set_free_user(__isl_take isl_id *id, diff --git a/interface/isl_test_cpp.cpp b/interface/isl_test_cpp.cpp index a6b1e631..942cb41f 100644 --- a/interface/isl_test_cpp.cpp +++ b/interface/isl_test_cpp.cpp @@ -314,6 +314,48 @@ void test_foreach(isl::ctx ctx) assert(ret2 == isl::stat::error); } +/* Test that identifiers are constructed correctly and their uniqueness + * property holds for both C and C++ interfaces. + * + * Verify that two identifiers with the same name and same user pointer are + * pointer-equal independently of how they were allocated. Check that + * identifier with an empty name is not equal to an identifier with a NULL + * name. + */ +void test_id(isl::ctx ctx) +{ + isl::id id1(ctx, "whatever"); + isl::id id2(ctx, "whatever"); + isl_id *id3 = isl_id_alloc(ctx.get(), "whatever", NULL); + int dummy; + isl_id *id4 = isl_id_alloc(ctx.get(), "whatever", &dummy); + + assert(id1.get() == id2.get()); + assert(id1.get() == id3); + assert(id2.get() == id3); + assert(id3 != id4); + assert(id1.get() != id4); + + isl::id id5 = isl::manage(id3); + isl::id id6 = isl::manage(id4); + assert(id5.get() == id1.get()); + + assert(id1.has_name()); + assert(id5.has_name()); + assert(id6.has_name()); + assert("whatever" == id1.get_name()); + assert("whatever" == id5.get_name()); + assert("whatever" == id6.get_name()); + + isl_id *nameless = isl_id_alloc(ctx.get(), NULL, &dummy); + isl::id id7 = isl::manage(nameless); + assert(!id7.has_name()); + + isl::id id8(ctx, ""); + assert(id8.has_name()); + assert(id8.get() != id7.get()); +} + /* Test the isl C++ interface * * This includes: @@ -322,6 +364,7 @@ void test_foreach(isl::ctx ctx) * - Different parameter types * - Different return types * - Foreach functions + * - Identifier allocation and equality */ int main() { @@ -332,6 +375,7 @@ int main() test_parameters(ctx); test_return(ctx); test_foreach(ctx); + test_id(ctx); isl_ctx_free(ctx); }