/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
#ifndef MEMORYSEGMENTUTILS_H
#define MEMORYSEGMENTUTILS_H
#include <libboundscheck/include/securec.h>
#include <cstdint>
#include <cstring>
#include <stdexcept>
#include <iostream>

class MemorySegmentUtils {
public:
    static const int ADDRESS_BITS_PER_WORD = 3;
    static const int BIT_BYTE_INDEX_MASK = 7;

    static inline uint8_t *getAll(uint8_t *offHeapBuffer)
    {
        return offHeapBuffer;
    }

    static inline uint8_t get(uint8_t *offHeapBuffer, int size, int index)
    {
        if (index >= 0 && index < size) {
            return *(offHeapBuffer + index);
        } else {
            std::cerr << "Index: " << index << " size: " << size << std::endl;
            throw std::logic_error("IndexOutOfBoundsException");
        }
    }

    static inline void put(uint8_t *offHeapBuffer, int size, int index, uint8_t byte)
    {
        if (index >= 0 && index < size) {
            *(offHeapBuffer + index) = byte;
        } else {
            std::cerr << "Index: " << index << " size: " << size << std::endl;
            throw std::logic_error("IndexOutOfBoundsException");
        }
    }

    static inline void put(uint8_t *offHeapBuffer, int size, int index, const uint8_t *src, int offset, int length)
    {
        if (index >= 0 && index <= size - length) {
            void *pos = static_cast<void *>(offHeapBuffer + index);
            memcpy_s(pos, length, src + offset, length);
        } else {
            std::cerr << "Index: " << index << " size: " << size << std::endl;
            throw std::out_of_range("Index out of bound");
        }
    }

    static inline int getSize(int size)
    {
        return size;
    }

    static inline void get(uint8_t *offHeapBuffer, int size, int index, uint8_t *dst, int offset, int length)
    {
        if (index >= 0 && index <= size - length) {
            void *srcPos = static_cast<void *>(offHeapBuffer + index);
            void *dstPos = static_cast<void *>(dst + offset);
            memcpy_s(dstPos, length, srcPos, length);
        } else {
            std::cerr << "Index: " << index << " size: " << size << std::endl;
            throw std::out_of_range("Index out of bound");
        }
    }

    static inline int size(int size)
    {
        return size;
    }

    static inline long *getLong(uint8_t *offHeapBuffer, int size, int index)
    {
        if (index >= 0 && index <= size - static_cast<int>(sizeof(long))) {
            return reinterpret_cast<long *>(offHeapBuffer + index);
        } else {
            std::cerr << "Index: " << index << " size: " << size << std::endl;
            throw std::logic_error("IndexOutOfBoundsException");
        }
    }

    static inline void putLong(uint8_t *offHeapBuffer, int size, int index, long value)
    {
        if (index >= 0 && index <= size - static_cast<int>(sizeof(long))) {
            memcpy_s(offHeapBuffer + index, sizeof(long), &value, sizeof(long));
        } else {
            std::cerr << "Index: " << index << " size: " << size << std::endl;
            throw std::logic_error("IndexOutOfBoundsException");
        }
    }

    static inline bool *getBool(uint8_t *offHeapBuffer, int size, int index)
    {
        if (index >= 0 && index <= size - static_cast<int>(sizeof(bool))) {
            return reinterpret_cast<bool *>(offHeapBuffer + index);
        } else {
            std::cerr << "Index: " << index << " size: " << size << std::endl;
            throw std::logic_error("IndexOutOfBoundsException");
        }
    }

    static inline void putBool(uint8_t *offHeapBuffer, int size, int index, bool value)
    {
        if (index >= 0 && index <= size - static_cast<int>(sizeof(bool))) {
            memcpy_s(offHeapBuffer + index, sizeof(bool), &value, sizeof(bool));
        } else {
            std::cerr << "Index: " << index << " size: " << size << std::endl;
            throw std::logic_error("IndexOutOfBoundsException");
        }
    }

    static inline int *getInt(uint8_t *offHeapBuffer, int size, int index)
    {
        if (index >= 0 && index <= size - static_cast<int>(sizeof(int))) {
            return reinterpret_cast<int *>(offHeapBuffer + index);
        } else {
            std::cerr << "Index: " << index << " size: " << size << std::endl;
            throw std::logic_error("IndexOutOfBoundsException");
        }
    }

    static inline void putInt(uint8_t *offHeapBuffer, int size, int index, int value)
    {
        if (index >= 0 && index <= size - static_cast<int>(sizeof(int))) {
            memcpy_s(offHeapBuffer + index, sizeof(int), &value, sizeof(int));
        } else {
            std::cerr << "Index: " << index << " size: " << size << std::endl;
            throw std::logic_error("IndexOutOfBoundsException");
        }
    }

    static inline bool equalTo(uint8_t *offHeapBuffer1, uint8_t *offHeapBuffer2, int offset1, int offset2, int length)
    {
        return (std::memcmp(offHeapBuffer1 + offset1, offHeapBuffer2 + offset2, length) == 0);
    }

    static inline int byteIndex(int bitIndex)
    {
        unsigned int ubitIndex = static_cast<unsigned int>(bitIndex);
        return static_cast<int>(ubitIndex >> ADDRESS_BITS_PER_WORD);
    }

    static inline void bitUnSet(uint8_t *offHeapBuffer, int size, int baseOffset, int index)
    {
        int offset = baseOffset + byteIndex(index);
        uint8_t current = get(offHeapBuffer, size, offset);
        unsigned int uindex = static_cast<unsigned int>(index);
        current &= ~(1 << (uindex & BIT_BYTE_INDEX_MASK));
        put(offHeapBuffer, size, offset, current);
    }

    static inline void bitSet(uint8_t *offHeapBuffer, int size, int baseOffset, int index)
    {
        int offset = baseOffset + byteIndex(index);
        uint8_t current = get(offHeapBuffer, size, offset);
        unsigned int uindex = static_cast<unsigned int>(index);
        current |= (1 << (uindex & BIT_BYTE_INDEX_MASK));
        put(offHeapBuffer, size, offset, current);
    }
    
    static inline void copy(uint8_t *source, int source_offset, uint8_t * dest, int dest_offset, int copy_len)
    {
        memcpy_s(dest + dest_offset, copy_len, source + source_offset, copy_len);
    }
};

#endif // MEMORYSEGMENTUTILS_H