@@ -27,132 +27,176 @@ distribution.
2727#include < stdint.h>
2828#include < string.h>
2929#include < stdlib.h>
30+
31+ #include < algorithm>
32+ #include < cstring>
3033#include < sstream>
3134#include < iterator>
35+
3236namespace DFHack
3337{
3438 template <typename T = int >
3539 class BitArray
3640 {
41+ private:
42+ // note that these are mandated by the implementation of flagarrayst in DF code, and must be exactly as below
43+ using buffer_type = unsigned char ;
44+ using size_type = int32_t ;
45+
46+ buffer_type* _bits;
47+ size_type _size;
48+
49+ void resize (size_type newsize, const BitArray<T>* replacement)
50+ {
51+ if (newsize == _size)
52+ return ;
53+
54+ if (newsize == 0 )
55+ {
56+ delete[] _bits;
57+ _bits = nullptr ;
58+ _size = 0 ;
59+ return ;
60+ }
61+
62+ buffer_type* old_data = _bits;
63+
64+ _bits = new buffer_type[newsize];
65+
66+ buffer_type* copysrc = replacement ? replacement->_bits : old_data;
67+ size_type copysize = replacement ? replacement->_size : _size;
68+
69+ if (copysrc)
70+ std::memcpy (_bits, copysrc, std::min (copysize, newsize));
71+
72+ if (newsize > _size)
73+ std::memset (_bits + _size, 0 , newsize - _size);
74+
75+ delete[] old_data;
76+
77+ _size = newsize;
78+ }
79+
80+ void extend (T index)
81+ {
82+ size_type newsize = (index + 7 ) / 8 ;
83+ if (newsize > _size)
84+ resize (newsize);
85+ }
86+
3787 public:
38- BitArray () : bits( NULL ), size (0 ) {}
39- BitArray (const BitArray<T> &other) : bits( NULL ), size (0 )
88+ BitArray () : _bits( nullptr ), _size (0 ) {}
89+ BitArray (const BitArray<T> &other) : _bits( nullptr ), _size (0 )
4090 {
41- * this = other;
91+ resize (other. _size , & other) ;
4292 }
4393 ~BitArray ()
4494 {
45- free (bits) ;
95+ delete [] _bits ;
4696 }
4797
48- explicit BitArray (T last) : bits( NULL ), size (0 ) {
98+ explicit BitArray (T last) : _bits( nullptr ), _size (0 ) {
4999 extend (last);
50100 }
51- explicit BitArray (unsigned bytes) : bits( NULL ), size (0 ) {
101+ explicit BitArray (unsigned bytes) : _bits( nullptr ), _size (0 ) {
52102 resize (bytes);
53103 }
54104
55- void clear_all ( void )
105+ size_type size () const { return _size; }
106+ buffer_type* bits () const { return _bits; }
107+
108+ void resize ( size_type newsize )
56109 {
57- if (bits)
58- memset (bits, 0 , size);
110+ resize (newsize, nullptr );
59111 }
60- void resize (unsigned newsize)
112+
113+ void clear_all ( void )
61114 {
62- if (newsize == size)
63- return ;
64- uint8_t * mem = (uint8_t *) realloc (bits, newsize);
65- if (!mem && newsize != 0 )
66- throw std::bad_alloc ();
67- bits = mem;
68- if (newsize > size)
69- memset (bits+size, 0 , newsize-size);
70- size = newsize;
71- }
72- BitArray<T> &operator = (const BitArray<T> &other)
73- {
74- resize (other.size );
75- memcpy (bits, other.bits , size);
76- return *this ;
115+ if (_bits)
116+ memset (_bits, 0 , _size);
77117 }
78- void extend (T index)
118+
119+ BitArray<T>& operator = (const BitArray<T>& other)
79120 {
80- unsigned newsize = (index / 8 ) + 1 ;
81- if (newsize > size)
82- resize (newsize);
121+ resize (other._size , &other);
122+ return *this ;
83123 }
124+
84125 void set (T index, bool value = true )
85126 {
86127 if (!value)
87128 {
88129 clear (index);
89130 return ;
90131 }
91- uint32_t byte = index / 8 ;
132+ size_type byte = index / 8 ;
92133 extend (index);
93- // if(byte < size)
94- {
95- uint8_t bit = 1 << (index % 8 );
96- bits[byte] |= bit;
97- }
134+ uint8_t bit = 1 << (index % 8 );
135+ _bits[byte] |= bit;
98136 }
137+
99138 void clear (T index)
100139 {
101- uint32_t byte = index / 8 ;
102- if (byte < size )
140+ size_type byte = index / 8 ;
141+ if (byte < _size )
103142 {
104143 uint8_t bit = 1 << (index % 8 );
105- bits [byte] &= ~bit;
144+ _bits [byte] &= ~bit;
106145 }
107146 }
147+
108148 void toggle (T index)
109149 {
110- uint32_t byte = index / 8 ;
150+ size_type byte = index / 8 ;
111151 extend (index);
112- // if(byte < size)
113- {
114- uint8_t bit = 1 << (index % 8 );
115- bits[byte] ^= bit;
116- }
152+ uint8_t bit = 1 << (index % 8 );
153+ _bits[byte] ^= bit;
117154 }
155+
118156 bool is_set (T index) const
119157 {
120- uint32_t byte = index / 8 ;
121- if (byte < size )
158+ size_type byte = index / 8 ;
159+ if (byte < _size )
122160 {
123161 uint8_t bit = 1 << (index % 8 );
124- return bit & bits [byte];
162+ return bit & _bits [byte];
125163 }
126164 else return false ;
127165 }
166+
128167 // / WARNING: this can truncate long bit arrays
129- uint32_t as_int ()
168+ template <typename I = uint32_t >
169+ I as_int () const
130170 {
131- if (!bits )
171+ if (!_bits )
132172 return 0 ;
133- if (size >= 4 )
134- return *(uint32_t *)bits;
135- uint32_t target = 0 ;
136- memcpy (&target, bits,size);
173+ if (_size >= sizeof (I))
174+ // FIXME (C++23): should be std::start_lifetime_as
175+ return *reinterpret_cast <I*>(_bits);
176+ I target = 0 ;
177+ std::memcpy (&target, _bits, _size);
137178 return target;
138179 }
180+
139181 // / WARNING: this can be truncated / only overwrite part of the data
140- bool operator =(uint32_t data)
182+ template <typename I = uint32_t >
183+ bool operator =(I data)
141184 {
142- if (!bits )
185+ if (!_bits )
143186 return false ;
144- if (size >= 4 )
187+ if (_size >= sizeof (I) )
145188 {
146- (*( uint32_t *)bits ) = data;
189+ * reinterpret_cast <I*>(_bits ) = data;
147190 return true ;
148191 }
149- memcpy (bits , &data, size );
192+ std:: memcpy (_bits , &data, _size );
150193 return true ;
151194 }
195+
152196 friend std::ostream& operator << (std::ostream &out, BitArray <T> &ba)
153197 {
154198 std::stringstream sstr;
155- for (int i = 0 ; i < ba.size * 8 ; i++)
199+ for (int i = 0 ; i < ba._size * 8 ; i++)
156200 {
157201 if (ba.is_set ((T)i))
158202 sstr << " 1 " ;
@@ -162,23 +206,44 @@ namespace DFHack
162206 out << sstr.str ();
163207 return out;
164208 }
165- uint8_t * bits;
166- uint32_t size;
167209 };
168210
169211 template <typename T = int >
170212 class DfArray
171213 {
214+ private:
172215 T *m_data;
173216 unsigned short m_size;
217+
218+ void resize (unsigned short new_size, const DfArray<T>* replacement)
219+ {
220+ if (new_size == m_size)
221+ return ;
222+
223+ T* old_data = m_data;
224+
225+ m_data = (T*) new T[new_size];
226+
227+ T* copysrc = replacement ? replacement->m_data : old_data;
228+ unsigned short copysize = replacement ? replacement->m_size : m_size;
229+
230+ if (copysrc)
231+ std::memcpy (m_data, copysrc, sizeof (T) * std::min (copysize, new_size));
232+
233+ if (new_size > m_size)
234+ std::memset (m_data + m_size, 0 , sizeof (T) * (new_size - m_size));
235+
236+ delete[] old_data;
237+
238+ m_size = new_size;
239+ }
174240 public:
175- DfArray () : m_data(NULL ), m_size(0 ) {}
176- ~DfArray () { free ( m_data) ; }
241+ DfArray () : m_data(nullptr ), m_size(0 ) {}
242+ ~DfArray () { delete[] m_data; }
177243
178- DfArray (const DfArray<T> &other) : m_data(NULL ), m_size(0 )
244+ DfArray (const DfArray<T> &other) : m_data(nullptr ), m_size(0 )
179245 {
180- resize (other.m_size );
181- memcpy (m_data, other.m_data ,m_size*sizeof (T));
246+ resize (other.m_size , &other);
182247 }
183248
184249 typedef T value_type;
@@ -195,28 +260,12 @@ namespace DFHack
195260
196261 void resize (unsigned new_size)
197262 {
198- if (new_size == m_size)
199- return ;
200- if (!m_data)
201- {
202- m_data = (T*) malloc (sizeof (T)*new_size);
203- }
204- else
205- {
206- T* mem = (T*) realloc (m_data, sizeof (T)*new_size);
207- if (!mem && new_size != 0 )
208- throw std::bad_alloc ();
209- m_data = mem;
210- }
211- if (new_size > m_size)
212- memset (m_data+sizeof (T)*m_size, 0 , sizeof (T)*(new_size - m_size));
213- m_size = new_size;
263+ resize (new_size, nullptr );
214264 }
215265
216266 DfArray &operator = (const DfArray<T> &other)
217267 {
218- resize (other.size ());
219- memcpy (data (), other.data (), sizeof (T)*size ());
268+ resize (other.size (), &other);
220269 return *this ;
221270 }
222271
0 commit comments