/*
 * 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.
 */

#include "paimon/memory/memory_segment.h"

#include <algorithm>

#include "paimon/common/utils/math.h"

namespace paimon {

uint64_t MemorySegment::GetLongBigEndian(int32_t index) const {
    auto value = GetValue<uint64_t>(index);
    if constexpr (SystemByteOrder() == ByteOrder::PAIMON_LITTLE_ENDIAN) {
        return EndianSwapValue(value);
    }
    return value;
}

int32_t MemorySegment::Compare(const MemorySegment& seg2, int32_t offset1, int32_t offset2,
                               int32_t len) const {
    while (len >= 8) {
        uint64_t l1 = GetLongBigEndian(offset1);
        uint64_t l2 = seg2.GetLongBigEndian(offset2);

        if (l1 != l2) {
            return (l1 < l2) ? -1 : 1;
        }

        offset1 += 8;
        offset2 += 8;
        len -= 8;
    }
    while (len > 0) {
        int32_t b1 = Get(offset1) & 0xff;
        int32_t b2 = seg2.Get(offset2) & 0xff;
        int32_t cmp = b1 - b2;
        if (cmp != 0) {
            return cmp;
        }
        offset1++;
        offset2++;
        len--;
    }
    return 0;
}

int32_t MemorySegment::Compare(const MemorySegment& seg2, int32_t offset1, int32_t offset2,
                               int32_t len1, int32_t len2) const {
    const int32_t min_length = std::min(len1, len2);
    int32_t c = Compare(seg2, offset1, offset2, min_length);
    return c == 0 ? (len1 - len2) : c;
}

bool MemorySegment::EqualTo(const MemorySegment& seg2, int32_t offset1, int32_t offset2,
                            int32_t length) const {
    int32_t i = 0;
    // we assume unaligned accesses are supported.
    // Compare 8 bytes at a time.
    while (i <= length - 8) {
        if (GetValue<int64_t>(offset1 + i) != seg2.GetValue<int64_t>(offset2 + i)) {
            return false;
        }
        i += 8;
    }

    // cover the last (length % 8) elements.
    while (i < length) {
        if (Get(offset1 + i) != seg2.Get(offset2 + i)) {
            return false;
        }
        i += 1;
    }

    return true;
}

}  // namespace paimon
