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

use crate::{ArrayData, ByteView};

pub(super) fn byte_view_equal(
    lhs: &ArrayData,
    rhs: &ArrayData,
    lhs_start: usize,
    rhs_start: usize,
    len: usize,
) -> bool {
    let lhs_views = &lhs.buffer::<u128>(0)[lhs_start..lhs_start + len];
    let lhs_buffers = &lhs.buffers()[1..];
    let rhs_views = &rhs.buffer::<u128>(0)[rhs_start..rhs_start + len];
    let rhs_buffers = &rhs.buffers()[1..];

    for (idx, (l, r)) in lhs_views.iter().zip(rhs_views).enumerate() {
        // Only checking one null mask here because by the time the control flow reaches
        // this point, the equality of the two masks would have already been verified.
        if lhs.is_null(idx) {
            continue;
        }

        let l_len_prefix = *l as u64;
        let r_len_prefix = *r as u64;
        // short-circuit, check length and prefix
        if l_len_prefix != r_len_prefix {
            return false;
        }

        let len = l_len_prefix as u32;
        // for inline storage, only need check view
        if len <= 12 {
            if l != r {
                return false;
            }
            continue;
        }

        // check buffers
        let l_view = ByteView::from(*l);
        let r_view = ByteView::from(*r);

        let l_buffer = &lhs_buffers[l_view.buffer_index as usize];
        let r_buffer = &rhs_buffers[r_view.buffer_index as usize];

        // prefixes are already known to be equal; skip checking them
        let len = len as usize - 4;
        let l_offset = l_view.offset as usize + 4;
        let r_offset = r_view.offset as usize + 4;
        if l_buffer[l_offset..l_offset + len] != r_buffer[r_offset..r_offset + len] {
            return false;
        }
    }
    true
}
