소스 검색

copy BitArray by reference

David Rose 19 년 전
부모
커밋
bf6bb54c31
3개의 변경된 파일44개의 추가작업 그리고 8개의 파일을 삭제
  1. 17 0
      panda/src/putil/bitArray.I
  2. 24 7
      panda/src/putil/bitArray.cxx
  3. 3 1
      panda/src/putil/bitArray.h

+ 17 - 0
panda/src/putil/bitArray.I

@@ -518,3 +518,20 @@ operator >> (int shift) const {
   result >>= shift;
   return result;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: BitArray::copy_on_write
+//       Access: Private
+//  Description: Called internally just before writing to the _array
+//               member, this makes a new copy of _array if it appears
+//               to be shared with any other objects--thus achieving
+//               copy-on-write.
+////////////////////////////////////////////////////////////////////
+INLINE void BitArray::
+copy_on_write() {
+  if (_array.get_ref_count() > 1) {
+    PTA(MaskType) new_array;
+    new_array.v() = _array.v();
+    _array = new_array;
+  }
+}

+ 24 - 7
panda/src/putil/bitArray.cxx

@@ -35,7 +35,7 @@ is_zero() const {
   }
 
   // Start from the high end, since that's more likely to be nonzero.
-  Array::const_reverse_iterator ai;
+  Array::reverse_iterator ai;
   for (ai = _array.rbegin(); ai != _array.rend(); ++ai) {
     if ((*ai) != 0) {
       return false;
@@ -157,6 +157,7 @@ clear_range(int low_bit, int size) {
 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);
@@ -328,6 +329,8 @@ 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
@@ -365,6 +368,8 @@ 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
@@ -402,6 +407,8 @@ 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
@@ -478,7 +485,7 @@ operator <<= (int shift) {
     for (ai = _array.begin(); ai != _array.end(); ++ai) {
       new_array.push_back(*ai);
     }
-    _array.swap(new_array);
+    _array = new_array;
 
   } else {
     // Harder case--we have to shuffle bits between words.
@@ -508,7 +515,7 @@ operator <<= (int shift) {
       next_bits |= ~MaskType::lower_on(b);
     }
     new_array.push_back(next_bits);
-    _array.swap(new_array);
+    _array = new_array;
   }
 
   normalize();
@@ -549,7 +556,7 @@ operator >>= (int shift) {
     for (ai = _array.begin() + w; ai != _array.end(); ++ai) {
       new_array.push_back(*ai);
     }
-    _array.swap(new_array);
+    _array = new_array;
 
   } else {
     // Harder case--we have to shuffle bits between words.
@@ -576,7 +583,7 @@ operator >>= (int shift) {
       next_bits |= ~MaskType::lower_on(upshift_count);
     }
     new_array.push_back(next_bits);
-    _array.swap(new_array);
+    _array = new_array;
   }
 
   normalize();
@@ -604,6 +611,8 @@ generate_hash(ChecksumHashGenerator &hashgen) const {
 ////////////////////////////////////////////////////////////////////
 void BitArray::
 ensure_has_word(int n) {
+  copy_on_write();
+
   if (_highest_bits) {
     while (n >= (int)_array.size()) {
       _array.push_back(MaskType::all_on());
@@ -625,12 +634,20 @@ ensure_has_word(int n) {
 void BitArray::
 normalize() {
   if (_highest_bits) {
-    while (!_array.empty() && _array.back() == MaskType::all_on()) {
+    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 {
-    while (!_array.empty() && _array.back().is_zero()) {
+    if (!_array.empty() && _array.back().is_zero()) {
+      copy_on_write();
       _array.pop_back();
+      while (!_array.empty() && _array.back().is_zero()) {
+        _array.pop_back();
+      }
     }
   }
 }

+ 3 - 1
panda/src/putil/bitArray.h

@@ -25,6 +25,7 @@
 #include "numeric_types.h"
 #include "typedObject.h"
 #include "indent.h"
+#include "pointerToArray.h"
 
 #include "checksumHashGenerator.h"
 
@@ -121,11 +122,12 @@ public:
   void generate_hash(ChecksumHashGenerator &hashgen) const;
 
 private:
+  INLINE void copy_on_write();
   void ensure_has_word(int n);
   void normalize();
 
 private:
-  typedef pvector<MaskType> Array;
+  typedef PTA(MaskType) Array;
   Array _array;
   int _highest_bits;  // Either 0 or 1.