Improved compression speed. Thanks to David Sterba for suggestion.
authoryann.collet.73@gmail.com <yann.collet.73@gmail.com@650e7d94-2a16-8b24-b05c-7c0b3f6821cd>
Wed, 4 Jan 2012 13:08:10 +0000 (13:08 +0000)
committeryann.collet.73@gmail.com <yann.collet.73@gmail.com@650e7d94-2a16-8b24-b05c-7c0b3f6821cd>
Wed, 4 Jan 2012 13:08:10 +0000 (13:08 +0000)
Compression ratio improvements in "small packet" mode (<64KB).

git-svn-id: https://lz4.googlecode.com/svn/trunk@44 650e7d94-2a16-8b24-b05c-7c0b3f6821cd

lz4.c

diff --git a/lz4.c b/lz4.c
index 2c522f1..11a2f1d 100644 (file)
--- a/lz4.c
+++ b/lz4.c
@@ -1,7 +1,7 @@
 /*\r
    LZ4 - Fast LZ compression algorithm\r
-   Copyright (C) 2011, Yann Collet.\r
-   BSD License\r
+   Copyright (C) 2011-2012, Yann Collet.\r
+   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\r
 \r
    Redistribution and use in source and binary forms, with or without\r
    modification, are permitted provided that the following conditions are\r
 #define restrict  // Disable restrict\r
 #endif\r
 \r
+#ifdef _MSC_VER\r
+#define inline __forceinline\r
+#endif\r
+\r
+\r
 \r
 //**************************************\r
 // Includes\r
@@ -54,6 +59,8 @@
 // Memory usage formula for 32 bits systems : N->2^(N+2) Bytes (examples : 17 -> 512KB ; 12 -> 16KB)\r
 #define HASH_LOG 12\r
 \r
+//#define _FORCE_SW_LOWBITCOUNT   // Uncomment for better performance if target platform has no hardware support for LowBitCount\r
+\r
 \r
 //**************************************\r
 // Basic Types\r
@@ -140,6 +147,21 @@ typedef struct _U16_S
 // Compression CODE\r
 //****************************\r
 \r
+inline static int LZ4_NbCommonBytes_LittleEndian( register U32 val )\r
+{\r
+    #if defined(_MSC_VER) && !defined(_FORCE_SW_LOWBITCOUNT)\r
+    unsigned long b = 0;\r
+    _BitScanForward( &b, val );\r
+    return (int)(b>>3);\r
+    #elif defined(__GNUC__)  && !defined(_FORCE_SW_LOWBITCOUNT)\r
+    return (__builtin_ctz(val) >> 3); \r
+    #else\r
+       static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };\r
+       return DeBruijnBytePos[((U32)((val & -val) * 0x077CB531U)) >> 27];\r
+    #endif\r
+}\r
+\r
+\r
 int LZ4_compressCtx(void** ctx,\r
                                 char* source, \r
                                 char* dest,\r
@@ -160,9 +182,6 @@ int LZ4_compressCtx(void** ctx,
 \r
        BYTE* op = (BYTE*) dest;\r
        \r
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\r
-       const size_t DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };\r
-#endif\r
        int len, length;\r
        const int skipStrength = SKIPSTRENGTH;\r
        U32 forwardH;\r
@@ -237,9 +256,9 @@ _next_match:
                while (ip<matchlimit-3)\r
                {\r
 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\r
-                       int diff = A32(ref) ^ A32(ip);\r
+                       U32 diff = A32(ref) ^ A32(ip);\r
                        if (!diff) { ip+=4; ref+=4; continue; }\r
-                       ip += DeBruijnBytePos[((U32)((diff & -diff) * 0x077CB531U)) >> 27];\r
+                       ip += LZ4_NbCommonBytes_LittleEndian(diff);\r
 #else\r
                        if (A32(ref) == A32(ip)) { ip+=4; ref+=4; continue; }\r
                        if (A16(ref) == A16(ip)) { ip+=2; ref+=2; }\r
@@ -250,9 +269,9 @@ _next_match:
                if ((ip<(matchlimit-1)) && (A16(ref) == A16(ip))) { ip+=2; ref+=2; }\r
                if ((ip<matchlimit) && (*ref == *ip)) ip++;\r
 _endCount:\r
-               len = (ip - anchor);\r
-               \r
+\r
                // Encode MatchLength\r
+               len = (ip - anchor);\r
                if (len>=(int)ML_MASK) { *token+=ML_MASK; len-=ML_MASK; for(; len > 509 ; len-=510) { *op++ = 255; *op++ = 255; } if (len > 254) { len-=255; *op++ = 255; } *op++ = (BYTE)len; } \r
                else *token += len;     \r
 \r
@@ -314,9 +333,6 @@ int LZ4_compress64kCtx(void** ctx,
 \r
        BYTE* op = (BYTE*) dest;\r
        \r
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\r
-       const size_t DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };\r
-#endif\r
        int len, length;\r
        const int skipStrength = SKIPSTRENGTH;\r
        U32 forwardH;\r
@@ -390,9 +406,9 @@ _next_match:
                while (ip<matchlimit-3)\r
                {\r
 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\r
-                       int diff = A32(ref) ^ A32(ip);\r
+                       U32 diff = A32(ref) ^ A32(ip);\r
                        if (!diff) { ip+=4; ref+=4; continue; }\r
-                       ip += DeBruijnBytePos[((U32)((diff & -diff) * 0x077CB531U)) >> 27];\r
+                       ip += LZ4_NbCommonBytes_LittleEndian(diff);\r
 #else\r
                        if (A32(ref) == A32(ip)) { ip+=4; ref+=4; continue; }\r
                        if (A16(ref) == A16(ip)) { ip+=2; ref+=2; }\r
@@ -403,15 +419,18 @@ _next_match:
                if ((ip<(matchlimit-1)) && (A16(ref) == A16(ip))) { ip+=2; ref+=2; }\r
                if ((ip<matchlimit) && (*ref == *ip)) ip++;\r
 _endCount:\r
-               len = (ip - anchor);\r
                \r
                // Encode MatchLength\r
+               len = (ip - anchor);\r
                if (len>=(int)ML_MASK) { *token+=ML_MASK; len-=ML_MASK; for(; len > 509 ; len-=510) { *op++ = 255; *op++ = 255; } if (len > 254) { len-=255; *op++ = 255; } *op++ = (BYTE)len; } \r
                else *token += len;     \r
 \r
                // Test end of chunk\r
                if (ip > mflimit) { anchor = ip;  break; }\r
 \r
+               // Fill table\r
+               HashTable[LZ4_HASH64K_VALUE(ip-2)] = ip - 2 - base;\r
+\r
                // Test next position\r
                ref = base + HashTable[LZ4_HASH64K_VALUE(ip)];\r
                HashTable[LZ4_HASH64K_VALUE(ip)] = ip - base;\r