RyanHub – file viewer
filename: src/nbt/ArrayTag.h
branch: feature/world
back to repo
/*
 *
 *               _____  _                 _
 *              /  ___|| |               | |
 *              \ `--. | |_  _ __   __ _ | |_   ___   ___
 *               `--. \| __|| '__| / _` || __| / _ \ / __|
 *              /\__/ /| |_ | |   | (_| || |_ | (_) |\__ \
 *              \____/  \__||_|    \__,_| \__| \___/ |___/
 *
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Copyright (C) 2025 Armen Deroian
 *
 */

#ifndef ARRAYTAG_H
#define ARRAYTAG_H
#include "io/NBTBuffer.h"
#include "Tag.h"

#include <vector>

namespace stratos::nbt {
namespace internal {
template<class T> struct getArrayType { static_assert(sizeof(T) != sizeof(T), "Invalid type parameter for tag_array, can only use byte or int"); };
template<> struct getArrayType<int8_t>  : std::integral_constant<TagType, TagType::ByteArray> {};
template<> struct getArrayType<int32_t> : std::integral_constant<TagType, TagType::IntArray> {};
template<> struct getArrayType<int64_t> : std::integral_constant<TagType, TagType::LongArray> {};
} // namespace stratos::nbt::internal

template <class T> class ArrayTag final : public CRTPTag<ArrayTag<T>> {
  public:
    typedef typename std::vector<T>::iterator       iterator;
    typedef typename std::vector<T>::const_iterator constIterator;

    typedef T                ValueType;
    static constexpr TagType type = internal::getArrayType<T>::value;

    ArrayTag() = default;
    ArrayTag(std::initializer_list<T> init) : data(init) {}
    explicit ArrayTag(std::vector<T>&& vec) noexcept : data(std::move(vec)) {}

    std::vector<T>&       get() { return data; }
    const std::vector<T>& get() const { return data; }

    T& at(size_t i) { return data.at(i); }
    T  at(size_t i) const { return data.at(i); }

    T& operator[](size_t i) { return data[i]; }
    T  operator[](size_t i) const { return data[i]; }

    void   push_back(T val) { data.push_back(val); }
    void   pop_back() { data.pop_back(); }
    [[nodiscard]] size_t size() const { return data.size(); }
    void   clear() { data.clear(); }

    iterator      begin() { return data.begin(); }
    iterator      end() { return data.end(); }
    constIterator begin() const { return data.begin(); }
    constIterator end() const { return data.end(); }
    constIterator cbegin() const { return data.cbegin(); }
    constIterator cend() const { return data.cend(); }

    void read(NBTBuffer& buffer) override;
    void write(NBTBuffer& buffer) const override;

  private:
    std::vector<T> data;
};
template <class T> void ArrayTag<T>::read(NBTBuffer& buffer) {
    clear();
    int size = buffer.readInt();
    data.reserve(size);
    switch (type) {
    case TagType::ByteArray: {
        for (int i = 0; i < size; ++i) {
            data.push_back(buffer.readByte());
        }
        break;
    }
    case TagType::IntArray: {
        for (int i = 0; i < size; ++i) {
            data.push_back(buffer.readInt());
        }
        break;
    }
    case TagType::LongArray: {
        for (int i = 0; i < size; ++i) {
            data.push_back(buffer.readLong());
        }
        break;
    }
    default:
        throw std::runtime_error("Invalid array tag type");
    }
}
template <class T> void ArrayTag<T>::write(NBTBuffer& buffer) const {
    buffer.writeInt(data.size());
    switch (type) {
    case TagType::ByteArray: {
        for (const T& val : data) {
            buffer.writeByte(static_cast<int8_t>(val));
        }
        break;
    }
    case TagType::IntArray: {
        for (const T& val : data) {
            buffer.writeInt(static_cast<int>(val));
        }
        break;
    }
    case TagType::LongArray: {
        for (const T& val : data) {
            buffer.writeLong(static_cast<int64_t>(val));
        }
        break;
    }
    default:
        throw std::runtime_error("Invalid array tag type");
    }
}

template <class T> bool operator==(const ArrayTag<T>& lhs, const ArrayTag<T>& rhs) { return lhs.get() == rhs.get(); }
template<class T> bool operator!=(const ArrayTag<T>& lhs, const ArrayTag<T>& rhs) { return !(lhs == rhs); }

typedef ArrayTag<int8_t> ByteArrayTag;
typedef ArrayTag<int32_t> IntArrayTag;
typedef ArrayTag<int64_t> LongArrayTag;
} // namespace stratos::nbt

#endif //ARRAYTAG_H