/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * License); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
#ifndef COMMON_CONTAINER_BYTE_BUFFER_H
#define COMMON_CONTAINER_BYTE_BUFFER_H

#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "common/allocator/alloc_base.h"
#include "common/global.h"
#include "utils/util_define.h"

namespace common {
class ByteBuffer {
   public:
    ByteBuffer()
        : data_(nullptr),
          variable_type_len_(sizeof(uint32_t)),
          real_data_size_(0),
          reserved_size_(0) {}

    ~ByteBuffer() {
        if (data_ && (reserved_size_ > 0)) {
            mem_free(data_);
            data_ = nullptr;
            real_data_size_ = 0;
            reserved_size_ = 0;
        }
    }

    FORCE_INLINE void init(uint32_t size) {
        data_ = static_cast<char*>(mem_alloc(size, MOD_TSBLOCK));
        reserved_size_ = size;
    }

    FORCE_INLINE void reset() { real_data_size_ = 0; }

    FORCE_INLINE int extend_memory(uint32_t new_size) {
        ASSERT(new_size > reserved_size_);
        char* new_data = static_cast<char*>(mem_realloc(data_, new_size));
        if (UNLIKELY(new_data == nullptr)) {
            return E_OOM;
        }
        data_ = new_data;
        reserved_size_ = new_size;
        return E_OK;
    }

    FORCE_INLINE int append_variable_value(const char* value, uint32_t len) {
        // dynamic growth
        if (UNLIKELY((real_data_size_ + len + variable_type_len_) >
                     reserved_size_)) {
            // extreme scenarios, when encountering very long string
            uint32_t growth_size =
                g_config_value_.tsblock_mem_inc_step_size_ > len
                    ? g_config_value_.tsblock_mem_inc_step_size_
                    : (len + 1);
            if (UNLIKELY(extend_memory(reserved_size_ + growth_size) != E_OK)) {
                return E_OOM;
            }
        }

        ASSERT(data_);
        // append len
        memcpy(&data_[real_data_size_], reinterpret_cast<char*>(&len),
               variable_type_len_);
        real_data_size_ += variable_type_len_;
        if (len > 0) {
            // append data
            memcpy(&data_[real_data_size_], value, len);
            real_data_size_ += len;
        }
        return E_OK;
    }

    FORCE_INLINE int append_fixed_value(const char* value, uint32_t len) {
        // dynamic growth
        if (UNLIKELY(real_data_size_ + len > reserved_size_)) {
            // extreme scenarios, when encountering very long string
            uint32_t growth_size =
                g_config_value_.tsblock_mem_inc_step_size_ > len
                    ? g_config_value_.tsblock_mem_inc_step_size_
                    : (len + 1);
            if (UNLIKELY(extend_memory(reserved_size_ + growth_size) != E_OK)) {
                return E_OOM;
            }
        }

        ASSERT(data_);
        memcpy(&data_[real_data_size_], value, len);
        real_data_size_ += len;
        return E_OK;
    }

    // for fixed len value
    FORCE_INLINE char* read(uint32_t offset, uint32_t len) {
        ASSERT((offset + len) <= real_data_size_);
        char* p = &data_[offset];
        return p;
    }

    // for variable len value
    FORCE_INLINE char* read(uint32_t offset, uint32_t* len) {
        ASSERT(offset + variable_type_len_ <= real_data_size_);
        uint32_t tmp;
        std::memcpy(&tmp, data_ + offset, sizeof(tmp));
        *len = tmp;
        ASSERT(offset + variable_type_len_ + *len <= real_data_size_);
        char* p = &data_[offset + variable_type_len_];
        return p;
    }

    FORCE_INLINE char* get_data() { return data_; }

    FORCE_INLINE uint32_t get_data_size() const { return real_data_size_; }

   private:
    char* data_;
    uint8_t variable_type_len_;
    uint32_t real_data_size_;
    uint32_t reserved_size_;  // malloc memory size from system
};

}  // namespace common
#endif  // COMMON_CONTAINER_BYTE_BUFFER_H
