Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit aaf62c9

Browse files
committedJun 24, 2021
Make Agent copyable and moveable
This allows implementing C++ iterator interface on top of the Agent more efficiently. C++ iterators must be copyable, and the only way to copy one previously was to repeat the query until the index.
1 parent 006020c commit aaf62c9

File tree

8 files changed

+222
-30
lines changed

8 files changed

+222
-30
lines changed
 

‎configure.ac

+7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ AC_PROG_INSTALL
1313

1414
AC_CONFIG_MACRO_DIR([m4])
1515

16+
# Sanitizers
17+
AC_ARG_ENABLE([asan], AS_HELP_STRING([--enable-asan], [Enable address sanitizer]))
18+
1619
# Macros for SSE availability check.
1720
AC_DEFUN([MARISA_ENABLE_SSE2],
1821
[AC_EGREP_CPP([yes], [
@@ -241,6 +244,10 @@ elif test "x${enable_sse2}" != "xno"; then
241244
CXXFLAGS="$CXXFLAGS -DMARISA_USE_SSE2 -msse2"
242245
fi
243246

247+
AS_IF([test "x$enable_asan" = "xyes"], [
248+
CXXFLAGS="$CXXFLAGS -fsanitize=address"
249+
])
250+
244251
AC_CONFIG_FILES([Makefile
245252
marisa.pc
246253
include/Makefile

‎include/marisa/agent.h

+16-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ class Agent {
2222
Agent();
2323
~Agent();
2424

25+
Agent(const Agent &other);
26+
Agent &operator=(const Agent &other);
27+
28+
#if __cplusplus >= 201103L
29+
Agent(Agent &&other) noexcept;
30+
Agent &operator=(Agent &&other) noexcept;
31+
#endif
32+
2533
const Query &query() const {
2634
return query_;
2735
}
@@ -37,6 +45,9 @@ class Agent {
3745
void set_query(const char *str);
3846
void set_query(const char *ptr, std::size_t length);
3947
void set_query(std::size_t key_id);
48+
void set_query(const Query &query) {
49+
query_ = query;
50+
}
4051

4152
const grimoire::trie::State &state() const {
4253
return *state_;
@@ -65,7 +76,7 @@ class Agent {
6576
}
6677

6778
bool has_state() const {
68-
return state_.get() != NULL;
79+
return state_ != NULL;
6980
}
7081
void init_state();
7182

@@ -75,11 +86,11 @@ class Agent {
7586
private:
7687
Query query_;
7788
Key key_;
78-
scoped_ptr<grimoire::trie::State> state_;
7989

80-
// Disallows copy and assignment.
81-
Agent(const Agent &);
82-
Agent &operator=(const Agent &);
90+
// Cannot be `scoped_ptr` because `State` is forward-declared.
91+
grimoire::trie::State *state_;
92+
93+
void clear_state();
8394
};
8495

8596
} // namespace marisa

‎include/marisa/scoped-array.h

+12
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ class scoped_array {
1111
scoped_array() : array_(NULL) {}
1212
explicit scoped_array(T *array) : array_(array) {}
1313

14+
#if __cplusplus >= 201103L
15+
scoped_array(scoped_array &&other) noexcept : array_(other.array_) {
16+
other.array_ = NULL;
17+
}
18+
scoped_array<T> &operator=(scoped_array<T> &&other) noexcept {
19+
delete [] array_;
20+
array_ = other.array_;
21+
other.array_ = NULL;
22+
return *this;
23+
}
24+
#endif
25+
1426
~scoped_array() {
1527
delete [] array_;
1628
}

‎include/marisa/scoped-ptr.h

+12
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ class scoped_ptr {
1515
delete ptr_;
1616
}
1717

18+
#if __cplusplus >= 201103L
19+
scoped_ptr(scoped_ptr &&other) noexcept : ptr_(other.ptr_) {
20+
other.ptr_ = NULL;
21+
}
22+
scoped_ptr<T> &operator=(scoped_ptr<T> &&other) noexcept {
23+
delete ptr_;
24+
ptr_ = other.ptr_;
25+
other.ptr_ = NULL;
26+
return *this;
27+
}
28+
#endif
29+
1830
void reset(T *ptr = NULL) {
1931
MARISA_DEBUG_IF((ptr != NULL) && (ptr == ptr_), MARISA_RESET_ERROR);
2032
scoped_ptr(ptr).swap(*this);

‎lib/marisa/agent.cc

+54-12
Original file line numberDiff line numberDiff line change
@@ -5,47 +5,89 @@
55

66
namespace marisa {
77

8-
Agent::Agent() : query_(), key_(), state_() {}
8+
Agent::Agent() : query_(), key_(), state_(NULL) {}
99

10-
Agent::~Agent() {}
10+
Agent::~Agent() {
11+
delete state_;
12+
}
13+
14+
Agent::Agent(const Agent &other)
15+
: query_(other.query_),
16+
key_(other.key_),
17+
state_(other.has_state() ? new (std::nothrow) grimoire::trie::State(other.state()) : NULL) {}
18+
19+
Agent &Agent::operator=(const Agent &other) {
20+
query_ = other.query_;
21+
key_ = other.key_;
22+
delete state_;
23+
if (other.has_state()) {
24+
state_ = new (std::nothrow) grimoire::trie::State(other.state());
25+
} else {
26+
state_ = NULL;
27+
}
28+
return *this;
29+
}
30+
31+
#if __cplusplus >= 201103L
32+
Agent::Agent(Agent &&other) noexcept
33+
: query_(other.query_), key_(other.key_), state_(other.state_) {
34+
other.state_ = NULL;
35+
}
36+
37+
Agent &Agent::operator=(Agent &&other) noexcept {
38+
query_ = other.query_;
39+
key_ = other.key_;
40+
delete state_;
41+
state_ = other.state_;
42+
other.state_ = NULL;
43+
return *this;
44+
}
45+
#endif
1146

1247
void Agent::set_query(const char *str) {
1348
MARISA_THROW_IF(str == NULL, MARISA_NULL_ERROR);
14-
if (state_.get() != NULL) {
15-
state_->reset();
49+
if (state_ != NULL) {
50+
clear_state();
1651
}
1752
query_.set_str(str);
1853
}
1954

2055
void Agent::set_query(const char *ptr, std::size_t length) {
2156
MARISA_THROW_IF((ptr == NULL) && (length != 0), MARISA_NULL_ERROR);
22-
if (state_.get() != NULL) {
23-
state_->reset();
57+
if (state_ != NULL) {
58+
clear_state();
2459
}
2560
query_.set_str(ptr, length);
2661
}
2762

2863
void Agent::set_query(std::size_t key_id) {
29-
if (state_.get() != NULL) {
30-
state_->reset();
64+
if (state_ != NULL) {
65+
clear_state();
3166
}
3267
query_.set_id(key_id);
3368
}
3469

3570
void Agent::init_state() {
36-
MARISA_THROW_IF(state_.get() != NULL, MARISA_STATE_ERROR);
37-
state_.reset(new (std::nothrow) grimoire::State);
38-
MARISA_THROW_IF(state_.get() == NULL, MARISA_MEMORY_ERROR);
71+
MARISA_THROW_IF(state_ != NULL, MARISA_STATE_ERROR);
72+
delete state_;
73+
state_ = new (std::nothrow) grimoire::State;
74+
MARISA_THROW_IF(state_ == NULL, MARISA_MEMORY_ERROR);
3975
}
4076

4177
void Agent::clear() {
4278
Agent().swap(*this);
4379
}
4480

81+
82+
void Agent::clear_state() {
83+
delete state_;
84+
state_ = nullptr;
85+
}
86+
4587
void Agent::swap(Agent &rhs) {
4688
query_.swap(rhs.query_);
4789
key_.swap(rhs.key_);
48-
state_.swap(rhs.state_);
90+
marisa::swap(state_, rhs.state_);
4991
}
5092

5193
} // namespace marisa

‎lib/marisa/grimoire/trie/state.h

+8-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ class State {
2424
: key_buf_(), history_(), node_id_(0), query_pos_(0),
2525
history_pos_(0), status_code_(MARISA_READY_TO_ALL) {}
2626

27+
State(const State &) = default;
28+
State &operator=(const State &) = default;
29+
30+
#if __cplusplus >= 201103L
31+
State(State &&) noexcept = default;
32+
State &operator=(State &&) noexcept = default;
33+
#endif
34+
2735
void set_node_id(std::size_t node_id) {
2836
MARISA_DEBUG_IF(node_id > MARISA_UINT32_MAX, MARISA_SIZE_ERROR);
2937
node_id_ = (UInt32)node_id;
@@ -104,10 +112,6 @@ class State {
104112
UInt32 query_pos_;
105113
UInt32 history_pos_;
106114
StatusCode status_code_;
107-
108-
// Disallows copy and assignment.
109-
State(const State &);
110-
State &operator=(const State &);
111115
};
112116

113117
} // namespace trie

‎lib/marisa/grimoire/vector/vector.h

+41-9
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,38 @@ class Vector {
2323
}
2424
}
2525

26+
Vector(const Vector<T> &other)
27+
: buf_(), objs_(NULL), const_objs_(NULL),
28+
size_(0), capacity_(0), fixed_(other.fixed_) {
29+
if (other.buf_.get() == NULL) {
30+
objs_ = other.objs_;
31+
const_objs_ = other.const_objs_;
32+
size_ = other.size_;
33+
capacity_ = other.capacity_;
34+
} else {
35+
copy(other.const_objs_, other.size_, other.capacity_);
36+
}
37+
}
38+
39+
Vector &operator=(const Vector<T> &other) {
40+
clear();
41+
fixed_ = other.fixed_;
42+
if (other.buf_.get() == NULL) {
43+
objs_ = other.objs_;
44+
const_objs_ = other.const_objs_;
45+
size_ = other.size_;
46+
capacity_ = other.capacity_;
47+
} else {
48+
copy(other.const_objs_, other.size_, other.capacity_);
49+
}
50+
return *this;
51+
}
52+
53+
#if __cplusplus >= 201103L
54+
Vector(Vector &&) noexcept = default;
55+
Vector &operator=(Vector<T> &&) noexcept = default;
56+
#endif
57+
2658
void map(Mapper &mapper) {
2759
Vector temp;
2860
temp.map_(mapper);
@@ -225,14 +257,17 @@ class Vector {
225257
// realloc() assumes that T's placement new does not throw an exception.
226258
void realloc(std::size_t new_capacity) {
227259
MARISA_DEBUG_IF(new_capacity > max_size(), MARISA_SIZE_ERROR);
260+
copy(objs_, size_, new_capacity);
261+
}
228262

229-
scoped_array<char> new_buf(
230-
new (std::nothrow) char[sizeof(T) * new_capacity]);
263+
// copy() assumes that T's placement new does not throw an exception.
264+
void copy(const T *src, std::size_t src_size, std::size_t capacity) {
265+
scoped_array<char> new_buf(new (std::nothrow) char[sizeof(T) * capacity]);
231266
MARISA_DEBUG_IF(new_buf.get() == NULL, MARISA_MEMORY_ERROR);
232267
T *new_objs = reinterpret_cast<T *>(new_buf.get());
233268

234-
for (std::size_t i = 0; i < size_; ++i) {
235-
new (&new_objs[i]) T(objs_[i]);
269+
for (std::size_t i = 0; i < src_size; ++i) {
270+
new (&new_objs[i]) T(src[i]);
236271
}
237272
for (std::size_t i = 0; i < size_; ++i) {
238273
objs_[i].~T();
@@ -241,12 +276,9 @@ class Vector {
241276
buf_.swap(new_buf);
242277
objs_ = new_objs;
243278
const_objs_ = new_objs;
244-
capacity_ = new_capacity;
279+
size_ = src_size;
280+
capacity_ = capacity;
245281
}
246-
247-
// Disallows copy and assignment.
248-
Vector(const Vector &);
249-
Vector &operator=(const Vector &);
250282
};
251283

252284
} // namespace vector

0 commit comments

Comments
 (0)
Please sign in to comment.