├── .gitignore ├── LICENSE ├── README.md └── svb ├── decode.go ├── decode_test.go ├── doc.go ├── encode.go ├── encode_test.go ├── lookup.go └── lookup_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # stream-vbyte-go 2 | A port of Stream VByte to Go 3 | 4 | Stream VByte is a variable-length unsigned int encoding designed to make SIMD processing more efficient. 5 | 6 | See https://lemire.me/blog/2017/09/27/stream-vbyte-breaking-new-speed-records-for-integer-compression/ and https://arxiv.org/pdf/1709.08990.pdf for details on the format. 7 | 8 | The reference C implementation is https://github.com/lemire/streamvbyte. 9 | 10 | There is also a Rust implementation https://bitbucket.org/marshallpierce/stream-vbyte-rust. 11 | -------------------------------------------------------------------------------- /svb/decode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Nelz 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svb 16 | 17 | import "io" 18 | 19 | // Uint32s decodes a quad of uint32 from the data buffer, returning 20 | // the four uint32s and the number of bytes consumed from the buffer. 21 | // If there aren't enough bytes in the data buffer to match what is required 22 | // by the ctrl byte, the quad is returned as zeros with n = 0. 23 | func Uint32s(ctrl byte, data []byte) (nums [4]uint32, n int) { 24 | blens := lookup[ctrl] 25 | if len(data) < int(blens[0]+blens[1]+blens[2]+blens[3]) { 26 | return nums, 0 27 | } 28 | for ix, blen := range blens { 29 | for jx := uint8(0); jx < blen; jx++ { 30 | nums[ix] <<= 8 31 | nums[ix] |= uint32(data[n]) 32 | n++ 33 | } 34 | } 35 | return nums, n 36 | } 37 | 38 | // ReadUint32s reads a quad of uint32 from d, using the information encoded 39 | // in the ctrl byte. 40 | func ReadUint32s(ctrl byte, d io.ByteReader) (nums [4]uint32, err error) { 41 | blens := lookup[ctrl] 42 | var n int 43 | for ix, blen := range blens { 44 | for jx := uint8(0); jx < blen; jx++ { 45 | b, err := d.ReadByte() 46 | if err != nil { 47 | return nums, err 48 | } 49 | nums[ix] <<= 8 50 | nums[ix] |= uint32(b) 51 | n++ 52 | } 53 | } 54 | return nums, nil 55 | } 56 | 57 | // GetU32Block decodes a single quad of uint32 values. (This function is the 58 | // read-side parallel to PutU32Block. These operations are optimized for read- 59 | // side speed.) 60 | // 61 | // The ctrl byte conveys information about the block being decoded. The data 62 | // parameter is the buffer where we will be pulling the raw data from, and may 63 | // require up to 16 bytes to be available. The diff parameter indicates whether 64 | // the values were encoded using "differential coding" (for more efficient 65 | // storage). 66 | // 67 | // The results are the quad of data decoded along with an indication of the 68 | // number of bytes consumed from the data buffer. 69 | // 70 | // Panics will be thrown if there are too few bytes available in the data 71 | // buffer. 72 | func GetU32Block(ctrl byte, data []byte, diff bool) (quad [4]uint32, n int) { 73 | blens := lookup[ctrl] 74 | for ix, blen := range blens { 75 | if blen == 4 { 76 | quad[ix] |= (uint32(data[n]) << 24) 77 | n++ 78 | } 79 | if blen >= 3 { 80 | quad[ix] |= (uint32(data[n]) << 16) 81 | n++ 82 | } 83 | if blen >= 2 { 84 | quad[ix] |= (uint32(data[n]) << 8) 85 | n++ 86 | } 87 | quad[ix] |= uint32(data[n]) 88 | n++ 89 | } 90 | if diff { 91 | quad[1] += quad[0] 92 | quad[2] += quad[1] 93 | quad[3] += quad[2] 94 | } 95 | return quad, n 96 | } 97 | -------------------------------------------------------------------------------- /svb/decode_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Nelz 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svb 16 | 17 | import ( 18 | "bytes" 19 | "math/rand" 20 | "testing" 21 | "time" 22 | ) 23 | 24 | func TestUint32s(t *testing.T) { 25 | tests := []struct { 26 | control byte 27 | data []byte 28 | results []uint32 29 | isErr bool 30 | }{ 31 | // Figure 3 from https://arxiv.org/pdf/1709.08990.pdf 32 | { 33 | 0x43, // 01 | 00 | 00 | 11 34 | []byte{ 35 | 0x04, 0x00, // 1024 36 | 0x0c, // 12 37 | 0x0a, // 10 38 | 0x40, 0x00, 0x00, 0x00, // 1,073,741,824 39 | }, 40 | []uint32{ 41 | 1024, 42 | 12, 43 | 10, 44 | 1073741824, 45 | }, 46 | false, 47 | }, 48 | // Figure 3 from https://arxiv.org/pdf/1709.08990.pdf 49 | { 50 | 0x01, // 00 | 00 | 00 | 01 51 | []byte{ 52 | 0x01, // 1 53 | 0x02, // 2 54 | 0x03, // 3 55 | 0x04, 0x00, // 1024 56 | }, 57 | []uint32{ 58 | 1, 59 | 2, 60 | 3, 61 | 1024, 62 | }, 63 | false, 64 | }, 65 | // This is an error case, expecting ErrInsufficient 66 | { 67 | 0x00, // 00 | 00 | 00 | 00 68 | []byte{0x00, 0x00, 0x00}, // insufficient 69 | []uint32{0, 0, 0, 0}, 70 | true, 71 | }, 72 | } 73 | 74 | for _, test := range tests { 75 | // raw buffer form // 76 | // - - - - - - - - // 77 | r, n := Uint32s(test.control, test.data) 78 | 79 | if test.isErr { 80 | if n != 0 { 81 | t.Errorf("%#x: %d != 0\n", test.control, n) 82 | } 83 | } else { 84 | blens := lookup[test.control] 85 | size := int(blens[0] + blens[1] + blens[2] + blens[3]) 86 | if n != size { 87 | t.Errorf("%#x: %d != %d\n", test.control, n, size) 88 | } 89 | } 90 | 91 | for ix, expected := range test.results { 92 | if r[ix] != expected { 93 | t.Errorf("%#x: %d != %d\n", test.control, r[ix], expected) 94 | } 95 | } 96 | 97 | // via io.ByteReader // 98 | // - - - - - - - - - // 99 | var err error 100 | r, err = ReadUint32s(test.control, bytes.NewBuffer(test.data)) 101 | if err != nil && !test.isErr { 102 | t.Errorf("unexpected: %v\n", err) 103 | } 104 | 105 | for ix, expected := range test.results { 106 | if r[ix] != expected { 107 | t.Errorf("%#x: %d != %d\n", test.control, r[ix], expected) 108 | } 109 | } 110 | } 111 | } 112 | 113 | func TestGetU32BlockPanicForData(t *testing.T) { 114 | defer func() { 115 | if r := recover(); r == nil { 116 | t.Errorf("no panic received") 117 | } 118 | }() 119 | GetU32Block(0xff, []byte{0x00, 0x00, 0x00}, false) 120 | } 121 | 122 | func TestGetU32Block(t *testing.T) { 123 | tests := []struct { 124 | ctrl byte 125 | data []byte 126 | quad []uint32 127 | size int 128 | }{ 129 | { // Smallest possible block 130 | 0x00, 131 | []byte{0x00, 0x00, 0x00, 0x00}, 132 | []uint32{0, 0, 0, 0}, 133 | 4, 134 | }, 135 | { // Smallest all-4-byte representation 136 | 0xff, 137 | []byte{ 138 | 0x01, 0x00, 0x00, 0x00, 139 | 0x01, 0x00, 0x00, 0x00, 140 | 0x01, 0x00, 0x00, 0x00, 141 | 0x01, 0x00, 0x00, 0x00, 142 | }, 143 | []uint32{(1 << 24), 2 * (1 << 24), 3 * (1 << 24), 4 * (1 << 24)}, 144 | 16, 145 | }, 146 | { // From whitepapaer: 1024, 12, 10, 1073741824 147 | 0x43, 148 | []byte{ 149 | 0x04, 0x00, // 1024 150 | 0x0c, // 12 151 | 0x0a, // 10 152 | 0x40, 0x00, 0x00, 0x00, // 1073741824 153 | }, 154 | []uint32{1024, 1036, 1046, 1073742870}, 155 | 8, 156 | }, 157 | { // From whitepapaer: 1, 2, 3, 1024 158 | 0x01, 159 | []byte{ 160 | 0x01, // 1 161 | 0x02, // 2 162 | 0x03, // 3 163 | 0x04, 0x00, // 1024 164 | }, 165 | []uint32{1, 3, 6, 1030}, 166 | 5, 167 | }, 168 | } 169 | 170 | for _, test := range tests { 171 | quad, size := GetU32Block(test.ctrl, test.data, true) 172 | if size != test.size { 173 | t.Errorf("mismatch size: %d != %d\n", size, test.size) 174 | } 175 | for ix := 0; ix < 4; ix++ { 176 | if quad[ix] != test.quad[ix] { 177 | t.Errorf("mismatch via %d: %x != %x\n", ix, quad[ix], test.quad[ix]) 178 | } 179 | } 180 | } 181 | } 182 | 183 | func TestU32BlockRoundtrip(t *testing.T) { 184 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 185 | data := make([]byte, 16) 186 | quad := []uint32{0, 0, 0, 0} 187 | for ix := 0; ix < 100; ix++ { 188 | diff := (ix%2 == 0) 189 | 190 | ctrl, size := PutU32Block(data, quad, diff) 191 | q, s := GetU32Block(ctrl, data[:size], diff) 192 | 193 | if s != size { 194 | t.Errorf("mismatch size: %d != %d for %v\n", s, size, quad) 195 | } 196 | 197 | // Test this block, but also setup the random data for 198 | // the next iteration 199 | for jx := range quad { 200 | if q[jx] != quad[jx] { 201 | t.Errorf("mismatch: %v != %v\n", q, quad) 202 | } 203 | 204 | // Generate random data for the next time round 205 | blen := uint(1 + r.Intn(4)) 206 | top := uint32(1) << (8 * blen) 207 | low := (uint32(1) << (8 * (blen - 1))) - 1 208 | quad[jx] = low + uint32(r.Intn(int(top-low))) 209 | // t.Logf("%d: %d\n", jx, quad[jx]) 210 | } 211 | // t.Logf("size: %d\n", size) 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /svb/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Nelz 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package svb is a Go port of the Stream VByte algorithm, as designed 16 | // by Lemire/Kurz/Rupp (https://arxiv.org/abs/1709.08990). 17 | package svb 18 | -------------------------------------------------------------------------------- /svb/encode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Nelz 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svb 16 | 17 | var offsets = []uint8{24, 16, 8, 0} 18 | 19 | // PutUint32s encodes a quad of uint32 into the data buffer, returning 20 | // the control byte that signifies the encoded byte lengths, and the length 21 | // of how many bytes got written to the data buffer. 22 | // If the buffer is too small, PutUStreamVByte will panic 23 | func PutUint32s(data []byte, num0, num1, num2, num3 uint32) (ctrl byte, n int) { 24 | for _, num := range []uint32{num0, num1, num2, num3} { 25 | ctrl <<= 2 26 | blen := byteLength(num) 27 | ctrl |= byte(blen - 1) 28 | for _, offset := range offsets[(4 - blen):] { 29 | data[n] = byte((num >> offset) & 0xff) 30 | n++ 31 | } 32 | } 33 | return ctrl, n 34 | } 35 | 36 | func byteLength(n uint32) uint8 { 37 | if n < 256 { 38 | return 1 39 | } 40 | if n < 65536 { 41 | return 2 42 | } 43 | if n < 16777216 { 44 | return 3 45 | } 46 | return 4 47 | } 48 | 49 | // PutU32Block encodes a single quad of uint32 values. (This function is the 50 | // write-side parallel to GetU32Block. These operations are optimized for 51 | // read-side speed, but the write-side is still pretty quick.) 52 | // 53 | // The data parameter is the buffer where the encoded values are written, and 54 | // may need up to 16 bytes available. The quad parameter is the buffer of 55 | // integers that are to be encoded, and needs to have 4 values available. 56 | // The diff value signifies that you want to use "differential coding" (for 57 | // more efficient storage of the values), but this requires that the values 58 | // must be in ascending sorted order. 59 | // 60 | // The ctrl byte returned is a required hint for decoding, and is expected to 61 | // be stored in parallel to the data buffer. And the return value n represents 62 | // the number of bytes used in the data buffer, as per the algorithm. 63 | // 64 | // Panics will be thrown if there are too few bytes available in the data 65 | // buffer, or too few values in the quad buffer. 66 | func PutU32Block(data []byte, quad []uint32, diff bool) (ctrl byte, n int) { 67 | var prev uint32 68 | for i := uint(0); i < 4; i++ { 69 | num := quad[i] 70 | if diff { 71 | num = num - prev 72 | prev += num 73 | } 74 | blen := byteLength(num) 75 | ctrl |= ((blen - 1) << (6 - 2*i)) 76 | if blen == 4 { 77 | data[n] = byte((num >> 24) & 0xff) 78 | n++ 79 | } 80 | if blen >= 3 { 81 | data[n] = byte((num >> 16) & 0xff) 82 | n++ 83 | } 84 | if blen >= 2 { 85 | data[n] = byte((num >> 8) & 0xff) 86 | n++ 87 | } 88 | data[n] = byte(num & 0xff) 89 | n++ 90 | } 91 | return ctrl, n 92 | } 93 | -------------------------------------------------------------------------------- /svb/encode_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Nelz 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svb 16 | 17 | import "testing" 18 | 19 | func TestPutUint32s(t *testing.T) { 20 | tests := []struct { 21 | input []uint32 22 | control byte 23 | data []byte 24 | }{ 25 | { 26 | []uint32{1024, 12, 10, 1073741824}, 27 | 0x43, // 01 | 00 | 00 | 11 28 | []byte{ 29 | 0x04, 0x00, // 1024 30 | 0x0c, // 12 31 | 0x0a, // 10 32 | 0x40, 0x00, 0x00, 0x00, // 1,073,741,824 33 | }, 34 | }, 35 | } 36 | 37 | for _, test := range tests { 38 | d := make([]byte, 16) 39 | c, n := PutUint32s(d, test.input[0], test.input[1], test.input[2], test.input[3]) 40 | 41 | if c != test.control { 42 | t.Errorf("control: %#x != %#x\n", c, test.control) 43 | } 44 | blens := lookup[c] 45 | size := blens[0] + blens[1] + blens[2] + blens[3] 46 | if n != int(size) { 47 | t.Errorf("size: %d != %d", n, size) 48 | } 49 | } 50 | } 51 | 52 | func TestPutUint32sPanic(t *testing.T) { 53 | defer func() { 54 | if r := recover(); r == nil { 55 | t.Errorf("no panic received") 56 | } 57 | }() 58 | PutUint32s([]byte{0x00}, 0, 1, 2, 3) 59 | } 60 | 61 | func TestPutU32BlockPanicForData(t *testing.T) { 62 | defer func() { 63 | if r := recover(); r == nil { 64 | t.Errorf("no panic received") 65 | } 66 | }() 67 | PutU32Block([]byte{}, []uint32{0, 0, 0, 0}, false) 68 | } 69 | 70 | func TestPutU32BlockPanicForQuad(t *testing.T) { 71 | defer func() { 72 | if r := recover(); r == nil { 73 | t.Errorf("no panic received") 74 | } 75 | }() 76 | data := make([]byte, 16) 77 | PutU32Block(data, []uint32{0}, false) 78 | } 79 | 80 | func TestPutU32Block(t *testing.T) { 81 | tests := []struct { 82 | quad []uint32 83 | ctrl byte 84 | size int 85 | }{ 86 | { // Smallest possible encoded 87 | []uint32{0, 0, 0, 0}, 88 | 0x00, 89 | 4, 90 | }, 91 | { // Smallest all-4-byte representation 92 | []uint32{(1 << 24), 2 * (1 << 24), 3 * (1 << 24), 4 * (1 << 24)}, 93 | 0xff, 94 | 16, 95 | }, 96 | { // From whitepapaer (after diff coding): 1024, 12, 10, 1073741824 97 | []uint32{1024, 1036, 1046, 1073742870}, 98 | 0x43, 99 | 8, 100 | }, 101 | { // From whitepapaer (after diff coding): 1, 2, 3, 1024 102 | []uint32{1, 3, 6, 1030}, 103 | 0x01, 104 | 5, 105 | }, 106 | } 107 | 108 | for _, test := range tests { 109 | data := make([]byte, 16) 110 | ctrl, size := PutU32Block(data, test.quad, true) 111 | if ctrl != test.ctrl { 112 | t.Errorf("ctrl mismatch: %x != %x\n", ctrl, test.ctrl) 113 | } 114 | if size != test.size { 115 | t.Errorf("size mismatch: %d != %d\n", size, test.size) 116 | } 117 | // t.Logf("% x\n", data[:size]) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /svb/lookup.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Nelz 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svb 16 | 17 | // lengths is the lookup table that is the shortcut to get from a control 18 | // byte to knowing the 4 individual data byte lengths (in index 0 - 3), as 19 | // well as the total data bytes needed for the given block (in index 4) 20 | var lookup = map[byte][4]uint8{ 21 | 0x00: [4]uint8{1, 1, 1, 1}, 22 | 0x01: [4]uint8{1, 1, 1, 2}, 23 | 0x02: [4]uint8{1, 1, 1, 3}, 24 | 0x03: [4]uint8{1, 1, 1, 4}, 25 | 0x04: [4]uint8{1, 1, 2, 1}, 26 | 0x05: [4]uint8{1, 1, 2, 2}, 27 | 0x06: [4]uint8{1, 1, 2, 3}, 28 | 0x07: [4]uint8{1, 1, 2, 4}, 29 | 0x08: [4]uint8{1, 1, 3, 1}, 30 | 0x09: [4]uint8{1, 1, 3, 2}, 31 | 0x0a: [4]uint8{1, 1, 3, 3}, 32 | 0x0b: [4]uint8{1, 1, 3, 4}, 33 | 0x0c: [4]uint8{1, 1, 4, 1}, 34 | 0x0d: [4]uint8{1, 1, 4, 2}, 35 | 0x0e: [4]uint8{1, 1, 4, 3}, 36 | 0x0f: [4]uint8{1, 1, 4, 4}, 37 | 0x10: [4]uint8{1, 2, 1, 1}, 38 | 0x11: [4]uint8{1, 2, 1, 2}, 39 | 0x12: [4]uint8{1, 2, 1, 3}, 40 | 0x13: [4]uint8{1, 2, 1, 4}, 41 | 0x14: [4]uint8{1, 2, 2, 1}, 42 | 0x15: [4]uint8{1, 2, 2, 2}, 43 | 0x16: [4]uint8{1, 2, 2, 3}, 44 | 0x17: [4]uint8{1, 2, 2, 4}, 45 | 0x18: [4]uint8{1, 2, 3, 1}, 46 | 0x19: [4]uint8{1, 2, 3, 2}, 47 | 0x1a: [4]uint8{1, 2, 3, 3}, 48 | 0x1b: [4]uint8{1, 2, 3, 4}, 49 | 0x1c: [4]uint8{1, 2, 4, 1}, 50 | 0x1d: [4]uint8{1, 2, 4, 2}, 51 | 0x1e: [4]uint8{1, 2, 4, 3}, 52 | 0x1f: [4]uint8{1, 2, 4, 4}, 53 | 0x20: [4]uint8{1, 3, 1, 1}, 54 | 0x21: [4]uint8{1, 3, 1, 2}, 55 | 0x22: [4]uint8{1, 3, 1, 3}, 56 | 0x23: [4]uint8{1, 3, 1, 4}, 57 | 0x24: [4]uint8{1, 3, 2, 1}, 58 | 0x25: [4]uint8{1, 3, 2, 2}, 59 | 0x26: [4]uint8{1, 3, 2, 3}, 60 | 0x27: [4]uint8{1, 3, 2, 4}, 61 | 0x28: [4]uint8{1, 3, 3, 1}, 62 | 0x29: [4]uint8{1, 3, 3, 2}, 63 | 0x2a: [4]uint8{1, 3, 3, 3}, 64 | 0x2b: [4]uint8{1, 3, 3, 4}, 65 | 0x2c: [4]uint8{1, 3, 4, 1}, 66 | 0x2d: [4]uint8{1, 3, 4, 2}, 67 | 0x2e: [4]uint8{1, 3, 4, 3}, 68 | 0x2f: [4]uint8{1, 3, 4, 4}, 69 | 0x30: [4]uint8{1, 4, 1, 1}, 70 | 0x31: [4]uint8{1, 4, 1, 2}, 71 | 0x32: [4]uint8{1, 4, 1, 3}, 72 | 0x33: [4]uint8{1, 4, 1, 4}, 73 | 0x34: [4]uint8{1, 4, 2, 1}, 74 | 0x35: [4]uint8{1, 4, 2, 2}, 75 | 0x36: [4]uint8{1, 4, 2, 3}, 76 | 0x37: [4]uint8{1, 4, 2, 4}, 77 | 0x38: [4]uint8{1, 4, 3, 1}, 78 | 0x39: [4]uint8{1, 4, 3, 2}, 79 | 0x3a: [4]uint8{1, 4, 3, 3}, 80 | 0x3b: [4]uint8{1, 4, 3, 4}, 81 | 0x3c: [4]uint8{1, 4, 4, 1}, 82 | 0x3d: [4]uint8{1, 4, 4, 2}, 83 | 0x3e: [4]uint8{1, 4, 4, 3}, 84 | 0x3f: [4]uint8{1, 4, 4, 4}, 85 | 0x40: [4]uint8{2, 1, 1, 1}, 86 | 0x41: [4]uint8{2, 1, 1, 2}, 87 | 0x42: [4]uint8{2, 1, 1, 3}, 88 | 0x43: [4]uint8{2, 1, 1, 4}, 89 | 0x44: [4]uint8{2, 1, 2, 1}, 90 | 0x45: [4]uint8{2, 1, 2, 2}, 91 | 0x46: [4]uint8{2, 1, 2, 3}, 92 | 0x47: [4]uint8{2, 1, 2, 4}, 93 | 0x48: [4]uint8{2, 1, 3, 1}, 94 | 0x49: [4]uint8{2, 1, 3, 2}, 95 | 0x4a: [4]uint8{2, 1, 3, 3}, 96 | 0x4b: [4]uint8{2, 1, 3, 4}, 97 | 0x4c: [4]uint8{2, 1, 4, 1}, 98 | 0x4d: [4]uint8{2, 1, 4, 2}, 99 | 0x4e: [4]uint8{2, 1, 4, 3}, 100 | 0x4f: [4]uint8{2, 1, 4, 4}, 101 | 0x50: [4]uint8{2, 2, 1, 1}, 102 | 0x51: [4]uint8{2, 2, 1, 2}, 103 | 0x52: [4]uint8{2, 2, 1, 3}, 104 | 0x53: [4]uint8{2, 2, 1, 4}, 105 | 0x54: [4]uint8{2, 2, 2, 1}, 106 | 0x55: [4]uint8{2, 2, 2, 2}, 107 | 0x56: [4]uint8{2, 2, 2, 3}, 108 | 0x57: [4]uint8{2, 2, 2, 4}, 109 | 0x58: [4]uint8{2, 2, 3, 1}, 110 | 0x59: [4]uint8{2, 2, 3, 2}, 111 | 0x5a: [4]uint8{2, 2, 3, 3}, 112 | 0x5b: [4]uint8{2, 2, 3, 4}, 113 | 0x5c: [4]uint8{2, 2, 4, 1}, 114 | 0x5d: [4]uint8{2, 2, 4, 2}, 115 | 0x5e: [4]uint8{2, 2, 4, 3}, 116 | 0x5f: [4]uint8{2, 2, 4, 4}, 117 | 0x60: [4]uint8{2, 3, 1, 1}, 118 | 0x61: [4]uint8{2, 3, 1, 2}, 119 | 0x62: [4]uint8{2, 3, 1, 3}, 120 | 0x63: [4]uint8{2, 3, 1, 4}, 121 | 0x64: [4]uint8{2, 3, 2, 1}, 122 | 0x65: [4]uint8{2, 3, 2, 2}, 123 | 0x66: [4]uint8{2, 3, 2, 3}, 124 | 0x67: [4]uint8{2, 3, 2, 4}, 125 | 0x68: [4]uint8{2, 3, 3, 1}, 126 | 0x69: [4]uint8{2, 3, 3, 2}, 127 | 0x6a: [4]uint8{2, 3, 3, 3}, 128 | 0x6b: [4]uint8{2, 3, 3, 4}, 129 | 0x6c: [4]uint8{2, 3, 4, 1}, 130 | 0x6d: [4]uint8{2, 3, 4, 2}, 131 | 0x6e: [4]uint8{2, 3, 4, 3}, 132 | 0x6f: [4]uint8{2, 3, 4, 4}, 133 | 0x70: [4]uint8{2, 4, 1, 1}, 134 | 0x71: [4]uint8{2, 4, 1, 2}, 135 | 0x72: [4]uint8{2, 4, 1, 3}, 136 | 0x73: [4]uint8{2, 4, 1, 4}, 137 | 0x74: [4]uint8{2, 4, 2, 1}, 138 | 0x75: [4]uint8{2, 4, 2, 2}, 139 | 0x76: [4]uint8{2, 4, 2, 3}, 140 | 0x77: [4]uint8{2, 4, 2, 4}, 141 | 0x78: [4]uint8{2, 4, 3, 1}, 142 | 0x79: [4]uint8{2, 4, 3, 2}, 143 | 0x7a: [4]uint8{2, 4, 3, 3}, 144 | 0x7b: [4]uint8{2, 4, 3, 4}, 145 | 0x7c: [4]uint8{2, 4, 4, 1}, 146 | 0x7d: [4]uint8{2, 4, 4, 2}, 147 | 0x7e: [4]uint8{2, 4, 4, 3}, 148 | 0x7f: [4]uint8{2, 4, 4, 4}, 149 | 0x80: [4]uint8{3, 1, 1, 1}, 150 | 0x81: [4]uint8{3, 1, 1, 2}, 151 | 0x82: [4]uint8{3, 1, 1, 3}, 152 | 0x83: [4]uint8{3, 1, 1, 4}, 153 | 0x84: [4]uint8{3, 1, 2, 1}, 154 | 0x85: [4]uint8{3, 1, 2, 2}, 155 | 0x86: [4]uint8{3, 1, 2, 3}, 156 | 0x87: [4]uint8{3, 1, 2, 4}, 157 | 0x88: [4]uint8{3, 1, 3, 1}, 158 | 0x89: [4]uint8{3, 1, 3, 2}, 159 | 0x8a: [4]uint8{3, 1, 3, 3}, 160 | 0x8b: [4]uint8{3, 1, 3, 4}, 161 | 0x8c: [4]uint8{3, 1, 4, 1}, 162 | 0x8d: [4]uint8{3, 1, 4, 2}, 163 | 0x8e: [4]uint8{3, 1, 4, 3}, 164 | 0x8f: [4]uint8{3, 1, 4, 4}, 165 | 0x90: [4]uint8{3, 2, 1, 1}, 166 | 0x91: [4]uint8{3, 2, 1, 2}, 167 | 0x92: [4]uint8{3, 2, 1, 3}, 168 | 0x93: [4]uint8{3, 2, 1, 4}, 169 | 0x94: [4]uint8{3, 2, 2, 1}, 170 | 0x95: [4]uint8{3, 2, 2, 2}, 171 | 0x96: [4]uint8{3, 2, 2, 3}, 172 | 0x97: [4]uint8{3, 2, 2, 4}, 173 | 0x98: [4]uint8{3, 2, 3, 1}, 174 | 0x99: [4]uint8{3, 2, 3, 2}, 175 | 0x9a: [4]uint8{3, 2, 3, 3}, 176 | 0x9b: [4]uint8{3, 2, 3, 4}, 177 | 0x9c: [4]uint8{3, 2, 4, 1}, 178 | 0x9d: [4]uint8{3, 2, 4, 2}, 179 | 0x9e: [4]uint8{3, 2, 4, 3}, 180 | 0x9f: [4]uint8{3, 2, 4, 4}, 181 | 0xa0: [4]uint8{3, 3, 1, 1}, 182 | 0xa1: [4]uint8{3, 3, 1, 2}, 183 | 0xa2: [4]uint8{3, 3, 1, 3}, 184 | 0xa3: [4]uint8{3, 3, 1, 4}, 185 | 0xa4: [4]uint8{3, 3, 2, 1}, 186 | 0xa5: [4]uint8{3, 3, 2, 2}, 187 | 0xa6: [4]uint8{3, 3, 2, 3}, 188 | 0xa7: [4]uint8{3, 3, 2, 4}, 189 | 0xa8: [4]uint8{3, 3, 3, 1}, 190 | 0xa9: [4]uint8{3, 3, 3, 2}, 191 | 0xaa: [4]uint8{3, 3, 3, 3}, 192 | 0xab: [4]uint8{3, 3, 3, 4}, 193 | 0xac: [4]uint8{3, 3, 4, 1}, 194 | 0xad: [4]uint8{3, 3, 4, 2}, 195 | 0xae: [4]uint8{3, 3, 4, 3}, 196 | 0xaf: [4]uint8{3, 3, 4, 4}, 197 | 0xb0: [4]uint8{3, 4, 1, 1}, 198 | 0xb1: [4]uint8{3, 4, 1, 2}, 199 | 0xb2: [4]uint8{3, 4, 1, 3}, 200 | 0xb3: [4]uint8{3, 4, 1, 4}, 201 | 0xb4: [4]uint8{3, 4, 2, 1}, 202 | 0xb5: [4]uint8{3, 4, 2, 2}, 203 | 0xb6: [4]uint8{3, 4, 2, 3}, 204 | 0xb7: [4]uint8{3, 4, 2, 4}, 205 | 0xb8: [4]uint8{3, 4, 3, 1}, 206 | 0xb9: [4]uint8{3, 4, 3, 2}, 207 | 0xba: [4]uint8{3, 4, 3, 3}, 208 | 0xbb: [4]uint8{3, 4, 3, 4}, 209 | 0xbc: [4]uint8{3, 4, 4, 1}, 210 | 0xbd: [4]uint8{3, 4, 4, 2}, 211 | 0xbe: [4]uint8{3, 4, 4, 3}, 212 | 0xbf: [4]uint8{3, 4, 4, 4}, 213 | 0xc0: [4]uint8{4, 1, 1, 1}, 214 | 0xc1: [4]uint8{4, 1, 1, 2}, 215 | 0xc2: [4]uint8{4, 1, 1, 3}, 216 | 0xc3: [4]uint8{4, 1, 1, 4}, 217 | 0xc4: [4]uint8{4, 1, 2, 1}, 218 | 0xc5: [4]uint8{4, 1, 2, 2}, 219 | 0xc6: [4]uint8{4, 1, 2, 3}, 220 | 0xc7: [4]uint8{4, 1, 2, 4}, 221 | 0xc8: [4]uint8{4, 1, 3, 1}, 222 | 0xc9: [4]uint8{4, 1, 3, 2}, 223 | 0xca: [4]uint8{4, 1, 3, 3}, 224 | 0xcb: [4]uint8{4, 1, 3, 4}, 225 | 0xcc: [4]uint8{4, 1, 4, 1}, 226 | 0xcd: [4]uint8{4, 1, 4, 2}, 227 | 0xce: [4]uint8{4, 1, 4, 3}, 228 | 0xcf: [4]uint8{4, 1, 4, 4}, 229 | 0xd0: [4]uint8{4, 2, 1, 1}, 230 | 0xd1: [4]uint8{4, 2, 1, 2}, 231 | 0xd2: [4]uint8{4, 2, 1, 3}, 232 | 0xd3: [4]uint8{4, 2, 1, 4}, 233 | 0xd4: [4]uint8{4, 2, 2, 1}, 234 | 0xd5: [4]uint8{4, 2, 2, 2}, 235 | 0xd6: [4]uint8{4, 2, 2, 3}, 236 | 0xd7: [4]uint8{4, 2, 2, 4}, 237 | 0xd8: [4]uint8{4, 2, 3, 1}, 238 | 0xd9: [4]uint8{4, 2, 3, 2}, 239 | 0xda: [4]uint8{4, 2, 3, 3}, 240 | 0xdb: [4]uint8{4, 2, 3, 4}, 241 | 0xdc: [4]uint8{4, 2, 4, 1}, 242 | 0xdd: [4]uint8{4, 2, 4, 2}, 243 | 0xde: [4]uint8{4, 2, 4, 3}, 244 | 0xdf: [4]uint8{4, 2, 4, 4}, 245 | 0xe0: [4]uint8{4, 3, 1, 1}, 246 | 0xe1: [4]uint8{4, 3, 1, 2}, 247 | 0xe2: [4]uint8{4, 3, 1, 3}, 248 | 0xe3: [4]uint8{4, 3, 1, 4}, 249 | 0xe4: [4]uint8{4, 3, 2, 1}, 250 | 0xe5: [4]uint8{4, 3, 2, 2}, 251 | 0xe6: [4]uint8{4, 3, 2, 3}, 252 | 0xe7: [4]uint8{4, 3, 2, 4}, 253 | 0xe8: [4]uint8{4, 3, 3, 1}, 254 | 0xe9: [4]uint8{4, 3, 3, 2}, 255 | 0xea: [4]uint8{4, 3, 3, 3}, 256 | 0xeb: [4]uint8{4, 3, 3, 4}, 257 | 0xec: [4]uint8{4, 3, 4, 1}, 258 | 0xed: [4]uint8{4, 3, 4, 2}, 259 | 0xee: [4]uint8{4, 3, 4, 3}, 260 | 0xef: [4]uint8{4, 3, 4, 4}, 261 | 0xf0: [4]uint8{4, 4, 1, 1}, 262 | 0xf1: [4]uint8{4, 4, 1, 2}, 263 | 0xf2: [4]uint8{4, 4, 1, 3}, 264 | 0xf3: [4]uint8{4, 4, 1, 4}, 265 | 0xf4: [4]uint8{4, 4, 2, 1}, 266 | 0xf5: [4]uint8{4, 4, 2, 2}, 267 | 0xf6: [4]uint8{4, 4, 2, 3}, 268 | 0xf7: [4]uint8{4, 4, 2, 4}, 269 | 0xf8: [4]uint8{4, 4, 3, 1}, 270 | 0xf9: [4]uint8{4, 4, 3, 2}, 271 | 0xfa: [4]uint8{4, 4, 3, 3}, 272 | 0xfb: [4]uint8{4, 4, 3, 4}, 273 | 0xfc: [4]uint8{4, 4, 4, 1}, 274 | 0xfd: [4]uint8{4, 4, 4, 2}, 275 | 0xfe: [4]uint8{4, 4, 4, 3}, 276 | 0xff: [4]uint8{4, 4, 4, 4}, 277 | } 278 | -------------------------------------------------------------------------------- /svb/lookup_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Nelz 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svb 16 | 17 | import "testing" 18 | 19 | func TestLengths(t *testing.T) { 20 | offsets := []uint8{6, 4, 2, 0} 21 | for key, vals := range lookup { 22 | var total uint8 23 | for ix, offset := range offsets { 24 | expected := uint8(1 + ((key >> offset) & 0x03)) 25 | total += expected 26 | if vals[ix] != expected { 27 | t.Errorf("%#x, %d: %d != %d\n", key, ix, expected, vals[ix]) 28 | } 29 | } 30 | } 31 | } 32 | --------------------------------------------------------------------------------