Skip to content

Commit e68ce0f

Browse files
authored
Merge pull request #5653 from ab9rf/bitarray
rewrite `BitArray` to be a little less crusty
2 parents e21f878 + de45ea4 commit e68ce0f

File tree

4 files changed

+136
-87
lines changed

4 files changed

+136
-87
lines changed

library/include/BitArray.h

Lines changed: 133 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
3236
namespace 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

library/include/DataDefs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,7 @@ namespace DFHack {
948948
inline void flagarray_to_string(std::vector<std::string> *pvec, const BitArray<T> &val) {
949949
typedef df::enum_traits<T> traits;
950950
int size = traits::last_item_value-traits::first_item_value+1;
951-
flagarrayToString(pvec, val.bits, val.size,
951+
flagarrayToString(pvec, val.bits(), val.size(),
952952
(int)traits::first_item_value, size, traits::key_table);
953953
}
954954

library/include/DataIdentity.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ namespace df
523523

524524
protected:
525525
virtual int item_count(void *ptr, CountMode cnt) const {
526-
return cnt == COUNT_LEN ? ((container*)ptr)->size * 8 : -1;
526+
return cnt == COUNT_LEN ? ((container*)ptr)->size() * 8 : -1;
527527
}
528528
virtual bool get_item(void *ptr, int idx) const {
529529
return ((container*)ptr)->is_set(idx);

library/include/RemoteTools.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ namespace DFHack
7474
*/
7575
template<class T>
7676
void flagarray_to_ints(RepeatedField<google::protobuf::int32> *pf, const BitArray<T> &val) {
77-
for (size_t i = 0; i < val.size*8; i++)
77+
for (size_t i = 0; i < size_t(val.size()*8); i++)
7878
if (val.is_set(T(i)))
7979
pf->Add(i);
8080
}

0 commit comments

Comments
 (0)