diff --git a/CHANGELOG.md b/CHANGELOG.md index 762dbbe6f..c40664a6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ The release run heads these entries with the version and opens a fresh ## Unreleased +- **Breaking**: `all_file_types()` and `all_text_encodings()` return a + `std::span` over the library's tables instead of a `std::vector`, like the + other table lookups. The bindings still hand out a list. + - `HtmlConfig::editing_scope` narrows the document view's editor to edits inside one paragraph (`paragraph`); the page refuses the rest with the new `ErrorCode::edit_out_of_scope` (1010, `outOfScope`). Bound in every binding. diff --git a/apple/src/ODROdr.mm b/apple/src/ODROdr.mm index b97a821a9..9898193ff 100644 --- a/apple/src/ODROdr.mm +++ b/apple/src/ODROdr.mm @@ -55,7 +55,7 @@ + (NSString *)identification { + (NSArray *)allFileTypes { return guarded_value( [&]() -> NSArray * { - const std::vector types = odr::all_file_types(); + const std::span types = odr::all_file_types(); NSMutableArray *const result = [NSMutableArray arrayWithCapacity:types.size()]; for (const odr::FileType type : types) { @@ -149,7 +149,7 @@ + (ODRFileTypeCapabilities *)capabilitiesForFileType:(ODRFileType)type { + (NSArray *)allTextEncodings { return guarded_value( [&]() -> NSArray * { - const std::vector encodings = + const std::span encodings = odr::all_text_encodings(); NSMutableArray *const result = [NSMutableArray arrayWithCapacity:encodings.size()]; diff --git a/python/src/bind_core.cpp b/python/src/bind_core.cpp index d63bcee93..58f8bc81b 100644 --- a/python/src/bind_core.cpp +++ b/python/src/bind_core.cpp @@ -63,10 +63,22 @@ void odr_python::bind_core(py::module_ &m) { } void odr_python::bind_functions(py::module_ &m) { - m.def("all_file_types", &odr::all_file_types, - "Every file type this library knows about."); - m.def("all_text_encodings", &odr::all_text_encodings, - "Every text encoding the library knows about, excluding `unknown`."); + // pybind11 has no caster for a span + m.def( + "all_file_types", + [] { + const auto types = odr::all_file_types(); + return std::vector(types.begin(), types.end()); + }, + "Every file type this library knows about."); + m.def( + "all_text_encodings", + [] { + const auto encodings = odr::all_text_encodings(); + return std::vector(encodings.begin(), + encodings.end()); + }, + "Every text encoding the library knows about, excluding `unknown`."); m.def( "text_encoding_to_string", [](const odr::TextEncoding encoding) { diff --git a/src/odr/internal/csv/PLAN.md b/src/odr/internal/csv/PLAN.md index 2ceaf4a2c..eff9063fb 100644 --- a/src/odr/internal/csv/PLAN.md +++ b/src/odr/internal/csv/PLAN.md @@ -75,7 +75,7 @@ fails when an alias is claimed twice. enum class TextEncoding { unknown, utf8, utf16le, utf16be, utf32le, utf32be, windows_1252, iso_8859_1, iso_8859_15, shift_jis, … }; -std::vector all_text_encodings(); +std::span all_text_encodings() noexcept; std::string text_encoding_to_string(TextEncoding); TextEncoding text_encoding_by_name(std::string_view) noexcept; // unknown if none std::span text_encoding_names(TextEncoding) noexcept; diff --git a/src/odr/internal/encoding/text_encoding_table.cpp b/src/odr/internal/encoding/text_encoding_table.cpp index 833438403..49145ff52 100644 --- a/src/odr/internal/encoding/text_encoding_table.cpp +++ b/src/odr/internal/encoding/text_encoding_table.cpp @@ -4,6 +4,7 @@ #include #include +#include #include namespace odr::internal::encoding { @@ -133,12 +134,24 @@ std::string normalize(const std::string_view name) { return result; } +constexpr auto encodings_column = [] { + std::array result{}; + for (std::size_t i = 0; i < table.size(); ++i) { + result[i] = table[i].encoding; + } + return result; +}(); + } // namespace std::span text_encoding_table::rows() noexcept { return table; } +std::span text_encoding_table::encodings() noexcept { + return encodings_column; +} + const text_encoding_table::Row * text_encoding_table::find(const TextEncoding encoding) noexcept { const auto it = std::ranges::find(table, encoding, &Row::encoding); diff --git a/src/odr/internal/encoding/text_encoding_table.hpp b/src/odr/internal/encoding/text_encoding_table.hpp index 81d518a9a..13a79f8a2 100644 --- a/src/odr/internal/encoding/text_encoding_table.hpp +++ b/src/odr/internal/encoding/text_encoding_table.hpp @@ -16,6 +16,8 @@ struct Row final { /// The whole table, one row per @ref TextEncoding, in declaration order. [[nodiscard]] std::span rows() noexcept; +/// The encoding column of @ref rows. +[[nodiscard]] std::span encodings() noexcept; /// The row for @p encoding, or `nullptr` if there is none. [[nodiscard]] const Row *find(TextEncoding encoding) noexcept; diff --git a/src/odr/internal/file_type_table.cpp b/src/odr/internal/file_type_table.cpp index 435a0c6d1..a7520c5bb 100644 --- a/src/odr/internal/file_type_table.cpp +++ b/src/odr/internal/file_type_table.cpp @@ -2,6 +2,7 @@ #include #include +#include namespace odr::internal { @@ -831,12 +832,24 @@ const Row *find_by_alias(const std::string_view needle, return it == std::ranges::end(table) ? nullptr : &*it; } +constexpr auto types_column = [] { + std::array result{}; + for (std::size_t i = 0; i < table.size(); ++i) { + result[i] = table[i].type; + } + return result; +}(); + } // namespace std::span file_type_table::rows() noexcept { return table; } +std::span file_type_table::types() noexcept { + return types_column; +} + const file_type_table::Row * file_type_table::find(const FileType type) noexcept { const auto it = std::ranges::find(table, type, &Row::type); diff --git a/src/odr/internal/file_type_table.hpp b/src/odr/internal/file_type_table.hpp index 9e641ab10..754fe12fb 100644 --- a/src/odr/internal/file_type_table.hpp +++ b/src/odr/internal/file_type_table.hpp @@ -20,6 +20,8 @@ struct Row final { /// The whole table, one row per @ref FileType, in declaration order. [[nodiscard]] std::span rows() noexcept; +/// The type column of @ref rows. +[[nodiscard]] std::span types() noexcept; /// The row for @p type, or `nullptr` if there is none. [[nodiscard]] const Row *find(FileType type) noexcept; diff --git a/src/odr/odr.cpp b/src/odr/odr.cpp index bcfab2a67..247cc5475 100644 --- a/src/odr/odr.cpp +++ b/src/odr/odr.cpp @@ -11,8 +11,6 @@ #include #include -#include -#include #include #include @@ -40,11 +38,8 @@ std::string odr::identify() noexcept { (is_dirty() ? " [dirty]" : "") + (is_debug() ? " [debug]" : ""); } -std::vector odr::all_file_types() { - std::vector result; - result.reserve(table::rows().size()); - std::ranges::transform(table::rows(), std::back_inserter(result), &Row::type); - return result; +std::span odr::all_file_types() noexcept { + return table::types(); } odr::FileType @@ -152,12 +147,8 @@ odr::capabilities_by_file_type(const FileType type) noexcept { return row == nullptr ? FileTypeCapabilities{} : row->capabilities; } -std::vector odr::all_text_encodings() { - std::vector result; - result.reserve(encoding_table::rows().size()); - std::ranges::transform(encoding_table::rows(), std::back_inserter(result), - &EncodingRow::encoding); - return result; +std::span odr::all_text_encodings() noexcept { + return encoding_table::encodings(); } std::string_view odr::text_encoding_to_string(const TextEncoding encoding) { diff --git a/src/odr/odr.hpp b/src/odr/odr.hpp index c6fb3a0cc..dbe79c769 100644 --- a/src/odr/odr.hpp +++ b/src/odr/odr.hpp @@ -23,7 +23,7 @@ namespace odr { /// Every file type this library knows about, in declaration order, including /// @ref FileType::unknown. -[[nodiscard]] std::vector all_file_types(); +[[nodiscard]] std::span all_file_types() noexcept; /// The file type for a file extension, @ref FileType::unknown if none. [[nodiscard]] FileType @@ -66,7 +66,7 @@ capabilities_by_file_type(FileType type) noexcept; /// Every text encoding this library knows about, in declaration order, /// excluding @ref TextEncoding::unknown. -[[nodiscard]] std::vector all_text_encodings(); +[[nodiscard]] std::span all_text_encodings() noexcept; /// The text encoding's canonical name, a label a browser accepts. /// @throws UnsupportedTextEncoding for @ref TextEncoding::unknown. diff --git a/test/src/odr_test.cpp b/test/src/odr_test.cpp index e32275895..f8067266c 100644 --- a/test/src/odr_test.cpp +++ b/test/src/odr_test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -115,9 +116,9 @@ TEST(odr, a_named_file_in_memory_is_offered_its_type) { TEST(FileTypeTable, covers_every_file_type_exactly_once) { const std::vector expected = every_file_type(); - const std::vector actual = all_file_types(); + const std::span actual = all_file_types(); - EXPECT_EQ(actual, expected); + EXPECT_TRUE(std::ranges::equal(actual, expected)); for (const FileType type : expected) { EXPECT_NE(file_type_to_string(type), "unnamed")