RyanHub – file viewer
filename: src/utils/collection/PalettedStorage.cpp
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
 *
 */

#include "PalettedStorage.h"

#include "utils/Validate.h"

#include <stdexcept>

namespace stratos {
PackedIntegerArray::PackedIntegerArray(const int bitsPerEntry, const int size) : PackedIntegerArray(bitsPerEntry, size, std::vector<int64_t>(0)) {}
PackedIntegerArray::PackedIntegerArray(const int bitsPerEntry, const int size, std::vector<int64_t>&& data) : bitsPerEntry(bitsPerEntry), size(size), elementsPerLong(64 / bitsPerEntry), maxValue((1LL << bitsPerEntry) - 1LL) {
    if (data.empty()) { // No data provided, initialize with zeros
        data.resize((size + elementsPerLong - 1) / elementsPerLong, 0LL);
    } else if (const int length = (size + elementsPerLong - 1) / elementsPerLong; data.size() != length) { // Check if the length matches the expected size
        throw std::invalid_argument("Invalid length given for palette data, expected " + std::to_string(length) + " but got " + std::to_string(data.size()));
    }
    this->data = std::move(data);
}
PackedIntegerArray::PackedIntegerArray(const int bitsPerEntry, const int size, const std::vector<int64_t>& data) : PackedIntegerArray(bitsPerEntry, size, std::vector(data)) {}
PackedIntegerArray::PackedIntegerArray(const int bitsPerEntry, const int size, const std::vector<int>& data) : PackedIntegerArray(bitsPerEntry, size) {
    int j;
    int i = 0;
    for (j = 0; j <= size - elementsPerLong; j += elementsPerLong) {
        int64_t value = 0;
        for (int k = elementsPerLong - 1; k >= 0; k--) {
            value <<= bitsPerEntry;
            value |= static_cast<int64_t>(data[j + k]) & maxValue;
        }
        this->data[i++] = value;
    }
    int l = size - j;
    if (l > 0) {
        int64_t value = 0;
        for (int k = l - 1; k >= 0; --k) {
            value <<= bitsPerEntry;
            value |= static_cast<int64_t>(data[j + k]) & maxValue;
        }
        this->data[i] = value;
    }
}
int PackedIntegerArray::getBitsPerEntry() const {
    return bitsPerEntry;
}
int PackedIntegerArray::getSize() const {
    return size;
}
int PackedIntegerArray::getMaxValue() const {
    return maxValue;
}
const std::vector<int64_t>& PackedIntegerArray::getData() const {
    return data;
}
int PackedIntegerArray::get(const int index) const {
    inclusiveBetween(0LL, size - 1LL, index);
    const int i = index / elementsPerLong;
    return data[i] >> ((index - i * elementsPerLong) * bitsPerEntry) & maxValue;
}
void PackedIntegerArray::set(const int index, const int value) {
    inclusiveBetween(0LL, size - 1LL, index);
    inclusiveBetween(0LL, maxValue, value);
    const int i = index / elementsPerLong;
    const int j = (index - i * elementsPerLong) * bitsPerEntry;
    data[i] = data[i] & (maxValue << j ^ 0xFFFFFFFFFFFFFFFFLL) | (static_cast<int64_t>(value) & maxValue) << j;
}
int PackedIntegerArray::swap(const int index, const int value) {
    inclusiveBetween(0LL, size - 1LL, index);
    inclusiveBetween(0LL, maxValue, value);
    const int     i       = index / elementsPerLong;
    const int64_t oldLong = data[i];
    const int     j       = (index - i * elementsPerLong) * bitsPerEntry;
    data[i]               = oldLong & (maxValue << j ^ 0xFFFFFFFFFFFFFFFFLL) | (static_cast<int64_t>(value) & maxValue) << j;
    return oldLong >> j & maxValue;
}
void PackedIntegerArray::writeIndices(std::vector<int>& data) const {
    data.resize(size);
    int64_t   value;
    const int elements = this->data.size();
    int       j        = 0;
    int       k;
    int       l;
    for (k = 0; k < elements - 1; ++k) {
        value = this->data[k];
        for (l = 0; l < elementsPerLong; ++l) {
            data[j + l] = static_cast<int>(value & maxValue);
            value >>= bitsPerEntry;
        }
        j += elementsPerLong;
    }
    k = size - j;
    if (k > 0) {
        value = this->data[elements - 1];
        for (l = 0; l < k; ++l) {
            data[j + l] = static_cast<int>(value & maxValue);
            value >>= bitsPerEntry;
        }
    }
}
std::vector<int64_t>& PackedIntegerArray::getData() {
    return data;
}
} // namespace stratos