Use copy-and-swap in Tokenizers
Ensures that the classes behave consistently when copied, moved, copy assigned, and move assigned.
This commit is contained in:
@ -68,6 +68,28 @@ Tokenizer::Tokenizer(Tokenizer && rhs) :
|
||||
reset();
|
||||
}
|
||||
|
||||
Tokenizer& Tokenizer::operator=(const Tokenizer& other)
|
||||
{
|
||||
Tokenizer tmp(other);
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tokenizer& Tokenizer::operator=(Tokenizer&& other)
|
||||
{
|
||||
Tokenizer tmp(std::move(other));
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Tokenizer::swap(Tokenizer& other)
|
||||
{
|
||||
std::swap(text, other.text);
|
||||
std::swap(separators, other.separators);
|
||||
std::swap(start, other.start);
|
||||
std::swap(ntokens, other.ntokens);
|
||||
}
|
||||
|
||||
/*! Re-position the tokenizer state to the first word,
|
||||
* i.e. the first non-separator character */
|
||||
void Tokenizer::reset() {
|
||||
@ -181,6 +203,25 @@ ValueTokenizer::ValueTokenizer(const ValueTokenizer &rhs) : tokens(rhs.tokens) {
|
||||
ValueTokenizer::ValueTokenizer(ValueTokenizer &&rhs) : tokens(std::move(rhs.tokens)) {
|
||||
}
|
||||
|
||||
ValueTokenizer& ValueTokenizer::operator=(const ValueTokenizer& other)
|
||||
{
|
||||
ValueTokenizer tmp(other);
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValueTokenizer& ValueTokenizer::operator=(ValueTokenizer&& other)
|
||||
{
|
||||
ValueTokenizer tmp(std::move(other));
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ValueTokenizer::swap(ValueTokenizer& other)
|
||||
{
|
||||
std::swap(tokens, other.tokens);
|
||||
}
|
||||
|
||||
/*! Indicate whether more tokens are available
|
||||
*
|
||||
* \return true if there are more tokens, false if not */
|
||||
|
||||
@ -37,8 +37,9 @@ public:
|
||||
Tokenizer(const std::string &str, const std::string &separators = TOKENIZER_DEFAULT_SEPARATORS);
|
||||
Tokenizer(Tokenizer &&);
|
||||
Tokenizer(const Tokenizer &);
|
||||
Tokenizer& operator=(const Tokenizer&) = default;
|
||||
Tokenizer& operator=(Tokenizer&&) = default;
|
||||
Tokenizer& operator=(const Tokenizer&);
|
||||
Tokenizer& operator=(Tokenizer&&);
|
||||
void swap(Tokenizer &);
|
||||
|
||||
void reset();
|
||||
void skip(int n=1);
|
||||
@ -93,8 +94,9 @@ public:
|
||||
ValueTokenizer(const std::string &str, const std::string &separators = TOKENIZER_DEFAULT_SEPARATORS);
|
||||
ValueTokenizer(const ValueTokenizer &);
|
||||
ValueTokenizer(ValueTokenizer &&);
|
||||
ValueTokenizer& operator=(const ValueTokenizer&) = default;
|
||||
ValueTokenizer& operator=(ValueTokenizer&&) = default;
|
||||
ValueTokenizer& operator=(const ValueTokenizer&);
|
||||
ValueTokenizer& operator=(ValueTokenizer&&);
|
||||
void swap(ValueTokenizer &);
|
||||
|
||||
std::string next_string();
|
||||
tagint next_tagint();
|
||||
|
||||
@ -101,6 +101,38 @@ TEST(Tokenizer, move_constructor)
|
||||
ASSERT_EQ(u.count(), 3);
|
||||
}
|
||||
|
||||
TEST(Tokenizer, copy_assignment)
|
||||
{
|
||||
Tokenizer t(" test word ", " ");
|
||||
Tokenizer u(" test2 word2 other2 ", " ");
|
||||
ASSERT_THAT(t.next(), Eq("test"));
|
||||
ASSERT_THAT(t.next(), Eq("word"));
|
||||
ASSERT_EQ(t.count(), 2);
|
||||
Tokenizer v = u;
|
||||
u = t;
|
||||
ASSERT_THAT(u.next(), Eq("test"));
|
||||
ASSERT_THAT(u.next(), Eq("word"));
|
||||
ASSERT_EQ(u.count(), 2);
|
||||
|
||||
ASSERT_THAT(v.next(), Eq("test2"));
|
||||
ASSERT_THAT(v.next(), Eq("word2"));
|
||||
ASSERT_THAT(v.next(), Eq("other2"));
|
||||
ASSERT_EQ(v.count(), 3);
|
||||
}
|
||||
|
||||
TEST(Tokenizer, move_assignment)
|
||||
{
|
||||
Tokenizer t(" test word ", " ");
|
||||
ASSERT_THAT(t.next(), Eq("test"));
|
||||
ASSERT_THAT(t.next(), Eq("word"));
|
||||
ASSERT_EQ(t.count(), 2);
|
||||
t = Tokenizer("test new word ", " ");
|
||||
ASSERT_THAT(t.next(), Eq("test"));
|
||||
ASSERT_THAT(t.next(), Eq("new"));
|
||||
ASSERT_THAT(t.next(), Eq("word"));
|
||||
ASSERT_EQ(t.count(), 3);
|
||||
}
|
||||
|
||||
TEST(Tokenizer, no_separator_path)
|
||||
{
|
||||
Tokenizer t("one", ":");
|
||||
@ -223,6 +255,38 @@ TEST(ValueTokenizer, move_constructor)
|
||||
ASSERT_EQ(u.count(), 3);
|
||||
}
|
||||
|
||||
TEST(ValueTokenizer, copy_assignment)
|
||||
{
|
||||
ValueTokenizer t(" test word ", " ");
|
||||
ValueTokenizer u(" test2 word2 other2 ", " ");
|
||||
ASSERT_THAT(t.next_string(), Eq("test"));
|
||||
ASSERT_THAT(t.next_string(), Eq("word"));
|
||||
ASSERT_EQ(t.count(), 2);
|
||||
ValueTokenizer v = u;
|
||||
u = t;
|
||||
ASSERT_THAT(u.next_string(), Eq("test"));
|
||||
ASSERT_THAT(u.next_string(), Eq("word"));
|
||||
ASSERT_EQ(u.count(), 2);
|
||||
|
||||
ASSERT_THAT(v.next_string(), Eq("test2"));
|
||||
ASSERT_THAT(v.next_string(), Eq("word2"));
|
||||
ASSERT_THAT(v.next_string(), Eq("other2"));
|
||||
ASSERT_EQ(v.count(), 3);
|
||||
}
|
||||
|
||||
TEST(ValueTokenizer, move_assignment)
|
||||
{
|
||||
ValueTokenizer t(" test word ", " ");
|
||||
ASSERT_THAT(t.next_string(), Eq("test"));
|
||||
ASSERT_THAT(t.next_string(), Eq("word"));
|
||||
ASSERT_EQ(t.count(), 2);
|
||||
t = ValueTokenizer("test new word ", " ");
|
||||
ASSERT_THAT(t.next_string(), Eq("test"));
|
||||
ASSERT_THAT(t.next_string(), Eq("new"));
|
||||
ASSERT_THAT(t.next_string(), Eq("word"));
|
||||
ASSERT_EQ(t.count(), 3);
|
||||
}
|
||||
|
||||
TEST(ValueTokenizer, bad_integer)
|
||||
{
|
||||
ValueTokenizer values("f10 f11 f12");
|
||||
|
||||
Reference in New Issue
Block a user