RyanHub – file viewer
filename: src/block/state/StateProperty.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 STATEPROPERTY_H
#define STATEPROPERTY_H
#include "utils/Hash.h"

#include <stdexcept>
#include <string>
#include <array>
#include <vector>

namespace stratos::block {

template <typename T> class Property {
  public:
    Property(std::string name, std::string type) : name(std::move(name)), type(std::move(type)) {}
    virtual ~Property() = default;

    [[nodiscard]] std::size_t hashCode() const;
    [[nodiscard]] virtual const std::vector<T>& getValues() const = 0;
  protected:
    [[nodiscard]] virtual std::size_t computeHashCode() const;
  private:
    std::string name;
    std::string type;
    int         hashCodeCache = -1;
};

class IntProperty final : public Property<int> {
public:
    [[nodiscard]] const std::vector<int>& getValues() const override;
    static IntProperty* create(std::string name, int min, int max);
protected:
    [[nodiscard]] std::size_t computeHashCode() const override;
private:
    IntProperty(std::string name, int min, int max);

    int min;
    int max;
    std::vector<int> values;
};

class BooleanProperty final : public Property<bool> {
public:
    [[nodiscard]] const std::vector<bool>& getValues() const override;
    static BooleanProperty* create(std::string name);
protected:
    [[nodiscard]] std::size_t computeHashCode() const override;
private:
    explicit BooleanProperty(std::string name);
    static std::vector<bool> values;
};

template <typename T>
class EnumProperty final : public Property<T> {
public:
    const std::vector<T>& getValues() const override;
    template <typename... Args>
    static EnumProperty* create(std::string name, Args&&... values);
protected:
    [[nodiscard]] std::size_t computeHashCode() const override;
private:
    template <typename... Args>
    explicit EnumProperty(std::string name, Args&&... values);
    std::vector<T> values;
};

template <typename T> std::size_t Property<T>::hashCode() const {
    if (hashCodeCache == -1)
        hashCodeCache = computeHashCode();
    return hashCodeCache;
}
template <typename T> std::size_t Property<T>::computeHashCode() const {
    return std::hash<std::string>()(name) ^ std::hash<std::string>()(type) << 1;
}
template <typename T> const std::vector<T>& EnumProperty<T>::getValues() const {
    return values;
}
template <typename T> template <typename... Args> EnumProperty<T>* EnumProperty<T>::create(std::string name, Args&&... values) {
    static_assert((std::is_convertible_v<Args, T> && ...), "All arguments must be convertible to T");
    if constexpr (sizeof...(values) == 0) throw std::invalid_argument("EnumProperty must have at least one value.");
    return new EnumProperty(std::move(name), std::forward<Args>(values)...);
}
template <typename T> std::size_t EnumProperty<T>::computeHashCode() const {
    return Property<T>::computeHashCode() ^ utils::hash(values) << 1;
}
template <typename T> template <typename... Args> EnumProperty<T>::EnumProperty(std::string name, Args&&... values) : Property<T>(std::move(name), typeid(T).name()), values(std::forward<Args>(values)...) {}
} // namespace stratos::block

#endif //STATEPROPERTY_H