Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add typesafe filter option methods to C++ API. #1062

Merged
merged 1 commit into from
Nov 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* Set LZ4, Zlib and Zstd compressors to build in release mode. [#1034](https://github.com/TileDB-Inc/TileDB/pull/1034)
* Added missing check if coordinates obey the global order in global order sparse writes. [#1039](https://github.com/TileDB-Inc/TileDB/pull/1039)
* Changed coordinates to always be split before filtering. #1054
* Added type-safe filter option methods to C++ API. #1062

# TileDB v1.4.0 Release Notes

Expand Down
32 changes: 30 additions & 2 deletions test/src/unit-cppapi-filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,39 @@ TEST_CASE("C++ API: Filter options", "[cppapi], [filter]") {
f.get_option(TILEDB_COMPRESSION_LEVEL, &get_level);
REQUIRE(get_level == 5);

// Check templated version
f.set_option(TILEDB_COMPRESSION_LEVEL, 4);
f.get_option(TILEDB_COMPRESSION_LEVEL, &get_level);
REQUIRE(get_level == 4);

// Check templated version with wrong type throws exception
uint32_t wrong_type_u = 1;
REQUIRE_THROWS_AS(
f.set_option(TILEDB_COMPRESSION_LEVEL, wrong_type_u),
std::invalid_argument);
REQUIRE_THROWS_AS(
f.get_option(TILEDB_COMPRESSION_LEVEL, &wrong_type_u),
std::invalid_argument);

// Check that you can bypass type safety (don't do this).
f.get_option(TILEDB_COMPRESSION_LEVEL, (void*)&wrong_type_u);
REQUIRE(wrong_type_u == 4);

// Unsupported option
uint32_t window;
REQUIRE_THROWS_AS(
f.set_option(TILEDB_BIT_WIDTH_MAX_WINDOW, &window), TileDBError);
REQUIRE_THROWS_AS(
f.get_option(TILEDB_BIT_WIDTH_MAX_WINDOW, &window), TileDBError);

Filter f2(ctx, TILEDB_FILTER_BIT_WIDTH_REDUCTION);
int32_t wrong_type_i = 1;
REQUIRE_THROWS_AS(f2.set_option(TILEDB_COMPRESSION_LEVEL, 1), TileDBError);
REQUIRE_THROWS_AS(
f.set_option(TILEDB_BIT_WIDTH_MAX_WINDOW, &set_level), TileDBError);
f2.set_option(TILEDB_BIT_WIDTH_MAX_WINDOW, -1), std::invalid_argument);
REQUIRE_THROWS_AS(
f.get_option(TILEDB_BIT_WIDTH_MAX_WINDOW, &set_level), TileDBError);
f2.set_option(TILEDB_BIT_WIDTH_MAX_WINDOW, wrong_type_i),
std::invalid_argument);
}

TEST_CASE("C++ API: Filter lists", "[cppapi], [filter]") {
Expand Down
95 changes: 95 additions & 0 deletions tiledb/sm/cpp_api/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,38 @@ class Filter {
*
* @code{.cpp}
* tiledb::Filter f(ctx, TILEDB_FILTER_ZSTD);
* f.set_option(TILEDB_COMPRESSION_LEVEL, 5);
* @endcode
*
* @tparam T Type of value of option to set.
* @param option Enumerated option to set.
* @param value Value of option to set.
* @return Reference to this Filter
*
* @throws TileDBError if the option cannot be set on the filter.
* @throws std::invalid_argument if the option value is the wrong type.
*/
template <
typename T,
typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
Filter& set_option(tiledb_filter_option_t option, T value) {
auto& ctx = ctx_.get();
option_value_typecheck<T>(option);
ctx.handle_error(
tiledb_filter_set_option(ctx, filter_.get(), option, &value));
return *this;
}

/**
* Sets an option on the filter. Options are filter dependent; this function
* throws an error if the given option is not valid for the given filter.
*
* This version of set_option performs no type checks.
*
* **Example:**
*
* @code{.cpp}
* tiledb::Filter f(ctx, TILEDB_FILTER_ZSTD);
* int level = 5;
* f.set_option(TILEDB_COMPRESSION_LEVEL, &level);
* @endcode
Expand All @@ -127,6 +159,8 @@ class Filter {
* @return Reference to this Filter
*
* @throws TileDBError if the option cannot be set on the filter.
*
* @note set_option<T>(option, T value) is preferred as it is safer.
*/
Filter& set_option(tiledb_filter_option_t option, const void* value) {
auto& ctx = ctx_.get();
Expand All @@ -147,13 +181,49 @@ class Filter {
* // level == -1 (the default compression level)
* @endcode
*
* @tparam T Type of option value to get.
* @param option Enumerated option to get.
* @param value Buffer that option value will be written to.
*
* @note The buffer pointed to by `value` must be large enough to hold the
* option value.
*
* @throws TileDBError if the option cannot be retrieved from the filter.
* @throws std::invalid_argument if the option value is the wrong type.
*/
template <
typename T,
typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
void get_option(tiledb_filter_option_t option, T* value) {
auto& ctx = ctx_.get();
option_value_typecheck<T>(option);
ctx.handle_error(
tiledb_filter_get_option(ctx, filter_.get(), option, value));
}

/**
* Gets an option value from the filter.
*
* This version of get_option performs no type checks.
*
* **Example:**
*
* @code{.cpp}
* tiledb::Filter f(ctx, TILEDB_FILTER_ZSTD);
* int32_t level;
* f.get_option(TILEDB_COMPRESSION_LEVEL, &level);
* // level == -1 (the default compression level)
* @endcode
*
* @param option Enumerated option to get.
* @param value Buffer that option value will be written to.
*
* @note The buffer pointed to by `value` must be large enough to hold the
* option value.
*
* @throws TileDBError if the option cannot be retrieved from the filter.
*
* @note get_option<T>(option, T* value) is preferred as it is safer.
*/
void get_option(tiledb_filter_option_t option, void* value) {
auto& ctx = ctx_.get();
Expand Down Expand Up @@ -215,6 +285,31 @@ class Filter {

/** The pointer to the C TileDB filter object. */
std::shared_ptr<tiledb_filter_t> filter_;

/**
* Throws an exception if the value type is not suitable for the given filter
* option.
*
* @tparam T Value type of filter option
* @param option Option to check
* @throws invalid_argument If the value type is invalid
*/
template <typename T>
void option_value_typecheck(tiledb_filter_option_t option) {
switch (option) {
case TILEDB_COMPRESSION_LEVEL:
if (!std::is_same<int32_t, T>::value)
throw std::invalid_argument("Option value must be int32_t.");
break;
case TILEDB_BIT_WIDTH_MAX_WINDOW:
case TILEDB_POSITIVE_DELTA_MAX_WINDOW:
if (!std::is_same<uint32_t, T>::value)
throw std::invalid_argument("Option value must be uint32_t.");
break;
default:
throw std::invalid_argument("Invalid option type");
}
}
};

/** Gets a string representation of a filter for an output stream. */
Expand Down