From 54cd739e8597665affb238bd8bd1575e64db08cc Mon Sep 17 00:00:00 2001 From: "Peter J. Jones" Date: Tue, 1 Sep 2026 13:31:29 +0200 Subject: [PATCH 1/4] spectra: Prefer primary dimensions by default The primary dimensions are those that are flagged `buffer_priority == true`. --- include/mzpeak/data/array_index.h | 3 +++ include/mzpeak/schema/cv.h | 6 +++++ include/mzpeak/schema/psi/data_type.h | 3 +++ src/data/array_index.cpp | 32 +++++++++++++++++++++------ src/schema/psi/data_type.cpp | 6 +++++ src/spectra.cpp | 12 ++++++++++ 6 files changed, 55 insertions(+), 7 deletions(-) diff --git a/include/mzpeak/data/array_index.h b/include/mzpeak/data/array_index.h index 74b3e6e..9179ee9 100644 --- a/include/mzpeak/data/array_index.h +++ b/include/mzpeak/data/array_index.h @@ -128,6 +128,9 @@ class ArrayIndex final { /// The type of elements stored in this dimension. Schema::PSI::ArrayType array_type; + /// Is this the primary dimension for array type? + bool buffer_priority; + /// Transformation information for this dimension. std::optional transform; diff --git a/include/mzpeak/schema/cv.h b/include/mzpeak/schema/cv.h index 0b75ce2..f2a953e 100644 --- a/include/mzpeak/schema/cv.h +++ b/include/mzpeak/schema/cv.h @@ -46,6 +46,12 @@ class CV { return code_ == other.code_ && accession_ == other.accession_; } + /// Less than. + bool operator<(const CV& other) const + { + return code_ < other.code_ && accession_ < other.accession_; + } + private: std::string code_; std::string accession_; diff --git a/include/mzpeak/schema/psi/data_type.h b/include/mzpeak/schema/psi/data_type.h index 07f97cc..99d1c38 100644 --- a/include/mzpeak/schema/psi/data_type.h +++ b/include/mzpeak/schema/psi/data_type.h @@ -95,6 +95,9 @@ class DataType { /// Equality. bool operator==(const DataType& other) const; + /// Less than (for sorting). + bool operator<(const DataType& other) const; + private: value_type val_; std::optional as_type_; diff --git a/src/data/array_index.cpp b/src/data/array_index.cpp index c19b200..cfdda08 100644 --- a/src/data/array_index.cpp +++ b/src/data/array_index.cpp @@ -16,6 +16,27 @@ directory of this repository. namespace MzPeak::Data { +/******************************************************************************/ +// How to compare entries. Must match EntryChunkFn below. +// +// TODO: Unify these two types. +struct EntryCmpFn { + bool operator()(const ArrayIndex::Entry& a, const ArrayIndex::Entry& b) const + { + return a.array_name < b.array_name && a.array_type < b.array_type && + a.data_type < b.data_type && a.buffer_priority > b.buffer_priority; + } +}; + +// How to chunk entries. Must match EntryCmpFn above. +struct EntryChunkFn { + bool operator()(const ArrayIndex::Entry& a, const ArrayIndex::Entry& b) const + { + return a.array_name == b.array_name && a.array_type == b.array_type && + a.data_type == b.data_type && a.buffer_priority == b.buffer_priority; + } +}; + /******************************************************************************/ ArrayIndex::Layout group_name_to_layout(const std::string& name) { @@ -248,7 +269,7 @@ ArrayIndex::ArrayIndex(EntityType entity_type, const json::object& obj) } } - std::ranges::sort(entries_, {}, &Entry::array_name); + std::ranges::sort(entries_, EntryCmpFn()); } /******************************************************************************/ @@ -279,10 +300,7 @@ std::optional ArrayIndex::num_entities() const { return num_entitie std::vector ArrayIndex::dimensions() const { std::vector> groups = - entries_ | std::views::chunk_by([](auto& a, auto& b) { - return a.array_name == b.array_name && a.data_type == b.data_type && - a.array_type == b.array_type; - }) | + entries_ | std::views::chunk_by(EntryChunkFn()) | std::ranges::to>>(); std::vector result; @@ -292,8 +310,8 @@ std::vector ArrayIndex::dimensions() const if (group.empty()) continue; auto& head = group[0]; - result.push_back({head.name, head.data_type, head.array_type, head.transform, - std::move(group)}); + result.push_back({head.name, head.data_type, head.array_type, + head.buffer_priority, head.transform, std::move(group)}); } return result; diff --git a/src/schema/psi/data_type.cpp b/src/schema/psi/data_type.cpp index f0d33d5..c847c08 100644 --- a/src/schema/psi/data_type.cpp +++ b/src/schema/psi/data_type.cpp @@ -111,4 +111,10 @@ bool DataType::operator==(const DataType& other) const return val_ == other.val_ && as_type_ == other.as_type_; } +/******************************************************************************/ +bool DataType::operator<(const DataType& other) const +{ + return as_type() < other.as_type(); +} + } // namespace MzPeak::Schema::PSI diff --git a/src/spectra.cpp b/src/spectra.cpp index f784038..1cde1dc 100644 --- a/src/spectra.cpp +++ b/src/spectra.cpp @@ -38,6 +38,18 @@ Spectrum Spectra::fetch(uint64_t index) }) | std::ranges::to>(); + // Sort so that arrays with buffer priority come first. + std::ranges::sort(dims, [](auto& a, auto& b) { + return a.array_type < b.array_type && a.buffer_priority > b.buffer_priority; + }); + + // Remove duplicates (on buffer priority). + const auto to_erase = std::ranges::unique(dims, [](const auto& a, const auto& b) { + return a.array_type == b.array_type; + }); + + dims.erase(to_erase.begin(), to_erase.end()); + std::unique_ptr slice = data_->select(dims, data_->index().eq(index)); return Spectrum(index, manager_, data_, dims, std::move(slice)); } From 2d5346db390861242fd2548130bf479e37aea2b3 Mon Sep 17 00:00:00 2001 From: "Peter J. Jones" Date: Tue, 1 Sep 2026 14:18:43 +0200 Subject: [PATCH 2/4] entity_type: Make this type a proper class It can now remember the original value given in the JSON. --- bin/mzp-inspect.cpp | 4 +- include/mzpeak/data/array_index.h | 4 +- include/mzpeak/index.h | 12 ++--- include/mzpeak/schema/entity_type.h | 67 ++++++++++++++++++------- include/mzpeak/schema/file.h | 2 +- include/mzpeak/util/manager.h | 2 +- src/data/array_index.cpp | 2 +- src/data/signals.cpp | 6 +-- src/index.cpp | 5 +- src/schema/entity_type.cpp | 78 +++++++++++++++++++++++++---- src/schema/file.cpp | 2 +- src/spectrum.cpp | 9 ++-- src/util/manager.cpp | 9 ++-- test/array_index_test.cpp | 11 ++-- test/executor_test.cpp | 4 +- test/group_test.cpp | 2 +- test/parquet_test.cpp | 6 +-- 17 files changed, 156 insertions(+), 69 deletions(-) diff --git a/bin/mzp-inspect.cpp b/bin/mzp-inspect.cpp index ed2dd76..9d244f7 100644 --- a/bin/mzp-inspect.cpp +++ b/bin/mzp-inspect.cpp @@ -23,7 +23,7 @@ namespace po = boost::program_options; std::unique_ptr open_parquet_file(MzPeak::Index& index, const std::string& file) { - auto it = index.find(file); + auto it = index.manager()->find_file(file); if (it == index.files().end()) { std::println(stderr, "file \"{}\" is not in the mzPeak file index", file); @@ -41,7 +41,7 @@ int print_array_index(MzPeak::Index& index, const std::string& file) auto fmd = parquet->file_metadata(); auto et = parquet->index_file().entity_type(); - auto key = MzPeak::Schema::entity_type_to_string(et) + "_array_index"; + auto key = et.array_index_name(); auto json = parquet->kv_string(fmd, key); if (!json.has_value()) { diff --git a/include/mzpeak/data/array_index.h b/include/mzpeak/data/array_index.h index 9179ee9..06b3df6 100644 --- a/include/mzpeak/data/array_index.h +++ b/include/mzpeak/data/array_index.h @@ -62,7 +62,7 @@ class ArrayIndex final { BufferFormat buffer_format = BufferFormat::Point; /// The entity type this column belongs to. - EntityType context = EntityType::Other; + EntityType context = EntityType("other"); /// The path from the *root* of the Parquet file's schema to this /// column. @@ -207,7 +207,7 @@ class ArrayIndex final { private: // The entity type for the entire Parquet file. - EntityType entity_type_ = EntityType::Other; + EntityType entity_type_ = EntityType("other"); // Root node. std::string prefix_ = "point"; diff --git a/include/mzpeak/index.h b/include/mzpeak/index.h index 8730603..4da5370 100644 --- a/include/mzpeak/index.h +++ b/include/mzpeak/index.h @@ -9,19 +9,16 @@ directory of this repository. #pragma once #include -#include #include +#include "mzpeak/schema/file.h" + namespace MzPeak { namespace IO { class Archive; } -namespace Schema { -class File; -} - namespace Util { class Manager; } @@ -42,9 +39,10 @@ class Index { const std::vector& files() const; /** - * Find a file in the mzPeak archive with the given name. + * Find a file given its `EntityType` and `DataKind`. */ - std::vector::const_iterator find(std::string_view) const; + std::vector::const_iterator find_file(Schema::EntityType::Type, + Schema::DataKind::Type) const; /** * Access the spectra in the file. diff --git a/include/mzpeak/schema/entity_type.h b/include/mzpeak/schema/entity_type.h index e0a72bd..ca76e15 100644 --- a/include/mzpeak/schema/entity_type.h +++ b/include/mzpeak/schema/entity_type.h @@ -8,36 +8,65 @@ directory of this repository. #pragma once +#include #include +#include namespace MzPeak::Schema { /** * The type of data entity stored in the file. */ -enum class EntityType { - /// Mass spectra. - Spectrum, +class EntityType { +public: + enum Type { + /// Mass spectra. + Spectrum, - /// Chromatograms or other measurements over time. - Chromatogram, + /// Chromatograms or other measurements over time. + Chromatogram, - /// Similar to Spectrum except the unit of measure is a wavelength - /// measurement. - WavelengthSpectrum, + /// Similar to Spectrum except the unit of measure is a wavelength + /// measurement. + WavelengthSpectrum, + }; - /// Unspecified. - Other -}; + // Internal storage type. + using value_type = std::variant; -/** - * Convert a EntityType to a string. - */ -std::string entity_type_to_string(EntityType); + /// Constructor. + EntityType(std::string_view); -/** - * Parse an EntityType from a string view. - */ -EntityType entity_type_from_string(std::string_view); + /// Constructor. + EntityType(Type); + + /** + * Return the string representation of an entity type. + */ + std::string to_string() const; + + /** + * Return the enumerated type if it is known. + */ + std::optional type() const; + + /** + * The name of the index column matching this entity. + */ + std::string index_column_name() const; + + /** + * The name of the array index metadata key. + */ + std::string array_index_name() const; + + /** + * The metadata key for the entity count. + */ + std::string metadata_count_key() const; + +private: + value_type val_; +}; } // namespace MzPeak::Schema diff --git a/include/mzpeak/schema/file.h b/include/mzpeak/schema/file.h index 264e155..f843d06 100644 --- a/include/mzpeak/schema/file.h +++ b/include/mzpeak/schema/file.h @@ -53,7 +53,7 @@ class File final { private: std::string file_name_; DataKind data_kind_ = DataKind("other"); - EntityType entity_type_ = EntityType::Other; + EntityType entity_type_ = EntityType("other"); std::vector columns_; }; diff --git a/include/mzpeak/util/manager.h b/include/mzpeak/util/manager.h index 2b2bde6..96ed154 100644 --- a/include/mzpeak/util/manager.h +++ b/include/mzpeak/util/manager.h @@ -39,7 +39,7 @@ class Manager final { /** * Find a file given its `EntityType` and `DataKind`. */ - std::vector::const_iterator find_file(Schema::EntityType, + std::vector::const_iterator find_file(Schema::EntityType::Type, Schema::DataKind::Type) const; /** diff --git a/src/data/array_index.cpp b/src/data/array_index.cpp index cfdda08..ec2849b 100644 --- a/src/data/array_index.cpp +++ b/src/data/array_index.cpp @@ -215,7 +215,7 @@ ArrayIndex::ArrayIndex(EntityType entity_type, const json::object& obj) entry.array_name = eo.at("array_name").as_string(); entry.buffer_format = buffer_format_from_string(eo.at("buffer_format").as_string()); - entry.context = entity_type_from_string(eo.at("context").as_string()); + entry.context = EntityType(eo.at("context").as_string()); entry.path = eo.at("path").as_string(); entry.name = entry.path.substr(prefix_.size() + 1); diff --git a/src/data/signals.cpp b/src/data/signals.cpp index 1b743bb..f1a5c23 100644 --- a/src/data/signals.cpp +++ b/src/data/signals.cpp @@ -38,10 +38,10 @@ std::shared_ptr Signals::Impl::parse_array_index() const Util::Parquet::file_metadata_t fmd(parquet_->file_metadata()); EntityType entity_type = parquet_->index_file().entity_type(); - std::string num_key(Schema::entity_type_to_string(entity_type) + "_count"); + std::string num_key(entity_type.metadata_count_key()); std::optional num_entities(parquet_->kv_size_t(fmd, num_key)); - std::string index_key(Schema::entity_type_to_string(entity_type) + "_array_index"); + std::string index_key(entity_type.array_index_name()); auto index_str(parquet_->kv_string(fmd, index_key)); if (!index_str.has_value()) throw ParquetError("missing array_index"); @@ -131,7 +131,7 @@ const std::shared_ptr& Signals::groups() const Util::Query::Builder Signals::index() const { auto entity_type = impl_->array_index_->entity_type(); - auto field_name = Schema::entity_type_to_string(entity_type) + "_index"; + auto field_name = entity_type.index_column_name(); auto index_field = column(field_name); if (!index_field.has_value()) { diff --git a/src/index.cpp b/src/index.cpp index 41330b0..e1c0f45 100644 --- a/src/index.cpp +++ b/src/index.cpp @@ -27,9 +27,10 @@ Index::Index(std::unique_ptr archive) const std::vector& Index::files() const { return manager_->files(); } /******************************************************************************/ -std::vector::const_iterator Index::find(std::string_view name) const +std::vector::const_iterator +Index::find_file(Schema::EntityType::Type et, Schema::DataKind::Type dk) const { - return manager_->find_file(name); + return manager_->find_file(et, dk); } /******************************************************************************/ diff --git a/src/schema/entity_type.cpp b/src/schema/entity_type.cpp index ec7b047..741c01f 100644 --- a/src/schema/entity_type.cpp +++ b/src/schema/entity_type.cpp @@ -6,32 +6,33 @@ directory of this repository. */ +#include + #include "mzpeak/schema/entity_type.h" namespace MzPeak::Schema { -std::string entity_type_to_string(EntityType et) +/******************************************************************************/ +std::string entity_type_to_string(EntityType::Type t) { - using enum EntityType; + using enum EntityType::Type; - switch (et) { + switch (t) { case Spectrum: return "spectrum"; case Chromatogram: return "chromatogram"; case WavelengthSpectrum: return "wavelength spectrum"; - case Other: - return "other"; } - // Make the compiler happy. - return "other"; + std::unreachable(); } -EntityType entity_type_from_string(std::string_view s) +/******************************************************************************/ +EntityType::value_type entity_type_from_string(std::string_view s) { - using enum EntityType; + using enum EntityType::Type; if (s == "spectrum") { return Spectrum; @@ -40,7 +41,64 @@ EntityType entity_type_from_string(std::string_view s) } else if (s == "wavelength spectrum") { return WavelengthSpectrum; } else { - return Other; + return std::string(s); } } + +/******************************************************************************/ +EntityType::EntityType(std::string_view s) + : val_(entity_type_from_string(s)) +{ +} + +/******************************************************************************/ +EntityType::EntityType(Type t) + : val_(t) +{ +} + +/******************************************************************************/ +std::string EntityType::to_string() const +{ + return std::visit( + [](auto&& v) { + using T = std::decay_t; + + if constexpr (std::is_same_v) { + return entity_type_to_string(v); + } else { + return v; + } + }, + val_); +} + +/******************************************************************************/ +std::optional EntityType::type() const +{ + return std::visit( + [](auto&& v) -> std::optional { + using T = std::decay_t; + + if constexpr (std::is_same_v) { + return v; + } else { + return std::nullopt; + } + }, + val_); +} + +/******************************************************************************/ +std::string EntityType::index_column_name() const { return to_string() + "_index"; } + +/******************************************************************************/ +std::string EntityType::array_index_name() const +{ + return to_string() + "_array_index"; +} + +/******************************************************************************/ +std::string EntityType::metadata_count_key() const { return to_string() + "_count"; } + } // namespace MzPeak::Schema diff --git a/src/schema/file.cpp b/src/schema/file.cpp index a377c41..3ae52fd 100644 --- a/src/schema/file.cpp +++ b/src/schema/file.cpp @@ -57,7 +57,7 @@ File::File(const std::string& name) File::File(const json::object& o) : file_name_(o.at("name").as_string()) , data_kind_(o.at("data_kind").as_string()) - , entity_type_(entity_type_from_string(o.at("entity_type").as_string())) + , entity_type_(o.at("entity_type").as_string()) , columns_() { auto cs = o.find("column_mapping"); diff --git a/src/spectrum.cpp b/src/spectrum.cpp index 7f7de6f..0c01079 100644 --- a/src/spectrum.cpp +++ b/src/spectrum.cpp @@ -16,9 +16,6 @@ top-level directory of this repository. namespace MzPeak { -/******************************************************************************/ -const static char* PRIMARY_METADATA_FILE = "spectra_metadata.parquet"; - /******************************************************************************/ Spectrum::Spectrum(uint64_t index, std::shared_ptr manager, @@ -33,11 +30,11 @@ Spectrum::Spectrum(uint64_t index, , scan_time_() , scans_() { - auto meta_it = manager_->find_file(PRIMARY_METADATA_FILE); + auto meta_it = + manager_->find_file(Schema::EntityType::Spectrum, Schema::DataKind::Metadata); if (meta_it == manager_->files().end()) { - throw ParquetError("missing necessary mzpeak file: " + - std::string(PRIMARY_METADATA_FILE)); + throw InvalidFormatError("missing necessary mzpeak file: spectra metadata"); } Metadata::Spectrum meta(manager_->parquet(*meta_it), index_); diff --git a/src/util/manager.cpp b/src/util/manager.cpp index 46156cf..82f0e5d 100644 --- a/src/util/manager.cpp +++ b/src/util/manager.cpp @@ -73,11 +73,14 @@ Manager::find_file(std::string_view name) const /******************************************************************************/ std::vector::const_iterator -Manager::find_file(Schema::EntityType et, Schema::DataKind::Type dkt) const +Manager::find_file(Schema::EntityType::Type et, Schema::DataKind::Type dkt) const { return std::ranges::find_if(files_, [&et, &dkt](const auto& file) -> bool { - auto type = file.data_kind().type(); - return file.entity_type() == et && type.has_value() && type.value() == dkt; + auto et_type = file.entity_type().type(); + auto dk_type = file.data_kind().type(); + + return et_type.has_value() && et_type.value() == et && dk_type.has_value() && + dk_type.value() == dkt; }); } diff --git a/test/array_index_test.cpp b/test/array_index_test.cpp index 11746d7..fce4fde 100644 --- a/test/array_index_test.cpp +++ b/test/array_index_test.cpp @@ -20,8 +20,8 @@ BOOST_AUTO_TEST_CASE(can_get_array_index) auto mzpeak = MzPeak::open("../test/files/small.mzpeak"); - auto entry = std::ranges::find(mzpeak.files(), Schema::EntityType::Spectrum, - &Schema::File::entity_type); + auto entry = mzpeak.find_file(Schema::EntityType::Type::Spectrum, + Schema::DataKind::DataArray); BOOST_TEST((entry != mzpeak.files().end())); @@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE(can_get_array_index) const Schema::PSI::DataType f64(Schema::PSI::DataType::Float64); BOOST_TEST((mz_it->buffer_format == Schema::BufferFormat::Point)); - BOOST_TEST((mz_it->context == Schema::EntityType::Spectrum)); + BOOST_TEST((mz_it->context.type() == Schema::EntityType::Spectrum)); BOOST_TEST((mz_it->path == "point.mz")); BOOST_TEST((mz_it->data_type == f64)); BOOST_TEST((mz_it->array_type == Schema::PSI::ArrayType::Mz)); @@ -69,8 +69,9 @@ BOOST_AUTO_TEST_CASE(can_read_mz_array) using namespace MzPeak; auto mzpeak = MzPeak::open("../test/files/small.mzpeak"); - auto entry = std::ranges::find(mzpeak.files(), Schema::EntityType::Spectrum, - &Schema::File::entity_type); + + auto entry = mzpeak.find_file(Schema::EntityType::Type::Spectrum, + Schema::DataKind::DataArray); BOOST_TEST((entry != mzpeak.files().end())); diff --git a/test/executor_test.cpp b/test/executor_test.cpp index cbf199f..0df5582 100644 --- a/test/executor_test.cpp +++ b/test/executor_test.cpp @@ -22,8 +22,8 @@ BOOST_AUTO_TEST_CASE(can_find_spectrum) using namespace MzPeak; auto index = MzPeak::open("../test/files/small.mzpeak"); - auto entry = std::ranges::find(index.files(), Schema::EntityType::Spectrum, - &Schema::File::entity_type); + auto entry = index.find_file(Schema::EntityType::Type::Spectrum, + Schema::DataKind::DataArray); BOOST_TEST((entry != index.files().end())); diff --git a/test/group_test.cpp b/test/group_test.cpp index efeaf12..652923c 100644 --- a/test/group_test.cpp +++ b/test/group_test.cpp @@ -19,7 +19,7 @@ BOOST_AUTO_TEST_CASE(can_load_all_groups) using namespace MzPeak::Util; auto mzpeak = MzPeak::open("../test/files/small.mzpeak"); - auto entry = mzpeak.find("spectra_metadata.parquet"); + auto entry = mzpeak.manager()->find_file("spectra_metadata.parquet"); BOOST_TEST((entry != mzpeak.files().end())); auto parquet = mzpeak.manager()->parquet(*entry); diff --git a/test/parquet_test.cpp b/test/parquet_test.cpp index 6ad40c3..8720c6e 100644 --- a/test/parquet_test.cpp +++ b/test/parquet_test.cpp @@ -20,15 +20,15 @@ BOOST_AUTO_TEST_CASE(can_get_kv_string) auto mzpeak = MzPeak::open("../test/files/small.mzpeak"); - auto entry = std::ranges::find(mzpeak.files(), Schema::EntityType::Spectrum, - &Schema::File::entity_type); + auto entry = mzpeak.find_file(Schema::EntityType::Type::Spectrum, + Schema::DataKind::DataArray); BOOST_TEST((entry != mzpeak.files().end())); auto parquet = mzpeak.manager()->parquet(*entry); auto fmd = parquet->file_metadata(); auto et = parquet->index_file().entity_type(); - auto key = MzPeak::Schema::entity_type_to_string(et) + "_array_index"; + auto key = et.array_index_name(); auto json = parquet->kv_string(fmd, key); BOOST_TEST(json.has_value()); From 6e5dde85cf33fb5b511d0f5712e8be7c9c9f0332 Mon Sep 17 00:00:00 2001 From: "Peter J. Jones" Date: Wed, 2 Sep 2026 15:20:04 +0200 Subject: [PATCH 3/4] Ensure all exceptions are correct and derive from the internal Exception type --- include/mzpeak/data/encoding.h | 3 ++- include/mzpeak/data/null_marking.h | 4 ++-- include/mzpeak/exception.h | 6 +++--- include/mzpeak/util/enumerable_proxy.h | 2 +- src/data/signals.cpp | 9 +++++---- src/index.cpp | 2 +- src/io/zip.cpp | 3 ++- 7 files changed, 16 insertions(+), 13 deletions(-) diff --git a/include/mzpeak/data/encoding.h b/include/mzpeak/data/encoding.h index 2c86801..ed95355 100644 --- a/include/mzpeak/data/encoding.h +++ b/include/mzpeak/data/encoding.h @@ -159,7 +159,8 @@ void Decoder::decode_with_nulls(const ArrayIndex::Dimension& dim, auto col = signals_->column(primary_entry); if (!col.has_value()) { - throw ParquetError("unable to decode dimension, not in schema: " + dim.name); + throw InvalidFormatError("unable to decode dimension, not in schema: " + + dim.name); } else if (!slice_->has_column(col.value())) { return; // No data to decode so we can exit early. } diff --git a/include/mzpeak/data/null_marking.h b/include/mzpeak/data/null_marking.h index 4cbee07..55e105b 100644 --- a/include/mzpeak/data/null_marking.h +++ b/include/mzpeak/data/null_marking.h @@ -142,7 +142,7 @@ std::optional Decoder::operator()(int64_t index) { // Sanity check. if (array_ == nullptr) { - throw("FIXME: assertion failed"); + throw(Exception("while decoding null marking an nullptr was encountered")); }; if (index != 0 && prior_.index == index - 1) { @@ -200,7 +200,7 @@ std::optional Decoder::operator()(int64_t index) return prior_.value; } else { // Shouldn't happen. - throw("FIXME: failed to decode NULL marking value"); + throw(Exception("failed to decode NULL marking value")); } } diff --git a/include/mzpeak/exception.h b/include/mzpeak/exception.h index f8b9d9f..3bcb770 100644 --- a/include/mzpeak/exception.h +++ b/include/mzpeak/exception.h @@ -92,16 +92,16 @@ class UnknownLayoutError final : public Exception { /** * Attempt to access an invalid iterator. */ -class InvalidIterator final : public Exception { +class InvalidIteratorError final : public Exception { public: /// Constructor. - InvalidIterator(const std::string& msg) + InvalidIteratorError(const std::string& msg) : Exception(msg) { } /// Destructor. - ~InvalidIterator() = default; + ~InvalidIteratorError() = default; }; /** diff --git a/include/mzpeak/util/enumerable_proxy.h b/include/mzpeak/util/enumerable_proxy.h index 6fe6766..d8beee2 100644 --- a/include/mzpeak/util/enumerable_proxy.h +++ b/include/mzpeak/util/enumerable_proxy.h @@ -101,7 +101,7 @@ class EnumerableProxy : public std::ranges::view_interface> { const_cast(this)->cache_ = std::make_pair<>(n_, fetch_(n_)); return cache_->second; } else { - throw InvalidIterator("attempt to dereference an invalid iterator"); + throw InvalidIteratorError("attempt to dereference an invalid iterator"); } } diff --git a/src/data/signals.cpp b/src/data/signals.cpp index f1a5c23..6f9fda7 100644 --- a/src/data/signals.cpp +++ b/src/data/signals.cpp @@ -43,7 +43,7 @@ std::shared_ptr Signals::Impl::parse_array_index() const std::string index_key(entity_type.array_index_name()); auto index_str(parquet_->kv_string(fmd, index_key)); - if (!index_str.has_value()) throw ParquetError("missing array_index"); + if (!index_str.has_value()) throw InvalidFormatError("missing array_index"); namespace json = boost::json; boost::system::error_code ec; @@ -98,7 +98,7 @@ std::size_t Signals::record_count() const // } // FIXME: Should we scan the file at this point? - throw ParquetError("no num_entities cache and no column statistics!"); + throw InvalidFormatError("no num_entities cache and no column statistics!"); } /******************************************************************************/ @@ -135,7 +135,8 @@ Util::Query::Builder Signals::index() const auto index_field = column(field_name); if (!index_field.has_value()) { - throw ParquetError("parquet file is missing the index column: " + field_name); + throw InvalidFormatError("parquet file is missing the index column: " + + field_name); } return Util::Query::Builder(index_field.value()); @@ -155,7 +156,7 @@ Signals::select(const std::vector& projection, auto field = impl_->array_index_->entry_column(*impl_->parquet_->groups(), entry); if (!field.has_value()) { - throw ParquetError("array entry not present in schema: " + entry.name); + throw InvalidFormatError("array entry not present in schema: " + entry.name); } else { columns.project(field.value()); } diff --git a/src/index.cpp b/src/index.cpp index e1c0f45..e2ae27b 100644 --- a/src/index.cpp +++ b/src/index.cpp @@ -39,7 +39,7 @@ Spectra Index::spectra() const auto data_it = manager_->find_file("spectra_data.parquet"); if (data_it == manager_->files().end()) { - throw ParquetError("missing files: spectra_data.parquet"); + throw InvalidFormatError("missing files: spectra_data.parquet"); } std::unique_ptr data = diff --git a/src/io/zip.cpp b/src/io/zip.cpp index 41ff62c..b5e1247 100644 --- a/src/io/zip.cpp +++ b/src/io/zip.cpp @@ -8,6 +8,7 @@ directory of this repository. #include +#include "mzpeak/exception.h" #include "mzpeak/io/zip.h" namespace MzPeak::IO { @@ -130,7 +131,7 @@ struct Zip::Impl { } m += zip_error_strerror(error_ptr); - throw(std::invalid_argument(m)); + throw(InvalidFormatError(m)); } /**************************************************************************/ From 29e8a03f4a57b4b9efd0a66ef2dd339cbd06ddaa Mon Sep 17 00:00:00 2001 From: "Peter J. Jones" Date: Wed, 2 Sep 2026 16:19:32 +0200 Subject: [PATCH 4/4] Remove more uses of std::function --- include/mzpeak/util/query.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/mzpeak/util/query.h b/include/mzpeak/util/query.h index 949397c..01265bb 100644 --- a/include/mzpeak/util/query.h +++ b/include/mzpeak/util/query.h @@ -9,6 +9,7 @@ top-level directory of this repository. #pragma once #include +#include #include #include @@ -192,12 +193,14 @@ class Query final { /// A function that when given an column type, should return a single value. /// If this isn't possible it should return `Result::skip()`. - using eval_callback_t = std::function(Schema::Column)>; + using eval_callback_t = + boost::compat::function_ref(Schema::Column)>; /// A func ion that when given an column type should return a min /// and max. If this isn't possible it should return /// `Result::skip()`. - using eval_range_callback_t = std::function(Schema::Column)>; + using eval_range_callback_t = + boost::compat::function_ref(Schema::Column)>; /** * Evaluate a query.