Skip to content

Commit 4cdabc0

Browse files
committed
Fix flexbuffer copy/assignment & clear method
Fixed freeing and deep copying `ddata_` from rhs, and fixed `clear` method to free `ddata_`.
1 parent 80ad5cd commit 4cdabc0

File tree

3 files changed

+93
-33
lines changed

3 files changed

+93
-33
lines changed

include/ack/bigint.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1282,7 +1282,7 @@ namespace ack {
12821282
{
12831283
if (&rhs != this)
12841284
{
1285-
buf_ = std::move(rhs.buf_);
1285+
buf_ = std::move( rhs.buf_ );
12861286
size_ = rhs.size_;
12871287
is_neg_ = rhs.is_neg_;
12881288
}

include/ack/buffer.hpp

Lines changed: 91 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@ namespace ack {
7070
public:
7171
using value_type = T;
7272

73-
constexpr fixed_buffer() = default;
74-
constexpr fixed_buffer(const fixed_buffer& rhs) = default;
75-
constexpr fixed_buffer(fixed_buffer&& rhs) = default;
76-
constexpr fixed_buffer& operator=(const fixed_buffer& rhs) = default;
77-
constexpr fixed_buffer& operator=(fixed_buffer&& rhs) = default;
73+
constexpr fixed_buffer() noexcept = default;
74+
constexpr fixed_buffer(const fixed_buffer& rhs) noexcept = default;
75+
constexpr fixed_buffer(fixed_buffer&& rhs) noexcept = default;
76+
constexpr fixed_buffer& operator=(const fixed_buffer& rhs) noexcept = default;
77+
constexpr fixed_buffer& operator=(fixed_buffer&& rhs) noexcept = default;
7878

79-
constexpr bool resize(size_t n)
79+
constexpr bool resize(size_t n) noexcept
8080
{
8181
if ( n > N ) {
8282
return false;
@@ -85,12 +85,12 @@ namespace ack {
8585
return true;
8686
}
8787

88-
constexpr void clear()
88+
constexpr void clear() noexcept
8989
{
9090
size_ = 0;
9191
}
9292

93-
constexpr T* data()
93+
constexpr T* data() noexcept
9494
{
9595
return data_.data();
9696
}
@@ -100,17 +100,17 @@ namespace ack {
100100
return data_.data();
101101
}
102102

103-
constexpr std::size_t size() const
103+
constexpr std::size_t size() const noexcept
104104
{
105105
return size_;
106106
}
107107

108-
constexpr std::size_t max_size() const
108+
constexpr std::size_t max_size() const noexcept
109109
{
110110
return N;
111111
}
112112

113-
constexpr void swap(fixed_buffer& rhs)
113+
constexpr void swap(fixed_buffer& rhs) noexcept
114114
{
115115
std::swap( data_, rhs.data_ );
116116
std::swap( size_, rhs.size_ );
@@ -138,25 +138,79 @@ namespace ack {
138138
* @warning if buffer is resized over the size of stack allocated memory (N)
139139
* data is re-allocated on the heap, and this data is never released
140140
* due to constexpr constrains which prohibits defining custom destructor.
141+
* You have to manually call `clear` to free heap allocated memory.
141142
* The flexbuffer should be used only in short lived environments like WASM.
142143
*/
143144
template<typename T, std::size_t N>
144145
class flexbuffer final: public buffer_base<flexbuffer<T, N>, T> {
145146
public:
146147
using value_type = T;
147148

148-
constexpr flexbuffer() = default;
149-
constexpr flexbuffer(const flexbuffer& rhs) = default;
150-
constexpr flexbuffer(flexbuffer&& rhs) = default;
151-
constexpr flexbuffer& operator=(const flexbuffer& rhs) = default;
152-
constexpr flexbuffer& operator=(flexbuffer&& rhs) = default;
149+
constexpr flexbuffer() noexcept = default;
150+
constexpr flexbuffer(const flexbuffer& rhs)
151+
{
152+
sdata_ = rhs.sdata_;
153+
size_ = rhs.size_;
154+
dsize_ = rhs.dsize_;
155+
if ( !std::is_constant_evaluated() ) {
156+
if ( rhs.ddata_ ) {
157+
ddata_ = new T[dsize_];
158+
memcpy( ddata_, rhs.ddata_ , dsize_ * sizeof( T ));
159+
}
160+
}
161+
}
162+
163+
constexpr flexbuffer(flexbuffer&& rhs) noexcept
164+
{
165+
sdata_ = std::move( rhs.sdata_ );
166+
size_ = rhs.size_;
167+
dsize_ = rhs.dsize_;
168+
ddata_ = rhs.ddata_;
169+
170+
rhs.size_ = 0;
171+
rhs.dsize_ = 0;
172+
rhs.ddata_ = nullptr;
173+
}
153174

154-
// ~flex_buffer() // destructor deleted otherwise flex_buffer can't be constructed at compile time
175+
constexpr flexbuffer& operator=(const flexbuffer& rhs)
176+
{
177+
if ( &rhs != this ) {
178+
this->clear();
179+
sdata_ = rhs.sdata_;
180+
size_ = rhs.size_;
181+
dsize_ = rhs.dsize_;
182+
if ( !std::is_constant_evaluated() ) {
183+
if ( rhs.ddata_ ) {
184+
ddata_ = new T[dsize_];
185+
memcpy( ddata_, rhs.ddata_ , dsize_ * sizeof( T ));
186+
}
187+
}
188+
}
189+
return *this;
190+
}
191+
192+
constexpr flexbuffer& operator=(flexbuffer&& rhs) noexcept
193+
{
194+
if ( &rhs != this ) {
195+
this->clear();
196+
sdata_ = std::move( rhs.sdata_ );
197+
size_ = rhs.size_;
198+
dsize_ = rhs.dsize_;
199+
ddata_ = rhs.ddata_;
200+
201+
rhs.size_ = 0;
202+
rhs.dsize_ = 0;
203+
rhs.ddata_ = nullptr;
204+
}
205+
return *this;
206+
}
207+
208+
// constexpr ~flex_buffer() // destructor deleted otherwise flex_buffer can't be constructed at compile time
155209
// {
156210
// if ( std::is_constant_evaluated() ) {
157-
// if ( ddata_ ) {
158-
// delete[] ddata_;
159-
// }
211+
// if ( ddata_ ) {
212+
// delete[] ddata_;
213+
// }
160214
// }
161215
// }
162216

@@ -168,19 +222,18 @@ namespace ack {
168222
}
169223
}
170224
else {
171-
if ( n > N && n > dsize ) {
172-
225+
if ( n > N && n > dsize_ ) {
173226
bool scpy = ( ddata_ == nullptr );
174227
T* pold = ddata_;
175228

176-
dsize += std::max( N, n );
177-
ddata_ = new T[dsize];
229+
dsize_ += std::max( N, n );
230+
ddata_ = new T[dsize_];
178231

179232
if ( scpy ) {
180233
memcpy( ddata_, sdata_.data(), N * sizeof( T ));
181234
}
182-
else{
183-
memcpy( ddata_, pold, (dsize - std::max( N, n )) * sizeof( T ));
235+
else {
236+
memcpy( ddata_, pold, (dsize_ - std::max( N, n )) * sizeof( T ));
184237
delete[] pold;
185238
pold = nullptr;
186239
}
@@ -193,7 +246,14 @@ namespace ack {
193246

194247
constexpr void clear()
195248
{
196-
size_ = 0;
249+
if ( !std::is_constant_evaluated() ) {
250+
if ( ddata_ ) {
251+
delete [] ddata_;
252+
ddata_ = nullptr;
253+
}
254+
}
255+
dsize_ = 0;
256+
size_ = 0;
197257
}
198258

199259
constexpr T* data()
@@ -203,7 +263,7 @@ namespace ack {
203263

204264
constexpr const T* data() const
205265
{
206-
return ddata_? ddata_ : sdata_.data();
266+
return ddata_ ? ddata_ : sdata_.data();
207267
}
208268

209269
constexpr std::size_t size() const
@@ -220,7 +280,7 @@ namespace ack {
220280
{
221281
std::swap( sdata_, rhs.sdata_ );
222282
if ( !std::is_constant_evaluated() ) {
223-
std::swap( dsize, rhs.dsize );
283+
std::swap( dsize_, rhs.dsize_ );
224284
std::swap( ddata_, rhs.ddata_ );
225285
}
226286
std::swap( size_, rhs.size_ );
@@ -251,8 +311,8 @@ namespace ack {
251311
private:
252312
std::array<T, N> sdata_ = {};
253313
T* ddata_ = nullptr; // replace with std::vector<T> when C++20 constexpr ctor is supported
254-
std::size_t size_ = 0;
255-
std::size_t dsize = 0;
314+
std::size_t size_ = 0;
315+
std::size_t dsize_ = 0;
256316
};
257317
template<std::size_t N>
258318
using fixed_word_buffer = fixed_buffer<word_t, N>;

include/ack/ec.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1697,7 +1697,7 @@ namespace ack {
16971697
*/
16981698
[[nodiscard]]
16991699
inline field_element_type compute_y(const field_element_type& x, const bool odd) const {
1700-
auto y = (( x * x + a ) * x + b ).sqrt();
1700+
auto y = (( x.sqr() + a ) * x + b ).sqrt();
17011701
if ( odd != y.value().test_bit( 0 )) {
17021702
y = -y;
17031703
}

0 commit comments

Comments
 (0)