summaryrefslogtreecommitdiff
path: root/src/locale/collation.cpp
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-10-30 15:47:38 +1100
committerjacqueline <me@jacqueline.id.au>2023-10-30 15:52:26 +1100
commitb58c08150853b8055093dc116d407ffd543f8ec8 (patch)
tree9b82d130d2c833fc234bca0f12f0fba1b7202c4d /src/locale/collation.cpp
parent18d90051c9145ead86d4da701a2bc54f45e4fb66 (diff)
downloadtangara-fw-b58c08150853b8055093dc116d407ffd543f8ec8.tar.gz
add locale-aware colation to db indexes
Diffstat (limited to 'src/locale/collation.cpp')
-rw-r--r--src/locale/collation.cpp92
1 files changed, 92 insertions, 0 deletions
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 <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "collation.hpp"
+
+#include <stdint.h>
+#include <memory>
+
+#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<esp_partition_type_t>(0x40);
+static constexpr esp_partition_subtype_t kLcCollateSubtype =
+ static_cast<esp_partition_subtype_t>(0x0);
+
+auto CreateCollator() -> std::unique_ptr<ICollator> {
+ std::unique_ptr<ICollator> 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, &region, &handle);
+ if (err != ESP_OK) {
+ ESP_LOGE(kTag, "LC_COLLATE mmap failed");
+ return nullptr;
+ }
+
+ auto data = std::make_unique<locale_data_t>();
+ 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_data_t> 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