@@ -150,7 +150,7 @@ void _TestAssert(int iCondition, const char* cstrFile, int iLine) {
150150#define IS_RESTRICTED (m ) (TERRITORY_BOUNDARIES[m].flags & 512) // Territory has access restrictions (bit 9)
151151#define IS_SPECIAL_SHAPE (m ) (TERRITORY_BOUNDARIES[m].flags & 1024) // Territory has non-standard shape (bit 10)
152152#define REC_TYPE (m ) ((TERRITORY_BOUNDARIES[m].flags >> 7) & 3) // Record type (bits 7-8): grid encoding method
153- #define SMART_DIV (m ) (TERRITORY_BOUNDARIES[m].flags >> 16) // Smart divider value (bits 16+): grid subdivision
153+ #define SMART_DIV (m ) ((int)((unsigned int)( TERRITORY_BOUNDARIES[m].flags) >> 16)) // Smart divider value (bits 16+): grid subdivision
154154#define HEADER_LETTER (m ) (ENCODE_CHARS[(TERRITORY_BOUNDARIES[m].flags >> 11) & 31]) // Header letter for encoding (bits 11-15)
155155
156156/**
@@ -337,6 +337,81 @@ static const char ENCODE_CHARS[34] = {
337337};
338338
339339
340+ ///////////////////////////////////////////////////////////////////////////////////////////////
341+ //
342+ // PRECOMPUTED COMPANION TABLES
343+ //
344+ // Derived once from TERRITORY_BOUNDARIES.flags; queried in hot encode/decode loops
345+ // to avoid repeated bit-masking on the same record per iteration.
346+ //
347+ ///////////////////////////////////////////////////////////////////////////////////////////////
348+
349+ #define KIND_BIT_NAMELESS 0x01u
350+ #define KIND_BIT_RESTRICTED 0x02u
351+ #define KIND_BIT_SPECIAL_SHAPE 0x04u
352+
353+ static unsigned char RECORD_CODEX [MAPCODE_BOUNDARY_MAX + 1 ];
354+ static unsigned char RECORD_REC_TYPE [MAPCODE_BOUNDARY_MAX + 1 ];
355+ static unsigned char RECORD_KIND [MAPCODE_BOUNDARY_MAX + 1 ];
356+ static unsigned char RECORD_HEADER_LETTER [MAPCODE_BOUNDARY_MAX + 1 ];
357+ static unsigned short RECORD_SMART_DIV [MAPCODE_BOUNDARY_MAX + 1 ];
358+
359+ #define TERRITORY_TABLE_SIZE (_TERRITORY_MAX - _TERRITORY_MIN)
360+ static int TERRITORY_FIRST_NAMELESS [TERRITORY_TABLE_SIZE ];
361+ static int TERRITORY_NAMELESS_COUNT [TERRITORY_TABLE_SIZE ];
362+
363+ /* Not thread-safe for concurrent first call. Duplicate concurrent init writes
364+ identical values so results are logically correct, but callers must ensure
365+ the library is initialized before spawning threads, or initialize once
366+ explicitly on the main thread. */
367+ static int companion_initialized = 0 ;
368+
369+ static void initCompanionTables (void ) {
370+ int m ;
371+ int t ;
372+ if (companion_initialized ) {
373+ return ;
374+ }
375+ for (m = 0 ; m <= MAPCODE_BOUNDARY_MAX ; m ++ ) {
376+ const int flags = TERRITORY_BOUNDARIES [m ].flags ;
377+ const int c = flags & 31 ;
378+ const int codex_val = 10 * (c / 5 ) + ((c % 5 ) + 1 );
379+ const int rec_type = (flags >> 7 ) & 3 ;
380+ unsigned char kind = 0 ;
381+ if (flags & 64 ) { kind |= KIND_BIT_NAMELESS ; }
382+ if (flags & 512 ) { kind |= KIND_BIT_RESTRICTED ; }
383+ if (flags & 1024 ) { kind |= KIND_BIT_SPECIAL_SHAPE ; }
384+ RECORD_CODEX [m ] = (unsigned char ) codex_val ;
385+ RECORD_REC_TYPE [m ] = (unsigned char ) rec_type ;
386+ RECORD_KIND [m ] = kind ;
387+ RECORD_HEADER_LETTER [m ] = (unsigned char ) ENCODE_CHARS [(flags >> 11 ) & 31 ];
388+ RECORD_SMART_DIV [m ] = (unsigned short ) ((unsigned int ) flags >> 16 );
389+ }
390+ for (t = 0 ; t < TERRITORY_TABLE_SIZE ; t ++ ) {
391+ TERRITORY_FIRST_NAMELESS [t ] = -1 ;
392+ TERRITORY_NAMELESS_COUNT [t ] = 0 ;
393+ }
394+ for (t = 0 ; t < TERRITORY_TABLE_SIZE - 1 ; t ++ ) {
395+ const int from = DATA_START [t ];
396+ const int upto_excl = DATA_START [t + 1 ];
397+ int i ;
398+ int first = -1 ;
399+ int count = 0 ;
400+ for (i = from ; i < upto_excl ; i ++ ) {
401+ if (RECORD_KIND [i ] & KIND_BIT_NAMELESS ) {
402+ if (first < 0 ) {
403+ first = i ;
404+ }
405+ count ++ ;
406+ }
407+ }
408+ TERRITORY_FIRST_NAMELESS [t ] = first ;
409+ TERRITORY_NAMELESS_COUNT [t ] = count ;
410+ }
411+ companion_initialized = 1 ;
412+ }
413+
414+
340415/**
341416 * @brief Convert ASCII character to base-31 value for mapcode decoding
342417 * @param ch ASCII character to decode
@@ -1578,6 +1653,7 @@ static int encodeLatLonToMapcodes_internal(Mapcodes* mapcodes,
15781653 enc .mapcodes -> count = 0 ;
15791654 ASSERT (mapcodes );
15801655 ASSERT ((0 <= extraDigits ) && (extraDigits <= MAX_PRECISION_DIGITS ));
1656+ initCompanionTables ();
15811657
15821658 if (convertCoordsToMicrosAndFractions (& enc .coord32 , & enc .fraclat , & enc .fraclon , lat , lon ) < 0 ) {
15831659 return 0 ;
@@ -2681,6 +2757,7 @@ static enum MapcodeError decoderEngine(DecodeRec* dec, int parseFlags) {
26812757 char * s ;
26822758 int wasAllDigits = 0 ;
26832759 ASSERT (dec );
2760+ initCompanionTables ();
26842761
26852762 // Parse the mapcode string into its components (territory, proper mapcode, extension)
26862763 err = parseMapcodeString (& dec -> mapcodeElements , dec -> orginput , parseFlags , dec -> context );
0 commit comments