// Filename: bitArray.cxx // Created by: drose (20Jan06) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) Carnegie Mellon University. All rights reserved. // // All use of this software is subject to the terms of the revised BSD // license. You should have received a copy of this license along // with this source code in a file named "LICENSE." // //////////////////////////////////////////////////////////////////// #include "bitArray.h" #include "sparseArray.h" #include "datagram.h" #include "datagramIterator.h" TypeHandle BitArray::_type_handle; //////////////////////////////////////////////////////////////////// // Function: BitArray::Constructor (from SparseArray) // Access: Published // Description: //////////////////////////////////////////////////////////////////// BitArray:: BitArray(const SparseArray &from) { _highest_bits = 0; int num_subranges = from.get_num_subranges(); for (int i = 0; i < num_subranges; ++i) { int begin = from.get_subrange_begin(i); int end = from.get_subrange_end(i); set_range(begin, end - begin); } if (from.is_inverse()) { invert_in_place(); } } //////////////////////////////////////////////////////////////////// // Function: BitArray::is_zero // Access: Published // Description: Returns true if the entire bitmask is zero, false // otherwise. //////////////////////////////////////////////////////////////////// bool BitArray:: is_zero() const { if (_highest_bits) { // If all the infinite highest bits are set, certainly the bitmask // is nonzero. return false; } // Start from the high end, since that's more likely to be nonzero. Array::reverse_iterator ai; for (ai = _array.rbegin(); ai != _array.rend(); ++ai) { if (!(*ai).is_zero()) { return false; } } return true; } //////////////////////////////////////////////////////////////////// // Function: BitArray::is_all_on // Access: Published // Description: Returns true if the entire bitmask is one, false // otherwise. //////////////////////////////////////////////////////////////////// bool BitArray:: is_all_on() const { if (!_highest_bits) { // If all the infinite highest bits are not set, certainly the // bitmask is not all on. return false; } Array::reverse_iterator ai; for (ai = _array.rbegin(); ai != _array.rend(); ++ai) { if (!(*ai).is_all_on()) { return false; } } return true; } //////////////////////////////////////////////////////////////////// // Function: BitArray::has_any_of // Access: Published // Description: Returns true if any bit in the indicated range is // set, false otherwise. //////////////////////////////////////////////////////////////////// bool BitArray:: has_any_of(int low_bit, int size) const { if ((low_bit + size - 1) / num_bits_per_word >= get_num_words()) { // This range touches the highest bits. if (_highest_bits) { return true; } } int w = low_bit / num_bits_per_word; int b = low_bit % num_bits_per_word; if (w >= get_num_words()) { // This range is entirely among the highest bits. return (_highest_bits != 0); } if (b + size <= num_bits_per_word) { // The whole thing fits within one word of the array. return get_word(w).has_any_of(b, size); } int num_high_bits = num_bits_per_word - b; if (_array[w].has_any_of(b, num_high_bits)) { return true; } size -= num_high_bits; ++w; while (size > 0) { if (size <= num_bits_per_word) { // The remainder fits within one word of the array. return _array[w].has_any_of(0, size); } // Keep going. if (!_array[w].is_zero()) { return true; } size -= num_bits_per_word; ++w; if (w >= get_num_words()) { // Now we're up to the highest bits. return (_highest_bits != 0); } } return false; } //////////////////////////////////////////////////////////////////// // Function: BitArray::has_all_of // Access: Published // Description: Returns true if all bits in the indicated range are // set, false otherwise. //////////////////////////////////////////////////////////////////// bool BitArray:: has_all_of(int low_bit, int size) const { if ((low_bit + size - 1) / num_bits_per_word >= get_num_words()) { // This range touches the highest bits. if (!_highest_bits) { return false; } } int w = low_bit / num_bits_per_word; int b = low_bit % num_bits_per_word; if (w >= get_num_words()) { // This range is entirely among the highest bits. return (_highest_bits != 0); } if (b + size <= num_bits_per_word) { // The whole thing fits within one word of the array. return get_word(w).has_all_of(b, size); } int num_high_bits = num_bits_per_word - b; if (!_array[w].has_all_of(b, num_high_bits)) { return false; } size -= num_high_bits; ++w; while (size > 0) { if (size <= num_bits_per_word) { // The remainder fits within one word of the array. return _array[w].has_all_of(0, size); } // Keep going. if (!_array[w].is_all_on()) { return false; } size -= num_bits_per_word; ++w; if (w >= get_num_words()) { // Now we're up to the highest bits. return (_highest_bits != 0); } } return true; } //////////////////////////////////////////////////////////////////// // Function: BitArray::set_range // Access: Published // Description: Sets the indicated range of bits on. //////////////////////////////////////////////////////////////////// void BitArray:: set_range(int low_bit, int size) { int w = low_bit / num_bits_per_word; int b = low_bit % num_bits_per_word; if (w >= get_num_words() && _highest_bits) { // All the highest bits are already on. return; } if (b + size <= num_bits_per_word) { // The whole thing fits within one word of the array. ensure_has_word(w); _array[w].set_range(b, size); normalize(); return; } ensure_has_word(w); int num_high_bits = num_bits_per_word - b; _array[w].set_range(b, num_high_bits); size -= num_high_bits; ++w; while (size > 0) { if (size <= num_bits_per_word) { // The remainder fits within one word of the array. ensure_has_word(w); _array[w].set_range(0, size); normalize(); return; } // Keep going. ensure_has_word(w); _array[w] = MaskType::all_on(); size -= num_bits_per_word; ++w; if (w >= get_num_words() && _highest_bits) { // All the highest bits are already on. normalize(); return; } } normalize(); } //////////////////////////////////////////////////////////////////// // Function: BitArray::clear_range // Access: Published // Description: Sets the indicated range of bits off. //////////////////////////////////////////////////////////////////// void BitArray:: clear_range(int low_bit, int size) { int w = low_bit / num_bits_per_word; int b = low_bit % num_bits_per_word; if (w >= get_num_words() && !_highest_bits) { // All the highest bits are already off. return; } if (b + size <= num_bits_per_word) { // The whole thing fits within one word of the array. ensure_has_word(w); _array[w].clear_range(b, size); normalize(); return; } ensure_has_word(w); int num_high_bits = num_bits_per_word - b; _array[w].clear_range(b, num_high_bits); size -= num_high_bits; ++w; while (size > 0) { if (size <= num_bits_per_word) { // The remainder fits within one word of the array. ensure_has_word(w); _array[w].clear_range(0, size); normalize(); return; } // Keep going. ensure_has_word(w); _array[w] = MaskType::all_off(); size -= num_bits_per_word; ++w; if (w >= get_num_words() && !_highest_bits) { // All the highest bits are already off. normalize(); return; } } normalize(); } //////////////////////////////////////////////////////////////////// // Function: BitArray::get_num_on_bits // Access: Published // Description: Returns the number of bits that are set to 1 in the // array. Returns -1 if there are an infinite number of // 1 bits. //////////////////////////////////////////////////////////////////// int BitArray:: get_num_on_bits() const { if (_highest_bits) { return -1; } int result = 0; Array::const_iterator ai; for (ai = _array.begin(); ai != _array.end(); ++ai) { result += (*ai).get_num_on_bits(); } return result; } //////////////////////////////////////////////////////////////////// // Function: BitArray::get_num_off_bits // Access: Published // Description: Returns the number of bits that are set to 0 in the // array. Returns -1 if there are an infinite number of // 0 bits. //////////////////////////////////////////////////////////////////// int BitArray:: get_num_off_bits() const { if (!_highest_bits) { return -1; } int result = 0; Array::const_iterator ai; for (ai = _array.begin(); ai != _array.end(); ++ai) { result += (*ai).get_num_off_bits(); } return result; } //////////////////////////////////////////////////////////////////// // Function: BitArray::get_lowest_on_bit // Access: Published // Description: Returns the index of the lowest 1 bit in the array. // Returns -1 if there are no 1 bits. //////////////////////////////////////////////////////////////////// int BitArray:: get_lowest_on_bit() const { int num_words = get_num_words(); for (int w = 0; w < num_words; ++w) { int b = _array[w].get_lowest_on_bit(); if (b != -1) { return w * num_bits_per_word + b; } } if (_highest_bits) { return num_words * num_bits_per_word; } else { return -1; } } //////////////////////////////////////////////////////////////////// // Function: BitArray::get_lowest_off_bit // Access: Published // Description: Returns the index of the lowest 0 bit in the array. // Returns -1 if there are no 0 bits. //////////////////////////////////////////////////////////////////// int BitArray:: get_lowest_off_bit() const { int num_words = get_num_words(); for (int w = 0; w < num_words; ++w) { int b = _array[w].get_lowest_off_bit(); if (b != -1) { return w * num_bits_per_word + b; } } if (!_highest_bits) { return num_words * num_bits_per_word; } else { return -1; } } //////////////////////////////////////////////////////////////////// // Function: BitArray::get_highest_on_bit // Access: Published // Description: Returns the index of the highest 1 bit in the array. // Returns -1 if there are no 1 bits or if there an // infinite number of 1 bits. //////////////////////////////////////////////////////////////////// int BitArray:: get_highest_on_bit() const { if (_highest_bits) { return -1; } int num_words = get_num_words(); for (int w = num_words - 1; w >= 0; --w) { int b = _array[w].get_highest_on_bit(); if (b != -1) { return w * num_bits_per_word + b; } } return -1; } //////////////////////////////////////////////////////////////////// // Function: BitArray::get_highest_off_bit // Access: Published // Description: Returns the index of the highest 0 bit in the array. // Returns -1 if there are no 0 bits or if there an // infinite number of 1 bits. //////////////////////////////////////////////////////////////////// int BitArray:: get_highest_off_bit() const { if (!_highest_bits) { return -1; } int num_words = get_num_words(); for (int w = num_words - 1; w >= 0; --w) { int b = _array[w].get_highest_off_bit(); if (b != -1) { return w * num_bits_per_word + b; } } return -1; } //////////////////////////////////////////////////////////////////// // Function: BitArray::get_next_higher_different_bit // Access: Published // Description: Returns the index of the next bit in the array, above // low_bit, whose value is different that the value of // low_bit. Returns low_bit again if all bits higher // than low_bit have the same value. // // This can be used to quickly iterate through all of // the bits in the array. //////////////////////////////////////////////////////////////////// int BitArray:: get_next_higher_different_bit(int low_bit) const { int w = low_bit / num_bits_per_word; int b = low_bit % num_bits_per_word; int num_words = get_num_words(); if (w >= num_words) { return low_bit; } int b2 = _array[w].get_next_higher_different_bit(b); if (b2 != b && b2 < num_bits_per_word) { // The next higher bit is within the same word. return w * num_bits_per_word + b2; } // Look for the next word with anything interesting. MaskType skip_next = (_array[w].get_bit(b)) ? MaskType::all_on() : MaskType::all_off(); int w2 = w; ++w2; while (w2 < num_words && _array[w2] == skip_next) { ++w2; } if (w2 >= num_words) { // All bits higher are the same value. int is_on = _array[w].get_bit(b); return is_on ? (num_words * num_bits_per_word) : low_bit; } if (_array[w2].get_bit(0) != _array[w].get_bit(b)) { // The first bit of word w2 is different. return w2 * num_bits_per_word; } b2 = _array[w2].get_next_higher_different_bit(0); return w2 * num_bits_per_word + b2; } //////////////////////////////////////////////////////////////////// // Function: BitArray::invert_in_place // Access: Published // Description: Inverts all the bits in the BitArray. This is // equivalent to array = ~array. //////////////////////////////////////////////////////////////////// void BitArray:: invert_in_place() { _highest_bits = !_highest_bits; copy_on_write(); Array::iterator ai; for (ai = _array.begin(); ai != _array.end(); ++ai) { (*ai) = ~(*ai); } } //////////////////////////////////////////////////////////////////// // Function: BitArray::has_bits_in_common // Access: Published // Description: Returns true if this BitArray has any "one" bits in // common with the other one, false otherwise. // // This is equivalent to (array & other) != 0, but may // be faster. //////////////////////////////////////////////////////////////////// bool BitArray:: has_bits_in_common(const BitArray &other) const { if (_highest_bits && other._highest_bits) { // Yup, in fact we have an infinite number of bits in common. return true; } size_t num_common_words = min(_array.size(), other._array.size()); // Consider the words that are on top of either array. if (other._array.size() < _array.size() && other._highest_bits) { // The other array has fewer actual words, and the top n words of // the other array are all ones. We have bits in common if any of // our top n words are nonzero. Array::const_iterator ai; for (ai = _array.begin() + other._array.size(); ai != _array.end(); ++ai) { if (!(*ai).is_zero()) { return true; } } } else if (_array.size() < other._array.size() && _highest_bits) { // This array has fewer actual words, and the top n words of this // array are all ones. We have bits in common if any of the the // other's top n words are nonzero. Array::const_iterator ai; for (ai = other._array.begin() + _array.size(); ai != other._array.end(); ++ai) { if (!(*ai).is_zero()) { return true; } } } // Consider the words that both arrays have in common. for (size_t i = 0; i < num_common_words; ++i) { if (!(_array[i] & other._array[i]).is_zero()) { return true; } } // Nope, nothing. return false; } //////////////////////////////////////////////////////////////////// // Function: BitArray::output // Access: Published // Description: Writes the BitArray out as a hex number. For a // BitArray, this is always the same as output_hex(); // it's too confusing for the output format to change // back and forth at runtime. //////////////////////////////////////////////////////////////////// void BitArray:: output(ostream &out) const { output_hex(out); } //////////////////////////////////////////////////////////////////// // Function: BitArray::output_binary // Access: Published // Description: Writes the BitArray out as a binary number, with // spaces every four bits. //////////////////////////////////////////////////////////////////// void BitArray:: output_binary(ostream &out, int spaces_every) const { if (_highest_bits) { out << "...1 "; } int num_bits = max(get_num_bits(), spaces_every); for (int i = num_bits - 1; i >= 0; i--) { if (spaces_every != 0 && ((i % spaces_every) == spaces_every - 1)) { out << ' '; } out << (get_bit(i) ? '1' : '0'); } } //////////////////////////////////////////////////////////////////// // Function: BitArray::output_hex // Access: Published // Description: Writes the BitArray out as a hexadecimal number, with // spaces every four digits. //////////////////////////////////////////////////////////////////// void BitArray:: output_hex(ostream &out, int spaces_every) const { int num_bits = get_num_bits(); int num_digits = max((num_bits + 3) / 4, spaces_every); if (_highest_bits) { out << "...f "; } for (int i = num_digits - 1; i >= 0; i--) { WordType digit = extract(i * 4, 4); if (spaces_every != 0 && ((i % spaces_every) == spaces_every - 1)) { out << ' '; } if (digit > 9) { out << (char)(digit - 10 + 'a'); } else { out << (char)(digit + '0'); } } } //////////////////////////////////////////////////////////////////// // Function: BitArray::write // Access: Published // Description: Writes the BitArray out as a binary or a hex number, // according to the number of bits. //////////////////////////////////////////////////////////////////// void BitArray:: write(ostream &out, int indent_level) const { indent(out, indent_level) << *this << "\n"; } //////////////////////////////////////////////////////////////////// // Function: BitArray::compare_to // Access: Published // Description: Returns a number less than zero if this BitArray sorts // before the indicated other BitArray, greater than zero // if it sorts after, or 0 if they are equivalent. This // is based on the same ordering defined by operator <. //////////////////////////////////////////////////////////////////// int BitArray:: compare_to(const BitArray &other) const { if (_highest_bits != other._highest_bits) { return _highest_bits ? 1 : -1; } int num_words = max(get_num_words(), other.get_num_words()); // Compare from highest-order to lowest-order word. for (int i = num_words - 1; i >= 0; --i) { int compare = get_word(i).compare_to(other.get_word(i)); if (compare != 0) { return compare; } } return 0; } //////////////////////////////////////////////////////////////////// // Function: BitArray::operator &= // Access: Published // Description: //////////////////////////////////////////////////////////////////// void BitArray:: operator &= (const BitArray &other) { size_t num_common_words = min(_array.size(), other._array.size()); copy_on_write(); // Consider the words that are on top of either array. if (other._array.size() < _array.size() && !other._highest_bits) { // The other array has fewer actual words, and the top n words of // the other array are all zeroes. "mask off" the top n words of // this array. _array.erase(_array.begin() + other._array.size(), _array.end()); } else if (_array.size() < other._array.size() && _highest_bits) { // This array has fewer actual words, and the top n words of this // array are all ones. "mask on" the top n words of the other // array. Array::const_iterator ai; for (ai = other._array.begin() + _array.size(); ai != other._array.end(); ++ai) { _array.push_back(*ai); } } // Consider the words that both arrays have in common. for (size_t i = 0; i < num_common_words; ++i) { _array[i] &= other._array[i]; } _highest_bits &= other._highest_bits; normalize(); } //////////////////////////////////////////////////////////////////// // Function: BitArray::operator |= // Access: Published // Description: //////////////////////////////////////////////////////////////////// void BitArray:: operator |= (const BitArray &other) { size_t num_common_words = min(_array.size(), other._array.size()); copy_on_write(); // Consider the words that are on top of either array. if (other._array.size() < _array.size() && other._highest_bits) { // The other array has fewer actual words, and the top n words of // the other array are all ones. The top n words of this array // become ones too (which means we can drop them out). _array.erase(_array.begin() + other._array.size(), _array.end()); } else if (_array.size() < other._array.size() && !_highest_bits) { // This array has fewer actual words, and the top n words of this // array are all zeros. Copy in the top n words of the other // array. Array::const_iterator ai; for (ai = other._array.begin() + _array.size(); ai != other._array.end(); ++ai) { _array.push_back(*ai); } } // Consider the words that both arrays have in common. for (size_t i = 0; i < num_common_words; ++i) { _array[i] |= other._array[i]; } _highest_bits |= other._highest_bits; normalize(); } //////////////////////////////////////////////////////////////////// // Function: BitArray::operator ^= // Access: Published // Description: //////////////////////////////////////////////////////////////////// void BitArray:: operator ^= (const BitArray &other) { size_t num_common_words = min(_array.size(), other._array.size()); copy_on_write(); // Consider the words that are on top of either array. if (other._array.size() < _array.size() && other._highest_bits) { // The other array has fewer actual words, and the top n words of // the other array are all ones. The top n words of this array // get inverted. Array::iterator ai; for (ai = _array.begin() + other._array.size(); ai != _array.end(); ++ai) { (*ai).invert_in_place(); } } else if (_array.size() < other._array.size()) { if (!_highest_bits) { // This array has fewer actual words, and the top n words of this // array are all zeros. Copy in the top n words of the other // array. Array::const_iterator ai; for (ai = other._array.begin() + _array.size(); ai != other._array.end(); ++ai) { _array.push_back(*ai); } } else { // This array has fewer actual words, and the top n words of this // array are all ones. Copy in the top n words of the other // array, inverted. Array::const_iterator ai; for (ai = other._array.begin() + _array.size(); ai != other._array.end(); ++ai) { _array.push_back(~(*ai)); } } } // Consider the words that both arrays have in common. for (size_t i = 0; i < num_common_words; ++i) { _array[i] ^= other._array[i]; } _highest_bits ^= other._highest_bits; normalize(); } //////////////////////////////////////////////////////////////////// // Function: BitArray::operator <<= // Access: Published // Description: Logical left shift. The rightmost bits are filled in // with zeroes. Since this is an infinite bit array, // none of the bits on the left are lost. //////////////////////////////////////////////////////////////////// void BitArray:: operator <<= (int shift) { if (shift == 0 || _array.empty()) { return; } if (shift < 0) { operator >>= (-shift); return; } int w = shift / num_bits_per_word; int b = shift % num_bits_per_word; if (b == 0) { // Easy case--word-at-a-time. Array new_array; new_array.reserve(_array.size() + w); for (int i = 0; i < w; ++i) { new_array.push_back(MaskType::all_off()); } Array::const_iterator ai; for (ai = _array.begin(); ai != _array.end(); ++ai) { new_array.push_back(*ai); } _array = new_array; } else { // Harder case--we have to shuffle bits between words. Array new_array; new_array.reserve(_array.size() + w + 1); for (int i = 0; i < w; ++i) { new_array.push_back(MaskType::all_off()); } int downshift_count = num_bits_per_word - b; MaskType lower_mask = MaskType::lower_on(downshift_count); MaskType upper_mask = ~lower_mask; Array::const_iterator ai = _array.begin(); nassertv(ai != _array.end()); MaskType next_bits = ((*ai) & upper_mask) >> downshift_count; new_array.push_back(((*ai) & lower_mask) << b); ++ai; while (ai != _array.end()) { new_array.push_back((((*ai) & lower_mask) << b) | next_bits); next_bits = ((*ai) & upper_mask) >> downshift_count; ++ai; } // Finally, the top n bits. if (_highest_bits) { next_bits |= ~MaskType::lower_on(b); } new_array.push_back(next_bits); _array = new_array; } normalize(); } //////////////////////////////////////////////////////////////////// // Function: BitArray::operator >>= // Access: Published // Description: Logical right shift. The rightmost bits are lost. // Since this is an infinite bit array, there is no // question of sign extension; there is no need to // synthesize bits on the left. //////////////////////////////////////////////////////////////////// void BitArray:: operator >>= (int shift) { if (shift == 0 || _array.empty()) { return; } if (shift < 0) { operator <<= (-shift); return; } int w = shift / num_bits_per_word; int b = shift % num_bits_per_word; if (w >= (int)_array.size()) { // Trivial case--shift to nothing. _array.clear(); return; } if (b == 0) { // Easy case--word-at-a-time. Array new_array; new_array.reserve(_array.size() - w); Array::const_iterator ai; for (ai = _array.begin() + w; ai != _array.end(); ++ai) { new_array.push_back(*ai); } _array = new_array; } else { // Harder case--we have to shuffle bits between words. Array new_array; new_array.reserve(_array.size() - w); int upshift_count = num_bits_per_word - b; MaskType lower_mask = MaskType::lower_on(b); MaskType upper_mask = ~lower_mask; Array::const_iterator ai = _array.begin() + w; nassertv(ai < _array.end()); MaskType next_bits = ((*ai) & upper_mask) >> b; ++ai; while (ai != _array.end()) { new_array.push_back((((*ai) & lower_mask) << upshift_count) | next_bits); next_bits = ((*ai) & upper_mask) >> b; ++ai; } // Finally, the top n bits. if (_highest_bits) { next_bits |= ~MaskType::lower_on(upshift_count); } new_array.push_back(next_bits); _array = new_array; } normalize(); } //////////////////////////////////////////////////////////////////// // Function: BitArray::generate_hash // Access: Public // Description: Adds the bitmask to the indicated hash generator. //////////////////////////////////////////////////////////////////// void BitArray:: generate_hash(ChecksumHashGenerator &hashgen) const { hashgen.add_int(_highest_bits); Array::const_iterator ai; for (ai = _array.begin(); ai != _array.end(); ++ai) { hashgen.add_int((*ai).get_word()); } } //////////////////////////////////////////////////////////////////// // Function: BitArray::ensure_has_word // Access: Private // Description: Ensures that at least word n has been allocated into // the array. //////////////////////////////////////////////////////////////////// void BitArray:: ensure_has_word(int n) { copy_on_write(); if (_highest_bits) { while (n >= (int)_array.size()) { _array.push_back(MaskType::all_on()); } } else { while (n >= (int)_array.size()) { _array.push_back(MaskType::all_off()); } } } //////////////////////////////////////////////////////////////////// // Function: BitArray::normalize // Access: Private // Description: Ensures that the array is the smallest array that // represents this same value, by removing the topmost // words that are all bits off (or on). //////////////////////////////////////////////////////////////////// void BitArray:: normalize() { if (_highest_bits) { if (!_array.empty() && _array.back() == MaskType::all_on()) { copy_on_write(); _array.pop_back(); while (!_array.empty() && _array.back() == MaskType::all_on()) { _array.pop_back(); } } } else { if (!_array.empty() && _array.back().is_zero()) { copy_on_write(); _array.pop_back(); while (!_array.empty() && _array.back().is_zero()) { _array.pop_back(); } } } } //////////////////////////////////////////////////////////////////// // Function: BitArray::write_datagram // Access: Public // Description: Writes the contents of this object to the datagram // for shipping out to a Bam file. //////////////////////////////////////////////////////////////////// void BitArray:: write_datagram(BamWriter *manager, Datagram &dg) const { dg.add_uint32(_array.size()); Array::const_iterator ai; for (ai = _array.begin(); ai != _array.end(); ++ai) { dg.add_uint32((*ai).get_word()); } dg.add_uint8(_highest_bits); } //////////////////////////////////////////////////////////////////// // Function: BitArray::read_datagram // Access: Public // Description: Reads the object that was previously written to a Bam // file. //////////////////////////////////////////////////////////////////// void BitArray:: read_datagram(DatagramIterator &scan, BamReader *manager) { size_t num_words = scan.get_uint32(); _array = Array::empty_array(num_words); for (size_t i = 0; i < num_words; ++i) { _array[i] = WordType(scan.get_uint32()); } _highest_bits = scan.get_uint8(); }