UNPKG

3.69 kBJavaScriptView Raw
1// Copyright 2012 The Obvious Corporation.
2
3/*
4 * bits: Bitwise buffer utilities. The utilities here treat a buffer
5 * as a little-endian bigint, so the lowest-order bit is bit #0 of
6 * `buffer[0]`, and the highest-order bit is bit #7 of
7 * `buffer[buffer.length - 1]`.
8 */
9
10/*
11 * Modules used
12 */
13"use strict";
14/*
15 * Exported bindings
16 */
17
18/**
19 * Extracts the given number of bits from the buffer at the indicated
20 * index, returning a simple number as the result. If bits are requested
21 * that aren't covered by the buffer, the `defaultBit` is used as their
22 * value.
23 *
24 * The `bitLength` must be no more than 32. The `defaultBit` if not
25 * specified is taken to be `0`.
26 */
27
28Object.defineProperty(exports, "__esModule", {
29 value: true
30});
31exports.extract = extract;
32exports.inject = inject;
33exports.getSign = getSign;
34exports.highOrder = highOrder;
35
36function extract(buffer, bitIndex, bitLength, defaultBit) {
37 if (bitLength < 0 || bitLength > 32) {
38 throw new Error("Bad value for bitLength.");
39 }
40
41 if (defaultBit === undefined) {
42 defaultBit = 0;
43 } else if (defaultBit !== 0 && defaultBit !== 1) {
44 throw new Error("Bad value for defaultBit.");
45 }
46
47 var defaultByte = defaultBit * 0xff;
48 var result = 0; // All starts are inclusive. The {endByte, endBit} pair is exclusive, but
49 // if endBit !== 0, then endByte is inclusive.
50
51 var lastBit = bitIndex + bitLength;
52 var startByte = Math.floor(bitIndex / 8);
53 var startBit = bitIndex % 8;
54 var endByte = Math.floor(lastBit / 8);
55 var endBit = lastBit % 8;
56
57 if (endBit !== 0) {
58 // `(1 << endBit) - 1` is the mask of all bits up to but not including
59 // the endBit.
60 result = get(endByte) & (1 << endBit) - 1;
61 }
62
63 while (endByte > startByte) {
64 endByte--;
65 result = result << 8 | get(endByte);
66 }
67
68 result >>>= startBit;
69 return result;
70
71 function get(index) {
72 var result = buffer[index];
73 return result === undefined ? defaultByte : result;
74 }
75}
76/**
77 * Injects the given bits into the given buffer at the given index. Any
78 * bits in the value beyond the length to set are ignored.
79 */
80
81
82function inject(buffer, bitIndex, bitLength, value) {
83 if (bitLength < 0 || bitLength > 32) {
84 throw new Error("Bad value for bitLength.");
85 }
86
87 var lastByte = Math.floor((bitIndex + bitLength - 1) / 8);
88
89 if (bitIndex < 0 || lastByte >= buffer.length) {
90 throw new Error("Index out of range.");
91 } // Just keeping it simple, until / unless profiling shows that this
92 // is a problem.
93
94
95 var atByte = Math.floor(bitIndex / 8);
96 var atBit = bitIndex % 8;
97
98 while (bitLength > 0) {
99 if (value & 1) {
100 buffer[atByte] |= 1 << atBit;
101 } else {
102 buffer[atByte] &= ~(1 << atBit);
103 }
104
105 value >>= 1;
106 bitLength--;
107 atBit = (atBit + 1) % 8;
108
109 if (atBit === 0) {
110 atByte++;
111 }
112 }
113}
114/**
115 * Gets the sign bit of the given buffer.
116 */
117
118
119function getSign(buffer) {
120 return buffer[buffer.length - 1] >>> 7;
121}
122/**
123 * Gets the zero-based bit number of the highest-order bit with the
124 * given value in the given buffer.
125 *
126 * If the buffer consists entirely of the other bit value, then this returns
127 * `-1`.
128 */
129
130
131function highOrder(bit, buffer) {
132 var length = buffer.length;
133 var fullyWrongByte = (bit ^ 1) * 0xff; // the other-bit extended to a full byte
134
135 while (length > 0 && buffer[length - 1] === fullyWrongByte) {
136 length--;
137 }
138
139 if (length === 0) {
140 // Degenerate case. The buffer consists entirely of ~bit.
141 return -1;
142 }
143
144 var byteToCheck = buffer[length - 1];
145 var result = length * 8 - 1;
146
147 for (var i = 7; i > 0; i--) {
148 if ((byteToCheck >> i & 1) === bit) {
149 break;
150 }
151
152 result--;
153 }
154
155 return result;
156}
\No newline at end of file