summaryrefslogtreecommitdiffstats
path: root/depends/libnbtplusplus/include/tag_list.h
diff options
context:
space:
mode:
Diffstat (limited to 'depends/libnbtplusplus/include/tag_list.h')
-rw-r--r--depends/libnbtplusplus/include/tag_list.h224
1 files changed, 224 insertions, 0 deletions
diff --git a/depends/libnbtplusplus/include/tag_list.h b/depends/libnbtplusplus/include/tag_list.h
new file mode 100644
index 00000000..5b0ba873
--- /dev/null
+++ b/depends/libnbtplusplus/include/tag_list.h
@@ -0,0 +1,224 @@
+/*
+ * 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_LIST_H_INCLUDED
+#define TAG_LIST_H_INCLUDED
+
+#include "crtp_tag.h"
+#include "tagfwd.h"
+#include "value_initializer.h"
+#include <stdexcept>
+#include <vector>
+
+#include "nbt++_export.h"
+
+namespace nbt
+{
+
+/**
+ * @brief Tag that contains multiple unnamed tags of the same type
+ *
+ * All the tags contained in the list have the same type, which can be queried
+ * with el_type(). The types of the values contained in the list should not
+ * be changed to mismatch the element type.
+ *
+ * If the list is empty, the type can be undetermined, in which case el_type()
+ * will return tag_type::Null. The type will then be set when the first tag
+ * is added to the list.
+ */
+class NBT___EXPORT tag_list final : public detail::crtp_tag<tag_list>
+{
+public:
+ //Iterator types
+ typedef std::vector<value>::iterator iterator;
+ typedef std::vector<value>::const_iterator const_iterator;
+
+ ///The type of the tag
+ static constexpr tag_type type = tag_type::List;
+
+ /**
+ * @brief Constructs a list of type T with the given values
+ *
+ * Example: @code tag_list::of<tag_byte>({3, 4, 5}) @endcode
+ * @param init list of values from which the elements are constructed
+ */
+ template<class T>
+ static tag_list of(std::initializer_list<T> init);
+
+ /**
+ * @brief Constructs an empty list
+ *
+ * The content type is determined when the first tag is added.
+ */
+ tag_list(): tag_list(tag_type::Null) {}
+
+ ///Constructs an empty list with the given content type
+ explicit tag_list(tag_type type): el_type_(type) {}
+
+ ///Constructs a list with the given contents
+ tag_list(std::initializer_list<int8_t> init);
+ tag_list(std::initializer_list<int16_t> init);
+ tag_list(std::initializer_list<int32_t> init);
+ tag_list(std::initializer_list<int64_t> init);
+ tag_list(std::initializer_list<float> init);
+ tag_list(std::initializer_list<double> init);
+ tag_list(std::initializer_list<std::string> init);
+ tag_list(std::initializer_list<tag_byte_array> init);
+ tag_list(std::initializer_list<tag_list> init);
+ tag_list(std::initializer_list<tag_compound> init);
+ tag_list(std::initializer_list<tag_int_array> init);
+
+ /**
+ * @brief Constructs a list with the given contents
+ * @throw std::invalid_argument if the tags are not all of the same type
+ */
+ tag_list(std::initializer_list<value> init);
+
+ /**
+ * @brief Accesses a tag by index with bounds checking
+ *
+ * Returns a value to the tag at the specified index, or throws an
+ * exception if it is out of range.
+ * @throw std::out_of_range if the index is out of range
+ */
+ value& at(size_t i);
+ const value& at(size_t i) const;
+
+ /**
+ * @brief Accesses a tag by index
+ *
+ * Returns a value to the tag at the specified index. No bounds checking
+ * is performed.
+ */
+ value& operator[](size_t i) { return tags[i]; }
+ const value& operator[](size_t i) const { return tags[i]; }
+
+ /**
+ * @brief Assigns a value at the given index
+ * @throw std::invalid_argument if the type of the value does not match the list's
+ * content type
+ * @throw std::out_of_range if the index is out of range
+ */
+ void set(size_t i, value&& val);
+
+ /**
+ * @brief Appends the tag to the end of the list
+ * @throw std::invalid_argument if the type of the tag does not match the list's
+ * content type
+ */
+ void push_back(value_initializer&& val);
+
+ /**
+ * @brief Constructs and appends a tag to the end of the list
+ * @throw std::invalid_argument if the type of the tag does not match the list's
+ * content type
+ */
+ template<class T, class... Args>
+ void emplace_back(Args&&... args);
+
+ ///Removes the last element of the list
+ void pop_back() { tags.pop_back(); }
+
+ ///Returns the content type of the list, or tag_type::Null if undetermined
+ tag_type el_type() const { return el_type_; }
+
+ ///Returns the number of tags in the list
+ size_t size() const { return tags.size(); }
+
+ ///Erases all tags from the list. Preserves the content type.
+ void clear() { tags.clear(); }
+
+ /**
+ * @brief Erases all tags from the list and changes the content type.
+ * @param type the new content type. Can be tag_type::Null to leave it undetermined.
+ */
+ void reset(tag_type type = tag_type::Null);
+
+ //Iterators
+ iterator begin() { return tags.begin(); }
+ iterator end() { return tags.end(); }
+ const_iterator begin() const { return tags.begin(); }
+ const_iterator end() const { return tags.end(); }
+ const_iterator cbegin() const { return tags.cbegin(); }
+ const_iterator cend() const { return tags.cend(); }
+
+ /**
+ * @inheritdoc
+ * In case of a list of tag_end, the content type will be undetermined.
+ */
+ void read_payload(io::stream_reader& reader) override;
+ /**
+ * @inheritdoc
+ * In case of a list of undetermined content type, the written type will be tag_end.
+ * @throw std::length_error if the list is too long for NBT
+ */
+ void write_payload(io::stream_writer& writer) const override;
+
+ /**
+ * @brief Equality comparison for lists
+ *
+ * Lists are considered equal if their content types and the contained tags
+ * are equal.
+ */
+ NBT___EXPORT friend bool operator==(const tag_list& lhs, const tag_list& rhs);
+ NBT___EXPORT friend bool operator!=(const tag_list& lhs, const tag_list& rhs);
+
+private:
+ std::vector<value> tags;
+ tag_type el_type_;
+
+ /**
+ * Internally used initialization function that initializes the list with
+ * tags of type T, with the constructor arguments of each T given by il.
+ * @param il list of values that are, one by one, given to a constructor of T
+ */
+ template<class T, class Arg>
+ void init(std::initializer_list<Arg> il);
+};
+
+template<class T>
+tag_list tag_list::of(std::initializer_list<T> il)
+{
+ tag_list result;
+ result.init<T, T>(il);
+ return result;
+}
+
+template<class T, class... Args>
+void tag_list::emplace_back(Args&&... args)
+{
+ if(el_type_ == tag_type::Null) //set content type if undetermined
+ el_type_ = T::type;
+ else if(el_type_ != T::type)
+ throw std::invalid_argument("The tag type does not match the list's content type");
+ tags.emplace_back(make_unique<T>(std::forward<Args>(args)...));
+}
+
+template<class T, class Arg>
+void tag_list::init(std::initializer_list<Arg> init)
+{
+ el_type_ = T::type;
+ tags.reserve(init.size());
+ for(const Arg& arg: init)
+ tags.emplace_back(make_unique<T>(arg));
+}
+
+}
+
+#endif // TAG_LIST_H_INCLUDED