From b58c08150853b8055093dc116d407ffd543f8ec8 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Mon, 30 Oct 2023 15:47:38 +1100 Subject: add locale-aware colation to db indexes --- src/locale/collation.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/locale/collation.cpp (limited to 'src/locale/collation.cpp') diff --git a/src/locale/collation.cpp b/src/locale/collation.cpp new file mode 100644 index 00000000..f5e8272a --- /dev/null +++ b/src/locale/collation.cpp @@ -0,0 +1,92 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "collation.hpp" + +#include +#include + +#include "esp_flash_spi_init.h" +#include "esp_log.h" +#include "esp_partition.h" +#include "hal/spi_flash_types.h" +#include "spi_flash_mmap.h" +#include "strxfrm.h" + +namespace locale { + +static constexpr char kTag[] = "collate"; + +static constexpr esp_partition_type_t kLocalePartitionType = + static_cast(0x40); +static constexpr esp_partition_subtype_t kLcCollateSubtype = + static_cast(0x0); + +auto CreateCollator() -> std::unique_ptr { + std::unique_ptr ret{GLibCollator::create()}; + if (!ret) { + ret.reset(new NoopCollator()); + } + return ret; +} + +auto GLibCollator::create() -> GLibCollator* { + uint32_t data_pages = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA); + ESP_LOGI(kTag, "free data pages: %lu (%lu KiB)", data_pages, data_pages * 64); + + const esp_partition_t* partition = + esp_partition_find_first(kLocalePartitionType, kLcCollateSubtype, NULL); + if (partition == NULL) { + ESP_LOGW(kTag, "no LC_COLLATE partition found"); + } + + ESP_LOGI(kTag, "found LC_COLLATE partition of size %lu", partition->size); + if (partition->size > data_pages * 64 * 1024) { + ESP_LOGE(kTag, "not enough free pages to map LC_COLLATE partition!"); + return nullptr; + } + + const void* region; + esp_partition_mmap_handle_t handle; + esp_err_t err = esp_partition_mmap(partition, 0, partition->size, + ESP_PARTITION_MMAP_DATA, ®ion, &handle); + if (err != ESP_OK) { + ESP_LOGE(kTag, "LC_COLLATE mmap failed"); + return nullptr; + } + + auto data = std::make_unique(); + if (!parse_locale_data(region, partition->size, data.get())) { + ESP_LOGE(kTag, "parsing locale data failed"); + esp_partition_munmap(handle); + return nullptr; + } + + return new GLibCollator(handle, std::move(data)); +} + +GLibCollator::GLibCollator(const esp_partition_mmap_handle_t handle, + std::unique_ptr locale) + : handle_(handle), locale_data_(std::move(locale)) {} + +GLibCollator::~GLibCollator() { + esp_partition_munmap(handle_); +} + +auto GLibCollator::Transform(const std::string& in) -> std::string { + char dest[256]; + size_t size = glib_strxfrm(dest, in.c_str(), 256, locale_data_.get()); + if (size >= 256) { + char* larger_dest = new char[size + 1]{0}; + glib_strxfrm(larger_dest, in.c_str(), size, locale_data_.get()); + std::string out{larger_dest, size}; + delete[] larger_dest; + return out; + } + return {dest, size}; +} + +} // namespace locale -- cgit v1.2.3