Skip to content

Commit

Permalink
Standalone 7/N: Implement and test Zarr common functions (#299)
Browse files Browse the repository at this point in the history
Depends on #298.
  • Loading branch information
aliddell authored Sep 26, 2024
1 parent 16c553f commit 89b4b6c
Show file tree
Hide file tree
Showing 16 changed files with 1,125 additions and 83 deletions.
4 changes: 4 additions & 0 deletions src/streaming/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ set(tgt acquire-zarr)
add_library(${tgt}
macros.hh
acquire.zarr.cpp
zarr.dimension.hh
zarr.dimension.cpp
zarr.stream.hh
zarr.stream.cpp
zarr.common.hh
zarr.common.cpp
)

target_include_directories(${tgt}
Expand Down
2 changes: 1 addition & 1 deletion src/streaming/acquire.zarr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ extern "C"
} catch (const std::bad_alloc&) {
LOG_ERROR("Failed to allocate memory for Zarr stream");
} catch (const std::exception& e) {
LOG_ERROR("Error creating Zarr stream: %s", e.what());
LOG_ERROR("Error creating Zarr stream: ", e.what());
}

return stream;
Expand Down
2 changes: 1 addition & 1 deletion src/streaming/macros.hh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
throw std::runtime_error(__err); \
} \
} while (0)
#define CHECK(e) EXPECT(e, "Expression evaluated as false:\n\t%s", #e)
#define CHECK(e) EXPECT(e, "Expression evaluated as false:\n\t", #e)

#define EXPECT_VALID_ARGUMENT(e, ...) \
do { \
Expand Down
92 changes: 92 additions & 0 deletions src/streaming/zarr.common.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#include "macros.hh"
#include "zarr.common.hh"

#include <stdexcept>

std::string
zarr::trim(std::string_view s)
{
if (s.empty()) {
return {};
}

// trim left
std::string trimmed(s);
trimmed.erase(trimmed.begin(),
std::find_if(trimmed.begin(), trimmed.end(), [](char c) {
return !std::isspace(c);
}));

// trim right
trimmed.erase(std::find_if(trimmed.rbegin(),
trimmed.rend(),
[](char c) { return !std::isspace(c); })
.base(),
trimmed.end());

return trimmed;
}

bool
zarr::is_empty_string(std::string_view s, std::string_view err_on_empty)
{
auto trimmed = trim(s);
if (trimmed.empty()) {
LOG_ERROR(err_on_empty);
return true;
}
return false;
}

size_t
zarr::bytes_of_type(ZarrDataType data_type)
{
switch (data_type) {
case ZarrDataType_int8:
case ZarrDataType_uint8:
return 1;
case ZarrDataType_int16:
case ZarrDataType_uint16:
return 2;
case ZarrDataType_int32:
case ZarrDataType_uint32:
case ZarrDataType_float32:
return 4;
case ZarrDataType_int64:
case ZarrDataType_uint64:
case ZarrDataType_float64:
return 8;
default:
throw std::invalid_argument("Invalid data type: " +
std::to_string(data_type));
}
}

size_t
zarr::bytes_of_frame(const ArrayDimensions& dims, ZarrDataType type)
{
const auto height = dims.height_dim().array_size_px;
const auto width = dims.width_dim().array_size_px;
return bytes_of_type(type) * height * width;
}

uint32_t
zarr::chunks_along_dimension(const ZarrDimension& dimension)
{
EXPECT(dimension.chunk_size_px > 0, "Invalid chunk size.");

return (dimension.array_size_px + dimension.chunk_size_px - 1) /
dimension.chunk_size_px;
}

uint32_t
zarr::shards_along_dimension(const ZarrDimension& dimension)
{
if (dimension.shard_size_chunks == 0) {
return 0;
}

const auto shard_size = dimension.shard_size_chunks;
const auto n_chunks = chunks_along_dimension(dimension);
return (n_chunks + shard_size - 1) / shard_size;
}
63 changes: 63 additions & 0 deletions src/streaming/zarr.common.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#pragma once

#include "zarr.dimension.hh"
#include "acquire.zarr.h"

namespace zarr {
/**
* @brief Trim whitespace from a string.
* @param s The string to trim.
* @return The string with leading and trailing whitespace removed.
*/
[[nodiscard]]
std::string
trim(std::string_view s);

/**
* @brief Check if a string is empty, including whitespace.
* @param s The string to check.
* @param err_on_empty The message to log if the string is empty.
* @return True if the string is empty, false otherwise.
*/
bool
is_empty_string(std::string_view s, std::string_view err_on_empty);

/**
* @brief Get the number of bytes for a given data type.
* @param data_type The data type.
* @return The number of bytes for the data type.
* @throw std::invalid_argument if the data type is not recognized.
*/
size_t
bytes_of_type(ZarrDataType data_type);

/**
* @brief Get the number of bytes for a frame with the given dimensions and
* data type.
* @param dims The dimensions of the full array.
* @param type The data type of the array.
* @return The number of bytes for a single frame.
* @throw std::invalid_argument if the data type is not recognized.
*/
size_t
bytes_of_frame(const ArrayDimensions& dims, ZarrDataType type);

/**
* @brief Get the number of chunks along a dimension.
* @param dimension A dimension.
* @return The number of, possibly ragged, chunks along the dimension, given
* the dimension's array and chunk sizes.
* @throw std::runtime_error if the chunk size is zero.
*/
uint32_t
chunks_along_dimension(const ZarrDimension& dimension);

/**
* @brief Get the number of shards along a dimension.
* @param dimension A dimension.
* @return The number of shards along the dimension, given the dimension's
* array, chunk, and shard sizes.
*/
uint32_t
shards_along_dimension(const ZarrDimension& dimension);
} // namespace zarr
Loading

0 comments on commit 89b4b6c

Please sign in to comment.