diff options
| author | ljfa-ag <ljfa-ag@web.de> | 2015-08-09 19:33:39 +0200 |
|---|---|---|
| committer | ljfa-ag <ljfa-ag@web.de> | 2015-08-09 19:33:39 +0200 |
| commit | 12374391af5b876094b802408e9b0e92429ae3c1 (patch) | |
| tree | d42489e01384a77a5e6815244e2da43c05c0f6d0 | |
| parent | b992d074054dc03b548e6b8a169cff5e1788ea73 (diff) | |
| download | Project-Tick-12374391af5b876094b802408e9b0e92429ae3c1.tar.gz Project-Tick-12374391af5b876094b802408e9b0e92429ae3c1.zip | |
Implement Visitor design pattern for tag
| -rw-r--r-- | include/crtp_tag.h | 9 | ||||
| -rw-r--r-- | include/tag.h | 9 | ||||
| -rw-r--r-- | include/tag_visitor.h | 55 | ||||
| -rw-r--r-- | test/nbttest.cpp | 46 |
4 files changed, 118 insertions, 1 deletions
diff --git a/include/crtp_tag.h b/include/crtp_tag.h index 25f87bf6e8..86f070e147 100644 --- a/include/crtp_tag.h +++ b/include/crtp_tag.h @@ -21,6 +21,7 @@ #define CRTP_TAG_H_INCLUDED #include "tag.h" +#include "tag_visitor.h" #include "make_unique.h" namespace nbt @@ -43,6 +44,8 @@ namespace detail tag& assign(tag&& rhs) override final; + void accept(tag_visitor& visitor); + private: bool equals(const tag& rhs) const override final; }; @@ -75,6 +78,12 @@ namespace detail } template<class Sub> + void crtp_tag<Sub>::accept(tag_visitor& visitor) + { + visitor.visit(static_cast<Sub&>(*this)); + } + + template<class Sub> bool crtp_tag<Sub>::equals(const tag& rhs) const { return static_cast<const Sub&>(*this) == static_cast<const Sub&>(rhs); diff --git a/include/tag.h b/include/tag.h index 569da446d6..f3e9696a53 100644 --- a/include/tag.h +++ b/include/tag.h @@ -51,7 +51,8 @@ enum class tag_type : int8_t */ bool is_valid_type(int type, bool allow_end = false); -//Forward declaration +//Forward declarations +class tag_visitor; namespace io { class stream_reader; } @@ -86,6 +87,12 @@ public: virtual tag& assign(tag&& rhs) = 0; /** + * @brief Calls the appropriate overload of @c visit() on the visitor with + * @c *this as argument + */ + virtual void accept(tag_visitor& visitor) = 0; + + /** * @brief Reads the tag's payload from the stream * @throw io::stream_reader::input_error on failure */ diff --git a/include/tag_visitor.h b/include/tag_visitor.h new file mode 100644 index 0000000000..bc5113918c --- /dev/null +++ b/include/tag_visitor.h @@ -0,0 +1,55 @@ +/* + * libnbt++ - A library for the Minecraft Named Binary Tag format. + * Copyright (C) 2013, 2015 ljfa-ag + * + * This file is part of libnbt++. + * + * libnbt++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libnbt++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libnbt++. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef TAG_VISITOR_H_INCLUDED +#define TAG_VISITOR_H_INCLUDED + +#include "tagfwd.h" + +namespace nbt +{ + +/** + * @brief Base class for visitors of tags + * + * Implementing the Visitor pattern + */ +class tag_visitor +{ +public: + virtual ~tag_visitor() noexcept = 0; //Abstract class + + virtual void visit(tag_byte& tag) {} + virtual void visit(tag_short& tag) {} + virtual void visit(tag_int& tag) {} + virtual void visit(tag_long& tag) {} + virtual void visit(tag_float& tag) {} + virtual void visit(tag_double& tag) {} + virtual void visit(tag_byte_array& tag) {} + virtual void visit(tag_string& tag) {} + virtual void visit(tag_list& tag) {} + virtual void visit(tag_compound& tag) {} + virtual void visit(tag_int_array& tag) {} +}; + +inline tag_visitor::~tag_visitor() noexcept {} + +} + +#endif // TAG_VISITOR_H_INCLUDED diff --git a/test/nbttest.cpp b/test/nbttest.cpp index b041d44aa8..4c46668f0b 100644 --- a/test/nbttest.cpp +++ b/test/nbttest.cpp @@ -19,6 +19,7 @@ */ #include "microtest.h" #include "nbt_tags.h" +#include "tag_visitor.h" #include <algorithm> #include <stdexcept> @@ -425,6 +426,50 @@ void test_tag_int_array() std::clog << "test_tag_int_array passed" << std::endl; } +void test_visitor() +{ + struct : public tag_visitor + { + tag_type visited = tag_type::Null; + + void visit(tag_byte& tag) override { visited = tag_type::Byte; } + void visit(tag_short& tag) override { visited = tag_type::Short; } + void visit(tag_int& tag) override { visited = tag_type::Int; } + void visit(tag_long& tag) override { visited = tag_type::Long; } + void visit(tag_float& tag) override { visited = tag_type::Float; } + void visit(tag_double& tag) override { visited = tag_type::Double; } + void visit(tag_byte_array& tag) override { visited = tag_type::Byte_Array; } + void visit(tag_string& tag) override { visited = tag_type::String; } + void visit(tag_list& tag) override { visited = tag_type::List; } + void visit(tag_compound& tag) override { visited = tag_type::Compound; } + void visit(tag_int_array& tag) override { visited = tag_type::Int_Array; } + } v; + + tag_byte().accept(v); + ASSERT(v.visited == tag_type::Byte); + tag_short().accept(v); + ASSERT(v.visited == tag_type::Short); + tag_int().accept(v); + ASSERT(v.visited == tag_type::Int); + tag_long().accept(v); + ASSERT(v.visited == tag_type::Long); + tag_float().accept(v); + ASSERT(v.visited == tag_type::Float); + tag_double().accept(v); + ASSERT(v.visited == tag_type::Double); + tag_byte_array().accept(v); + ASSERT(v.visited == tag_type::Byte_Array); + tag_string().accept(v); + ASSERT(v.visited == tag_type::String); + tag_list().accept(v); + ASSERT(v.visited == tag_type::List); + tag_compound().accept(v); + ASSERT(v.visited == tag_type::Compound); + tag_int_array().accept(v); + ASSERT(v.visited == tag_type::Int_Array); + std::clog << "test_visitor passed" << std::endl; +} + int main() { test_tag(); @@ -436,4 +481,5 @@ int main() test_tag_list(); test_tag_byte_array(); test_tag_int_array(); + test_visitor(); } |
