mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			
		
			
				
	
	
		
			796 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			796 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
//
 | 
						|
//  pithy.c
 | 
						|
//  http://github.com/johnezang/pithy
 | 
						|
//  Licensed under the terms of the BSD License, as specified below.
 | 
						|
//
 | 
						|
 | 
						|
/*
 | 
						|
 Copyright (c) 2011, John Engelhart
 | 
						|
 | 
						|
 All rights reserved.
 | 
						|
 | 
						|
 Redistribution and use in source and binary forms, with or without
 | 
						|
 modification, are permitted provided that the following conditions are met:
 | 
						|
 | 
						|
 * Redistributions of source code must retain the above copyright
 | 
						|
 notice, this list of conditions and the following disclaimer.
 | 
						|
 | 
						|
 * Redistributions in binary form must reproduce the above copyright
 | 
						|
 notice, this list of conditions and the following disclaimer in the
 | 
						|
 documentation and/or other materials provided with the distribution.
 | 
						|
 | 
						|
 * Neither the name of the Zang Industries nor the names of its
 | 
						|
 contributors may be used to endorse or promote products derived from
 | 
						|
 this software without specific prior written permission.
 | 
						|
 | 
						|
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
						|
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
						|
 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
						|
 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
						|
 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
						|
 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 | 
						|
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
						|
 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 | 
						|
 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
						|
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
						|
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
*/
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdint.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
#if defined(__arm__) && defined(__ARM_NEON__)
 | 
						|
#include <arm_neon.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include "pithy.h"
 | 
						|
 | 
						|
#define kBlockLog   20ul
 | 
						|
#define kBlockSize  ((size_t)(1 << kBlockLog))
 | 
						|
 | 
						|
// The maximum size that can be compressed while still allowing for the worst case compression expansion.
 | 
						|
#define PITHY_UNCOMPRESSED_MAX_LENGTH 0xdb6db6bfu // 0xdb6db6bf == 3681400511, or 3510.857 Mbytes.
 | 
						|
 | 
						|
typedef const char *pithy_hashOffset_t;
 | 
						|
 | 
						|
enum {
 | 
						|
    PITHY_LITERAL            = 0,
 | 
						|
    PITHY_COPY_1_BYTE_OFFSET = 1,
 | 
						|
    PITHY_COPY_2_BYTE_OFFSET = 2,
 | 
						|
    PITHY_COPY_3_BYTE_OFFSET = 3
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
#if       defined (__GNUC__) && (__GNUC__ >= 3)
 | 
						|
#define PITHY_ATTRIBUTES(attr, ...)        __attribute__((attr, ##__VA_ARGS__))
 | 
						|
#define PITHY_EXPECTED(cond, expect)       __builtin_expect((long)(cond), (expect))
 | 
						|
#define PITHY_EXPECT_T(cond)               PITHY_EXPECTED(cond, 1u)
 | 
						|
#define PITHY_EXPECT_F(cond)               PITHY_EXPECTED(cond, 0u)
 | 
						|
#define PITHY_PREFETCH(ptr)                __builtin_prefetch(ptr)
 | 
						|
#else  // defined (__GNUC__) && (__GNUC__ >= 3) 
 | 
						|
#define PITHY_ATTRIBUTES(attr, ...)
 | 
						|
#define PITHY_EXPECTED(cond, expect)       (cond)
 | 
						|
#define PITHY_EXPECT_T(cond)               (cond)
 | 
						|
#define PITHY_EXPECT_F(cond)               (cond)
 | 
						|
#define PITHY_PREFETCH(ptr)
 | 
						|
#endif // defined (__GNUC__) && (__GNUC__ >= 3) 
 | 
						|
 | 
						|
#define PITHY_STATIC_INLINE        static inline PITHY_ATTRIBUTES(always_inline)
 | 
						|
#define PITHY_ALIGNED(x)                         PITHY_ATTRIBUTES(aligned(x))
 | 
						|
 | 
						|
#if defined(NS_BLOCK_ASSERTIONS) && !defined(NDEBUG)
 | 
						|
#define NDEBUG
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef NDEBUG
 | 
						|
#define DCHECK(condition)
 | 
						|
#else
 | 
						|
#define DCHECK(condition) do {                                                  \
 | 
						|
  if(PITHY_EXPECT_F(!(condition))) {                                            \
 | 
						|
    fprintf(stderr, "%s / %s @ %ld: Invalid parameter not satisfying: %s",      \
 | 
						|
    __FILE__, __PRETTY_FUNCTION__, (long)__LINE__, #condition); fflush(stderr); \
 | 
						|
    abort();                                                                    \
 | 
						|
    }                                                                           \
 | 
						|
  } while(0)
 | 
						|
#endif
 | 
						|
 | 
						|
PITHY_STATIC_INLINE const char *pithy_Parse32WithLimit(const char *p, const char *l, size_t *OUTPUT);
 | 
						|
PITHY_STATIC_INLINE char       *pithy_Encode32(char *ptr, uint32_t v);
 | 
						|
 | 
						|
PITHY_STATIC_INLINE uint32_t    pithy_GetUint32AtOffset(uint64_t v, uint32_t offset);
 | 
						|
PITHY_STATIC_INLINE uint32_t    pithy_HashBytes(uint32_t bytes, uint32_t shift);
 | 
						|
PITHY_STATIC_INLINE size_t      pithy_FindMatchLength(const char *s1, const char *s2, const char *s2_limit);
 | 
						|
PITHY_STATIC_INLINE char       *pithy_EmitLiteral(char *op, const char *literal, size_t len, int allow_fast_path);
 | 
						|
PITHY_STATIC_INLINE char       *pithy_EmitCopyGreaterThan63(char *op, size_t offset, size_t len);
 | 
						|
PITHY_STATIC_INLINE char       *pithy_EmitCopyLessThan63(char *op, size_t offset, size_t len);
 | 
						|
PITHY_STATIC_INLINE char       *pithy_EmitCopy(char *op, size_t offset, size_t len);
 | 
						|
 | 
						|
PITHY_STATIC_INLINE uint16_t pithy_Load16(const void *p)        { uint16_t t; memcpy(&t, p, sizeof(t)); return (t); }
 | 
						|
PITHY_STATIC_INLINE uint32_t pithy_Load32(const void *p)        { uint32_t t; memcpy(&t, p, sizeof(t)); return (t); }
 | 
						|
PITHY_STATIC_INLINE uint64_t pithy_Load64(const void *p)        { uint64_t t; memcpy(&t, p, sizeof(t)); return (t); }
 | 
						|
PITHY_STATIC_INLINE void     pithy_Store16(void *p, uint16_t v) { memcpy(p, &v, sizeof(v)); }
 | 
						|
PITHY_STATIC_INLINE void     pithy_Store32(void *p, uint32_t v) { memcpy(p, &v, sizeof(v)); }
 | 
						|
PITHY_STATIC_INLINE void     pithy_Store64(void *p, uint64_t v) { memcpy(p, &v, sizeof(v)); }
 | 
						|
 | 
						|
#define pithy_Move64(dst,src)  pithy_Store64(dst, pithy_Load64(src));
 | 
						|
#define pithy_Move128(dst,src) pithy_Move64(dst, src); pithy_Move64(dst + 8ul, src + 8ul);
 | 
						|
 | 
						|
#ifdef __BIG_ENDIAN__
 | 
						|
 | 
						|
#ifdef _MSC_VER
 | 
						|
#include <stdlib.h>
 | 
						|
#define pithy_bswap_16(x) _byteswap_ushort(x)
 | 
						|
#define pithy_bswap_32(x) _byteswap_ulong(x)
 | 
						|
#define pithy_bswap_64(x) _byteswap_uint64(x)
 | 
						|
 | 
						|
#elif defined(__APPLE__)
 | 
						|
 | 
						|
// Mac OS X / Darwin features
 | 
						|
#include <libkern/OSByteOrder.h>
 | 
						|
#define pithy_bswap_16(x) OSSwapInt16(x)
 | 
						|
#define pithy_bswap_32(x) OSSwapInt32(x)
 | 
						|
#define pithy_bswap_64(x) OSSwapInt64(x)
 | 
						|
#else
 | 
						|
#include <byteswap.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#endif  // __BIG_ENDIAN__
 | 
						|
 | 
						|
// Conversion functions.
 | 
						|
#ifdef __BIG_ENDIAN__
 | 
						|
#define pithy_FromHost16(x)    ((uint16_t)pithy_bswap_16(x))
 | 
						|
#define pithy_ToHost16(x)      ((uint16_t)pithy_bswap_16(x))
 | 
						|
#define pithy_FromHost32(x)    ((uint32_t)pithy_bswap_32(x))
 | 
						|
#define pithy_ToHost32(x)      ((uint32_t)pithy_bswap_32(x))
 | 
						|
#define pithy_IsLittleEndian() (0)
 | 
						|
 | 
						|
#else  // !defined(__BIG_ENDIAN__)
 | 
						|
#define pithy_FromHost16(x)    ((uint16_t)(x))
 | 
						|
#define pithy_ToHost16(x)      ((uint16_t)(x))
 | 
						|
#define pithy_FromHost32(x)    ((uint32_t)(x))
 | 
						|
#define pithy_ToHost32(x)      ((uint32_t)(x))
 | 
						|
#define pithy_IsLittleEndian() (1)
 | 
						|
 | 
						|
#endif  // !defined(__BIG_ENDIAN__)
 | 
						|
 | 
						|
#define pithy_LoadHost16(p)     pithy_ToHost16(pithy_Load16((const void *)(p)))
 | 
						|
#define pithy_StoreHost16(p, v) pithy_Store16((void *)(p), pithy_FromHost16(v))
 | 
						|
#define pithy_LoadHost32(p)     pithy_ToHost32(pithy_Load32((p)))
 | 
						|
#define pithy_StoreHost32(p, v) pithy_Store32((p), pithy_FromHost32(v))
 | 
						|
 | 
						|
PITHY_STATIC_INLINE void pithy_StoreHost24(char *p, uint32_t v)
 | 
						|
{
 | 
						|
    *p++ = (v & 0xffu);
 | 
						|
    *p++ = ((v >> 8) & 0xffu);
 | 
						|
    *p++ = ((v >> 16) & 0xffu);
 | 
						|
}
 | 
						|
 | 
						|
#if defined (__GNUC__) && (__GNUC__ >= 3)
 | 
						|
 | 
						|
#define pithy_Log2Floor(n)           ({typeof(n) _n = (n); _n == 0 ? (int)-1 : (int)(31 ^ __builtin_clz(_n));})
 | 
						|
#define pithy_FindLSBSetNonZero32(n) ((int)__builtin_ctz((uint32_t)(n)))
 | 
						|
#define pithy_FindLSBSetNonZero64(n) ((int)__builtin_ctzll((uint64_t)(n)))
 | 
						|
#define pithy_FindMSBSetNonZero32(n) ((int)__builtin_clz((uint32_t)(n)))
 | 
						|
#define pithy_FindMSBSetNonZero64(n) ((int)__builtin_clzll((uint64_t)(n)))
 | 
						|
 | 
						|
#else  // Portable versions, !GNUC || GNUC < 3
 | 
						|
 | 
						|
PITHY_STATIC_INLINE int pithy_Log2Floor(uint32_t n)
 | 
						|
{
 | 
						|
    if (n == 0u) {
 | 
						|
        return (-1);
 | 
						|
    }
 | 
						|
    int i = 0, log = 0;
 | 
						|
    uint32_t value = n;
 | 
						|
    for (i = 4; i >= 0; --i) {
 | 
						|
        int shift = (1 << i);
 | 
						|
        uint32_t x = value >> shift;
 | 
						|
        if (x != 0u) {
 | 
						|
            value = x;
 | 
						|
            log += shift;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    DCHECK(value == 1);
 | 
						|
    return (log);
 | 
						|
}
 | 
						|
 | 
						|
PITHY_STATIC_INLINE int pithy_FindLSBSetNonZero32(uint32_t n)
 | 
						|
{
 | 
						|
    int i = 0, rc = 31, shift = 0;
 | 
						|
    for (i = 4, shift = 1 << 4; i >= 0; --i) {
 | 
						|
        const uint32_t x = n << shift;
 | 
						|
        if (x != 0u) {
 | 
						|
            n = x;
 | 
						|
            rc -= shift;
 | 
						|
        }
 | 
						|
        shift >>= 1;
 | 
						|
    }
 | 
						|
    return (rc);
 | 
						|
}
 | 
						|
 | 
						|
PITHY_STATIC_INLINE int pithy_FindLSBSetNonZero64(uint64_t n)
 | 
						|
{
 | 
						|
    const uint32_t bottomBits = n;
 | 
						|
    if (bottomBits == 0u) {
 | 
						|
        return (32 + pithy_FindLSBSetNonZero32((n >> 32)));
 | 
						|
    } else {
 | 
						|
        return (pithy_FindLSBSetNonZero32(bottomBits));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
PITHY_STATIC_INLINE int pithy_FindMSBSetNonZero32(uint32_t n)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    uint32_t x, rc = 32, shift = 1 << 4;
 | 
						|
    for (i = 3; i >= 0; --i) {
 | 
						|
        x = n >> shift;
 | 
						|
        if (x != 0) {
 | 
						|
            rc -= shift;
 | 
						|
            n = x;
 | 
						|
        }
 | 
						|
        shift >>= 1;
 | 
						|
    }
 | 
						|
    x = n >> shift;
 | 
						|
    return (rc - ((x != 0) ? 2 : n));
 | 
						|
}
 | 
						|
 | 
						|
PITHY_STATIC_INLINE int pithy_FindMSBSetNonZero64(uint64_t n)
 | 
						|
{
 | 
						|
    const uint32_t upperBits = n >> 32;
 | 
						|
    if (upperBits == 0u) {
 | 
						|
        return (32 + pithy_FindMSBSetNonZero32((n)));
 | 
						|
    } else {
 | 
						|
        return (pithy_FindMSBSetNonZero32(upperBits));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#endif  // End portable versions.
 | 
						|
 | 
						|
PITHY_STATIC_INLINE const char *pithy_Parse32WithLimit(const char *p, const char *l, size_t *resultOut)
 | 
						|
{
 | 
						|
    const unsigned char *ptr = (const unsigned char *)p, *limit = (const unsigned char *)l;
 | 
						|
    size_t   resultShift = 0ul, result = 0ul;
 | 
						|
    uint32_t encodedByte = 0u;
 | 
						|
 | 
						|
    for (resultShift = 0ul; resultShift <= 28ul; resultShift += 7ul) {
 | 
						|
        if (ptr >= limit) {
 | 
						|
            return (NULL);
 | 
						|
        }
 | 
						|
        encodedByte = *(ptr++);
 | 
						|
        result |= (encodedByte & 127u) << resultShift;
 | 
						|
        if (encodedByte < ((resultShift == 28ul) ? 16u : 128u)) {
 | 
						|
            goto done;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return (NULL);
 | 
						|
done:
 | 
						|
    *resultOut = result;
 | 
						|
    return ((const char *)ptr);
 | 
						|
}
 | 
						|
 | 
						|
PITHY_STATIC_INLINE char *pithy_Encode32(char *sptr, uint32_t v)
 | 
						|
{
 | 
						|
    unsigned char *ptr = (unsigned char *)sptr;
 | 
						|
    if (v < (1u <<  7)) {
 | 
						|
        *(ptr++) = v;
 | 
						|
    } else if (v < (1u << 14)) {
 | 
						|
        *(ptr++) = v | 0x80u;
 | 
						|
        *(ptr++) = (v >> 7);
 | 
						|
    } else if (v < (1u << 21)) {
 | 
						|
        *(ptr++) = v | 0x80u;
 | 
						|
        *(ptr++) = (v >> 7) | 0x80u;
 | 
						|
        *(ptr++) = (v >> 14);
 | 
						|
    } else if (v < (1u << 28)) {
 | 
						|
        *(ptr++) = v | 0x80u;
 | 
						|
        *(ptr++) = (v >> 7) | 0x80u;
 | 
						|
        *(ptr++) = (v >> 14) | 0x80u;
 | 
						|
        *(ptr++) = (v >> 21);
 | 
						|
    } else {
 | 
						|
        *(ptr++) = v | 0x80u;
 | 
						|
        *(ptr++) = (v >> 7) | 0x80u;
 | 
						|
        *(ptr++) = (v >> 14) | 0x80u;
 | 
						|
        *(ptr++) = (v >> 21) | 0x80u;
 | 
						|
        *(ptr++) = (v >> 28);
 | 
						|
    }
 | 
						|
    return ((char *)ptr);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
PITHY_STATIC_INLINE uint32_t pithy_GetUint32AtOffset(uint64_t v, uint32_t offset)
 | 
						|
{
 | 
						|
    DCHECK(offset <= 4);
 | 
						|
    return (v >> (pithy_IsLittleEndian() ? (8u * offset) : (32u - (8u * offset))));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
PITHY_STATIC_INLINE uint32_t pithy_HashBytes(uint32_t bytes, uint32_t shift)
 | 
						|
{
 | 
						|
    uint32_t kMul = 0x1e35a7bdU;
 | 
						|
    return ((bytes * kMul) >> shift);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
PITHY_STATIC_INLINE size_t pithy_FindMatchLength(const char *s1, const char *s2, const char *s2_limit)
 | 
						|
{
 | 
						|
    DCHECK(s2_limit >= s2);
 | 
						|
    const char *ms1 = s1, *ms2 = s2;
 | 
						|
 | 
						|
#if defined(__LP64__)
 | 
						|
    while (PITHY_EXPECT_T(ms2 < (s2_limit - 8ul))) {
 | 
						|
        uint64_t x = pithy_Load64(ms1) ^ pithy_Load64(ms2);
 | 
						|
        if (PITHY_EXPECT_F(x == 0ul))  {
 | 
						|
            ms1 += 8ul;
 | 
						|
            ms2 += 8ul;
 | 
						|
        } else {
 | 
						|
            return ((ms1 - s1) + ((unsigned int)(pithy_IsLittleEndian() ? (pithy_FindLSBSetNonZero64(x) >> 3) :
 | 
						|
                                                 (pithy_FindMSBSetNonZero64(x) >> 3))));
 | 
						|
        }
 | 
						|
    }
 | 
						|
#else
 | 
						|
    while (PITHY_EXPECT_T(ms2 < (s2_limit - 4u ))) {
 | 
						|
        uint32_t x = pithy_Load32(ms1) ^ pithy_Load32(ms2);
 | 
						|
        if (PITHY_EXPECT_F(x == 0u))  {
 | 
						|
            ms1 += 4u;
 | 
						|
            ms2 += 4u;
 | 
						|
        } else {
 | 
						|
            return ((ms1 - s1) + ((unsigned int)(pithy_IsLittleEndian() ?
 | 
						|
                                    (pithy_FindLSBSetNonZero32(x) >> 3) : (pithy_FindMSBSetNonZero32(x) >> 3))));
 | 
						|
        }
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    while (PITHY_EXPECT_T(ms2 <  s2_limit)) {
 | 
						|
        if (PITHY_EXPECT_T(*ms1 == *ms2)) {
 | 
						|
            ms1++;
 | 
						|
            ms2++;
 | 
						|
        } else {
 | 
						|
            return (ms1 - s1);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return (ms1 - s1);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
PITHY_STATIC_INLINE char *pithy_EmitLiteral(char *op, const char *literal, size_t len, int allow_fast_path)
 | 
						|
{
 | 
						|
    int n = len - 1l;
 | 
						|
    if (PITHY_EXPECT_T(n < 60l)) {
 | 
						|
        *op++ = PITHY_LITERAL | (n << 2);
 | 
						|
        if (PITHY_EXPECT_T(allow_fast_path) && PITHY_EXPECT_T(len <= 16ul)) {
 | 
						|
            pithy_Move128(op, literal);
 | 
						|
            return (op + len);
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        char *base = op;
 | 
						|
        int count = 0;
 | 
						|
        op++;
 | 
						|
        while (n > 0l) {
 | 
						|
            *op++ = n & 0xff;
 | 
						|
            n >>= 8;
 | 
						|
            count++;
 | 
						|
        }
 | 
						|
        DCHECK((count >= 1) && (count <= 4));
 | 
						|
        *base = PITHY_LITERAL | ((59 + count) << 2);
 | 
						|
    }
 | 
						|
    memcpy(op, literal, len);
 | 
						|
    return (op + len);
 | 
						|
}
 | 
						|
 | 
						|
PITHY_STATIC_INLINE char *pithy_EmitCopyGreaterThan63(char *op, size_t offset, size_t len)
 | 
						|
{
 | 
						|
    DCHECK((len < 65536ul) && (len >= 63ul) && (offset < kBlockSize));
 | 
						|
    if (PITHY_EXPECT_T(offset < 65536ul)) {
 | 
						|
        if (PITHY_EXPECT_T(len < (256ul + 63ul))) {
 | 
						|
            *op++ = PITHY_COPY_2_BYTE_OFFSET | (62 << 2);
 | 
						|
            pithy_StoreHost16(op, offset);
 | 
						|
            op += 2ul;
 | 
						|
            *op++ = (len - 63ul);
 | 
						|
        } else {
 | 
						|
            *op++ = PITHY_COPY_2_BYTE_OFFSET | (63 << 2);
 | 
						|
            pithy_StoreHost16(op, offset);
 | 
						|
            op += 2ul;
 | 
						|
            pithy_StoreHost16(op, len);
 | 
						|
            op += 2ul;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        if (PITHY_EXPECT_T(len < (256ul + 63ul))) {
 | 
						|
            *op++ = PITHY_COPY_3_BYTE_OFFSET | (62 << 2);
 | 
						|
            pithy_StoreHost24(op, offset);
 | 
						|
            op += 3ul;
 | 
						|
            *op++ = (len - 63ul);
 | 
						|
        } else {
 | 
						|
            *op++ = PITHY_COPY_3_BYTE_OFFSET | (63 << 2);
 | 
						|
            pithy_StoreHost24(op, offset);
 | 
						|
            op += 3ul;
 | 
						|
            pithy_StoreHost16(op, len);
 | 
						|
            op += 2ul;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return (op);
 | 
						|
}
 | 
						|
 | 
						|
PITHY_STATIC_INLINE char *pithy_EmitCopyLessThan63(char *op, size_t offset, size_t len)
 | 
						|
{
 | 
						|
    DCHECK((len < 63ul) && (len >= 4ul) && (offset < kBlockSize));
 | 
						|
    if (PITHY_EXPECT_T(len < 12ul) && PITHY_EXPECT_T(offset < 2048ul)) {
 | 
						|
        int lenMinus4 = len - 4l;
 | 
						|
        DCHECK(lenMinus4 < 8l);
 | 
						|
        *op++ = PITHY_COPY_1_BYTE_OFFSET | (lenMinus4 << 2) | ((offset >> 8) << 5);
 | 
						|
        *op++ = offset & 0xff;
 | 
						|
    } else {
 | 
						|
        if (PITHY_EXPECT_T(offset < 65536ul)) {
 | 
						|
            *op++ = PITHY_COPY_2_BYTE_OFFSET | ((len - 1ul) << 2);
 | 
						|
            pithy_StoreHost16(op, offset);
 | 
						|
            op += 2ul;
 | 
						|
        } else {
 | 
						|
            *op++ = PITHY_COPY_3_BYTE_OFFSET | ((len - 1ul) << 2);
 | 
						|
            pithy_StoreHost24(op, offset);
 | 
						|
            op += 3ul;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return (op);
 | 
						|
}
 | 
						|
 | 
						|
PITHY_STATIC_INLINE char *pithy_EmitCopy(char *op, size_t offset, size_t len)
 | 
						|
{
 | 
						|
    while (PITHY_EXPECT_F(len >= 63ul)) {
 | 
						|
        op = pithy_EmitCopyGreaterThan63(op, offset, (len >= 65539ul) ? 65535ul : len);
 | 
						|
        len -= (len >= 65539ul) ? 65535ul : len;
 | 
						|
    }
 | 
						|
    DCHECK((len > 0ul) ? ((len >= 4ul) && (len < 63ul)) : 1);
 | 
						|
    if ( PITHY_EXPECT_T(len >  0ul)) {
 | 
						|
        op = pithy_EmitCopyLessThan63(op, offset, len);
 | 
						|
        len -= len;
 | 
						|
    }
 | 
						|
    return (op);
 | 
						|
}
 | 
						|
 | 
						|
size_t pithy_MaxCompressedLength(size_t inputLength)
 | 
						|
{
 | 
						|
    return ((inputLength >= PITHY_UNCOMPRESSED_MAX_LENGTH) ? 0ul : 32ul + inputLength + (inputLength / 6ul));
 | 
						|
}
 | 
						|
 | 
						|
size_t pithy_Compress(const char *uncompressed,
 | 
						|
                      size_t uncompressedLength,
 | 
						|
                      char *compressedOut,
 | 
						|
                      size_t compressedOutLength,
 | 
						|
                      int compressionLevel)
 | 
						|
{
 | 
						|
 | 
						|
    if ((pithy_MaxCompressedLength(uncompressedLength) > compressedOutLength) ||
 | 
						|
            (uncompressedLength >= PITHY_UNCOMPRESSED_MAX_LENGTH) ||
 | 
						|
            (uncompressedLength == 0ul)) {
 | 
						|
        return (0ul);
 | 
						|
    }
 | 
						|
 | 
						|
    char *compressedPtr = compressedOut;
 | 
						|
 | 
						|
    size_t hashTableSize = 0x100ul, maxHashTableSize = 1 << (12ul + (((compressionLevel < 0) ? 0 :
 | 
						|
                           (compressionLevel > 9) ? 9 : compressionLevel) / 2ul));
 | 
						|
    while ((hashTableSize < maxHashTableSize) && (hashTableSize < uncompressedLength)) {
 | 
						|
        hashTableSize <<= 1;
 | 
						|
    }
 | 
						|
    pithy_hashOffset_t stackHashTable[hashTableSize], *heapHashTable = NULL, *hashTable = stackHashTable;
 | 
						|
    if ((sizeof(pithy_hashOffset_t) * hashTableSize) >= (1024ul * 128ul)) {
 | 
						|
        if ((heapHashTable = malloc(sizeof(pithy_hashOffset_t) * hashTableSize)) == NULL) {
 | 
						|
            return (0ul);
 | 
						|
        }
 | 
						|
        hashTable = heapHashTable;
 | 
						|
    }
 | 
						|
    size_t x = 0ul;
 | 
						|
    for (x = 0ul; x < hashTableSize; x++) {
 | 
						|
        hashTable[x] = uncompressed;
 | 
						|
    }
 | 
						|
 | 
						|
#ifndef NDEBUG
 | 
						|
    char *const compressedOutEnd = compressedOut + compressedOutLength;
 | 
						|
#endif
 | 
						|
    compressedPtr = pithy_Encode32(compressedPtr, uncompressedLength);
 | 
						|
    DCHECK(compressedPtr <= compressedOutEnd);
 | 
						|
    {
 | 
						|
        const char *uncompressedPtr = uncompressed;
 | 
						|
        const char *uncompressedEnd = uncompressed + uncompressedLength;
 | 
						|
        const char *nextEmitUncompressedPtr = uncompressedPtr;
 | 
						|
        DCHECK((hashTableSize & (hashTableSize - 1l)) == 0);
 | 
						|
        const int shift = 32 - pithy_Log2Floor(hashTableSize);
 | 
						|
        DCHECK((UINT32_MAX >> shift) == (hashTableSize - 1l));
 | 
						|
        size_t skip = 32ul;
 | 
						|
 | 
						|
        if (PITHY_EXPECT_T(uncompressedLength >= 15ul)) {
 | 
						|
            const char *uncompressedEndLimit = uncompressed + uncompressedLength - 15ul;
 | 
						|
            uint32_t uncompressedBytes;
 | 
						|
            uint32_t nextUncompressedBytes = pithy_Load32(++uncompressedPtr);
 | 
						|
            uint32_t nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift);
 | 
						|
 | 
						|
            while (1) {
 | 
						|
                DCHECK(nextEmitUncompressedPtr < uncompressedPtr);
 | 
						|
                const char *nextUncompressedPtr = uncompressedPtr, *matchCandidatePtr = NULL;
 | 
						|
 | 
						|
                skip = (((skip - 32ul) * 184ul) >> 8) + 32ul;
 | 
						|
 | 
						|
                do {
 | 
						|
                    uncompressedPtr   = nextUncompressedPtr;
 | 
						|
                    uncompressedBytes = nextUncompressedBytes;
 | 
						|
                    uint32_t uncompressedBytesHash = nextUncompressedBytesHash;
 | 
						|
                    DCHECK(uncompressedBytesHash == pithy_HashBytes(uncompressedBytes, shift));
 | 
						|
                    size_t skipBytesBetweenHashLookups = skip >> 5;
 | 
						|
                    skip += ((skip * 7ul) >> 11) + 1ul;
 | 
						|
                    nextUncompressedPtr              = uncompressedPtr + skipBytesBetweenHashLookups;
 | 
						|
                    if (PITHY_EXPECT_F(nextUncompressedPtr > uncompressedEndLimit)) {
 | 
						|
                        goto emit_remainder;
 | 
						|
                    }
 | 
						|
                    nextUncompressedBytes            = pithy_Load32(nextUncompressedPtr);
 | 
						|
                    nextUncompressedBytesHash        = pithy_HashBytes(nextUncompressedBytes, shift);
 | 
						|
                    matchCandidatePtr                = hashTable[uncompressedBytesHash];
 | 
						|
                    DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr < uncompressedPtr));
 | 
						|
                    hashTable[uncompressedBytesHash] = uncompressedPtr;
 | 
						|
                } while ((PITHY_EXPECT_T(uncompressedBytes != pithy_Load32(matchCandidatePtr))) ||
 | 
						|
                         PITHY_EXPECT_F((uncompressedPtr - matchCandidatePtr) >= ((int)(kBlockSize - 2ul))));
 | 
						|
 | 
						|
                DCHECK((nextEmitUncompressedPtr + 16ul) <= uncompressedEnd);
 | 
						|
                compressedPtr = pithy_EmitLiteral(compressedPtr,
 | 
						|
                                                  nextEmitUncompressedPtr,
 | 
						|
                                                  uncompressedPtr - nextEmitUncompressedPtr,
 | 
						|
                                                  1);
 | 
						|
                DCHECK(compressedPtr <= compressedOutEnd);
 | 
						|
                uint64_t uncompressedBytes64 = 0ul;
 | 
						|
 | 
						|
                do {
 | 
						|
                    if (compressionLevel > 2) {
 | 
						|
                        DCHECK((uncompressedPtr + 5ul) <= uncompressedEnd);
 | 
						|
                        uncompressedBytes64 = pithy_Load64((uint64_t*)uncompressedPtr + 1ul);
 | 
						|
                        hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 0u), shift)] =
 | 
						|
                            uncompressedPtr + 1ul;
 | 
						|
                        if (compressionLevel > 4) {
 | 
						|
                            hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 1u), shift)] =
 | 
						|
                                uncompressedPtr + 2ul;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
 | 
						|
                    DCHECK((matchCandidatePtr >= uncompressed) &&
 | 
						|
                           (matchCandidatePtr <= uncompressedPtr) &&
 | 
						|
                           ((matchCandidatePtr + 4ul) <= uncompressedEnd) &&
 | 
						|
                           ((uncompressedPtr + 4ul) <= uncompressedEnd));
 | 
						|
 | 
						|
                    size_t matchCandidateLength = 4ul + pithy_FindMatchLength(matchCandidatePtr + 4ul,
 | 
						|
                                                  uncompressedPtr + 4ul,
 | 
						|
                                                  uncompressedEnd);
 | 
						|
                    DCHECK(((matchCandidatePtr + matchCandidateLength) >= uncompressed) &&
 | 
						|
                           ((matchCandidatePtr + matchCandidateLength) <= uncompressedEnd));
 | 
						|
                    DCHECK(0 == memcmp(uncompressedPtr, matchCandidatePtr, matchCandidateLength));
 | 
						|
                    compressedPtr = pithy_EmitCopy(compressedPtr,
 | 
						|
                                                   uncompressedPtr - matchCandidatePtr,
 | 
						|
                                                   matchCandidateLength);
 | 
						|
                    DCHECK(compressedPtr <= compressedOutEnd);
 | 
						|
                    uncompressedPtr += matchCandidateLength;
 | 
						|
                    DCHECK(uncompressedPtr <= uncompressedEnd);
 | 
						|
                    nextEmitUncompressedPtr = uncompressedPtr;
 | 
						|
                    if (PITHY_EXPECT_F(uncompressedPtr >= uncompressedEndLimit)) {
 | 
						|
                        goto emit_remainder;
 | 
						|
                    }
 | 
						|
 | 
						|
                    DCHECK(((uncompressedPtr - 3ul) >= uncompressed) && (uncompressedPtr <= uncompressedEnd));
 | 
						|
 | 
						|
                    uncompressedBytes64 = pithy_Load64((uint64_t*)uncompressedPtr - 3ul);
 | 
						|
 | 
						|
                    if (compressionLevel > 0) {
 | 
						|
                        if (compressionLevel > 8) {
 | 
						|
                            hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 0u), shift)] =
 | 
						|
                                uncompressedPtr - 3ul;
 | 
						|
                        }
 | 
						|
                        if (compressionLevel > 6) {
 | 
						|
                            hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 1u), shift)] =
 | 
						|
                                uncompressedPtr - 2ul;
 | 
						|
                        }
 | 
						|
                        hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 2u), shift)] =
 | 
						|
                            uncompressedPtr - 1ul;
 | 
						|
                    }
 | 
						|
 | 
						|
                    uncompressedBytes = pithy_GetUint32AtOffset(uncompressedBytes64, 3u);
 | 
						|
                    uint32_t uncompressedBytesHash = pithy_HashBytes(uncompressedBytes, shift);
 | 
						|
                    matchCandidatePtr = hashTable[uncompressedBytesHash];
 | 
						|
                    DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr < uncompressedPtr));
 | 
						|
                    hashTable[uncompressedBytesHash] = uncompressedPtr;
 | 
						|
                } while (PITHY_EXPECT_F(uncompressedBytes == pithy_Load32(matchCandidatePtr)) &&
 | 
						|
                         PITHY_EXPECT_T((uncompressedPtr - matchCandidatePtr) < ((int)(kBlockSize - 2ul))));
 | 
						|
 | 
						|
                nextUncompressedBytes = pithy_GetUint32AtOffset(uncompressedBytes64, 4u);
 | 
						|
                nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift);
 | 
						|
                uncompressedPtr++;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
emit_remainder:
 | 
						|
        if (nextEmitUncompressedPtr < uncompressedEnd) {
 | 
						|
            compressedPtr = pithy_EmitLiteral(compressedPtr,
 | 
						|
                                              nextEmitUncompressedPtr,
 | 
						|
                                              uncompressedEnd - nextEmitUncompressedPtr,
 | 
						|
                                              0);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    pithy_Store32(compressedPtr, 0);
 | 
						|
    compressedPtr += 4;
 | 
						|
 | 
						|
    DCHECK((size_t)(compressedPtr - compressedOut) <= compressedOutLength);
 | 
						|
    if (heapHashTable != NULL) {
 | 
						|
        free(heapHashTable);
 | 
						|
        heapHashTable = NULL;
 | 
						|
        hashTable = NULL;
 | 
						|
    }
 | 
						|
    return (compressedPtr - compressedOut);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static const uint32_t pithy_wordmask[] = {
 | 
						|
    0u, 0xffu, 0xffffu, 0xffffffu, 0xffffffffu
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
static const uint16_t pithy_charTable[256] = {
 | 
						|
    0x0001, 0x0804, 0x1001, 0x1801, 0x0002, 0x0805, 0x1002, 0x1802,
 | 
						|
    0x0003, 0x0806, 0x1003, 0x1803, 0x0004, 0x0807, 0x1004, 0x1804,
 | 
						|
    0x0005, 0x0808, 0x1005, 0x1805, 0x0006, 0x0809, 0x1006, 0x1806,
 | 
						|
    0x0007, 0x080a, 0x1007, 0x1807, 0x0008, 0x080b, 0x1008, 0x1808,
 | 
						|
    0x0009, 0x0904, 0x1009, 0x1809, 0x000a, 0x0905, 0x100a, 0x180a,
 | 
						|
    0x000b, 0x0906, 0x100b, 0x180b, 0x000c, 0x0907, 0x100c, 0x180c,
 | 
						|
    0x000d, 0x0908, 0x100d, 0x180d, 0x000e, 0x0909, 0x100e, 0x180e,
 | 
						|
    0x000f, 0x090a, 0x100f, 0x180f, 0x0010, 0x090b, 0x1010, 0x1810,
 | 
						|
    0x0011, 0x0a04, 0x1011, 0x1811, 0x0012, 0x0a05, 0x1012, 0x1812,
 | 
						|
    0x0013, 0x0a06, 0x1013, 0x1813, 0x0014, 0x0a07, 0x1014, 0x1814,
 | 
						|
    0x0015, 0x0a08, 0x1015, 0x1815, 0x0016, 0x0a09, 0x1016, 0x1816,
 | 
						|
    0x0017, 0x0a0a, 0x1017, 0x1817, 0x0018, 0x0a0b, 0x1018, 0x1818,
 | 
						|
    0x0019, 0x0b04, 0x1019, 0x1819, 0x001a, 0x0b05, 0x101a, 0x181a,
 | 
						|
    0x001b, 0x0b06, 0x101b, 0x181b, 0x001c, 0x0b07, 0x101c, 0x181c,
 | 
						|
    0x001d, 0x0b08, 0x101d, 0x181d, 0x001e, 0x0b09, 0x101e, 0x181e,
 | 
						|
    0x001f, 0x0b0a, 0x101f, 0x181f, 0x0020, 0x0b0b, 0x1020, 0x1820,
 | 
						|
    0x0021, 0x0c04, 0x1021, 0x1821, 0x0022, 0x0c05, 0x1022, 0x1822,
 | 
						|
    0x0023, 0x0c06, 0x1023, 0x1823, 0x0024, 0x0c07, 0x1024, 0x1824,
 | 
						|
    0x0025, 0x0c08, 0x1025, 0x1825, 0x0026, 0x0c09, 0x1026, 0x1826,
 | 
						|
    0x0027, 0x0c0a, 0x1027, 0x1827, 0x0028, 0x0c0b, 0x1028, 0x1828,
 | 
						|
    0x0029, 0x0d04, 0x1029, 0x1829, 0x002a, 0x0d05, 0x102a, 0x182a,
 | 
						|
    0x002b, 0x0d06, 0x102b, 0x182b, 0x002c, 0x0d07, 0x102c, 0x182c,
 | 
						|
    0x002d, 0x0d08, 0x102d, 0x182d, 0x002e, 0x0d09, 0x102e, 0x182e,
 | 
						|
    0x002f, 0x0d0a, 0x102f, 0x182f, 0x0030, 0x0d0b, 0x1030, 0x1830,
 | 
						|
    0x0031, 0x0e04, 0x1031, 0x1831, 0x0032, 0x0e05, 0x1032, 0x1832,
 | 
						|
    0x0033, 0x0e06, 0x1033, 0x1833, 0x0034, 0x0e07, 0x1034, 0x1834,
 | 
						|
    0x0035, 0x0e08, 0x1035, 0x1835, 0x0036, 0x0e09, 0x1036, 0x1836,
 | 
						|
    0x0037, 0x0e0a, 0x1037, 0x1837, 0x0038, 0x0e0b, 0x1038, 0x1838,
 | 
						|
    0x0039, 0x0f04, 0x1039, 0x1839, 0x003a, 0x0f05, 0x103a, 0x183a,
 | 
						|
    0x003b, 0x0f06, 0x103b, 0x183b, 0x003c, 0x0f07, 0x103c, 0x183c,
 | 
						|
    0x0801, 0x0f08, 0x103d, 0x183d, 0x1001, 0x0f09, 0x103e, 0x183e,
 | 
						|
    0x1801, 0x0f0a, 0x103f, 0x183f, 0x2001, 0x0f0b, 0x1040, 0x1840
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
int pithy_GetDecompressedLength(const char *compressed, size_t compressedLength, size_t *decompressedOutLengthResult)
 | 
						|
{
 | 
						|
    const char *compressedEnd = compressed + compressedLength;
 | 
						|
    size_t decompressedLength = 0ul;
 | 
						|
    if (pithy_Parse32WithLimit(compressed, compressedEnd, &decompressedLength) != NULL) {
 | 
						|
        *decompressedOutLengthResult = decompressedLength;
 | 
						|
        return (1);
 | 
						|
    } else {
 | 
						|
        return (0);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int pithy_Decompress(const char *compressed, size_t compressedLength, char *decompressedOut,
 | 
						|
                     size_t decompressedOutLength)
 | 
						|
{
 | 
						|
    const char *nextCompressedPtr = NULL, *compressedEnd = (compressed + compressedLength);
 | 
						|
    size_t parsedDecompressedLength = 0ul;
 | 
						|
    if (((nextCompressedPtr = pithy_Parse32WithLimit(compressed, compressedEnd, &parsedDecompressedLength)) == NULL) ||
 | 
						|
            (parsedDecompressedLength > decompressedOutLength)) {
 | 
						|
        return (0);
 | 
						|
    }
 | 
						|
 | 
						|
    char *decompressedPtr = decompressedOut, *decompressedEnd = decompressedOut + parsedDecompressedLength;
 | 
						|
 | 
						|
    while (1) {
 | 
						|
        const char *compressedPtr = nextCompressedPtr;
 | 
						|
        DCHECK(compressedPtr <= compressedEnd);
 | 
						|
        if (PITHY_EXPECT_F(compressedPtr >= compressedEnd)) {
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        const unsigned char c          = *((const unsigned char *)(compressedPtr++));
 | 
						|
        const unsigned char cLowerBits = (c & 0x3u);
 | 
						|
        const int       spaceLeft  = (decompressedEnd - decompressedPtr);
 | 
						|
 | 
						|
        if ((cLowerBits == PITHY_LITERAL)) {
 | 
						|
            size_t literalLength = (c >> 2) + 1;
 | 
						|
            if (PITHY_EXPECT_T(literalLength <= 16ul) && PITHY_EXPECT_T((compressedEnd - compressedPtr) >= 16l) &&
 | 
						|
                    PITHY_EXPECT_T(spaceLeft >= 16l)) {
 | 
						|
                pithy_Move128(decompressedPtr, compressedPtr);
 | 
						|
            } else {
 | 
						|
                if (PITHY_EXPECT_F(literalLength > 60)) {
 | 
						|
                    if (PITHY_EXPECT_F((compressedPtr + 4) > compressedEnd)) {
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                    size_t literalLengthBytes = literalLength - 60;
 | 
						|
                    literalLength = (pithy_LoadHost32(compressedPtr) & pithy_wordmask[literalLengthBytes]) + 1;
 | 
						|
                    compressedPtr += literalLengthBytes;
 | 
						|
                }
 | 
						|
                if (PITHY_EXPECT_F(spaceLeft < (int)literalLength) ||
 | 
						|
                        PITHY_EXPECT_F((compressedPtr + literalLength) > compressedEnd)) {
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                memcpy(decompressedPtr, compressedPtr, literalLength);
 | 
						|
            }
 | 
						|
            nextCompressedPtr  = compressedPtr + literalLength;
 | 
						|
            decompressedPtr   += literalLength;
 | 
						|
        } else {
 | 
						|
            const uint32_t entry      = pithy_charTable[c];
 | 
						|
            const size_t   trailer    = pithy_LoadHost32(compressedPtr) & pithy_wordmask[cLowerBits];
 | 
						|
            size_t   length     = entry & 0xffu;
 | 
						|
            const size_t   copyOffset = ((entry & 0x700u) + trailer);
 | 
						|
 | 
						|
            compressedPtr += cLowerBits;
 | 
						|
 | 
						|
            DCHECK((compressedPtr <= compressedEnd) && (copyOffset > 0ul) && (spaceLeft > 0l) && (length > 0ul));
 | 
						|
 | 
						|
            if (PITHY_EXPECT_F((decompressedPtr - decompressedOut) <= ((int)copyOffset - 1l))) {
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            if (PITHY_EXPECT_T(length <= 16ul) && 
 | 
						|
                PITHY_EXPECT_T(copyOffset >= 16ul) && 
 | 
						|
                PITHY_EXPECT_T(spaceLeft >= 16l)) {
 | 
						|
                pithy_Move128(decompressedPtr, decompressedPtr - copyOffset);
 | 
						|
            } else {
 | 
						|
                if (PITHY_EXPECT_F(length >= 63ul)) {
 | 
						|
                    if (PITHY_EXPECT_T(length == 63ul)) {
 | 
						|
                        if (PITHY_EXPECT_F((compressedPtr + 1) > compressedEnd)) {
 | 
						|
                            break;
 | 
						|
                        }
 | 
						|
                        length = (*((unsigned char *)compressedPtr++)) + 63ul;
 | 
						|
                    } else {
 | 
						|
                        if (PITHY_EXPECT_F((compressedPtr + 2) > compressedEnd)) {
 | 
						|
                            break;
 | 
						|
                        }
 | 
						|
                        length = pithy_LoadHost16(compressedPtr);
 | 
						|
                        compressedPtr += 2ul;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                char    *copyFrom   = decompressedPtr - copyOffset, *copyTo = decompressedPtr;
 | 
						|
                int  copyLength = (int)length;
 | 
						|
 | 
						|
                if (PITHY_EXPECT_F(copyLength > 256l) && PITHY_EXPECT_T(copyOffset > (size_t)copyLength)) {
 | 
						|
                    if (PITHY_EXPECT_F(spaceLeft < copyLength)) {
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                    memcpy(copyTo, copyFrom, copyLength);
 | 
						|
                } else {
 | 
						|
                    if (PITHY_EXPECT_T(spaceLeft >= (copyLength + 24)) && PITHY_EXPECT_T(copyLength > 0l)) {
 | 
						|
                        while ((copyTo - copyFrom) < 16l) {
 | 
						|
                            pithy_Move128(copyTo, copyFrom);
 | 
						|
                            copyLength -= copyTo - copyFrom;
 | 
						|
                            copyTo += copyTo - copyFrom;
 | 
						|
                        }
 | 
						|
                        while (copyLength          > 0l)  {
 | 
						|
                            pithy_Move128(copyTo, copyFrom);
 | 
						|
                            copyFrom   += 16l;
 | 
						|
                            copyTo += 16l;
 | 
						|
                            copyLength -= 16l;
 | 
						|
                        }
 | 
						|
                    } else {
 | 
						|
                        if (PITHY_EXPECT_F(spaceLeft < copyLength) || PITHY_EXPECT_F(copyLength <= 0l)) {
 | 
						|
                            break;
 | 
						|
                        }
 | 
						|
                        do {
 | 
						|
                            *copyTo++ = *copyFrom++;
 | 
						|
                        } while (--copyLength > 0l);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            nextCompressedPtr  = compressedPtr;
 | 
						|
            decompressedPtr   += length;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return (decompressedPtr == decompressedEnd);
 | 
						|
}
 |