1 // Copyright 2017-2019 VMware, Inc.
2 // SPDX-License-Identifier: BSD-2-Clause
3 //
4 // The BSD-2 license (the License) set forth below applies to all parts of the
5 // Cascade project. You may not use this file except in compliance with the
6 // License.
7 //
8 // BSD-2 License
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are met:
12 //
13 // 1. Redistributions of source code must retain the above copyright notice, this
14 // list of conditions and the following disclaimer.
15 //
16 // 2. Redistributions in binary form must reproduce the above copyright notice,
17 // this list of conditions and the following disclaimer in the documentation
18 // and/or other materials provided with the distribution.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND
21 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 #ifndef CASCADE_SRC_COMMON_BITS_H
32 #define CASCADE_SRC_COMMON_BITS_H
33
34 #include <algorithm>
35 #include <cassert>
36 #include <cctype>
37 #include <cmath>
38 #include <iostream>
39 #include <stdint.h>
40 #include <string>
41 #include <type_traits>
42 #include <vector>
43 #include "common/serializable.h"
44 #include "common/vector.h"
45
46 namespace cascade {
47
48 // This class is the fundamental representation of a bit string.
49
50 template <typename T, typename BT, typename ST>
51 class BitsBase : public Serializable {
52 public:
53 // Supporting Concepts:
54 enum class Type : uint8_t {
55 UNSIGNED = 0,
56 SIGNED,
57 REAL
58 };
59
60 // Constructors:
61 BitsBase();
62 explicit BitsBase(size_t n, Type t);
63 explicit BitsBase(bool b);
64 explicit BitsBase(char c);
65 explicit BitsBase(double d);
66 explicit BitsBase(const std::string& s);
67 explicit BitsBase(size_t n, T val);
68
69 // Compiler-Generated Constructors:
70 BitsBase(const BitsBase& rhs) = default;
71 BitsBase(BitsBase&& rhs) = default;
72 BitsBase& operator=(const BitsBase& rhs) = default;
73 BitsBase& operator=(BitsBase&& rhs) = default;
74 ~BitsBase() override = default;
75
76 // Serial I/O:
77 void read(std::istream& is, size_t base);
78 void write(std::ostream& os, size_t base) const;
79 size_t deserialize(std::istream& is) override;
80 size_t serialize(std::ostream& os) const override;
81
82 // Block I/O:
83 template <typename B>
84 B read_word(size_t n) const;
85 template <typename B>
86 void write_word(size_t n, B b);
87
88 // Value I/O:
89 void read(char c);
90
91 // Type Introspection:
92 size_t size() const;
93 Type get_type() const;
94 bool is_signed() const;
95 bool is_real() const;
96
97 // Native Casts:
98 bool to_bool() const;
99 char to_char() const;
100 double to_double() const;
101 std::string to_string() const;
102 T to_uint() const;
103
104 // Verilog Casts:
105 void resize(size_t n);
106 void cast_type(Type t);
107 void reinterpret_type(Type t);
108
109 // Bitwise Operators:
110 //
111 // Apply a bitwise operator to operands and store the result here. These
112 // methods assume equivalent bit-width between operands and destination and
113 // do not sign extend. These methods are undefined for reals.
114 void bitwise_and(const BitsBase& lhs, const BitsBase& rhs);
115 void bitwise_or(const BitsBase& lhs, const BitsBase& rhs);
116 void bitwise_xor(const BitsBase& lhs, const BitsBase& rhs);
117 void bitwise_xnor(const BitsBase& lhs, const BitsBase& rhs);
118 void bitwise_sll(const BitsBase& lhs, const BitsBase& rhs);
119 void bitwise_sal(const BitsBase& lhs, const BitsBase& rhs);
120 void bitwise_slr(const BitsBase& lhs, const BitsBase& rhs);
121 void bitwise_sar(const BitsBase& lhs, const BitsBase& rhs);
122 void bitwise_not(const BitsBase& lhs);
123
124 // Arithmetic Operators:
125 //
126 // Apply an arithmetic operator to operands and store the result here.
127 // These methods all assume equivalent bit-width between operands and
128 // destination and do not sign extend. These methods all work on signed,
129 // unsigned, and real values (with the exception of mod).
130 void arithmetic_plus(const BitsBase& lhs);
131 void arithmetic_plus(const BitsBase& lhs, const BitsBase& rhs);
132 void arithmetic_minus(const BitsBase& lhs);
133 void arithmetic_minus(const BitsBase& lhs, const BitsBase& rhs);
134 void arithmetic_multiply(const BitsBase& lhs, const BitsBase& rhs);
135 void arithmetic_divide(const BitsBase& lhs, const BitsBase& rhs);
136 void arithmetic_mod(const BitsBase& lhs, const BitsBase& rhs);
137 void arithmetic_pow(const BitsBase& lhs, const BitsBase& rhs);
138
139 // Logical Operators:
140 //
141 // Apply a logical operator to operands and store the result here. These
142 // methods all assume equivalent bit-width between operands and do not
143 // perform sign extension. These methods all work on signed, unsigned, and
144 // real values, but assume that their desintation is not real.
145 void logical_and(const BitsBase& lhs, const BitsBase& rhs);
146 void logical_or(const BitsBase& lhs, const BitsBase& rhs);
147 void logical_not(const BitsBase& lhs);
148 void logical_eq(const BitsBase& lhs, const BitsBase& rhs);
149 void logical_ne(const BitsBase& lhs, const BitsBase& rhs);
150 void logical_lt(const BitsBase& lhs, const BitsBase& rhs);
151 void logical_lte(const BitsBase& lhs, const BitsBase& rhs);
152 void logical_gt(const BitsBase& lhs, const BitsBase& rhs);
153 void logical_gte(const BitsBase& lhs, const BitsBase& rhs);
154
155 // Reduction Operators:
156 //
157 // Apply a reduction operator to an operand and store the result here.
158 // These methods all assume single bit-width in their destination and do
159 // not perform sign extension. These methods are undefined for real values.
160 void reduce_and(const BitsBase& lhs);
161 void reduce_nand(const BitsBase& lhs);
162 void reduce_or(const BitsBase& lhs);
163 void reduce_nor(const BitsBase& lhs);
164 void reduce_xor(const BitsBase& lhs);
165 void reduce_xnor(const BitsBase& lhs);
166
167 // Concatenation Operations:
168 //
169 // Concatenate two variables. This method is undefined for real values.
170 void concat(const BitsBase& rhs);
171
172 // Comparison Operators:
173 //
174 // Check for value equality. These methods make no assumptions with respect
175 // to size or type and cast rhs as necessary.
176 bool eq(const BitsBase& rhs) const;
177 bool eq(size_t idx, const BitsBase& rhs) const;
178 bool eq(size_t msb, size_t lsb, const BitsBase& rhs) const;
179
180 // Assignment Operators:
181 //
182 // Assign bits. These methods make no assumptions made with respect to
183 // sizes and handle sign-extension and type conversion as necessary.
184 // Subscripting operations are undefined for real operands.
185 //
186 // TODO(eschkufz> The latter two methods are undefined for reals period.
187 // This is to simplify their implementation based on the limited context in
188 // which they are called. Is this asymmetry masking a more elegant
189 // implementation?
190 void assign(const BitsBase& rhs);
191 void assign(size_t idx, const BitsBase& rhs);
192 void assign(size_t msb, size_t lsb, const BitsBase& rhs);
193 void assign(const BitsBase& rhs, size_t idx);
194 void assign(const BitsBase& rhs, size_t msb, size_t lsb);
195
196 // Copy Operators:
197 //
198 // Nothing fancy. Copies the state of the rhs.
199 void copy(const BitsBase& rhs);
200
201 // Bitwise Operators:
202 //
203 // These operators are meant for use outside of the constraints imposed by
204 // the verilog semantics for variables and have no restrictions on type.
205 bool get(size_t idx) const;
206 void set(size_t idx, bool b);
207 void flip(size_t idx);
208
209 // Built-in Comparison Operators:
210 //
211 // Logical comparison, assumes equal operand sizes and types for integer
212 // valeus. Will automatically cast reals to integers as necessary.
213 bool operator==(const BitsBase& rhs) const;
214 bool operator!=(const BitsBase& rhs) const;
215 bool operator<(const BitsBase& rhs) const;
216 bool operator<=(const BitsBase& rhs) const;
217 bool operator>(const BitsBase& rhs) const;
218 bool operator>=(const BitsBase& rhs) const;
219
220 private:
221 // Bit-string representation
222 Vector<T> val_;
223 // Total number of bits in this string
224 uint32_t size_;
225 // How is this value being interpreted
226 Type type_;
227
228 // Reads a real number, sets size to 64
229 void read_real(std::istream& is);
230 // Reads an unsigned number in base 2, 8, or 16, sets size based on result
231 void read_2_8_16(std::istream& is, size_t base);
232 // Reads a number in base 10, sets size and type based on result
233 void read_10(std::istream& is);
234 // Writes a number as a real
235 void write_real(std::ostream& os) const;
236 // Writes a number in base 2, 8, or 16 as an unsigned value
237 void write_2_8_16(std::ostream& os, size_t base) const;
238 // Writes a number in base 10 as a signed or unsigned value
239 void write_10(std::ostream& os) const;
240 // Halves a decimal value, stored as a string
241 void dec_halve(std::string& s) const;
242 // Returns true if a decimal value, stored as a string is 0
243 bool dec_zero(const std::string& s) const;
244 // Doubles a decimal value, stored as a string in reverse order
245 void dec_double(std::string& s) const;
246 // Increments a decimal value, stored as a string in reverse order
247 void dec_inc(std::string& s) const;
248
249 // Shift Helpers:
250 void bitwise_sll_const(const BitsBase& lhs, size_t samt);
251 void bitwise_sxr_const(const BitsBase& lhs, size_t samt, bool arith);
252
253 // Returns the nth (possibly greater than val_.size()th) word of this value.
254 // Performs sign extension as necessary.
255 T signed_get(size_t n) const;
256
257 // Returns true if this is a signed number with high order bit set
258 bool is_neg_signed() const;
259 // Zeros out bits with index greater than size_
260 void trim();
261 // Extends representation to n bits and zero pads
262 void extend_to(size_t n);
263 // Extends representation to n bits and sign extends if necessary
264 void sign_extend_to(size_t n);
265 // Shrinks size and calls trim
266 void shrink_to(size_t n);
267 // Shrinks to size one and sets val
268 void shrink_to_bool(bool b);
269 // Inverts bits and adds one
270 void invert_add_one();
271 // Updates size and type; sets value according to to_double().
272 void cast_int_to_real();
273 // Updates type according to arg, value and size according to_double().
274 void cast_real_to_int(bool s);
275
276 // Returns the number of bits in a word
277 constexpr size_t bits_per_word() const;
278 // Returns the number of bytes in a word
279 constexpr size_t bytes_per_word() const;
280 // Returns the number of unique values representable by T as a double
281 constexpr double range() const;
282 };
283
284 #ifdef __LP64__
285 using Bits = BitsBase<uint64_t, __uint128_t, int64_t>;
286 #else
287 using Bits = BitsBase<uint32_t, uint64_t, int32_t>;
288 #endif
289
290 template <typename T, typename BT, typename ST>
BitsBase()291 inline BitsBase<T, BT, ST>::BitsBase() {
292 val_.push_back(0);
293 size_ = 1;
294 type_ = Type::UNSIGNED;
295 }
296
297 template <typename T, typename BT, typename ST>
BitsBase(size_t n,Type t)298 inline BitsBase<T, BT, ST>::BitsBase(size_t n, Type t) {
299 if (type_ == Type::REAL) {
300 assert(n == 64);
301 val_.resize(64/bits_per_word());
302 *reinterpret_cast<double*>(val_.data()) = 0.0;
303 } else {
304 assert(n > 0);
305 val_.resize((n+bits_per_word()-1)/bits_per_word(), static_cast<T>(0));
306 }
307 size_ = n;
308 type_ = t;
309 }
310
311 template <typename T, typename BT, typename ST>
BitsBase(bool b)312 inline BitsBase<T, BT, ST>::BitsBase(bool b) {
313 val_.push_back(b ? static_cast<T>(1) : static_cast<T>(0));
314 size_ = 1;
315 type_ = Type::UNSIGNED;
316 }
317
318 template <typename T, typename BT, typename ST>
BitsBase(char c)319 inline BitsBase<T, BT, ST>::BitsBase(char c) {
320 val_.push_back(static_cast<T>(c));
321 size_ = 8;
322 type_ = Type::UNSIGNED;
323 }
324
325 template <typename T, typename BT, typename ST>
BitsBase(double d)326 inline BitsBase<T, BT, ST>::BitsBase(double d) {
327 val_.resize(64/bits_per_word());
328 *reinterpret_cast<double*>(val_.data()) = d;
329 size_ = 64;
330 type_ = Type::REAL;
331 }
332
333 template <typename T, typename BT, typename ST>
BitsBase(const std::string & s)334 inline BitsBase<T, BT, ST>::BitsBase(const std::string& s) {
335 val_.resize((s.length()+bytes_per_word()-1)/bytes_per_word(), static_cast<T>(0));
336 for (int pos = 0, i = s.length()-1; i >= 0; --i, ++pos) {
337 const auto idx = pos/bytes_per_word();
338 const auto off = 8*(pos%bytes_per_word());
339 val_[idx] |= (static_cast<T>(s[i]) << off);
340 }
341 size_ = 8*s.length();
342 type_ = Type::UNSIGNED;
343 }
344
345 template <typename T, typename BT, typename ST>
BitsBase(size_t n,T val)346 inline BitsBase<T, BT, ST>::BitsBase(size_t n, T val) {
347 assert(n > 0);
348 val_.resize((n+bits_per_word()-1)/bits_per_word(), static_cast<T>(0));
349 val_[0] = val;
350 size_ = n;
351 type_ = Type::UNSIGNED;
352 trim();
353 }
354
355 template <typename T, typename BT, typename ST>
read(std::istream & is,size_t base)356 inline void BitsBase<T, BT, ST>::read(std::istream& is, size_t base) {
357 switch (base) {
358 case 1:
359 return read_real(is);
360 case 2:
361 case 8:
362 case 16:
363 return read_2_8_16(is, base);
364 case 10:
365 return read_10(is);
366 default:
367 assert(false);
368 }
369 }
370
371 template <typename T, typename BT, typename ST>
write(std::ostream & os,size_t base)372 inline void BitsBase<T, BT, ST>::write(std::ostream& os, size_t base) const {
373 switch (base) {
374 case 0:
375 return is_real() ? write_real(os) : write_10(os);
376 case 1:
377 return write_real(os);
378 case 2:
379 case 8:
380 case 16:
381 return write_2_8_16(os, base);
382 case 10:
383 return write_10(os);
384 default:
385 assert(false);
386 }
387 }
388
389 template <typename T, typename BT, typename ST>
deserialize(std::istream & is)390 inline size_t BitsBase<T, BT, ST>::deserialize(std::istream& is) {
391 uint32_t header;
392 is.read(reinterpret_cast<char*>(&header), 4);
393
394 shrink_to_bool(false);
395 extend_to(header & 0x3fffffffu);
396 type_ = static_cast<Type>(header >> 30);
397
398 const auto n = (size_+7) / 8;
399 for (size_t i = 0; i < n; ++i) {
400 uint8_t b = is.get();
401 val_[i/bytes_per_word()] |= (static_cast<T>(b) << (8*(i%bytes_per_word())));
402 }
403
404 return 4 + n;
405 }
406
407 template <typename T, typename BT, typename ST>
serialize(std::ostream & os)408 inline size_t BitsBase<T, BT, ST>::serialize(std::ostream& os) const {
409 uint32_t header = size_ | (static_cast<uint32_t>(type_) << 30);
410 os.write(reinterpret_cast<char*>(&header), 4);
411
412 const auto n = (size_+7) / 8;
413 for (size_t i = 0; i < n; ++i) {
414 const uint8_t b = (val_[i/bytes_per_word()] >> (8*(i%bytes_per_word()))) & static_cast<T>(0xffu);
415 os.put(b);
416 }
417
418 return 4 + n;
419 }
420
421 template <typename T, typename BT, typename ST>
422 template <typename B>
read_word(size_t n)423 inline B BitsBase<T, BT, ST>::read_word(size_t n) const {
424 assert(sizeof(B) <= sizeof(T));
425
426 // Easy Case:
427 if (sizeof(B) == sizeof(T)) {
428 assert(n < val_.size());
429 return val_[n];
430 }
431
432 // Hard Case:
433 const auto b_per_word = sizeof(T) / sizeof(B);
434 const auto idx = n / b_per_word;
435 const auto off = n % b_per_word;
436
437 assert(idx < val_.size());
438 return val_[idx] >> (8*sizeof(B)*off);
439 }
440
441 template <typename T, typename BT, typename ST>
442 template <typename B>
write_word(size_t n,B b)443 inline void BitsBase<T, BT, ST>::write_word(size_t n, B b) {
444 assert(sizeof(B) <= sizeof(T));
445
446 // Easy Case:
447 if (sizeof(B) == sizeof(T)) {
448 assert(n < val_.size());
449 val_[n] = b;
450 return;
451 }
452
453 // Hard Case:
454 const auto b_per_word = sizeof(T) / sizeof(B);
455 const auto idx = n / b_per_word;
456 const auto off = n % b_per_word;
457
458 assert(idx < val_.size());
459 const T bmask = static_cast<B>(-1);
460 const auto mask = ~(bmask << (8*sizeof(B)*off));
461 val_[idx] &= mask;
462 val_[idx] |= (static_cast<T>(b) << (8*sizeof(B)*off));
463 trim();
464 }
465
466 template <typename T, typename BT, typename ST>
read(char c)467 inline void BitsBase<T, BT, ST>::read(char c) {
468 val_.resize(1);
469 val_[0] = static_cast<T>(c);
470 size_ = 8;
471 type_ = Type::UNSIGNED;
472 }
473
474 template <typename T, typename BT, typename ST>
size()475 inline size_t BitsBase<T, BT, ST>::size() const {
476 return size_;
477 }
478
479 template <typename T, typename BT, typename ST>
get_type()480 inline typename BitsBase<T, BT, ST>::Type BitsBase<T, BT, ST>::get_type() const {
481 return type_;
482 }
483
484 template <typename T, typename BT, typename ST>
is_signed()485 inline bool BitsBase<T, BT, ST>::is_signed() const {
486 return type_ != Type::UNSIGNED;
487 }
488
489 template <typename T, typename BT, typename ST>
is_real()490 inline bool BitsBase<T, BT, ST>::is_real() const {
491 return type_ == Type::REAL;
492 }
493
494 template <typename T, typename BT, typename ST>
to_bool()495 inline bool BitsBase<T, BT, ST>::to_bool() const {
496 // Special handling for real values.
497 if (type_ == Type::REAL) {
498 return *reinterpret_cast<const double*>(val_.data()) != 0.0;
499 }
500 // Otherwise check whether any bits are non-zero.
501 for (const auto& v : val_) {
502 if (v) {
503 return true;
504 }
505 }
506 return false;
507 }
508
509 template <typename T, typename BT, typename ST>
to_char()510 inline char BitsBase<T, BT, ST>::to_char() const {
511 return static_cast<char>(to_uint() & 0xffu);
512 }
513
514 template <typename T, typename BT, typename ST>
to_double()515 inline double BitsBase<T, BT, ST>::to_double() const {
516 switch (type_) {
517 case Type::SIGNED:
518 if (get(size_-1)) {
519 const_cast<BitsBase*>(this)->invert_add_one();
520 const_cast<BitsBase*>(this)->type_ = Type::UNSIGNED;
521 const auto res = to_double();
522 const_cast<BitsBase*>(this)->type_ = Type::SIGNED;
523 const_cast<BitsBase*>(this)->invert_add_one();
524 return res;
525 }
526 // Fallthrough...
527 case Type::UNSIGNED: {
528 double res = 0.0;
529 double base = 1.0;
530 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
531 res += base * val_[i];
532 base *= range();
533 }
534 return res;
535 }
536 case Type::REAL:
537 return *reinterpret_cast<const double*>(val_.data());
538 default:
539 assert(false);
540 return 0;
541 }
542 }
543
544 template <typename T, typename BT, typename ST>
to_string()545 inline std::string BitsBase<T, BT, ST>::to_string() const {
546 auto temp = *this;
547 // Cast real values to unsigned ints before printing.
548 if (type_ == Type::REAL) {
549 temp.cast_real_to_int(false);
550 }
551 // Pad values out to a multiple of 8 bits.
552 const auto trailing = temp.size() % 8;
553 if (trailing > 0) {
554 temp.sign_extend_to(temp.size() + 8 - trailing);
555 }
556 // Print characters, eight bits at a time.
557 std::string res(temp.size()/8, ' ');
558 for (int pos = 0, i = res.length()-1; i >= 0; --i, ++pos) {
559 const auto idx = pos/bytes_per_word();
560 const auto off = 8*(pos%bytes_per_word());
561 const auto val = (temp.val_[idx] >> off) & static_cast<T>(0xffu);
562 res[i] = ((val == 0) ? ' ' : static_cast<char>(val));
563 }
564 return res;
565 }
566
567 template <typename T, typename BT, typename ST>
to_uint()568 inline T BitsBase<T, BT, ST>::to_uint() const {
569 switch (type_) {
570 case Type::UNSIGNED:
571 case Type::SIGNED:
572 return val_[0];
573 case Type::REAL:
574 return std::round(*reinterpret_cast<const double*>(val_.data()));
575 default:
576 assert(false);
577 return 0;
578 }
579 }
580
581 template <typename T, typename BT, typename ST>
resize(size_t n)582 inline void BitsBase<T, BT, ST>::resize(size_t n) {
583 assert((type_ != Type::REAL) || (n == 64));
584 if (n < size_) {
585 shrink_to(n);
586 } else if (n > size_) {
587 sign_extend_to(n);
588 }
589 }
590
591 template <typename T, typename BT, typename ST>
cast_type(Type t)592 inline void BitsBase<T, BT, ST>::cast_type(Type t) {
593 if (type_ == t) {
594 return;
595 } else if (t == Type::REAL) {
596 cast_int_to_real();
597 } else if (type_ == Type::REAL) {
598 cast_real_to_int(t == Type::SIGNED);
599 } else {
600 type_ = t;
601 }
602 }
603
604 template <typename T, typename BT, typename ST>
reinterpret_type(Type t)605 inline void BitsBase<T, BT, ST>::reinterpret_type(Type t) {
606 if (type_ == t) {
607 return;
608 }
609 type_ = t;
610 if (type_ == Type::REAL) {
611 val_.resize(64/bits_per_word());
612 }
613 }
614
615 template <typename T, typename BT, typename ST>
bitwise_and(const BitsBase & lhs,const BitsBase & rhs)616 inline void BitsBase<T, BT, ST>::bitwise_and(const BitsBase& lhs, const BitsBase& rhs) {
617 assert(!is_real() && !lhs.is_real() && !rhs.is_real());
618 assert(size() == lhs.size());
619 assert(size() == rhs.size());
620
621 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
622 val_[i] = lhs.val_[i] & rhs.val_[i];
623 }
624 }
625
626 template <typename T, typename BT, typename ST>
bitwise_or(const BitsBase & lhs,const BitsBase & rhs)627 inline void BitsBase<T, BT, ST>::bitwise_or(const BitsBase& lhs, const BitsBase& rhs) {
628 assert(!is_real() && !lhs.is_real() && !rhs.is_real());
629 assert(size() == lhs.size());
630 assert(size() == rhs.size());
631
632 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
633 val_[i] = lhs.val_[i] | rhs.val_[i];
634 }
635 }
636
637 template <typename T, typename BT, typename ST>
bitwise_xor(const BitsBase & lhs,const BitsBase & rhs)638 inline void BitsBase<T, BT, ST>::bitwise_xor(const BitsBase& lhs, const BitsBase& rhs) {
639 assert(!is_real() && !lhs.is_real() && !rhs.is_real());
640 assert(size() == lhs.size());
641 assert(size() == rhs.size());
642
643 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
644 val_[i] = lhs.val_[i] ^ rhs.val_[i];
645 }
646 }
647
648 template <typename T, typename BT, typename ST>
bitwise_xnor(const BitsBase & lhs,const BitsBase & rhs)649 inline void BitsBase<T, BT, ST>::bitwise_xnor(const BitsBase& lhs, const BitsBase& rhs) {
650 assert(!is_real() && !lhs.is_real() && !rhs.is_real());
651 assert(size() == lhs.size());
652 assert(size() == rhs.size());
653
654 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
655 val_[i] = ~(lhs.val_[i] ^ rhs.val_[i]);
656 }
657 trim();
658 }
659
660 template <typename T, typename BT, typename ST>
bitwise_sll(const BitsBase & lhs,const BitsBase & rhs)661 inline void BitsBase<T, BT, ST>::bitwise_sll(const BitsBase& lhs, const BitsBase& rhs) {
662 assert(!rhs.is_real());
663 const auto samt = rhs.to_uint();
664 bitwise_sll_const(lhs, samt);
665 }
666
667 template <typename T, typename BT, typename ST>
bitwise_sal(const BitsBase & lhs,const BitsBase & rhs)668 inline void BitsBase<T, BT, ST>::bitwise_sal(const BitsBase& lhs, const BitsBase& rhs) {
669 // Equivalent to sll
670 bitwise_sll(lhs, rhs);
671 }
672
673 template <typename T, typename BT, typename ST>
bitwise_slr(const BitsBase & lhs,const BitsBase & rhs)674 inline void BitsBase<T, BT, ST>::bitwise_slr(const BitsBase& lhs, const BitsBase& rhs) {
675 assert(!rhs.is_real());
676 const auto samt = rhs.to_uint();
677 bitwise_sxr_const(lhs, samt, false);
678 }
679
680 template <typename T, typename BT, typename ST>
bitwise_sar(const BitsBase & lhs,const BitsBase & rhs)681 inline void BitsBase<T, BT, ST>::bitwise_sar(const BitsBase& lhs, const BitsBase& rhs) {
682 assert(!rhs.is_real());
683 const auto samt = rhs.to_uint();
684 bitwise_sxr_const(lhs, samt, true);
685 }
686
687 template <typename T, typename BT, typename ST>
bitwise_not(const BitsBase & lhs)688 inline void BitsBase<T, BT, ST>::bitwise_not(const BitsBase& lhs) {
689 assert(!is_real() && !lhs.is_real());
690 assert(size() == lhs.size());
691
692 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
693 val_[i] = ~lhs.val_[i];
694 }
695 trim();
696 }
697
698 template <typename T, typename BT, typename ST>
arithmetic_plus(const BitsBase & lhs)699 inline void BitsBase<T, BT, ST>::arithmetic_plus(const BitsBase& lhs) {
700 // This is a copy; identical implementation for reals and integers
701 assert(size() == lhs.size());
702 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
703 val_[i] = lhs.val_[i];
704 }
705 }
706
707 template <typename T, typename BT, typename ST>
arithmetic_plus(const BitsBase & lhs,const BitsBase & rhs)708 inline void BitsBase<T, BT, ST>::arithmetic_plus(const BitsBase& lhs, const BitsBase& rhs) {
709 if (lhs.is_real() || rhs.is_real()) {
710 assert(size() == 64);
711 *reinterpret_cast<double*>(val_.data()) = lhs.to_double() + rhs.to_double();
712 return;
713 }
714
715 assert(size() == lhs.size());
716 assert(size() == rhs.size());
717
718 T carry = 0;
719 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
720 val_[i] = lhs.val_[i] + rhs.val_[i] + carry;
721 if (carry) {
722 carry = (val_[i] <= lhs.val_[i]) ? static_cast<T>(1) : static_cast<T>(0);
723 } else {
724 carry = (val_[i] < lhs.val_[i]) ? static_cast<T>(1) : static_cast<T>(0);
725 }
726 }
727 trim();
728 }
729
730 template <typename T, typename BT, typename ST>
arithmetic_minus(const BitsBase & lhs)731 inline void BitsBase<T, BT, ST>::arithmetic_minus(const BitsBase& lhs) {
732 if (lhs.is_real()) {
733 assert(size() == 64);
734 *reinterpret_cast<double*>(val_.data()) = -lhs.to_double();
735 return;
736 }
737
738 assert(size() == lhs.size());
739
740 T carry = 1;
741 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
742 val_[i] = ~lhs.val_[i];
743 const T sum = val_[i] + carry;
744 carry = (sum < val_[i]) ? static_cast<T>(1) : static_cast<T>(0);
745 val_[i] = sum;
746 }
747 trim();
748 }
749
750 template <typename T, typename BT, typename ST>
arithmetic_minus(const BitsBase & lhs,const BitsBase & rhs)751 inline void BitsBase<T, BT, ST>::arithmetic_minus(const BitsBase& lhs, const BitsBase& rhs) {
752 if (lhs.is_real() || rhs.is_real()) {
753 assert(size() == 64);
754 *reinterpret_cast<double*>(val_.data()) = lhs.to_double() - rhs.to_double();
755 return;
756 }
757
758 assert(size() == lhs.size());
759 assert(size() == rhs.size());
760
761 T carry = 0;
762 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
763 val_[i] = lhs.val_[i] - rhs.val_[i] - carry;
764 if (carry) {
765 carry = (val_[i] >= lhs.val_[i]) ? static_cast<T>(1) : static_cast<T>(0);
766 } else {
767 carry = (val_[i] > lhs.val_[i]) ? static_cast<T>(1) : static_cast<T>(0);
768 }
769 }
770 trim();
771 }
772
773 template <typename T, typename BT, typename ST>
arithmetic_multiply(const BitsBase & lhs,const BitsBase & rhs)774 inline void BitsBase<T, BT, ST>::arithmetic_multiply(const BitsBase& lhs, const BitsBase& rhs) {
775 if (lhs.is_real() || rhs.is_real()) {
776 assert(size() == 64);
777 *reinterpret_cast<double*>(val_.data()) = lhs.to_double() * rhs.to_double();
778 return;
779 }
780
781 assert(size() == lhs.size());
782 assert(size() == rhs.size());
783
784 // This is the optimized space algorithm described in wiki's multiplication
785 // algorithm article. The code is simplified here, as we can assume that both
786 // inputs and the result are capped at S words.
787
788 const auto S = val_.size();
789 BT tot = 0;
790 for (size_t ri = 0; ri < S; ++ri) {
791 for (size_t bi = 0; bi <= ri; ++bi) {
792 size_t ai = ri - bi;
793 tot += static_cast<BT>(lhs.val_[ai]) * static_cast<BT>(rhs.val_[bi]);
794 }
795 val_[ri] = static_cast<T>(tot);
796 tot >>= bits_per_word();
797 }
798 trim();
799 }
800
801 template <typename T, typename BT, typename ST>
arithmetic_divide(const BitsBase & lhs,const BitsBase & rhs)802 inline void BitsBase<T, BT, ST>::arithmetic_divide(const BitsBase& lhs, const BitsBase& rhs) {
803 if (lhs.is_real() || rhs.is_real()) {
804 assert(size() == 64);
805 *reinterpret_cast<double*>(val_.data()) = lhs.to_double() / rhs.to_double();
806 return;
807 }
808
809 assert(size() == lhs.size());
810 assert(size() == rhs.size());
811
812 // TODO(eschkufz) This only words for single word inputs
813 assert(val_.size() == 1);
814
815 if ((lhs.type_ == Type::SIGNED) && (rhs.type_ == Type::SIGNED)) {
816 const ST l = lhs.is_neg_signed() ? (lhs.val_[0] | (static_cast<BT>(-1) << size_)) : lhs.val_[0];
817 const ST r = rhs.is_neg_signed() ? (rhs.val_[0] | (static_cast<BT>(-1) << rhs.size_)) : rhs.val_[0];
818 val_[0] = l / r;
819 } else {
820 val_[0] = lhs.val_[0] / rhs.val_[0];
821 }
822 trim();
823 }
824
825 template <typename T, typename BT, typename ST>
arithmetic_mod(const BitsBase & lhs,const BitsBase & rhs)826 inline void BitsBase<T, BT, ST>::arithmetic_mod(const BitsBase& lhs, const BitsBase& rhs) {
827 assert(!lhs.is_real() && !rhs.is_real());
828 assert(size() == lhs.size());
829 assert(size() == rhs.size());
830
831 // TODO(eschkufz) This only words for single word inputs
832 assert(val_.size() == 1);
833
834 if ((lhs.type_ == Type::SIGNED) && (rhs.type_ == Type::SIGNED)) {
835 const ST l = lhs.is_neg_signed() ? (lhs.val_[0] | (static_cast<BT>(-1) << size_)) : lhs.val_[0];
836 const ST r = rhs.is_neg_signed() ? (rhs.val_[0] | (static_cast<BT>(-1) << rhs.size_)) : rhs.val_[0];
837 val_[0] = l % r;
838 } else {
839 val_[0] = lhs.val_[0] % rhs.val_[0];
840 }
841 trim();
842 }
843
844 template <typename T, typename BT, typename ST>
arithmetic_pow(const BitsBase & lhs,const BitsBase & rhs)845 inline void BitsBase<T, BT, ST>::arithmetic_pow(const BitsBase& lhs, const BitsBase& rhs) {
846 // TODO(eschkufz) There's a lot wrong here:
847 // 1. We're not respecting verilog semantics (wrt sign and result)
848 // 2. This only works for single word inputs
849 // 3. We're not supporting reals, which this should be defined for
850
851 assert(!lhs.is_real() && !rhs.is_real());
852 assert(size() == lhs.size());
853 assert(size() == rhs.size());
854 assert(val_.size() == 1);
855
856 // No resize. This method preserves the bit-width of lhs
857 val_[0] = std::pow(lhs.val_[0], rhs.val_[0]);
858 trim();
859 }
860
861 template <typename T, typename BT, typename ST>
logical_and(const BitsBase & lhs,const BitsBase & rhs)862 inline void BitsBase<T, BT, ST>::logical_and(const BitsBase& lhs, const BitsBase& rhs) {
863 assert(!is_real());
864 val_[0] = (lhs.to_bool() && rhs.to_bool()) ? static_cast<T>(1) : static_cast<T>(0);
865 trim();
866 }
867
868 template <typename T, typename BT, typename ST>
logical_or(const BitsBase & lhs,const BitsBase & rhs)869 inline void BitsBase<T, BT, ST>::logical_or(const BitsBase& lhs, const BitsBase& rhs) {
870 assert(!is_real());
871 val_[0] = (lhs.to_bool() || rhs.to_bool()) ? static_cast<T>(1) : static_cast<T>(0);
872 trim();
873 }
874
875 template <typename T, typename BT, typename ST>
logical_not(const BitsBase & lhs)876 inline void BitsBase<T, BT, ST>::logical_not(const BitsBase& lhs) {
877 assert(!is_real());
878 val_[0] = lhs.to_bool() ? static_cast<T>(0) : static_cast<T>(1);
879 trim();
880 }
881
882 template <typename T, typename BT, typename ST>
logical_eq(const BitsBase & lhs,const BitsBase & rhs)883 inline void BitsBase<T, BT, ST>::logical_eq(const BitsBase& lhs, const BitsBase& rhs) {
884 assert(!is_real());
885 val_[0] = (lhs == rhs) ? static_cast<T>(1) : static_cast<T>(0);
886 trim();
887 }
888
889 template <typename T, typename BT, typename ST>
logical_ne(const BitsBase & lhs,const BitsBase & rhs)890 inline void BitsBase<T, BT, ST>::logical_ne(const BitsBase& lhs, const BitsBase& rhs) {
891 assert(!is_real());
892 val_[0] = (lhs != rhs) ? static_cast<T>(1) : static_cast<T>(0);
893 trim();
894 }
895
896 template <typename T, typename BT, typename ST>
logical_lt(const BitsBase & lhs,const BitsBase & rhs)897 inline void BitsBase<T, BT, ST>::logical_lt(const BitsBase& lhs, const BitsBase& rhs) {
898 assert(!is_real());
899 val_[0] = (lhs < rhs) ? static_cast<T>(1) : static_cast<T>(0);
900 trim();
901 }
902
903 template <typename T, typename BT, typename ST>
logical_lte(const BitsBase & lhs,const BitsBase & rhs)904 inline void BitsBase<T, BT, ST>::logical_lte(const BitsBase& lhs, const BitsBase& rhs) {
905 assert(!is_real());
906 val_[0] = (lhs <= rhs) ? static_cast<T>(1) : static_cast<T>(0);
907 trim();
908 }
909
910 template <typename T, typename BT, typename ST>
logical_gt(const BitsBase & lhs,const BitsBase & rhs)911 inline void BitsBase<T, BT, ST>::logical_gt(const BitsBase& lhs, const BitsBase& rhs) {
912 assert(!is_real());
913 val_[0] = (lhs > rhs) ? static_cast<T>(1) : static_cast<T>(0);
914 trim();
915 }
916
917 template <typename T, typename BT, typename ST>
logical_gte(const BitsBase & lhs,const BitsBase & rhs)918 inline void BitsBase<T, BT, ST>::logical_gte(const BitsBase& lhs, const BitsBase& rhs){
919 assert(!is_real());
920 val_[0] = (lhs >= rhs) ? static_cast<T>(1) : static_cast<T>(0);
921 trim();
922 }
923
924 template <typename T, typename BT, typename ST>
reduce_and(const BitsBase & lhs)925 inline void BitsBase<T, BT, ST>::reduce_and(const BitsBase& lhs) {
926 assert(!is_real() && !lhs.is_real());
927 // Logical operations always yield unsigned results
928 for (size_t i = 0, ie = lhs.val_.size()-1; i < ie; ++i) {
929 if (lhs.val_[i] != static_cast<T>(-1)) {
930 val_[0] = static_cast<T>(0);
931 trim();
932 return;
933 }
934 }
935 const auto mask = (static_cast<T>(1) << (size_ % bits_per_word())) - 1;
936 if ((lhs.val_.back() & mask) != mask) {
937 val_[0] = static_cast<T>(0);
938 trim();
939 return;
940 }
941 val_[0] = static_cast<T>(1);
942 trim();
943 return;
944 }
945
946 template <typename T, typename BT, typename ST>
reduce_nand(const BitsBase & lhs)947 inline void BitsBase<T, BT, ST>::reduce_nand(const BitsBase& lhs) {
948 assert(!is_real() && !lhs.is_real());
949 reduce_and(lhs);
950 val_[0] = (val_[0] != 0) ? static_cast<T>(0) : static_cast<T>(1);
951 }
952
953 template <typename T, typename BT, typename ST>
reduce_or(const BitsBase & lhs)954 inline void BitsBase<T, BT, ST>::reduce_or(const BitsBase& lhs) {
955 assert(!is_real() && !lhs.is_real());
956 for (size_t i = 0, ie = lhs.val_.size(); i < ie; ++i) {
957 if (lhs.val_[i]) {
958 val_[0] = static_cast<T>(1);
959 trim();
960 return;
961 }
962 }
963 val_[0] = static_cast<T>(0);
964 trim();
965 }
966
967 template <typename T, typename BT, typename ST>
reduce_nor(const BitsBase & lhs)968 inline void BitsBase<T, BT, ST>::reduce_nor(const BitsBase& lhs) {
969 assert(!is_real() && !lhs.is_real());
970 reduce_or(lhs);
971 val_[0] = (val_[0] != 0) ? static_cast<T>(0) : static_cast<T>(1);
972 }
973
974 template <typename T, typename BT, typename ST>
reduce_xor(const BitsBase & lhs)975 inline void BitsBase<T, BT, ST>::reduce_xor(const BitsBase& lhs) {
976 assert(!is_real() && !lhs.is_real());
977 size_t cnt = 0;
978 for (size_t i = 0, ie = lhs.val_.size(); i < ie; ++i) {
979 cnt += __builtin_popcount(lhs.val_[i]);
980 }
981 val_[0] = static_cast<T>(cnt % 2);
982 trim();
983 }
984
985 template <typename T, typename BT, typename ST>
reduce_xnor(const BitsBase & lhs)986 inline void BitsBase<T, BT, ST>::reduce_xnor(const BitsBase& lhs) {
987 assert(!is_real() && !lhs.is_real());
988 reduce_xor(lhs);
989 val_[0] = (val_[0] != 0) ? static_cast<T>(0) : static_cast<T>(1);
990 }
991
992 template <typename T, typename BT, typename ST>
concat(const BitsBase & rhs)993 inline void BitsBase<T, BT, ST>::concat(const BitsBase& rhs) {
994 assert(!is_real() && !rhs.is_real());
995
996 bitwise_sll_const(*this, rhs.size_);
997 for (size_t i = 0, ie = std::min(val_.size(), rhs.val_.size()); i < ie; ++i) {
998 val_[i] |= rhs.val_[i];
999 }
1000 }
1001
1002 template <typename T, typename BT, typename ST>
eq(const BitsBase & rhs)1003 inline bool BitsBase<T, BT, ST>::eq(const BitsBase& rhs) const {
1004 if (is_real() && rhs.is_real()) {
1005 return *reinterpret_cast<const double*>(val_.data()) == *reinterpret_cast<const double*>(rhs.val_.data());
1006 }
1007 if (is_real()) {
1008 auto temp = *this;
1009 temp.cast_type(Type::SIGNED);
1010 return temp.eq(rhs);
1011 }
1012 if (rhs.is_real()) {
1013 auto temp = rhs;
1014 temp.cast_type(Type::SIGNED);
1015 return eq(temp);
1016 }
1017
1018 size_t i = 0;
1019 for (size_t ie = val_.size()-1; i < ie; ++i) {
1020 const auto rval = rhs.signed_get(i);
1021 if (val_[i] != rval) {
1022 return false;
1023 }
1024 }
1025 const auto rval = rhs.signed_get(i);
1026 const auto lover = size_ % bits_per_word();
1027 if (lover == 0) {
1028 return val_[i] == rval;
1029 } else {
1030 const auto mask = (static_cast<T>(1) << lover) - 1;
1031 return val_[i] == (rval & mask);
1032 }
1033 }
1034
1035 template <typename T, typename BT, typename ST>
eq(size_t idx,const BitsBase & rhs)1036 inline bool BitsBase<T, BT, ST>::eq(size_t idx, const BitsBase& rhs) const {
1037 assert(!is_real());
1038 if (rhs.is_real()) {
1039 auto temp = rhs;
1040 temp.cast_type(Type::SIGNED);
1041 return eq(idx, temp);
1042 }
1043
1044 assert(idx < size_);
1045 return get(idx) == rhs.get(0);
1046 }
1047
1048 template <typename T, typename BT, typename ST>
eq(size_t msb,size_t lsb,const BitsBase & rhs)1049 inline bool BitsBase<T, BT, ST>::eq(size_t msb, size_t lsb, const BitsBase& rhs) const {
1050 assert(!is_real());
1051 if (rhs.is_real()) {
1052 auto temp = rhs;
1053 temp.cast_type(Type::SIGNED);
1054 return eq(msb, lsb, temp);
1055 }
1056
1057 // Corner Case: Is this a single bit range?
1058 if (msb == lsb) {
1059 return eq(msb, rhs);
1060 }
1061
1062 assert(msb < size_);
1063 assert(msb >= lsb);
1064
1065 // Compute the size of this slice
1066 const auto slice = (msb - lsb) + 1;
1067 // How many full words does it span and what's left over at the end?
1068 const auto span = slice / bits_per_word();
1069 const auto lover = slice % bits_per_word();
1070 // Compute indices and offsets
1071 const auto lower = lsb / bits_per_word();
1072 const auto loff = lsb % bits_per_word();
1073 const auto uoff = bits_per_word() - loff;
1074
1075 // Common Case: Full word comparison
1076 for (size_t i = 0; i < span; ++i) {
1077 auto word = (val_[lower+i] >> loff);
1078 const auto rval = rhs.signed_get(i);
1079 if (loff > 0) {
1080 word |= (val_[lower+i+1] << uoff);
1081 }
1082 if (word != rval) {
1083 return false;
1084 }
1085 }
1086
1087 // Nothing to do if there are no leftovers:
1088 if (lover == 0) {
1089 return true;
1090 }
1091 // Edge Case: Compare the remaining bits
1092 auto word = (val_[lower+span] >> loff);
1093 const auto rval = rhs.signed_get(span);
1094 if ((loff > 0) && ((lower+span+1) < val_.size())) {
1095 word |= (val_[lower+span+1] << uoff);
1096 }
1097 const auto mask = (static_cast<T>(1) << lover) - 1;
1098 return (word & mask) == (rval & mask);
1099 }
1100
1101 template <typename T, typename BT, typename ST>
assign(const BitsBase & rhs)1102 inline void BitsBase<T, BT, ST>::assign(const BitsBase& rhs) {
1103 if (is_real()) {
1104 const auto val = rhs.is_real() ? *reinterpret_cast<const double*>(rhs.val_.data()) : rhs.to_double();
1105 *reinterpret_cast<double*>(val_.data()) = val;
1106 return;
1107 }
1108 if (rhs.is_real()) {
1109 auto temp = rhs;
1110 temp.cast_real_to_int(false);
1111 return assign(temp);
1112 }
1113
1114 assert(!is_real() && !rhs.is_real());
1115 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
1116 val_[i] = rhs.signed_get(i);
1117 }
1118 trim();
1119 }
1120
1121 template <typename T, typename BT, typename ST>
assign(size_t idx,const BitsBase & rhs)1122 inline void BitsBase<T, BT, ST>::assign(size_t idx, const BitsBase& rhs) {
1123 assert(!is_real());
1124 assert(idx < size_);
1125 set(idx, rhs.to_uint() & static_cast<T>(1));
1126 }
1127
1128 template <typename T, typename BT, typename ST>
assign(size_t msb,size_t lsb,const BitsBase & rhs)1129 inline void BitsBase<T, BT, ST>::assign(size_t msb, size_t lsb, const BitsBase& rhs) {
1130 // Corner Case: Is this range one bit?
1131 if (msb == lsb) {
1132 return assign(msb, rhs);
1133 }
1134 // Corner Case: Do we need to convert rhs to an integer?
1135 if (rhs.is_real()) {
1136 auto temp = rhs;
1137 temp.cast_real_to_int(false);
1138 return assign(msb, lsb, temp);
1139 }
1140
1141 assert(!is_real() && !rhs.is_real());
1142 assert(msb < size_);
1143 assert(msb >= lsb);
1144
1145 // Compute the size of this slice
1146 const auto slice = (msb - lsb) + 1;
1147 // How many full words does it span and what's left over at the end?
1148 const auto span = slice / bits_per_word();
1149 const auto lover = slice % bits_per_word();
1150 // Compute indices and offsets
1151 const auto lower = lsb / bits_per_word();
1152 const auto loff = lsb % bits_per_word();
1153 const auto uoff = bits_per_word() - loff;
1154 const auto mask = (static_cast<T>(1) << loff) - 1;
1155
1156 // Common Case: Copy entire words
1157 for (size_t i = 0; i < span; ++i) {
1158 const auto rval = rhs.signed_get(i);
1159 val_[lower+i] &= mask;
1160 val_[lower+i] |= (rval << loff);
1161 if (loff > 0) {
1162 val_[lower+i+1] &= ~mask;
1163 val_[lower+i+1] |= (rval >> uoff);
1164 }
1165 }
1166
1167 // Nothing to do if there are no leftovers
1168 if (lover == 0) {
1169 return;
1170 }
1171 // Edge Case: Copy the remaining bits
1172 const auto lmask = (static_cast<T>(1) << lover) - 1;
1173 const auto rval = rhs.signed_get(span);
1174 val_[lower+span] &= ~(lmask << loff);
1175 val_[lower+span] |= ((rval & lmask) << loff);
1176
1177 if ((lover + loff) > bits_per_word()) {
1178 const auto delta = (lover + loff) - bits_per_word();
1179 const auto hmask = (static_cast<T>(1) << delta) - 1;
1180 val_[lower+span+1] &= ~hmask;
1181 val_[lower+span+1] |= ((rval >> (lover-delta)) & hmask);
1182 }
1183 }
1184
1185 template <typename T, typename BT, typename ST>
assign(const BitsBase & rhs,size_t idx)1186 inline void BitsBase<T, BT, ST>::assign(const BitsBase& rhs, size_t idx) {
1187 assert(!is_real() && !rhs.is_real());
1188
1189 val_[0] = (idx < rhs.size()) ? rhs.get(idx) : static_cast<T>(0);
1190 for (size_t i = 1, ie = val_.size(); i < ie; ++i) {
1191 val_[i] = static_cast<T>(0);
1192 }
1193 }
1194
1195 template <typename T, typename BT, typename ST>
assign(const BitsBase & rhs,size_t msb,size_t lsb)1196 inline void BitsBase<T, BT, ST>::assign(const BitsBase& rhs, size_t msb, size_t lsb) {
1197 assert(!is_real() && !rhs.is_real());
1198
1199 // Corner Case: Is this range 1 bit?
1200 if (msb == lsb) {
1201 return assign(rhs, msb);
1202 }
1203
1204 assert(msb < rhs.size_);
1205 assert(msb >= lsb);
1206
1207 // How many words does this slice span? Where does it start?
1208 const auto span = ((msb-lsb)+bits_per_word()) / bits_per_word();
1209 const auto base = lsb / bits_per_word();
1210 const auto bamt = lsb % bits_per_word();
1211 // Create a mask for extracting the lowest bamt bits from top
1212 const auto mamt = bits_per_word() - bamt;
1213 const auto mask = (static_cast<T>(1) << bamt) - 1;
1214
1215 // Copy as much of rhs as we can (maybe along with a few bits extra)
1216 size_t i = 0;
1217 for (size_t ie = std::min(span, val_.size()); i < ie; ++i) {
1218 if (bamt == 0) {
1219 val_[i] = rhs.val_[base+i];
1220 } else {
1221 const auto top = ((base+i+1) < rhs.val_.size()) ? rhs.val_[base+i+1] : static_cast<T>(0);
1222 val_[i] = ((top & mask) << mamt) | (rhs.val_[base+i] >> bamt);
1223 }
1224 }
1225
1226 // Zero out anything which is left over
1227 const auto top = std::min(static_cast<uint32_t>((msb-lsb)+1), size_);
1228 const auto zword = top / bits_per_word();
1229 const auto zidx = top % bits_per_word();
1230
1231 if (zword < val_.size()) {
1232 val_[zword] &= (static_cast<T>(1) << zidx) - 1;
1233 }
1234 for (size_t i = zword+1, ie = val_.size(); i < ie; ++i) {
1235 val_[i] = static_cast<T>(0);
1236 }
1237 }
1238
1239 template <typename T, typename BT, typename ST>
copy(const BitsBase & rhs)1240 inline void BitsBase<T, BT, ST>::copy(const BitsBase& rhs) {
1241 val_.resize(rhs.val_.size());
1242 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
1243 val_[i] = rhs.val_[i];
1244 }
1245 size_ = rhs.size_;
1246 type_ = rhs.type_;
1247 }
1248
1249 template <typename T, typename BT, typename ST>
get(size_t idx)1250 inline bool BitsBase<T, BT, ST>::get(size_t idx) const {
1251 assert(idx < size_);
1252
1253 const auto widx = idx / bits_per_word();
1254 const auto bidx = idx % bits_per_word();
1255 return val_[widx] & (static_cast<T>(1) << bidx);
1256 }
1257
1258 template <typename T, typename BT, typename ST>
set(size_t idx,bool b)1259 inline void BitsBase<T, BT, ST>::set(size_t idx, bool b) {
1260 assert(idx < size_);
1261
1262 const auto widx = idx / bits_per_word();
1263 const auto bidx = idx % bits_per_word();
1264 if (b) {
1265 val_[widx] |= (static_cast<T>(1) << bidx);
1266 } else {
1267 val_[widx] &= ~(static_cast<T>(1) << bidx);
1268 }
1269 }
1270
1271 template <typename T, typename BT, typename ST>
flip(size_t idx)1272 inline void BitsBase<T, BT, ST>::flip(size_t idx) {
1273 assert(idx < size_);
1274
1275 const auto widx = idx / bits_per_word();
1276 const auto bidx = idx % bits_per_word();
1277 const bool b = (val_[widx] >> bidx) & static_cast<T>(1);
1278 if (!b) {
1279 val_[widx] |= (static_cast<T>(1) << bidx);
1280 } else {
1281 val_[widx] &= ~(static_cast<T>(1) << bidx);
1282 }
1283 }
1284
1285 template <typename T, typename BT, typename ST>
1286 inline bool BitsBase<T, BT, ST>::operator==(const BitsBase& rhs) const {
1287 if (is_real() && rhs.is_real()) {
1288 return *reinterpret_cast<const double*>(val_.data()) == *reinterpret_cast<const double*>(rhs.val_.data());
1289 }
1290 if (is_real()) {
1291 auto temp = *this;
1292 temp.cast_type(Type::SIGNED);
1293 temp.resize(rhs.size_);
1294 return temp == rhs;
1295 }
1296 if (rhs.is_real()) {
1297 auto temp = rhs;
1298 temp.cast_type(Type::SIGNED);
1299 temp.resize(size_);
1300 return *this == temp;
1301 }
1302
1303 assert(size_ == rhs.size_);
1304 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
1305 if (val_[i] != rhs.val_[i]) {
1306 return false;
1307 }
1308 }
1309 return true;
1310 }
1311
1312 template <typename T, typename BT, typename ST>
1313 inline bool BitsBase<T, BT, ST>::operator!=(const BitsBase& rhs) const {
1314 return !(*this == rhs);
1315 }
1316
1317 template <typename T, typename BT, typename ST>
1318 inline bool BitsBase<T, BT, ST>::operator<(const BitsBase& rhs) const {
1319 if (is_real() && rhs.is_real()) {
1320 return *reinterpret_cast<const double*>(val_.data()) < *reinterpret_cast<const double*>(rhs.val_.data());
1321 }
1322 if (is_real()) {
1323 auto temp = *this;
1324 temp.cast_type(Type::SIGNED);
1325 temp.resize(rhs.size_);
1326 return temp < rhs;
1327 }
1328 if (rhs.is_real()) {
1329 auto temp = rhs;
1330 temp.cast_type(Type::SIGNED);
1331 temp.resize(size_);
1332 return *this < temp;
1333 }
1334
1335 assert(size_ == rhs.size_);
1336 if ((type_ == Type::SIGNED) && (rhs.type_ == Type::SIGNED)) {
1337 const auto lneg = is_neg_signed();
1338 const auto rneg = rhs.is_neg_signed();
1339 if (lneg && !rneg) {
1340 return true;
1341 } else if (!lneg && rneg) {
1342 return false;
1343 }
1344 }
1345 for (int i = val_.size()-1; i >= 0; --i) {
1346 if (val_[i] < rhs.val_[i]) {
1347 return true;
1348 } else if (val_[i] > rhs.val_[i]) {
1349 return false;
1350 }
1351 }
1352 return false;
1353 }
1354
1355 template <typename T, typename BT, typename ST>
1356 inline bool BitsBase<T, BT, ST>::operator<=(const BitsBase& rhs) const {
1357 if (is_real() && rhs.is_real()) {
1358 return *reinterpret_cast<const double*>(val_.data()) <= *reinterpret_cast<const double*>(rhs.val_.data());
1359 }
1360 if (is_real()) {
1361 auto temp = *this;
1362 temp.cast_type(Type::SIGNED);
1363 temp.resize(rhs.size_);
1364 return temp <= rhs;
1365 }
1366 if (rhs.is_real()) {
1367 auto temp = rhs;
1368 temp.cast_type(Type::SIGNED);
1369 temp.resize(size_);
1370 return *this <= temp;
1371 }
1372
1373 assert(size_ == rhs.size_);
1374 if ((type_ == Type::SIGNED) && (rhs.type_ == Type::SIGNED)) {
1375 const auto lneg = is_neg_signed();
1376 const auto rneg = rhs.is_neg_signed();
1377 if (lneg && !rneg) {
1378 return true;
1379 } else if (!lneg && rneg) {
1380 return false;
1381 }
1382 }
1383
1384 for (int i = val_.size()-1; i >= 0; --i) {
1385 if (val_[i] < rhs.val_[i]) {
1386 return true;
1387 } else if (val_[i] > rhs.val_[i]) {
1388 return false;
1389 }
1390 }
1391 return true;
1392 }
1393
1394 template <typename T, typename BT, typename ST>
1395 inline bool BitsBase<T, BT, ST>::operator>(const BitsBase& rhs) const {
1396 return !(*this <= rhs);
1397 }
1398
1399 template <typename T, typename BT, typename ST>
1400 inline bool BitsBase<T, BT, ST>::operator>=(const BitsBase& rhs) const {
1401 return !(*this < rhs);
1402 }
1403
1404 template <typename T, typename BT, typename ST>
read_real(std::istream & is)1405 inline void BitsBase<T, BT, ST>::read_real(std::istream& is) {
1406 double d;
1407 is >> d;
1408 val_.resize(64/bits_per_word());
1409 *reinterpret_cast<double*>(val_.data()) = d;
1410 size_ = 64;
1411 type_ = Type::REAL;
1412 }
1413
1414 template <typename T, typename BT, typename ST>
read_2_8_16(std::istream & is,size_t base)1415 inline void BitsBase<T, BT, ST>::read_2_8_16(std::istream& is, size_t base) {
1416 // Input Buffer:
1417 std::string s;
1418 is >> s;
1419
1420 // Reset to a 1-bit unsigned value
1421 shrink_to_bool(false);
1422 type_ = Type::UNSIGNED;
1423
1424 // Return immediately if reading s failed.
1425 if (s.empty()) {
1426 return;
1427 }
1428
1429 // How many bits do we generate per character? Resize internal storage.
1430 const auto step = (base == 2) ? 1 : (base == 8) ? 3 : 4;
1431 extend_to(step * s.length());
1432
1433 // Walk over the buffer from lowest to highest order (that's in reverse)
1434 size_t word = 0;
1435 size_t idx = 0;
1436 for (int i = s.length()-1; i >= 0; --i) {
1437 // Convert character to bits
1438 const T bits = static_cast<bool>(isalpha(s[i])) ? ((s[i]-'a')+10) : (s[i]-'0');
1439 // Copy bits into storage and bump idx.
1440 val_[word] |= (bits << idx);
1441 idx += step;
1442 // Keep going if there's still room in this word, otherwise on to the next
1443 if (idx < bits_per_word()) {
1444 continue;
1445 }
1446 ++word;
1447 // Easy Case: Step divides words evenly
1448 if (idx == bits_per_word()) {
1449 idx = 0;
1450 continue;
1451 }
1452 // Hard Case: Bit overflow
1453 idx -= bits_per_word();
1454 val_[word] |= (bits >> (step-idx));
1455 }
1456 }
1457
1458 template <typename T, typename BT, typename ST>
read_10(std::istream & is)1459 inline void BitsBase<T, BT, ST>::read_10(std::istream& is) {
1460 // Check for negative
1461 const auto is_neg = is.peek() == '-';
1462 if (is_neg) {
1463 is.get();
1464 }
1465
1466 // Input Buffer:
1467 std::string s;
1468 is >> s;
1469
1470 // Reset to 1-bit signed value
1471 shrink_to_bool(false);
1472 type_ = is_neg ? Type::SIGNED : Type::UNSIGNED;
1473
1474 // Halve decimal string until it becomes zero. Add 1s when least significant
1475 // digit is odd, 0s otherwise. An empty string will leave this loop
1476 // immediately.
1477 for (size_t i = 1; !dec_zero(s); ++i) {
1478 extend_to(i);
1479 set(i-1, (s.back()-'0') % 2);
1480 dec_halve(s);
1481 }
1482 // Add padding for sign bit and negate if necessary
1483 extend_to(size_+1);
1484 if (is_neg) {
1485 invert_add_one();
1486 }
1487 }
1488
1489 template <typename T, typename BT, typename ST>
write_real(std::ostream & os)1490 inline void BitsBase<T, BT, ST>::write_real(std::ostream& os) const {
1491 os << to_double();
1492 }
1493
1494 template <typename T, typename BT, typename ST>
write_2_8_16(std::ostream & os,size_t base)1495 inline void BitsBase<T, BT, ST>::write_2_8_16(std::ostream& os, size_t base) const {
1496 // Cast to unsigned
1497 if (type_ != Type::UNSIGNED) {
1498 auto temp = *this;
1499 temp.cast_type(Type::UNSIGNED);
1500 return temp.write_2_8_16(os, base);
1501 }
1502
1503 // TODO(eschkufz): This would be a lot faster if we traversed the value from
1504 // most to least significant bit and didn't store a temporary array.
1505
1506 // Output Buffer:
1507 std::vector<uint8_t> buf;
1508
1509 // How many bits do we consume per character? Make a mask.
1510 const size_t step = (base == 2) ? 1 : (base == 8) ? 3 : 4;
1511 const auto mask = (static_cast<T>(1) << step) - 1;
1512
1513 // Walk over the string from lowest to highest order
1514 size_t off = 0;
1515 for (size_t i = 0, ie = size(); i < ie; i += step) {
1516 const auto pos = i / bits_per_word();
1517 // Extract mask bits
1518 buf.push_back((val_[pos] >> off) & mask);
1519 off += step;
1520 // Easy case: Step divides words evenly
1521 if (off == bits_per_word()) {
1522 off = 0;
1523 }
1524 // Hard case: Look ahead for more bits
1525 else if (off > bits_per_word()) {
1526 off %= bits_per_word();
1527 if ((pos+1) != val_.size()) {
1528 buf.back() |= (val_[pos+1] & ((static_cast<T>(1) << off) - 1)) << (step - off);
1529 }
1530 }
1531 }
1532
1533 // Print the result
1534 for (int i = buf.size()-1; i >= 0; --i) {
1535 if (buf[i] > 9) {
1536 os << static_cast<char>('a' + (buf[i] - 10));
1537 } else {
1538 os << static_cast<int>(buf[i]);
1539 }
1540 }
1541 }
1542
1543
1544 template <typename T, typename BT, typename ST>
write_10(std::ostream & os)1545 inline void BitsBase<T, BT, ST>::write_10(std::ostream& os) const {
1546 // Cast reals down to integers
1547 if (type_ == Type::REAL) {
1548 auto temp = *this;
1549 temp.cast_type(Type::SIGNED);
1550 return temp.write_10(os);
1551 }
1552
1553 // Check whether this is a negative number
1554 const auto is_neg = is_neg_signed();
1555
1556 // Print negative and invert if necessary
1557 if (is_neg) {
1558 os << "-";
1559 const_cast<BitsBase*>(this)->invert_add_one();
1560 }
1561 // Output Buffer (lsb in index 0):
1562 std::string buf = "0";
1563 // Walk binary string from highest to lowest.
1564 // Double result each time, add 1s as they appear.
1565 for (int i = size_-1; i >= 0; --i) {
1566 dec_double(buf);
1567 if (get(i)) {
1568 dec_inc(buf);
1569 }
1570 }
1571 // Print the result in reverse
1572 for (int i = buf.length()-1; i >= 0; --i) {
1573 os << buf[i];
1574 }
1575 // Restore bits if they were inverted
1576 if (is_neg) {
1577 const_cast<BitsBase*>(this)->invert_add_one();
1578 }
1579 }
1580
1581 template <typename T, typename BT, typename ST>
dec_halve(std::string & s)1582 inline void BitsBase<T, BT, ST>::dec_halve(std::string& s) const {
1583 auto next_carry = 0;
1584 for (size_t i = 0, ie = s.length(); i < ie; ++i) {
1585 const auto val = s[i] - '0';
1586 auto carry = next_carry;
1587 next_carry = ((val % 2) != 0) ? 5 : 0;
1588 s[i] = ((val/2) + carry) + '0';
1589 }
1590 }
1591
1592 template <typename T, typename BT, typename ST>
dec_zero(const std::string & s)1593 inline bool BitsBase<T, BT, ST>::dec_zero(const std::string& s) const {
1594 for (auto c : s) {
1595 if (c != '0') {
1596 return false;
1597 }
1598 }
1599 return true;
1600 }
1601
1602 template <typename T, typename BT, typename ST>
dec_double(std::string & s)1603 inline void BitsBase<T, BT, ST>::dec_double(std::string& s) const {
1604 auto carry = 0;
1605 for (size_t i = 0, ie = s.size(); i < ie; ++i) {
1606 auto val = s[i] - '0';
1607 val = (2*val) + carry;
1608 if (val >= 10) {
1609 s[i] = '0' + (val - 10);
1610 carry = 1;
1611 } else {
1612 s[i] = '0' + val;
1613 carry = 0;
1614 }
1615 }
1616 if (carry) {
1617 s.push_back('1');
1618 }
1619 }
1620
1621 template <typename T, typename BT, typename ST>
dec_inc(std::string & s)1622 inline void BitsBase<T, BT, ST>::dec_inc(std::string& s) const {
1623 for (size_t i = 0, ie = s.size(); i < ie; ++i) {
1624 if (++s[i] == ('0'+10)) {
1625 s[i] = '0';
1626 } else {
1627 return;
1628 }
1629 }
1630 s.push_back('1');
1631 }
1632
1633 template <typename T, typename BT, typename ST>
bitwise_sll_const(const BitsBase & lhs,size_t samt)1634 inline void BitsBase<T, BT, ST>::bitwise_sll_const(const BitsBase& lhs, size_t samt) {
1635 assert(!is_real() && !lhs.is_real());
1636 assert(size() == lhs.size());
1637
1638 // Easy Case: We're not actually shifting
1639 if (samt == 0) {
1640 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
1641 val_[i] = lhs.val_[i];
1642 }
1643 return;
1644 }
1645
1646 // This algorithm works from highest to lowest order, one word at a time
1647 // word: The current word we're looking at
1648 // top/bottom: The words that will be shifted into word; word can equal top
1649
1650 // How many words ahead is bottom?
1651 const auto delta = ((samt + bits_per_word()) - 1) / bits_per_word();
1652 // How many bits are we taking from bottom and shifting top?
1653 const auto bamt = samt % bits_per_word();
1654 // Create a mask for extracting the highest bamt bits from bottom
1655 const auto mamt = bits_per_word() - bamt;
1656 const auto mask = ((static_cast<T>(1) << bamt) - 1) << mamt;
1657
1658 // Work our way down until bottom hits zero
1659 int w = val_.size() - 1;
1660 for (int b = w-delta; b >= 0; --w, --b) {
1661 if (bamt == 0) {
1662 val_[w] = lhs.val_[b];
1663 } else {
1664 val_[w] = (lhs.val_[b+1] << bamt) | ((lhs.val_[b] & mask) >> mamt);
1665 }
1666 }
1667 // There's one more block to build where bottom is implicitly zero
1668 val_[w--] = (bamt == 0) ? static_cast<T>(0) : (lhs.val_[0] << bamt);
1669 // Everything else is zero
1670 for (; w >= 0; --w) {
1671 val_[w] = static_cast<T>(0);
1672 }
1673 // Trim the top and we're done
1674 trim();
1675 }
1676
1677 template <typename T, typename BT, typename ST>
bitwise_sxr_const(const BitsBase & lhs,size_t samt,bool arith)1678 inline void BitsBase<T, BT, ST>::bitwise_sxr_const(const BitsBase& lhs, size_t samt, bool arith) {
1679 assert(!is_real() && !lhs.is_real());
1680 assert(size() == lhs.size());
1681
1682 // Easy Case: We're not actually shifting
1683 if (samt == 0) {
1684 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
1685 val_[i] = lhs.val_[i];
1686 }
1687 return;
1688 }
1689 // Another Easy Case: We're shifting more bits than we have here
1690 if (samt >= lhs.size()) {
1691 const auto val = (arith && lhs.get(lhs.size()-1)) ? T(-1) : T(0);
1692 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
1693 val_[i] = val;
1694 }
1695 return;
1696 }
1697
1698 // This algorithm works from lowest to highest order, one word at a time
1699 // word: The current word we're looking at
1700 // top/bottom: The words that will be shifted into word; word can equal bottom
1701
1702 // Is the highest order bit a 1 and do we care?
1703 const auto idx = (size_-1) % bits_per_word();
1704 const auto hob = arith && ((lhs.val_.back() & (static_cast<T>(1) << idx)) != 0);
1705 // How many words ahead is top?
1706 const auto delta = ((samt + bits_per_word()) - 1) / bits_per_word();
1707 // How many bits are we taking from top and shifting bottom?
1708 const auto bamt = samt % bits_per_word();
1709 // Create a mask for extracting the lowest bamt bits from top
1710 const auto mamt = bits_per_word() - bamt;
1711 const auto mask = (static_cast<T>(1) << bamt) - 1;
1712 // val_ is an array of unsigned values. If we are working with signed values,
1713 // we want the top bits of the top-most word to be filled with ones.
1714 // This is only used in the case where hob is set and the top word is not
1715 // completely full.
1716 const auto upper_most_word = ((static_cast<T>(-1) << idx) | lhs.val_.back());
1717
1718 // Work our way up until top goes out of range
1719 size_t w = 0;
1720 for (size_t t = w+delta, te = val_.size(); t < te; ++w, ++t) {
1721 if (bamt == 0) {
1722 val_[w] = lhs.val_[t];
1723 } else {
1724 const auto upper_most = (t == (val_.size() - 1)) ? upper_most_word : lhs.val_[t];
1725 val_[w] = (lhs.val_[t-1] >> bamt) | ((upper_most & mask) << mamt);
1726 }
1727 }
1728 // There's one more block to build where top is implicitly zero
1729 if (hob) {
1730 val_[w++] = (bamt == 0) ? static_cast<T>(-1) : ((upper_most_word >> bamt) | (mask << mamt));
1731 } else {
1732 val_[w++] = (bamt == 0) ? static_cast<T>(0) : (lhs.val_.back() >> bamt);
1733 }
1734 // Everything else is zero or padded 1s
1735 for (size_t we = val_.size(); w < we; ++w) {
1736 val_[w] = hob ? static_cast<T>(-1) : static_cast<T>(0);
1737 }
1738 // Trim since we could have introduced trailing 1s
1739 trim();
1740 }
1741
1742 template <typename T, typename BT, typename ST>
signed_get(size_t n)1743 inline T BitsBase<T, BT, ST>::signed_get(size_t n) const {
1744 // Easiest Case: This is an unisgned value, so return what's in range or zero
1745 if (!is_neg_signed()) {
1746 return (n < val_.size()) ? val_[n] : static_cast<T>(0);
1747 }
1748 // Another Case: An in bounds signed value
1749 else if (n < (val_.size()-1)) {
1750 return val_[n];
1751 }
1752 // One More Easy Case: An out of bounds signed value
1753 else if (n >= val_.size()) {
1754 return static_cast<T>(-1);
1755 }
1756 // The Hard Case: We need to sign extend
1757 else {
1758 const auto top = size_ % bits_per_word();
1759 return (top == 0) ? val_[n] : (val_[n] | (static_cast<T>(-1) << top));
1760 }
1761 }
1762
1763 template <typename T, typename BT, typename ST>
is_neg_signed()1764 inline bool BitsBase<T, BT, ST>::is_neg_signed() const {
1765 return (type_ == Type::SIGNED) && get(size_-1);
1766 }
1767
1768 template <typename T, typename BT, typename ST>
trim()1769 inline void BitsBase<T, BT, ST>::trim() {
1770 // How many bits do we care about in the top word?
1771 const auto trailing = size_ % bits_per_word();
1772 // Zero means we're full
1773 if (trailing == 0) {
1774 return;
1775 }
1776 // Otherwise, mask these off
1777 const auto mask = (static_cast<T>(1) << trailing) - 1;
1778 val_.back() &= mask;
1779 }
1780
1781 template <typename T, typename BT, typename ST>
extend_to(size_t n)1782 inline void BitsBase<T, BT, ST>::extend_to(size_t n) {
1783 assert(n >= size_);
1784 const auto words = ((n + bits_per_word()) - 1) / bits_per_word();
1785 val_.resize(words, static_cast<T>(0));
1786 size_ = n;
1787 }
1788
1789 template <typename T, typename BT, typename ST>
sign_extend_to(size_t n)1790 inline void BitsBase<T, BT, ST>::sign_extend_to(size_t n) {
1791 assert(n >= size_);
1792 const auto words = ((n + bits_per_word()) - 1) / bits_per_word();
1793 if (is_neg_signed()) {
1794 val_.back() |= (static_cast<T>(-1) << (size_ % bits_per_word()));
1795 val_.resize(words, static_cast<T>(-1));
1796 size_ = n;
1797 trim();
1798 } else {
1799 val_.resize(words, static_cast<T>(0));
1800 size_ = n;
1801 }
1802 }
1803
1804 template <typename T, typename BT, typename ST>
shrink_to(size_t n)1805 inline void BitsBase<T, BT, ST>::shrink_to(size_t n) {
1806 assert(n <= size_);
1807 const auto words = ((n + bits_per_word()) - 1) / bits_per_word();
1808 val_.resize(words, static_cast<T>(0));
1809 size_ = n;
1810 trim();
1811 }
1812
1813 template <typename T, typename BT, typename ST>
shrink_to_bool(bool b)1814 inline void BitsBase<T, BT, ST>::shrink_to_bool(bool b) {
1815 val_.resize(1, static_cast<T>(0));
1816 val_[0] = b ? 1 : 0;
1817 size_ = 1;
1818 }
1819
1820 template <typename T, typename BT, typename ST>
invert_add_one()1821 inline void BitsBase<T, BT, ST>::invert_add_one() {
1822 T carry = 1;
1823 for (size_t i = 0, ie = val_.size(); i < ie; ++i) {
1824 val_[i] = ~val_[i];
1825 const T sum = val_[i] + carry;
1826 carry = (sum < val_[i]) ? static_cast<T>(1) : static_cast<T>(0);
1827 val_[i] = sum;
1828 }
1829 trim();
1830 }
1831
1832 template <typename T, typename BT, typename ST>
cast_int_to_real()1833 inline void BitsBase<T, BT, ST>::cast_int_to_real() {
1834 assert(type_ != Type::REAL);
1835 const auto d = to_double();
1836 val_.resize(64/bits_per_word());
1837 *reinterpret_cast<double*>(val_.data()) = d;
1838 size_ = 64;
1839 type_ = Type::REAL;
1840 }
1841
1842 template <typename T, typename BT, typename ST>
cast_real_to_int(bool s)1843 inline void BitsBase<T, BT, ST>::cast_real_to_int(bool s) {
1844 assert(type_ == Type::REAL);
1845 auto d = std::round(*reinterpret_cast<const double*>(val_.data()));
1846 const auto is_neg = d < 0.0;
1847 if (is_neg) {
1848 d = -d;
1849 }
1850
1851 shrink_to_bool(false);
1852 for (size_t i = 1; d > 0; d = std::floor(d/2), ++i) {
1853 extend_to(i);
1854 set(i-1, static_cast<T>(d) % 2);
1855 }
1856 if (s) {
1857 extend_to(size_+1);
1858 }
1859 if (is_neg) {
1860 invert_add_one();
1861 }
1862 type_ = s ? Type::SIGNED : Type::UNSIGNED;
1863 }
1864
1865 template <typename T, typename BT, typename ST>
bits_per_word()1866 inline constexpr size_t BitsBase<T, BT, ST>::bits_per_word() const {
1867 return 8 * bytes_per_word();
1868 }
1869
1870 template <typename T, typename BT, typename ST>
bytes_per_word()1871 inline constexpr size_t BitsBase<T, BT, ST>::bytes_per_word() const {
1872 return sizeof(T);
1873 }
1874
1875 template <typename T, typename BT, typename ST>
range()1876 inline constexpr double BitsBase<T, BT, ST>::range() const {
1877 return std::pow(2, bits_per_word());
1878 }
1879
1880 } // namespace cascade
1881
1882 #endif
1883