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:
Richard Berger
2021-04-26 14:28:13 -04:00
parent 0eee2d013d
commit 462f27d661
3 changed files with 111 additions and 4 deletions

View File

@ -68,6 +68,28 @@ Tokenizer::Tokenizer(Tokenizer && rhs) :
reset(); 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, /*! Re-position the tokenizer state to the first word,
* i.e. the first non-separator character */ * i.e. the first non-separator character */
void Tokenizer::reset() { 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(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 /*! Indicate whether more tokens are available
* *
* \return true if there are more tokens, false if not */ * \return true if there are more tokens, false if not */

View File

@ -37,8 +37,9 @@ public:
Tokenizer(const std::string &str, const std::string &separators = TOKENIZER_DEFAULT_SEPARATORS); Tokenizer(const std::string &str, const std::string &separators = TOKENIZER_DEFAULT_SEPARATORS);
Tokenizer(Tokenizer &&); Tokenizer(Tokenizer &&);
Tokenizer(const Tokenizer &); Tokenizer(const Tokenizer &);
Tokenizer& operator=(const Tokenizer&) = default; Tokenizer& operator=(const Tokenizer&);
Tokenizer& operator=(Tokenizer&&) = default; Tokenizer& operator=(Tokenizer&&);
void swap(Tokenizer &);
void reset(); void reset();
void skip(int n=1); void skip(int n=1);
@ -93,8 +94,9 @@ public:
ValueTokenizer(const std::string &str, const std::string &separators = TOKENIZER_DEFAULT_SEPARATORS); ValueTokenizer(const std::string &str, const std::string &separators = TOKENIZER_DEFAULT_SEPARATORS);
ValueTokenizer(const ValueTokenizer &); ValueTokenizer(const ValueTokenizer &);
ValueTokenizer(ValueTokenizer &&); ValueTokenizer(ValueTokenizer &&);
ValueTokenizer& operator=(const ValueTokenizer&) = default; ValueTokenizer& operator=(const ValueTokenizer&);
ValueTokenizer& operator=(ValueTokenizer&&) = default; ValueTokenizer& operator=(ValueTokenizer&&);
void swap(ValueTokenizer &);
std::string next_string(); std::string next_string();
tagint next_tagint(); tagint next_tagint();

View File

@ -101,6 +101,38 @@ TEST(Tokenizer, move_constructor)
ASSERT_EQ(u.count(), 3); 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) TEST(Tokenizer, no_separator_path)
{ {
Tokenizer t("one", ":"); Tokenizer t("one", ":");
@ -223,6 +255,38 @@ TEST(ValueTokenizer, move_constructor)
ASSERT_EQ(u.count(), 3); 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) TEST(ValueTokenizer, bad_integer)
{ {
ValueTokenizer values("f10 f11 f12"); ValueTokenizer values("f10 f11 f12");