// Copyright 2014 The zappy Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Copyright 2011 The Snappy-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the SNAPPY-GO-LICENSE file.

/*
Package zappy implements the zappy block-based compression format.  It aims for
a combination of good speed and reasonable compression.

Zappy is a format incompatible, API compatible fork of snappy[1]. The C++
snappy implementation is at [2].

Reasons for the fork

The snappy compression is pretty good. Yet it has one problem built into its
format definition[3] - the maximum length of a copy "instruction" is 64 bytes.
For some specific usage patterns with long runs of repeated data, it turns out
the compression is suboptimal. For example a 1:1000 "sparseness" 64kB bit index
with only few set bits is compressed to about 3kB (about 1000 of 64B copy, 3
byte "instructions").

Format description

Zappy uses much less complicated format than snappy. Each encoded block begins
with the uvarint-encoded[4] length of the decoded data, followed by a sequence
of chunks. Chunks begin and end on byte boundaries. The chunk starts with a
varint encoded number N:

	N >= 0: N+1 literal bytes follow.

	N < 0: copy -N bytes, starting at offset M (in the following uvarint).

Performance issues

Compression rate is roughly the same as of snappy for the reference data set:

                  testdata/html: snappy   23320, zappy   22943, 0.984, orig  102400
              testdata/urls.10K: snappy  334437, zappy  355163, 1.062, orig  702087
             testdata/house.jpg: snappy  126711, zappy  126694, 1.000, orig  126958
  testdata/mapreduce-osdi-1.pdf: snappy   77227, zappy   77646, 1.005, orig   94330
              testdata/html_x_4: snappy   92350, zappy   22956, 0.249, orig  409600
               testdata/cp.html: snappy   11938, zappy   12961, 1.086, orig   24603
              testdata/fields.c: snappy    4825, zappy    5395, 1.118, orig   11150
           testdata/grammar.lsp: snappy    1814, zappy    1933, 1.066, orig    3721
           testdata/kennedy.xls: snappy  423518, zappy  440597, 1.040, orig 1029744
           testdata/alice29.txt: snappy   89550, zappy  104016, 1.162, orig  152089
          testdata/asyoulik.txt: snappy   79583, zappy   91345, 1.148, orig  125179
            testdata/lcet10.txt: snappy  238761, zappy  275488, 1.154, orig  426754
          testdata/plrabn12.txt: snappy  324567, zappy  376885, 1.161, orig  481861
                  testdata/ptt5: snappy   96350, zappy   91465, 0.949, orig  513216
                   testdata/sum: snappy   18927, zappy   20015, 1.057, orig   38240
               testdata/xargs.1: snappy    2532, zappy    2793, 1.103, orig    4227
         testdata/geo.protodata: snappy   23362, zappy   20759, 0.889, orig  118588
             testdata/kppkn.gtb: snappy   73962, zappy   87200, 1.179, orig  184320
                          TOTAL: snappy 2043734, zappy 2136254, 1.045, orig 4549067

Zappy has better RLE handling (1/1000+1 non zero bytes in each index):

     Sparse bit index      16 B: snappy       9, zappy       9, 1.000
     Sparse bit index      32 B: snappy      10, zappy      10, 1.000
     Sparse bit index      64 B: snappy      11, zappy      10, 0.909
     Sparse bit index     128 B: snappy      16, zappy      14, 0.875
     Sparse bit index     256 B: snappy      22, zappy      14, 0.636
     Sparse bit index     512 B: snappy      36, zappy      16, 0.444
     Sparse bit index    1024 B: snappy      57, zappy      18, 0.316
     Sparse bit index    2048 B: snappy     111, zappy      32, 0.288
     Sparse bit index    4096 B: snappy     210, zappy      31, 0.148
     Sparse bit index    8192 B: snappy     419, zappy      75, 0.179
     Sparse bit index   16384 B: snappy     821, zappy     138, 0.168
     Sparse bit index   32768 B: snappy    1627, zappy     232, 0.143
     Sparse bit index   65536 B: snappy    3243, zappy     451, 0.139

When compiled with CGO_ENABLED=1, zappy is now faster than Go snappy.
Old=Go snappy, new=zappy:

 benchmark                   old MB/s     new MB/s  speedup
 BenchmarkWordsDecode1e3       148.98       189.04    1.27x
 BenchmarkWordsDecode1e4       150.29       182.51    1.21x
 BenchmarkWordsDecode1e5       145.79       182.95    1.25x
 BenchmarkWordsDecode1e6       167.43       187.69    1.12x
 BenchmarkWordsEncode1e3        47.11       145.69    3.09x
 BenchmarkWordsEncode1e4        81.47       136.50    1.68x
 BenchmarkWordsEncode1e5        78.86       127.93    1.62x
 BenchmarkWordsEncode1e6        96.81       142.95    1.48x
 Benchmark_UFlat0              316.87       463.19    1.46x
 Benchmark_UFlat1              231.56       350.32    1.51x
 Benchmark_UFlat2             3656.68      8258.39    2.26x
 Benchmark_UFlat3              892.56      1270.09    1.42x
 Benchmark_UFlat4              315.84       959.08    3.04x
 Benchmark_UFlat5              211.70       301.55    1.42x
 Benchmark_UFlat6              211.59       258.29    1.22x
 Benchmark_UFlat7              209.80       272.21    1.30x
 Benchmark_UFlat8              254.59       301.70    1.19x
 Benchmark_UFlat9              163.39       192.66    1.18x
 Benchmark_UFlat10             155.46       189.70    1.22x
 Benchmark_UFlat11             170.11       198.95    1.17x
 Benchmark_UFlat12             148.32       178.78    1.21x
 Benchmark_UFlat13             359.25       579.99    1.61x
 Benchmark_UFlat14             197.27       291.33    1.48x
 Benchmark_UFlat15             185.75       248.07    1.34x
 Benchmark_UFlat16             362.74       582.66    1.61x
 Benchmark_UFlat17             222.95       240.01    1.08x
 Benchmark_ZFlat0              188.66       311.89    1.65x
 Benchmark_ZFlat1              101.46       201.34    1.98x
 Benchmark_ZFlat2               93.62       244.50    2.61x
 Benchmark_ZFlat3              102.79       243.34    2.37x
 Benchmark_ZFlat4              191.64       625.32    3.26x
 Benchmark_ZFlat5              103.09       169.39    1.64x
 Benchmark_ZFlat6              110.35       182.57    1.65x
 Benchmark_ZFlat7               89.56       190.53    2.13x
 Benchmark_ZFlat8              154.05       235.68    1.53x
 Benchmark_ZFlat9               87.58       133.51    1.52x
 Benchmark_ZFlat10              82.08       127.51    1.55x
 Benchmark_ZFlat11              91.36       138.91    1.52x
 Benchmark_ZFlat12              79.24       123.02    1.55x
 Benchmark_ZFlat13             217.04       374.26    1.72x
 Benchmark_ZFlat14             100.33       168.03    1.67x
 Benchmark_ZFlat15              80.79       160.46    1.99x
 Benchmark_ZFlat16             213.32       375.79    1.76x
 Benchmark_ZFlat17             135.37       197.13    1.46x

The package builds with CGO_ENABLED=0 as well, but the performance is worse.


 $ CGO_ENABLED=0 go test -test.run=NONE -test.bench=. > old.benchcmp
 $ CGO_ENABLED=1 go test -test.run=NONE -test.bench=. > new.benchcmp
 $ benchcmp old.benchcmp new.benchcmp
 benchmark                  old ns/op    new ns/op    delta
 BenchmarkWordsDecode1e3         9735         5288  -45.68%
 BenchmarkWordsDecode1e4       100229        55369  -44.76%
 BenchmarkWordsDecode1e5      1037611       546420  -47.34%
 BenchmarkWordsDecode1e6      9559352      5335307  -44.19%
 BenchmarkWordsEncode1e3        16206         6629  -59.10%
 BenchmarkWordsEncode1e4       140283        73161  -47.85%
 BenchmarkWordsEncode1e5      1476657       781756  -47.06%
 BenchmarkWordsEncode1e6     12702229      6997656  -44.91%
 Benchmark_UFlat0              397307       221198  -44.33%
 Benchmark_UFlat1             3890483      2008341  -48.38%
 Benchmark_UFlat2               35810        15398  -57.00%
 Benchmark_UFlat3              140850        74194  -47.32%
 Benchmark_UFlat4              814575       426783  -47.61%
 Benchmark_UFlat5              156995        81473  -48.10%
 Benchmark_UFlat6               77645        43161  -44.41%
 Benchmark_UFlat7               25415        13579  -46.57%
 Benchmark_UFlat8             6372440      3412916  -46.44%
 Benchmark_UFlat9             1453679       789956  -45.66%
 Benchmark_UFlat10            1243146       660747  -46.85%
 Benchmark_UFlat11            3903493      2146334  -45.02%
 Benchmark_UFlat12            5106250      2696144  -47.20%
 Benchmark_UFlat13            1641394       884969  -46.08%
 Benchmark_UFlat14             262206       131174  -49.97%
 Benchmark_UFlat15              32325        17047  -47.26%
 Benchmark_UFlat16             366991       204877  -44.17%
 Benchmark_UFlat17            1343988       770907  -42.64%
 Benchmark_ZFlat0              579954       329812  -43.13%
 Benchmark_ZFlat1             6564692      3504867  -46.61%
 Benchmark_ZFlat2              902029       513700  -43.05%
 Benchmark_ZFlat3              678722       384312  -43.38%
 Benchmark_ZFlat4             1197389       654361  -45.35%
 Benchmark_ZFlat5              262677       144939  -44.82%
 Benchmark_ZFlat6              111249        60876  -45.28%
 Benchmark_ZFlat7               39024        19420  -50.24%
 Benchmark_ZFlat8             8046106      4387928  -45.47%
 Benchmark_ZFlat9             2043167      1143139  -44.05%
 Benchmark_ZFlat10            1781604       980528  -44.96%
 Benchmark_ZFlat11            5478647      3078585  -43.81%
 Benchmark_ZFlat12            7245995      3929863  -45.77%
 Benchmark_ZFlat13            2432529      1371606  -43.61%
 Benchmark_ZFlat14             420315       227494  -45.88%
 Benchmark_ZFlat15              52378        26564  -49.28%
 Benchmark_ZFlat16             567047       316196  -44.24%
 Benchmark_ZFlat17            1630820       937310  -42.53%

 benchmark                   old MB/s     new MB/s  speedup
 BenchmarkWordsDecode1e3       102.71       189.08    1.84x
 BenchmarkWordsDecode1e4        99.77       180.60    1.81x
 BenchmarkWordsDecode1e5        96.38       183.01    1.90x
 BenchmarkWordsDecode1e6       104.61       187.43    1.79x
 BenchmarkWordsEncode1e3        61.70       150.85    2.44x
 BenchmarkWordsEncode1e4        71.28       136.68    1.92x
 BenchmarkWordsEncode1e5        67.72       127.92    1.89x
 BenchmarkWordsEncode1e6        78.73       142.90    1.82x
 Benchmark_UFlat0              257.73       462.93    1.80x
 Benchmark_UFlat1              180.46       349.59    1.94x
 Benchmark_UFlat2             3545.30      8244.61    2.33x
 Benchmark_UFlat3              669.72      1271.39    1.90x
 Benchmark_UFlat4              502.84       959.74    1.91x
 Benchmark_UFlat5              156.71       301.98    1.93x
 Benchmark_UFlat6              143.60       258.33    1.80x
 Benchmark_UFlat7              146.41       274.01    1.87x
 Benchmark_UFlat8              161.59       301.72    1.87x
 Benchmark_UFlat9              104.62       192.53    1.84x
 Benchmark_UFlat10             100.70       189.45    1.88x
 Benchmark_UFlat11             109.33       198.83    1.82x
 Benchmark_UFlat12              94.37       178.72    1.89x
 Benchmark_UFlat13             312.67       579.93    1.85x
 Benchmark_UFlat14             145.84       291.52    2.00x
 Benchmark_UFlat15             130.77       247.95    1.90x
 Benchmark_UFlat16             323.14       578.82    1.79x
 Benchmark_UFlat17             137.14       239.09    1.74x
 Benchmark_ZFlat0              176.57       310.48    1.76x
 Benchmark_ZFlat1              106.95       200.32    1.87x
 Benchmark_ZFlat2              140.75       247.14    1.76x
 Benchmark_ZFlat3              138.98       245.45    1.77x
 Benchmark_ZFlat4              342.08       625.95    1.83x
 Benchmark_ZFlat5               93.66       169.75    1.81x
 Benchmark_ZFlat6              100.23       183.16    1.83x
 Benchmark_ZFlat7               95.35       191.60    2.01x
 Benchmark_ZFlat8              127.98       234.68    1.83x
 Benchmark_ZFlat9               74.44       133.04    1.79x
 Benchmark_ZFlat10              70.26       127.66    1.82x
 Benchmark_ZFlat11              77.89       138.62    1.78x
 Benchmark_ZFlat12              66.50       122.62    1.84x
 Benchmark_ZFlat13             210.98       374.17    1.77x
 Benchmark_ZFlat14              90.98       168.09    1.85x
 Benchmark_ZFlat15              80.70       159.12    1.97x
 Benchmark_ZFlat16             209.13       375.04    1.79x
 Benchmark_ZFlat17             113.02       196.65    1.74x
 $

Build tags

If a constraint 'purego' appears in the build constraints [5] then a pure Go
version is built regardless of the $CGO_ENABLED value.

	$ touch zappy.go ; go install -tags purego github.com/cznic/zappy # for example

Information sources

... referenced from the above documentation.

 [1]: http://github.com/golang/snappy
 [2]: http://code.google.com/p/snappy/
 [3]: http://code.google.com/p/snappy/source/browse/trunk/format_description.txt
 [4]: http://golang.org/pkg/encoding/binary/
 [5]: http://golang.org/pkg/go/build/#hdr-Build_Constraints
*/
package zappy
