Optimize is_diacritic

is_diacritic is used for pretty much all of the text display sizing
Timing here matters, so important it uses a
priority buffer in order to cut down on searching the database.

This patch is verified functionally equlivalent but
saves 80 bytes and is ~20% faster for the clip+ I tested it on

Several things were done:

Optimizing the copy loop for the priority buffer

Globbing some operations together

but the main one has to do with the database structure its self
--
Rather than a bit packed struct it combines the lower 8 bytes into
one value [info] and uses flags to access the values instead

Change-Id: I475073419b647639ef1eeaa3b9213e4e1067c0db
This commit is contained in:
William Wilgus 2017-11-09 18:03:33 +01:00
parent dd40c46d50
commit b977b77fb7

View file

@ -10,6 +10,7 @@
* Copyright (C) 2009 Phinitnun Chanasabaeng * Copyright (C) 2009 Phinitnun Chanasabaeng
* Initial work * Initial work
* Copyright (C) 2009 Tomer Shalev * Copyright (C) 2009 Tomer Shalev
* Copyright (C) 2018 William Wilgus
* *
* Rockbox diacritic positioning * Rockbox diacritic positioning
* Based on initial work by Phinitnun Chanasabaeng * Based on initial work by Phinitnun Chanasabaeng
@ -27,19 +28,23 @@
#include "system.h" #include "system.h"
#define DIAC_NUM_RANGES (ARRAYLEN(diac_ranges)) #define DIAC_NUM_RANGES (ARRAYLEN(diac_ranges))
#define DIAC_RTL (1 << 7)
#define DIAC_CNT (0xFF ^ DIAC_RTL)
/* Each diac_range_ struct defines a Unicode range that begins with /* Each diac_range_ struct defines a Unicode range that begins with
* N diacritic characters, and continues with non-diacritic characters up to the * N diacritic characters, and continues with non-diacritic characters up to the
* base of the next item in the array */ * base of the next item in the array, [info] packs RTL status and the count of
* diacritic chars after [base]. RTL occupies the MSB and CNT the (7) lower bits
*/
struct diac_range struct diac_range
{ {
unsigned base : 16; uint16_t base;
unsigned num_diacritics : 7; uint8_t info; /* [RTL:1 CNT:7] */
unsigned is_rtl : 1;
}; };
#define DIAC_RANGE_ENTRY(first_diac, first_non_diac, is_rtl) \ #define DIAC_RANGE_ENTRY(first_diac, first_non_diac, is_rtl) \
{ first_diac, first_non_diac - first_diac, is_rtl } { first_diac, ((first_non_diac - first_diac) & DIAC_CNT) | (is_rtl * DIAC_RTL)}
/* Sorted by Unicode value */ /* Sorted by Unicode value */
static const struct diac_range diac_ranges[] = static const struct diac_range diac_ranges[] =
@ -190,22 +195,28 @@ static const struct diac_range diac_ranges[] =
#define MRU_MAX_LEN 32 #define MRU_MAX_LEN 32
static unsigned short mru_len = 0;
static unsigned short diacritic_mru[MRU_MAX_LEN];
bool is_diacritic(const unsigned short char_code, bool *is_rtl) bool is_diacritic(const unsigned short char_code, bool *is_rtl)
{ {
unsigned short mru, i; static uint8_t mru_len = 0;
static uint8_t diacritic_mru[MRU_MAX_LEN];
uint8_t i, itmp;
uint8_t info, mru;
const struct diac_range *diac; const struct diac_range *diac;
/* Search in MRU */ /* Search in MRU */
for (mru = 0; mru < mru_len; mru++) for (mru = 0, i = 0; mru < mru_len; mru++)
{ {
/* Items shifted >> 1 */
itmp = i;
i = diacritic_mru[mru]; i = diacritic_mru[mru];
diacritic_mru[mru] = itmp;
/* Found in MRU */ /* Found in MRU */
if (diac_ranges[i].base <= char_code && if ((char_code >= (diac = &diac_ranges[i])->base)
char_code < diac_ranges[i + 1].base) && (char_code < (++diac)->base))
{ {
goto Found; goto Found;
} }
@ -219,23 +230,21 @@ bool is_diacritic(const unsigned short char_code, bool *is_rtl)
break; break;
} }
/* Add MRU entry, or overwrite LRU if MRU array is full */ /* Add MRU entry */
if (mru_len < MRU_MAX_LEN) if (mru_len < MRU_MAX_LEN)
mru_len++; mru_len++;
else
mru--;
Found: Found:
/* Promote MRU item to top of MRU */ /* Promote MRU item to top of MRU */
for ( ; mru > 0; mru--)
diacritic_mru[mru] = diacritic_mru[mru - 1];
diacritic_mru[0] = i; diacritic_mru[0] = i;
diac = &diac_ranges[i]; diac = &diac_ranges[i];
info = diac->info;
/* Update RTL */ /* Update RTL */
if (is_rtl) if (is_rtl)
*is_rtl = diac->is_rtl; *is_rtl = ((DIAC_RTL & info) == DIAC_RTL);
return (char_code < diac->base + diac->num_diacritics); return (char_code < diac->base + (info & DIAC_CNT));
} }