Modo de entrada

Cada línea es una entrada del índice — una celda (idioma × ID). Las cadenas idénticas y los sufijos se fusionan.

Ancho de puntero
0 Entradas de índice
0 Tras dedup
0 Tras tail-merge
0 Tamaño del pool
Tabla de punteros
Tabla de índice
Blob de cadenas
Total
Relocations
Pool empaquetado (uint16)
Tabla de índice
Blob de cadenas
Total
Relocations

Toda cadena — almacenada o tail-merged — se lee con pool + offset, así que la recuperación es O(1) e idéntica independientemente de la fusión.

Desglose por cadena
CadenaAparicionesOffsetBytes en poolEstado

Todo se ejecuta en tu navegador — no se sube nada.

Sobre esta herramienta

El firmware que muestra texto de UI en varios idiomas suele guardarlo como una tabla 2-D de punteros const char* — uno por celda (idioma × ID de cadena). En un MCU de 32 bits cada puntero son 4 bytes de puro coste de índice, antes de un solo carácter de texto. Esta herramienta muestra lo que ahorras al pasar a un único pool de cadenas empaquetado más una tabla de offsets uint16 de 2 bytes, con las cadenas idénticas deduplicadas y los sufijos tail-merged dentro de cadenas más largas.

Es el complemento interactivo del artículo

What the Linker Won’t Do: Packing i18n Strings on an MCU

.

Dos modos

  • Líneas — pega cadenas una por línea; cada línea es una entrada del índice (una celda idioma × ID).

  • CSV — el formato real del firmware: una cabecera id,en,es,… y una fila por ID de cadena, una columna por idioma. Cada celda es una entrada del índice, y un lookup por identificador × idioma simula el tr() del firmware: eliges un ID y un idioma y la herramienta muestra el offset y la cadena resueltos (gen::string(lang, id)pool + offset).

¿Cómo se usa?

  1. Elige el modo Líneas o CSV y pega tus datos (usa Cargar ejemplo como punto de partida).

  2. Elige el ancho de puntero de tu objetivo (4 bytes para un MCU de 32 bits, 8 bytes para un host de 64 bits).

  3. Lee la comparación: bytes de la tabla de índice, bytes del blob de cadenas y el total para el enfoque de tabla de punteros y el de pool empaquetado.

  4. Revisa el desglose por cadena — con el offset en bytes de cada una — para ver cuáles se deduplicaron y cuáles se fusionaron por sufijo (tail-merge) dentro de una cadena más larga (su offset apunta dentro de esa entrada más larga).

¿Qué calcula?

  • Tabla de índice — entradas × 4 B (punteros) frente a entradas × 2 B (offsets uint16). Esta reducción a la mitad es la ganancia estructural que ningún linker hace por ti.

  • Dedup — las cadenas idénticas (compartidas entre idiomas, como “OK”) se guardan una sola vez.

  • Tail-merge — una cadena que es el sufijo de otra reutiliza los bytes de la más larga (colocada primero la más larga), justo lo que hace el generador en tiempo de compilación.

  • Guardia uint16 — avisa cuando el pool supera los 64 KiB, punto en el que los offsets ya no caben en un uint16.

  • Recuperación — toda cadena, almacenada o tail-merged, se lee con pool + offset. Una cadena tail-merged nunca se guarda aparte; su offset simplemente cae dentro de una entrada más larga, así que la búsqueda sigue siendo O(1) e idéntica para todas.

¿Mis datos son privados?

Todo el análisis, la deduplicación, el tail-merge y el conteo de bytes ocurren por completo en tu navegador. Nada de lo que escribes se transmite a ningún servidor.

Preguntas frecuentes

¿Por qué las tablas de punteros const char* desperdician tanta flash en un MCU?

Cada celda de una tabla 2-D (idioma × ID de cadena) guarda un puntero, que son 4 bytes en un MCU de 32 bits antes de un solo carácter de texto. Pasar a una tabla de offsets uint16 reduce ese coste de índice a la mitad, una ganancia estructural que el linker no hace por ti.

¿Cuánto puede ahorrar un pool de cadenas empaquetado y tail-merged frente a una tabla de punteros?

El ahorro viene de tres sitios: reducir el índice a la mitad (de punteros de 4 bytes a offsets uint16 de 2 bytes), deduplicar las cadenas idénticas compartidas entre idiomas y fusionar por sufijo las cadenas que son sufijo de otras más largas. Pega tus cadenas reales para ver el total exacto de bytes de ambos formatos.

¿Qué es el tail-merge en un pool de cadenas?

El tail-merge guarda una cadena que es el sufijo de otra más larga apuntando su offset dentro de esa entrada más larga, en lugar de almacenarla aparte. Las cadenas se colocan primero las más largas para que el sufijo más corto reutilice los mismos bytes.

¿Cuándo dejan de funcionar los offsets uint16 en un pool de cadenas?

Los offsets uint16 solo pueden direccionar los primeros 64 KiB del pool. La herramienta avisa cuando tu pool supera ese límite, momento en el que necesitarías offsets más anchos para alcanzar las cadenas posteriores.

¿Esta herramienta envía mis cadenas a un servidor?

No. Todo el análisis, la deduplicación, el tail-merge y el conteo de bytes ocurren por completo en tu navegador, y nada de lo que escribes se transmite a ningún sitio.