-
Notifications
You must be signed in to change notification settings - Fork 0
/
bitpack.c
165 lines (129 loc) · 3.41 KB
/
bitpack.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "assert.h"
#include "except.h"
Except_T Bitpack_Overflow = { "Overflow Packing Bits" };
uint64_t shl(uint64_t word, unsigned bits) {
assert(bits <= 64);
if (bits == 64) {
// shifting 64 results in 64 0s
return 0;
} else {
// otherwise shift by bits
return (word << bits);
}
}
uint64_t shr(uint64_t word, unsigned bits) {
assert(bits <= 64);
if (bits == 64) {
// shifting 64 results in 64 0s
return 0;
} else {
// otherwise shift by bits
return (word >> bits);
}
}
uint64_t sra(uint64_t word, unsigned bits) {
assert(bits <= 64);
if (bits == 64) {
bits = 63;
}
return (int64_t)word >> bits;
}
bool Bitpack_fitsu(uint64_t n, unsigned width) {
assert(width <= 64);
// limit is equal to all 1 bits
uint64_t limit = ~0;
// limit = 2^63
limit = shl(limit, 63);
// limit = 2^(width+1);
limit = shr(limit, 64-width-1);
if (n < limit) {
return true;
} else {
return false;
}
}
bool Bitpack_fitss(int64_t n, unsigned width) {
assert(width <= 64);
// limit is equal to all 1 bits
int64_t lower_limit = ~0;
// shifted 1 bits in signed are lower limit
lower_limit = (int64_t)shl(lower_limit, width-1);
if (n >= lower_limit && n <= ~lower_limit) {
return true;
} else {
return false;
}
}
uint64_t Bitpack_getu(uint64_t word, unsigned width, unsigned lsb) {
assert(width <= 64);
// isolate bits in desired region
uint64_t n = ~0;
n = shl(n, (64-width));
n = shr(n, (64-width-lsb));
// logical and isolates desired bits in word
word = (word & n);
// moves isolated bits to the least significant bits in word
word = shr(word, lsb);
return word;
}
int64_t Bitpack_gets(uint64_t word, unsigned width, unsigned lsb) {
assert(width <= 64);
// isolate bits in desired region
uint64_t n = ~0;
n = shl(n, (64-width));
n = shr(n, (64-width-lsb));
// logical and isolated bits in word
word = (word & n);
// shifts isolated bits to the most significant bits to appease signed notation
word = shl(word, (64-width-lsb));
// shifts the bits to the right
word = sra(word, (64-width));
return (uint64_t)word;
}
uint64_t Bitpack_newu(uint64_t word, unsigned width, unsigned lsb, uint64_t value) {
assert(width <= 64);
// if the value fits in the desired bits
if (Bitpack_fitsu(value, width)) {
// isolate desired bits
int64_t n = ~0;
n = shl(n, (64-width));
n = shr(n, (64-width-lsb));
// move value bits to desired range
value = shl(value, lsb);
// logical and isolates the desired bits
// in the desired location in value
value = (value & n);
// logical and clears the desired bits in word
word = (word & ~n);
// logical or combines word and value into word
word = (word | value);
} else {
RAISE(Bitpack_Overflow);
}
return word;
}
uint64_t Bitpack_news(uint64_t word, unsigned width, unsigned lsb, int64_t value) {
assert(width <= 64);
// if the value fits in the desired bits
if (Bitpack_fitss(value, width)) {
// isolate desired bits
int64_t n = ~0;
n = shl(n, (64-width));
n = shr(n, (64-width-lsb));
// move value bits to desired range
value = shl(value, lsb);
// logical and isolates the desired bits
// in the desired location in value
value = (value & n);
// logical and clears the desired bits in word
word = (word & ~n);
// logical or combines word and value into word
word = (word | value);
} else {
RAISE(Bitpack_Overflow);
}
return word;
}