Skip to content

Commit

Permalink
Add an aspect template argument to class CAPIFunction.
Browse files Browse the repository at this point in the history
This PR makes two changes to the template signature of `class CAPIFunction`. The central one is to add an aspect argument that can provide hooks into `CAPIFunction::function`. In this initial version there's a single aspect point (the aspect member function `call`) that is only an observer. The `call` of the default aspect does nothing. The second change in template signature is to infer the return value of the wrapper function and to suppress return statements if that type is `void`. This allows the elimination of subsidiary wrapper for `void` functions to give them a (constant) return value.

Tests for the aspect implement `class LoggingAspect`, a primitive call-logger sufficient for testing, and provide an override header to activate it. The override header also generates a traits class for each C API implementation function that provides data for `LoggingAspect`. These elements are exercised by two new test runners that share a common set of tests; only the results differ depending on whether the hook is active or not.

In order to automatically generate metadata for API functions, the PR introduces a set of macros to define the C API interface functions. These functions are already essentially boilerplate, but they cannot be defined with function templates because they must have "C" linkage. The macros provide a pair of macro hooks for generating code either before or after the function definition.
  • Loading branch information
eric-hughes-tiledb committed Oct 17, 2023
1 parent 5200bbb commit 9d4b4cf
Show file tree
Hide file tree
Showing 15 changed files with 716 additions and 197 deletions.
127 changes: 41 additions & 86 deletions tiledb/api/c_api/config/config_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*
* The MIT License
*
* @copyright Copyright (c) 2022 TileDB, Inc.
* @copyright Copyright (c) 2022-2023 TileDB, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -172,122 +172,77 @@ capi_return_t tiledb_config_iter_done(

} // namespace tiledb::api

using tiledb::api::api_entry_error;

capi_return_t tiledb_config_alloc(
tiledb_config_t** config, tiledb_error_t** error) noexcept {
return api_entry_error<tiledb::api::tiledb_config_alloc>(error, config);
}
CAPI_ERROR_BEGIN(config_alloc, tiledb_config_t** config)
CAPI_ERROR_END(config_alloc, config)

/*
* API Audit: Void return means no possible signal for an error. No channel that
* can return an error.
* Possible errors: `config` may be null or an invalid handle.
*/
void tiledb_config_free(tiledb_config_t** config) noexcept {
return tiledb::api::api_entry_void<tiledb::api::tiledb_config_free>(config);
}
CAPI_VOID_BEGIN(config_free, tiledb_config_t** config)
CAPI_VOID_END(config_free, config)

capi_return_t tiledb_config_set(
tiledb_config_t* config,
const char* param,
const char* value,
tiledb_error_t** error) noexcept {
return api_entry_error<tiledb::api::tiledb_config_set>(
error, config, param, value);
}
CAPI_ERROR_BEGIN(
config_set, tiledb_config_t* config, const char* param, const char* value)
CAPI_ERROR_END(config_set, config, param, value)

capi_return_t tiledb_config_get(
tiledb_config_t* config,
const char* param,
const char** value,
tiledb_error_t** error) noexcept {
return api_entry_error<tiledb::api::tiledb_config_get>(
error, config, param, value);
}
CAPI_ERROR_BEGIN(
config_get, tiledb_config_t* config, const char* param, const char** value)
CAPI_ERROR_END(config_get, config, param, value)

capi_return_t tiledb_config_unset(
tiledb_config_t* config,
const char* param,
tiledb_error_t** error) noexcept {
return api_entry_error<tiledb::api::tiledb_config_unset>(
error, config, param);
}
CAPI_ERROR_BEGIN(config_unset, tiledb_config_t* config, const char* param)
CAPI_ERROR_END(config_unset, config, param)

capi_return_t tiledb_config_load_from_file(
tiledb_config_t* config,
const char* filename,
tiledb_error_t** error) noexcept {
return api_entry_error<tiledb::api::tiledb_config_load_from_file>(
error, config, filename);
}
CAPI_ERROR_BEGIN(
config_load_from_file, tiledb_config_t* config, const char* filename)
CAPI_ERROR_END(config_load_from_file, config, filename)

capi_return_t tiledb_config_save_to_file(
tiledb_config_t* config,
const char* filename,
tiledb_error_t** error) noexcept {
return api_entry_error<tiledb::api::tiledb_config_save_to_file>(
error, config, filename);
}
CAPI_ERROR_BEGIN(
config_save_to_file, tiledb_config_t* config, const char* filename)
CAPI_ERROR_END(config_save_to_file, config, filename)

/*
* API Audit: No channel that can return an error.
* Possible errors: Both `lhs` and `rhs` may be null or an invalid handle.
* `equal` may be a null pointer
*/
capi_return_t tiledb_config_compare(
tiledb_config_t* lhs, tiledb_config_t* rhs, uint8_t* equal) noexcept {
return tiledb::api::api_entry_plain<tiledb::api::tiledb_config_compare>(
lhs, rhs, equal);
}
CAPI_PLAIN_BEGIN(
config_compare, tiledb_config_t* lhs, tiledb_config_t* rhs, uint8_t* equal)
CAPI_PLAIN_END(config_compare, lhs, rhs, equal)

capi_return_t tiledb_config_iter_alloc(
CAPI_ERROR_BEGIN(
config_iter_alloc,
tiledb_config_t* config,
const char* prefix,
tiledb_config_iter_t** config_iter,
tiledb_error_t** error) noexcept {
return api_entry_error<tiledb::api::tiledb_config_iter_alloc>(
error, config, prefix, config_iter);
}
tiledb_config_iter_t** config_iter)
CAPI_ERROR_END(config_iter_alloc, config, prefix, config_iter)

capi_return_t tiledb_config_iter_reset(
CAPI_ERROR_BEGIN(
config_iter_reset,
tiledb_config_t* config,
tiledb_config_iter_t* config_iter,
const char* prefix,
tiledb_error_t** error) noexcept {
return api_entry_error<tiledb::api::tiledb_config_iter_reset>(
error, config, config_iter, prefix);
}
const char* prefix)
CAPI_ERROR_END(config_iter_reset, config, config_iter, prefix)

/*
* API Audit: Void return means no possible signal for an error. No channel that
* can return an error.
* Possible errors: `config` may be null or an invalid handle.
*/
void tiledb_config_iter_free(tiledb_config_iter_t** config_iter) noexcept {
tiledb::api::api_entry_void<tiledb::api::tiledb_config_iter_free>(
config_iter);
}
CAPI_VOID_BEGIN(config_iter_free, tiledb_config_iter_t** config_iter)
CAPI_VOID_END(config_iter_free, config_iter)

capi_return_t tiledb_config_iter_here(
CAPI_ERROR_BEGIN(
config_iter_here,
tiledb_config_iter_t* config_iter,
const char** param,
const char** value,
tiledb_error_t** error) noexcept {
return api_entry_error<tiledb::api::tiledb_config_iter_here>(
error, config_iter, param, value);
}
const char** value)
CAPI_ERROR_END(config_iter_here, config_iter, param, value)

capi_return_t tiledb_config_iter_next(
tiledb_config_iter_t* config_iter, tiledb_error_t** error) noexcept {
return api_entry_error<tiledb::api::tiledb_config_iter_next>(
error, config_iter);
}
CAPI_ERROR_BEGIN(config_iter_next, tiledb_config_iter_t* config_iter)
CAPI_ERROR_END(config_iter_next, config_iter)

capi_return_t tiledb_config_iter_done(
tiledb_config_iter_t* config_iter,
int32_t* done,
tiledb_error_t** error) noexcept {
return api_entry_error<tiledb::api::tiledb_config_iter_done>(
error, config_iter, done);
}
CAPI_ERROR_BEGIN(
config_iter_done, tiledb_config_iter_t* config_iter, int32_t* done)
CAPI_ERROR_END(config_iter_done, config_iter, done)
90 changes: 41 additions & 49 deletions tiledb/api/c_api/context/context_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*
* The MIT License
*
* @copyright Copyright (c) 2022 TileDB, Inc.
* @copyright Copyright (c) 2022-2023 TileDB, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -138,75 +138,67 @@ using tiledb::api::api_entry_with_context;
/*
* API Audit: No channel to return error message (failure code only)
*/
capi_return_t tiledb_ctx_alloc(
tiledb_config_handle_t* config, tiledb_ctx_handle_t** ctx) noexcept {
return tiledb::api::api_entry_plain<tiledb::api::tiledb_ctx_alloc>(
config, ctx);
}
CAPI_PLAIN_BEGIN(
ctx_alloc, tiledb_config_handle_t* config, tiledb_ctx_handle_t** ctx)
CAPI_PLAIN_END(ctx_alloc,config, ctx)

/*
* We have a special case with tiledb_ctx_alloc_with_error. It's declared in
* tiledb_experimental.h. Rather than all the apparatus needed to split up that
* header (as tiledb.h is), we declare its linkage separately at the point of
* definition.
* header (as tiledb.h is), we declare it separately here, at the point of
* definition, with its correct link specification.
*
* Not including the experimental header means that we're not using the compiler
* to check the definition against the declaration. This won't scale
* particularly well, but it doesn't need to for the time being.
*/
extern "C" {

capi_return_t tiledb_ctx_alloc_with_error(
tiledb_config_handle_t* config,
tiledb_ctx_handle_t** ctx,
tiledb_error_handle_t** error) noexcept {
/*
* Wrapped with the `api_entry_error` variation. Note that the same function
* is wrapped with `api_entry_plain` above.
*/
return tiledb::api::api_entry_error<tiledb::api::tiledb_ctx_alloc>(
error, config, ctx);
}

tiledb_error_t** error) noexcept;
} // extern "C"

/*
* This is a special case. The API function does not match the name of the
* implementation function. See`capi_definition.h` for more information.
*/
/* clang-format off */
capi_return_t tiledb_ctx_alloc_with_error(
tiledb_config_handle_t* config,
tiledb_ctx_handle_t** ctx,
tiledb_error_t** error)
CAPI_MIDDLE(ctx_alloc, error)
CAPI_ERROR_END(ctx_alloc_with_error, config, ctx)
/* clang-format on */

/*
* API Audit: void return
*/
void tiledb_ctx_free(tiledb_ctx_handle_t** ctx) noexcept {
return tiledb::api::api_entry_void<tiledb::api::tiledb_ctx_free>(ctx);
}
CAPI_VOID_BEGIN(ctx_free, tiledb_ctx_handle_t** ctx)
CAPI_VOID_END(ctx_free,ctx)

capi_return_t tiledb_ctx_get_stats(
tiledb_ctx_t* ctx, char** stats_json) noexcept {
return api_entry_with_context<tiledb::api::tiledb_ctx_get_stats>(
ctx, stats_json);
}
CAPI_WITH_CONTEXT_BEGIN(ctx_get_stats, tiledb_ctx_t* ctx, char** stats_json)
CAPI_WITH_CONTEXT_END(ctx_get_stats,ctx, stats_json)

capi_return_t tiledb_ctx_get_config(
tiledb_ctx_t* ctx, tiledb_config_handle_t** config) noexcept {
return api_entry_with_context<tiledb::api::tiledb_ctx_get_config>(
ctx, config);
}
CAPI_WITH_CONTEXT_BEGIN(
ctx_get_config, tiledb_ctx_t* ctx, tiledb_config_handle_t** config)
CAPI_WITH_CONTEXT_END(ctx_get_config, ctx, config)

capi_return_t tiledb_ctx_get_last_error(
tiledb_ctx_t* ctx, tiledb_error_handle_t** err) noexcept {
return api_entry_with_context<tiledb::api::tiledb_ctx_get_last_error>(
ctx, err);
}
CAPI_WITH_CONTEXT_BEGIN(
ctx_get_last_error, tiledb_ctx_t* ctx, tiledb_error_handle_t** err)
CAPI_WITH_CONTEXT_END(ctx_get_last_error,ctx, err)

capi_return_t tiledb_ctx_is_supported_fs(
tiledb_ctx_t* ctx, tiledb_filesystem_t fs, int32_t* is_supported) noexcept {
return api_entry_with_context<tiledb::api::tiledb_ctx_is_supported_fs>(
ctx, fs, is_supported);
}
CAPI_WITH_CONTEXT_BEGIN(
ctx_is_supported_fs,
tiledb_ctx_t* ctx,
tiledb_filesystem_t fs,
int32_t* is_supported)
CAPI_WITH_CONTEXT_END(ctx_is_supported_fs,ctx, fs, is_supported)

capi_return_t tiledb_ctx_cancel_tasks(tiledb_ctx_t* ctx) noexcept {
return api_entry_with_context<tiledb::api::tiledb_ctx_cancel_tasks>(ctx);
}
CAPI_WITH_CONTEXT_BEGIN(ctx_cancel_tasks, tiledb_ctx_t* ctx)
CAPI_WITH_CONTEXT_END(ctx_cancel_tasks,ctx)

capi_return_t tiledb_ctx_set_tag(
tiledb_ctx_t* ctx, const char* key, const char* value) noexcept {
return api_entry_with_context<tiledb::api::tiledb_ctx_set_tag>(
ctx, key, value);
}
CAPI_WITH_CONTEXT_BEGIN(
ctx_set_tag, tiledb_ctx_t* ctx, const char* key, const char* value)
CAPI_WITH_CONTEXT_END(ctx_set_tag,ctx, key, value)
12 changes: 4 additions & 8 deletions tiledb/api/c_api/error/error_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,8 @@ void tiledb_error_free(tiledb_error_handle_t** err) {

} // namespace tiledb::api

capi_return_t tiledb_error_message(
tiledb_error_handle_t* err, const char** errmsg) noexcept {
return tiledb::api::api_entry_plain<tiledb::api::tiledb_error_message>(
err, errmsg);
}
CAPI_PLAIN_BEGIN(error_message, tiledb_error_handle_t* err, const char** errmsg)
CAPI_PLAIN_END(error_message, err, errmsg)

void tiledb_error_free(tiledb_error_handle_t** err) noexcept {
return tiledb::api::api_entry_void<tiledb::api::tiledb_error_free>(err);
}
CAPI_VOID_BEGIN(error_free, tiledb_error_handle_t** err)
CAPI_VOID_END(error_free, err)
4 changes: 4 additions & 0 deletions tiledb/api/c_api_support/c_api_support.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
#define TILEDB_CAPI_SUPPORT_H

#include "argument_validation.h"
#include "tiledb/api/c_api_support/exception_wrapper/capi_definition.h"
#include "tiledb/api/c_api_support/exception_wrapper/exception_wrapper.h"
#if __has_include("capi_function_override.h")
#include "capi_function_override.h"
#endif

#endif // TILEDB_CAPI_SUPPORT_H
1 change: 0 additions & 1 deletion tiledb/api/c_api_support/exception_wrapper/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ include(object_library)
# only. `exception_wrapper.cc` is an empty source file needed to allow the
# OBJECT syntax.

# No actual source files at present.
list(APPEND SOURCES
exception_wrapper.cc
)
Expand Down
Loading

0 comments on commit 9d4b4cf

Please sign in to comment.