@@ -117,18 +117,28 @@ static double graymodel_interpolate(struct graymodel *gm, double x, double y)
117117 return gm -> C [0 ]* x + gm -> C [1 ]* y + gm -> C [2 ];
118118}
119119
120- struct quick_decode_entry
120+ // Uses pragma to ensure this occupies exactly 3 bytes (no padding).
121+ #pragma pack(push, 1)
122+ struct quick_decode_val
121123{
122- uint64_t rcode ; // the queried code
123- uint16_t id ; // the tag ID (a small integer)
124- uint8_t hamming ; // how many errors corrected?
125- uint8_t rotation ; // number of rotations [0, 3]
124+ uint16_t id ;
125+ uint8_t hamming ;
126126};
127+ #pragma pack(pop)
127128
128129struct quick_decode
129130{
130131 int nentries ;
131- struct quick_decode_entry * entries ;
132+ uint64_t * keys ;
133+ struct quick_decode_val * values ;
134+ };
135+
136+ struct quick_decode_entry
137+ {
138+ uint64_t rcode ;
139+ uint16_t id ;
140+ uint8_t hamming ;
141+ uint8_t rotation ;
132142};
133143
134144/**
@@ -173,13 +183,13 @@ static void quick_decode_add(struct quick_decode *qd, uint64_t code, int id, int
173183{
174184 uint32_t bucket = code % qd -> nentries ;
175185
176- while (qd -> entries [bucket ]. rcode != UINT64_MAX ) {
186+ while (qd -> keys [bucket ] != UINT64_MAX ) {
177187 bucket = (bucket + 1 ) % qd -> nentries ;
178188 }
179189
180- qd -> entries [bucket ]. rcode = code ;
181- qd -> entries [bucket ].id = id ;
182- qd -> entries [bucket ].hamming = hamming ;
190+ qd -> keys [bucket ] = code ;
191+ qd -> values [bucket ].id = ( uint16_t ) id ;
192+ qd -> values [bucket ].hamming = ( uint8_t ) hamming ;
183193}
184194
185195static void quick_decode_uninit (apriltag_family_t * fam )
@@ -188,7 +198,8 @@ static void quick_decode_uninit(apriltag_family_t *fam)
188198 return ;
189199
190200 struct quick_decode * qd = (struct quick_decode * ) fam -> impl ;
191- free (qd -> entries );
201+ free (qd -> keys );
202+ free (qd -> values );
192203 free (qd );
193204 fam -> impl = NULL ;
194205}
@@ -198,9 +209,9 @@ static void quick_decode_init(apriltag_family_t *family, int maxhamming)
198209 assert (family -> impl == NULL );
199210 assert (family -> ncodes < 65536 );
200211
201- struct quick_decode * qd = calloc (1 , sizeof (struct quick_decode ));
212+ struct quick_decode * qd = (struct quick_decode * )calloc (1 , sizeof (struct quick_decode ));
213+
202214 int capacity = family -> ncodes ;
203-
204215 int nbits = family -> nbits ;
205216
206217 if (maxhamming >= 1 )
@@ -214,81 +225,49 @@ static void quick_decode_init(apriltag_family_t *family, int maxhamming)
214225
215226 qd -> nentries = capacity * 3 ;
216227
217- // debug_print("capacity %d, size: %.0f kB\n",
218- // capacity, qd->nentries * sizeof(struct quick_decode_entry) / 1024.0 );
228+ qd -> keys = ( uint64_t * ) malloc ( qd -> nentries * sizeof ( uint64_t ));
229+ qd -> values = ( struct quick_decode_val * ) malloc ( qd -> nentries * sizeof (struct quick_decode_val ) );
219230
220- qd -> entries = calloc (qd -> nentries , sizeof (struct quick_decode_entry ));
221- if (qd -> entries == NULL ) {
222- debug_print ("Failed to allocate hamming decode table\n" );
223- // errno already set to ENOMEM (Error No MEMory) by calloc() failure
231+ if (qd -> keys == NULL || qd -> values == NULL ) {
232+ // debug_print("Failed to allocate hamming decode table\n");
233+ if (qd -> keys ) free (qd -> keys );
234+ if (qd -> values ) free (qd -> values );
235+ free (qd );
224236 return ;
225237 }
226238
227- for (int i = 0 ; i < qd -> nentries ; i ++ )
228- qd -> entries [i ].rcode = UINT64_MAX ;
239+ for (int i = 0 ; i < qd -> nentries ; i ++ ) {
240+ qd -> keys [i ] = UINT64_MAX ;
241+ }
229242
230243 errno = 0 ;
231244
232245 for (uint32_t i = 0 ; i < family -> ncodes ; i ++ ) {
233246 uint64_t code = family -> codes [i ];
234247
235- // add exact code (hamming = 0)
248+ // Hamming 0
236249 quick_decode_add (qd , code , i , 0 );
237250
238251 if (maxhamming >= 1 ) {
239- // add hamming 1
240252 for (int j = 0 ; j < nbits ; j ++ )
241253 quick_decode_add (qd , code ^ (APRILTAG_U64_ONE << j ), i , 1 );
242254 }
243255
244256 if (maxhamming >= 2 ) {
245- // add hamming 2
246257 for (int j = 0 ; j < nbits ; j ++ )
247258 for (int k = 0 ; k < j ; k ++ )
248259 quick_decode_add (qd , code ^ (APRILTAG_U64_ONE << j ) ^ (APRILTAG_U64_ONE << k ), i , 2 );
249260 }
250261
251262 if (maxhamming >= 3 ) {
252- // add hamming 3
253- for (int j = 0 ; j < nbits ; j ++ )
263+ for (int j = 0 ; j < nbits ; j ++ )
254264 for (int k = 0 ; k < j ; k ++ )
255265 for (int m = 0 ; m < k ; m ++ )
256266 quick_decode_add (qd , code ^ (APRILTAG_U64_ONE << j ) ^ (APRILTAG_U64_ONE << k ) ^ (APRILTAG_U64_ONE << m ), i , 3 );
257267 }
258-
259- if (maxhamming > 3 ) {
260- debug_print ("\"maxhamming\" beyond 3 not supported\n" );
261- // set errno to Error INvalid VALue
262- errno = EINVAL ;
263- return ;
264- }
265268 }
266269
267270 family -> impl = qd ;
268-
269- #if 0
270- int longest_run = 0 ;
271- int run = 0 ;
272- int run_sum = 0 ;
273- int run_count = 0 ;
274-
275- // This accounting code doesn't check the last possible run that
276- // occurs at the wrap-around. That's pretty insignificant.
277- for (int i = 0 ; i < qd -> nentries ; i ++ ) {
278- if (qd -> entries [i ].rcode == UINT64_MAX ) {
279- if (run > 0 ) {
280- run_sum += run ;
281- run_count ++ ;
282- }
283- run = 0 ;
284- } else {
285- run ++ ;
286- longest_run = imax (longest_run , run );
287- }
288- }
289-
290- printf ("quick decode: longest run: %d, average run %.3f\n" , longest_run , 1.0 * run_sum / run_count );
291- #endif
292271}
293272
294273// returns an entry with hamming set to 255 if no decode was found.
@@ -297,18 +276,22 @@ static void quick_decode_codeword(apriltag_family_t *tf, uint64_t rcode,
297276{
298277 struct quick_decode * qd = (struct quick_decode * ) tf -> impl ;
299278
300- // qd might be null if detector_add_family_bits() failed
279+ // qd might be null if init failed
301280 for (int ridx = 0 ; qd != NULL && ridx < 4 ; ridx ++ ) {
302-
303- for (int bucket = rcode % qd -> nentries ;
304- qd -> entries [bucket ].rcode != UINT64_MAX ;
305- bucket = (bucket + 1 ) % qd -> nentries ) {
306-
307- if (qd -> entries [bucket ].rcode == rcode ) {
308- * entry = qd -> entries [bucket ];
281+
282+ uint32_t bucket = rcode % qd -> nentries ;
283+
284+ while (qd -> keys [bucket ] != UINT64_MAX ) {
285+
286+ if (qd -> keys [bucket ] == rcode ) {
287+ entry -> rcode = rcode ;
288+ entry -> id = qd -> values [bucket ].id ;
289+ entry -> hamming = qd -> values [bucket ].hamming ;
309290 entry -> rotation = ridx ;
310291 return ;
311292 }
293+
294+ bucket = (bucket + 1 ) % qd -> nentries ;
312295 }
313296
314297 rcode = rotate90 (rcode , tf -> nbits );
0 commit comments