Skip to content

Commit

Permalink
Switch to pinned versions of all C++ libraries.
Browse files Browse the repository at this point in the history
  • Loading branch information
LTLA committed Jan 5, 2024
1 parent beb1897 commit 8c7913b
Show file tree
Hide file tree
Showing 16 changed files with 164 additions and 52 deletions.
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: alabaster.base
Title: Save Bioconductor Objects To File
Version: 1.3.15
Date: 2024-01-02
Version: 1.3.16
Date: 2024-01-05
Authors@R: person("Aaron", "Lun", role=c("aut", "cre"), email="[email protected]")
License: MIT + file LICENSE
Description:
Expand Down
6 changes: 3 additions & 3 deletions inst/include/fetch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ harvester() {
harvester millijson https://github.com/ArtifactDB/millijson v1.0.0
harvester byteme https://github.com/LTLA/byteme v1.1.0
harvester comservatory https://github.com/ArtifactDB/comservatory v2.0.1
harvester uzuki2 https://github.com/ArtifactDB/uzuki2 master
harvester ritsuko https://github.com/ArtifactDB/ritsuko master
harvester takane https://github.com/ArtifactDB/takane master
harvester uzuki2 https://github.com/ArtifactDB/uzuki2 v1.4.0
harvester ritsuko https://github.com/ArtifactDB/ritsuko v0.4.0
harvester takane https://github.com/ArtifactDB/takane v0.6.0
2 changes: 1 addition & 1 deletion inst/include/ritsuko/hdf5/Stream1dNumericDataset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class Stream1dNumericDataset {
public:
/**
* @param ptr Pointer to a HDF5 dataset handle.
* @param size Length of the dataset as a 1-dimensional vector.
* @param length Length of the dataset as a 1-dimensional vector.
* @param buffer_size Size of the buffer for holding streamed blocks of values.
* Larger buffers improve speed at the cost of some memory efficiency.
*/
Expand Down
1 change: 0 additions & 1 deletion inst/include/ritsuko/hdf5/exceeds_limit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ inline bool exceeds_float_limit(const H5::DataSet& handle, size_t precision) {
*
* @param handle Handle for a HDF5 attribute.
* @param precision Number of bits in the limiting integer type, assuming 2's complement.
* @param is_signed Whether the limiting integer type is signed.
*
* @return Whether the dataset uses a datatype than cannot be represented by the limiting integer type.
*/
Expand Down
4 changes: 2 additions & 2 deletions inst/include/ritsuko/hdf5/load_attribute.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
#include "_strings.hpp"

/**
* @file load_scalar_string_attribute.hpp
* @brief Load a scalar string HDF5 attribute.
* @file load_attribute.hpp
* @brief Load HDF5 attributes.
*/

namespace ritsuko {
Expand Down
6 changes: 3 additions & 3 deletions inst/include/ritsuko/hdf5/validate_string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ inline void validate_1d_string_dataset(const H5::DataSet& handle, hsize_t buffer
* Currently, this involves checking that there are no `NULL` entries for variable-length string datatypes.
* For fixed-width string attributes, this function is a no-op.
*
* @param handle Handle to the HDF5 string attribute.
* @param attr Handle to the HDF5 string attribute.
*/
inline void validate_scalar_string_attribute(const H5::Attribute& attr) {
auto dtype = attr.getDataType();
Expand All @@ -113,7 +113,7 @@ inline void validate_scalar_string_attribute(const H5::Attribute& attr) {
* Currently, this involves checking that there are no `NULL` entries for variable-length string datatypes.
* For fixed-width string attributes, this function is a no-op.
*
* @param handle Handle to the HDF5 string attribute.
* @param attr Handle to the HDF5 string attribute.
* @param full_length Length of the attribute as a 1-dimensional vector.
*/
inline void validate_1d_string_attribute(const H5::Attribute& attr, hsize_t full_length) {
Expand All @@ -135,7 +135,7 @@ inline void validate_1d_string_attribute(const H5::Attribute& attr, hsize_t full

/**
* Overload for `validate_1d_string_attribute()` that automatically determines its length via `get_1d_length()`.
* @param handle Handle to the HDF5 string attribute.
* @param attr Handle to the HDF5 string attribute.
*/
inline void validate_1d_string_attribute(const H5::Attribute& attr) {
validate_1d_string_attribute(attr, get_1d_length(attr, false));
Expand Down
12 changes: 12 additions & 0 deletions inst/include/ritsuko/parse_version_string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
#include <stdexcept>
#include <string>

/**
* @file parse_version_string.hpp
* @brief Parse version strings.
*/

namespace ritsuko {

/**
Expand Down Expand Up @@ -179,6 +184,13 @@ inline void throw_version_error(const char* version_string, size_t size, const c
* @endcond
*/

/**
* @param[in] version_string Pointer to a version string.
* @param size Length of the `version_string`.
* @param skip_patch Whether to skip the patch number.
* @return A `Version` object containing the version number.
* If `skip_patch = true`, the `patch` number is always zero.
*/
inline Version parse_version_string(const char* version_string, size_t size, bool skip_patch = false) {
int major = 0, minor = 0, patch = 0;
size_t i = 0, end = size;
Expand Down
85 changes: 85 additions & 0 deletions inst/include/takane/_derived_from.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#ifndef TAKANE_DERIVED_FROM_HPP
#define TAKANE_DERIVED_FROM_HPP

#include <unordered_set>
#include <unordered_map>
#include <string>

namespace takane {

/**
* @cond
*/
namespace internal_derived_from {

inline void fill(const std::unordered_map<std::string, std::unordered_set<std::string> >& registry, std::unordered_set<std::string>& host, const std::string& derived) {
auto it = registry.find(derived);
if (it != registry.end()) {
for (auto d : it->second) {
host.insert(d);
fill(registry, host, d);
}
}
}

inline auto default_registry() {
std::unordered_map<std::string, std::unordered_set<std::string> > registry;
registry["summarized_experiment"] = { "ranged_summarized_experiment" };
registry["ranged_summarized_experiment"] = { "single_cell_experiment" };
registry["single_cell_experiment"] = { "spatial_experiment" };

// Recursively fill the registry to expand the children.
for (auto& p : registry) {
auto& host = p.second;
std::vector<std::string> copy(host.begin(), host.end());
for (const auto& d : copy) {
host.insert(d);
fill(registry, host, d);
}
}

return registry;
}

}
/**
* @endcond
*/

/**
* Registry of derived object types and their base types.
* Each key is the base object type and each value is the set of all of its derived types.
* Derived types satisfy the same file requirements of the base type, but usually add more files to represent additional functionality.
*
* Applications can extend the **takane** framework by adding custom derived types to each set.
* Note that derived types must be manually included in every base type's set,
* e.g., if B is derived from A and C is derived from B, C must be added to the sets for both A and B.
*/
inline std::unordered_map<std::string, std::unordered_set<std::string> > derived_from_registry = internal_derived_from::default_registry();

/**
* Check whether a particular object type is derived from a base objct type.
* This can be used by specifications to check that child components satisfy certain expectations.
*
* @param type Object type.
* @param base Base object type.
* @returns Whether `type` is derived from `base` or is equal to `base`.
*/
inline bool derived_from(const std::string& type, const std::string& base) {
if (type == base) {
return true;
}

auto it = derived_from_registry.find(base);
if (it == derived_from_registry.end()) {
return false;
}

const auto& listing = it->second;
return (listing.find(type) != listing.end());
}

}

#endif

18 changes: 16 additions & 2 deletions inst/include/takane/_satisfies_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <unordered_set>
#include <unordered_map>
#include <string>
#include "_derived_from.hpp"

namespace takane {

Expand All @@ -16,7 +17,7 @@ inline auto default_registry() {
std::unordered_map<std::string, std::unordered_set<std::string> > registry;
registry["SIMPLE_LIST"] = { "simple_list" };
registry["DATA_FRAME"] = { "data_frame" };
registry["SUMMARIZED_EXPERIMENT"] = { "summarized_experiment", "ranged_summarized_experiment", "single_cell_experiment" };
registry["SUMMARIZED_EXPERIMENT"] = { "summarized_experiment", "vcf_experiment" };
return registry;
}

Expand All @@ -28,7 +29,9 @@ inline auto default_registry() {
/**
* Registry of object types that satisfy a particular object interface.
* Each key is the interface and each value is the set of all types that satisfy it.
*
* Applications can extend the **takane** framework by adding custom types to each set.
* Note that, if a type is included in a particular set, it is not necessary to add its derived types, as `satisfies_interface()` will automatically call `derived_from()`.
*/
inline std::unordered_map<std::string, std::unordered_set<std::string> > satisfies_interface_registry = internal_satisfies_interface::default_registry();

Expand All @@ -45,8 +48,19 @@ inline bool satisfies_interface(const std::string& type, const std::string& inte
if (it == satisfies_interface_registry.end()) {
return false;
}

const auto& listing = it->second;
return listing.find(type) != listing.end();
if (listing.find(type) != listing.end()) {
return true;
}

for (const auto& d : listing) {
if (derived_from(type, d)) {
return true;
}
}

return false;
}

}
Expand Down
57 changes: 25 additions & 32 deletions inst/include/takane/genomic_ranges.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ namespace takane {
* @cond
*/
void validate(const std::filesystem::path&, const ObjectMetadata&, const Options& options);
bool derived_from(const std::string&, const std::string&);
/**
* @endcond
*/
Expand All @@ -43,14 +44,14 @@ namespace genomic_ranges {
namespace internal {

struct SequenceLimits {
SequenceLimits(size_t n) : restricted(n), seqlen(n) {}
std::vector<unsigned char> restricted;
SequenceLimits(size_t n) : has_circular(n), circular(n), has_seqlen(n), seqlen(n) {}
std::vector<unsigned char> has_circular, circular, has_seqlen;
std::vector<uint64_t> seqlen;
};

inline SequenceLimits find_sequence_limits(const std::filesystem::path& path, const Options& options) {
auto smeta = read_object_metadata(path);
if (smeta.type != "sequence_information") {
if (!derived_from(smeta.type, "sequence_information")) {
throw std::runtime_error("'sequence_information' directory should contain a 'sequence_information' object");
}
::takane::validate(path, smeta, options);
Expand All @@ -68,23 +69,13 @@ inline SequenceLimits find_sequence_limits(const std::filesystem::path& path, co
auto cmissing = ritsuko::hdf5::open_and_load_optional_numeric_missing_placeholder<int32_t>(chandle, "missing-value-placeholder");

SequenceLimits output(num_seq);
auto& restricted = output.restricted;
auto& seqlen = output.seqlen;

for (size_t i = 0; i < num_seq; ++i, lstream.next(), cstream.next()) {
auto slen = lstream.get();
auto circ = cstream.get();
seqlen[i] = slen;

// Skipping restriction if the sequence length is missing OR the sequence is circular.
if (lmissing.first && lmissing.second == slen) {
continue;
}
if (circ && !(cmissing.first && cmissing.second == circ)) {
continue;
}

restricted[i] = true;
output.has_seqlen[i] = !(lmissing.first && lmissing.second == slen);
output.seqlen[i] = slen;
output.has_circular[i] = !(cmissing.first && cmissing.second == circ);
output.circular[i] = circ;
}

return output;
Expand All @@ -109,9 +100,7 @@ inline void validate(const std::filesystem::path& path, const ObjectMetadata& me

// Figuring out the sequence length constraints.
auto limits = internal::find_sequence_limits(path / "sequence_information", options);
const auto& restricted = limits.restricted;
const auto& seqlen = limits.seqlen;
size_t num_sequences = restricted.size();
size_t num_sequences = limits.seqlen.size();

// Now loading all three components.
auto handle = ritsuko::hdf5::open_file(path / "ranges.h5");
Expand Down Expand Up @@ -151,22 +140,26 @@ inline void validate(const std::filesystem::path& path, const ObjectMetadata& me
auto start = start_stream.get();
auto width = width_stream.get();

if (restricted[id]) {
// If it's definitely non-circular, the start position should be positive.
if (limits.has_circular[id] && !limits.circular[id]) {
if (start < 1) {
throw std::runtime_error("non-positive start position (" + std::to_string(start) + ") for non-circular sequence");
}

auto spos = static_cast<uint64_t>(start);
auto limit = seqlen[id];
if (spos > limit) {
throw std::runtime_error("start position beyond sequence length (" + std::to_string(start) + " > " + std::to_string(limit) + ") for non-circular sequence");
}

// The LHS should not overflow as 'spos >= 1' so 'limit - spos + 1' should still be no greater than 'limit'.
if (limit - spos + 1 < width) {
throw std::runtime_error("end position beyond sequence length (" +
std::to_string(start) + " + " + std::to_string(width) + " > " + std::to_string(limit) +
") for non-circular sequence");
if (limits.has_seqlen[id]) {
// If the sequence length is provided, the end position shouldn't overflow.
auto spos = static_cast<uint64_t>(start);
auto limit = limits.seqlen[id];
if (spos > limit) {
throw std::runtime_error("start position beyond sequence length (" + std::to_string(start) + " > " + std::to_string(limit) + ") for non-circular sequence");
}

// The LHS should not overflow as 'spos >= 1' so 'limit - spos + 1' should still be no greater than 'limit'.
if (limit - spos + 1 < width) {
throw std::runtime_error("end position beyond sequence length (" +
std::to_string(start) + " + " + std::to_string(width) + " > " + std::to_string(limit) +
") for non-circular sequence");
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion inst/include/takane/ranged_summarized_experiment.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ inline void validate(const std::filesystem::path& path, const ObjectMetadata& me
auto rangedir = path / "row_ranges";
if (std::filesystem::exists(rangedir)) {
auto rangemeta = read_object_metadata(rangedir);
if (rangemeta.type != "genomic_ranges" && rangemeta.type != "genomic_ranges_list") {
if (!derived_from(rangemeta.type, "genomic_ranges") && !derived_from(rangemeta.type, "genomic_ranges_list")) {
throw std::runtime_error("object in 'row_ranges' must be a 'genomic_ranges' or 'genomic_ranges_list'");
}

Expand Down
10 changes: 9 additions & 1 deletion inst/include/takane/spatial_experiment.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@

namespace takane {

/**
* @cond
*/
bool derived_from(const std::string&, const std::string&);
/**
* @endcond
*/

/**
* @namespace takane::spatial_experiment
* @brief Definitions for spatial experiments.
Expand All @@ -32,7 +40,7 @@ namespace internal {
inline void validate_coordinates(const std::filesystem::path& path, size_t ncols, const Options& options) {
auto coord_path = path / "coordinates";
auto coord_meta = read_object_metadata(coord_path);
if (coord_meta.type != "dense_array") {
if (!derived_from(coord_meta.type, "dense_array")) {
throw std::runtime_error("'coordinates' should be a dense array");
}

Expand Down
1 change: 1 addition & 0 deletions inst/include/takane/takane.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "_validate.hpp"
#include "_height.hpp"
#include "_satisfies_interface.hpp"
#include "_derived_from.hpp"
#include "_dimensions.hpp"

/**
Expand Down
3 changes: 2 additions & 1 deletion inst/include/takane/utils_bumpy_array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace takane {
void validate(const std::filesystem::path&, const ObjectMetadata&, const Options&);
size_t height(const std::filesystem::path&, const ObjectMetadata&, const Options&);
bool satisfies_interface(const std::string&, const std::string&);
bool derived_from(const std::string&, const std::string&);

namespace internal_bumpy_array {

Expand Down Expand Up @@ -139,7 +140,7 @@ void validate_directory(const std::filesystem::path& path, const std::string& ob
throw std::runtime_error("'concatenated' should satisfy the '" + concatenated_type + "' interface");
}
} else {
if (catmeta.type != concatenated_type) {
if (!derived_from(catmeta.type, concatenated_type)) {
throw std::runtime_error("'concatenated' should contain an '" + concatenated_type + "' object");
}
}
Expand Down
Loading

0 comments on commit 8c7913b

Please sign in to comment.