Ticket #326: optimise_unpack_uint.patch

File optimise_unpack_uint.patch, 2.7 KB (added by Richard Boulton, 15 years ago)

Optimise the pack_uint function in chert with a specialised version for om_uint32

  • chert_utils.h

     
    109109    }
    110110}
    111111
     112inline bool
     113unpack_uint(const char ** src,
     114            const char * src_end,
     115            om_uint32 * resultptr)
     116{
     117    // Check byte is what it's meant to be
     118    STATIC_ASSERT(sizeof(om_byte) == 1);
    112119
     120    // Check om_uint32 is what it's meant to be
     121    STATIC_ASSERT_UNSIGNED_TYPE(om_uint32);
     122    STATIC_ASSERT(sizeof(om_uint32) == 4);
     123
     124    om_byte part;
     125    om_uint32 result = 0;
     126    if (src_end - *src >= 5 || (src_end - *src > 0 && !(src_end[-1] & 0x80))) {
     127        // No need to check src_end again, can't run off end.
     128        part = static_cast<om_byte>(**src);
     129        result = (part & 0x7f);
     130        if (part & 0x80) {
     131            part = static_cast<om_byte>((*src)[1]);
     132            result |= ((part & 0x7f) << 7);
     133            if (part & 0x80) {
     134                part = static_cast<om_byte>((*src)[2]);
     135                result |= ((part & 0x7f) << 14);
     136                if (part & 0x80) {
     137                    part = static_cast<om_byte>((*src)[3]);
     138                    result |= ((part & 0x7f) << 21);
     139                    if (part & 0x80) {
     140                        part = static_cast<om_byte>((*src)[4]);
     141                        if (part & 0xf0) {
     142                            *src += 5;
     143                            goto overflow;
     144                        }
     145                        result |= ((part & 0x0f) << 28);
     146                        *src += 5;
     147                    } else {
     148                        *src += 4;
     149                    }
     150                } else {
     151                    *src += 3;
     152                }
     153            } else {
     154                *src += 2;
     155            }
     156        } else {
     157            (*src)++;
     158        }
     159        if (resultptr) *resultptr = result;
     160        return true;
     161    } else {
     162        // Slow path - need to check end at each step.
     163        // Should be rare for this to be called, though.
     164
     165        unsigned int shift = 0;
     166
     167        while (true) {
     168            if ((*src) == src_end) {
     169                *src = 0;
     170                return false;
     171            }
     172
     173            part = static_cast<om_byte>(**src);
     174            (*src)++;
     175
     176            // if new byte might cause overflow, and it does
     177            if (((shift > (sizeof(om_uint32) - 1) * 8 + 1) &&
     178                 ((part & 0x7f) << (shift % 8)) >= 0x100) ||
     179                (shift >= sizeof(om_uint32) * 8))  {
     180                // Overflowed - move to end of this integer
     181                while (true) {
     182                    if ((part & 0x80) == 0) return false;
     183                    if ((*src) == src_end) {
     184                        *src = 0;
     185                        return false;
     186                    }
     187                    part = static_cast<om_byte>(**src);
     188                    (*src)++;
     189                }
     190            }
     191
     192            result += om_uint32(part & 0x7f) << shift;
     193            shift += 7;
     194
     195            if ((part & 0x80) == 0) {
     196                if (resultptr) *resultptr = result;
     197                return true;
     198            }
     199        }
     200    }
     201
     202overflow:
     203    // Overflowed - move to end of this integer
     204    while (true) {
     205        if ((*src) == src_end) {
     206            *src = 0;
     207            return false;
     208        }
     209        part = static_cast<om_byte>(**src);
     210        (*src)++;
     211        if ((part & 0x80) == 0) return false;
     212    }
     213}
     214
    113215/** Generates a packed representation of an integer.
    114216 *
    115217 *  @param value  The integer to represent.