<commit_before>// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;

use VulkanObject;
use device::Device;
use format::FormatTy;
use image::ImageAccess;
use image::ImageDimensions;
use sampler::Filter;

/// Checks whether a blit image command is valid.
///
/// # Panic
///
/// - Panics if the source or the destination was not created with `device`.
///
pub fn check_blit_image<S, D>(device: &Device, source: &S, source_top_left: [i32; 3],
                              source_bottom_right: [i32; 3], source_base_array_layer: u32,
                              source_mip_level: u32, destination: &D, destination_top_left: [i32; 3],
                              destination_bottom_right: [i32; 3], destination_base_array_layer: u32,
                              destination_mip_level: u32, layer_count: u32, filter: Filter)
                           -> Result<(), CheckBlitImageError>
    where S: ?Sized + ImageAccess,
          D: ?Sized + ImageAccess
{
    let source_inner = source.inner();
    let destination_inner = destination.inner();

    assert_eq!(source_inner.image.device().internal_object(),
               device.internal_object());
    assert_eq!(destination_inner.image.device().internal_object(),
               device.internal_object());

    if !source_inner.image.usage_transfer_source() {
        return Err(CheckBlitImageError::MissingTransferSourceUsage);
    }

    if !destination_inner.image.usage_transfer_destination() {
        return Err(CheckBlitImageError::MissingTransferDestinationUsage);
    }

    if source_inner.image.supports_blit_source() {
        return Err(CheckBlitImageError::SourceFormatNotSupported);
    }

    if source_inner.image.supports_blit_destination() {
        return Err(CheckBlitImageError::DestinationFormatNotSupported);
    }

    if source.format().ty().is_depth_and_or_stencil() {
        if source.format() != destination.format() {
            return Err(CheckBlitImageError::DepthStencilFormatMismatch);
        }

        if filter != Filter::Nearest {
            return Err(CheckBlitImageError::DepthStencilNearestMandatory);
        }
    }

    if source.format().ty() == FormatTy::Uint && destination.format().ty() != FormatTy::Uint {
        return Err(CheckBlitImageError::IncompatibleFormatsTypes {
            source_format_ty: source.format().ty(),
            destination_format_ty: destination.format().ty()
        });
    }

    if source.format().ty() == FormatTy::Sint && destination.format().ty() != FormatTy::Sint {
        return Err(CheckBlitImageError::IncompatibleFormatsTypes {
            source_format_ty: source.format().ty(),
            destination_format_ty: destination.format().ty()
        });
    }

    if source_mip_level >= source.mipmap_levels() {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if destination_mip_level >= destination.mipmap_levels() {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    let source_dimensions = source.dimensions();
    let destination_dimensions = destination.dimensions();

    if source_base_array_layer + layer_count >= source_dimensions.array_layers() {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if destination_base_array_layer + layer_count >= destination_dimensions.array_layers() {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    if source_top_left[0] < 0 || source_top_left[0] > source_dimensions.width() as i32 {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if source_top_left[1] < 0 || source_top_left[1] > source_dimensions.height() as i32 {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if source_top_left[2] < 0 || source_top_left[2] > source_dimensions.depth() as i32 {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if source_bottom_right[0] < 0 || source_bottom_right[0] > source_dimensions.width() as i32 {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if source_bottom_right[1] < 0 || source_bottom_right[1] > source_dimensions.height() as i32 {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if source_bottom_right[2] < 0 || source_bottom_right[2] > source_dimensions.depth() as i32 {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if destination_top_left[0] < 0 || destination_top_left[0] > destination_dimensions.width() as i32 {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    if destination_top_left[1] < 0 || destination_top_left[1] > destination_dimensions.height() as i32 {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    if destination_top_left[2] < 0 || destination_top_left[2] > destination_dimensions.depth() as i32 {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    if destination_bottom_right[0] < 0 || destination_bottom_right[0] > destination_dimensions.width() as i32 {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    if destination_bottom_right[1] < 0 || destination_bottom_right[1] > destination_dimensions.height() as i32 {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    if destination_bottom_right[2] < 0 || destination_bottom_right[2] > destination_dimensions.depth() as i32 {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    match source_dimensions {
        ImageDimensions::Dim1d { .. } => {
            if source_top_left[1] != 0 || source_bottom_right[1] != 0 {
                return Err(CheckBlitImageError::IncompatibleRangeForImageType);
            }
            if source_top_left[2] != 0 || source_bottom_right[2] != 0 {
                return Err(CheckBlitImageError::IncompatibleRangeForImageType);
            }
        },
        ImageDimensions::Dim2d { .. } => {
            if source_top_left[2] != 0 || source_bottom_right[2] != 0 {
                return Err(CheckBlitImageError::IncompatibleRangeForImageType);
            }
        },
        ImageDimensions::Dim3d { .. } => {},
    }

    match destination_dimensions {
        ImageDimensions::Dim1d { .. } => {
            if destination_top_left[1] != 0 || destination_bottom_right[1] != 0 {
                return Err(CheckBlitImageError::IncompatibleRangeForImageType);
            }
            if destination_top_left[2] != 0 || destination_bottom_right[2] != 0 {
                return Err(CheckBlitImageError::IncompatibleRangeForImageType);
            }
        },
        ImageDimensions::Dim2d { .. } => {
            if destination_top_left[2] != 0 || destination_bottom_right[2] != 0 {
                return Err(CheckBlitImageError::IncompatibleRangeForImageType);
            }
        },
        ImageDimensions::Dim3d { .. } => {},
    }

    Ok(())
}

/// Error that can happen from `check_clear_color_image`.
#[derive(Debug, Copy, Clone)]
pub enum CheckBlitImageError {
    /// The source is missing the transfer source usage.
    MissingTransferSourceUsage,
    /// The destination is missing the transfer destination usage.
    MissingTransferDestinationUsage,
    /// The format of the source image doesn't support blit operations.
    SourceFormatNotSupported,
    /// The format of the destination image doesn't support blit operations.
    DestinationFormatNotSupported,
    /// You must use the nearest filter when blitting depth/stencil images.
    DepthStencilNearestMandatory,
    /// The format of the source and destination must be equal when blitting depth/stencil images.
    DepthStencilFormatMismatch,
    /// The types of the source format and the destination format aren't compatible.
    IncompatibleFormatsTypes {
        source_format_ty: FormatTy,
        destination_format_ty: FormatTy,
    },
    /// Blitting between multisampled images is forbidden.
    UnexpectedMultisampled,
    /// The offsets, array layers and/or mipmap levels are out of range in the source image.
    SourceCoordinatesOutOfRange,
    /// The offsets, array layers and/or mipmap levels are out of range in the destination image.
    DestinationCoordinatesOutOfRange,
    /// The top-left and/or bottom-right coordinates are incompatible with the image type.
    IncompatibleRangeForImageType,
}

impl error::Error for CheckBlitImageError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            CheckBlitImageError::MissingTransferSourceUsage => {
                "the source is missing the transfer source usage"
            },
            CheckBlitImageError::MissingTransferDestinationUsage => {
                "the destination is missing the transfer destination usage"
            },
            CheckBlitImageError::SourceFormatNotSupported => {
                "the format of the source image doesn't support blit operations"
            },
            CheckBlitImageError::DestinationFormatNotSupported => {
                "the format of the destination image doesn't support blit operations"
            },
            CheckBlitImageError::DepthStencilNearestMandatory => {
                "you must use the nearest filter when blitting depth/stencil images"
            },
            CheckBlitImageError::DepthStencilFormatMismatch => {
                "the format of the source and destination must be equal when blitting \
                 depth/stencil images"
            },
            CheckBlitImageError::IncompatibleFormatsTypes { .. } => {
                "the types of the source format and the destination format aren't compatible"
            },
            CheckBlitImageError::UnexpectedMultisampled => {
                "blitting between multisampled images is forbidden"
            },
            CheckBlitImageError::SourceCoordinatesOutOfRange => {
                "the offsets, array layers and/or mipmap levels are out of range in the source \
                 image"
            },
            CheckBlitImageError::DestinationCoordinatesOutOfRange => {
                "the offsets, array layers and/or mipmap levels are out of range in the \
                 destination image"
            },
            CheckBlitImageError::IncompatibleRangeForImageType => {
                "the top-left and/or bottom-right coordinates are incompatible with the image type"
            },
        }
    }
}

impl fmt::Display for CheckBlitImageError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}
<commit_msg>Fix missing samples check<commit_after>// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;

use VulkanObject;
use device::Device;
use format::FormatTy;
use image::ImageAccess;
use image::ImageDimensions;
use sampler::Filter;

/// Checks whether a blit image command is valid.
///
/// # Panic
///
/// - Panics if the source or the destination was not created with `device`.
///
pub fn check_blit_image<S, D>(device: &Device, source: &S, source_top_left: [i32; 3],
                              source_bottom_right: [i32; 3], source_base_array_layer: u32,
                              source_mip_level: u32, destination: &D, destination_top_left: [i32; 3],
                              destination_bottom_right: [i32; 3], destination_base_array_layer: u32,
                              destination_mip_level: u32, layer_count: u32, filter: Filter)
                           -> Result<(), CheckBlitImageError>
    where S: ?Sized + ImageAccess,
          D: ?Sized + ImageAccess
{
    let source_inner = source.inner();
    let destination_inner = destination.inner();

    assert_eq!(source_inner.image.device().internal_object(),
               device.internal_object());
    assert_eq!(destination_inner.image.device().internal_object(),
               device.internal_object());

    if !source_inner.image.usage_transfer_source() {
        return Err(CheckBlitImageError::MissingTransferSourceUsage);
    }

    if !destination_inner.image.usage_transfer_destination() {
        return Err(CheckBlitImageError::MissingTransferDestinationUsage);
    }

    if source_inner.image.supports_blit_source() {
        return Err(CheckBlitImageError::SourceFormatNotSupported);
    }

    if source_inner.image.supports_blit_destination() {
        return Err(CheckBlitImageError::DestinationFormatNotSupported);
    }

    if source.samples() != 1 || destination.samples() != 1 {
        return Err(CheckBlitImageError::UnexpectedMultisampled);
    }

    if source.format().ty().is_depth_and_or_stencil() {
        if source.format() != destination.format() {
            return Err(CheckBlitImageError::DepthStencilFormatMismatch);
        }

        if filter != Filter::Nearest {
            return Err(CheckBlitImageError::DepthStencilNearestMandatory);
        }
    }

    if source.format().ty() == FormatTy::Uint && destination.format().ty() != FormatTy::Uint {
        return Err(CheckBlitImageError::IncompatibleFormatsTypes {
            source_format_ty: source.format().ty(),
            destination_format_ty: destination.format().ty()
        });
    }

    if source.format().ty() == FormatTy::Sint && destination.format().ty() != FormatTy::Sint {
        return Err(CheckBlitImageError::IncompatibleFormatsTypes {
            source_format_ty: source.format().ty(),
            destination_format_ty: destination.format().ty()
        });
    }

    if source_mip_level >= source.mipmap_levels() {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if destination_mip_level >= destination.mipmap_levels() {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    let source_dimensions = source.dimensions();
    let destination_dimensions = destination.dimensions();

    if source_base_array_layer + layer_count >= source_dimensions.array_layers() {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if destination_base_array_layer + layer_count >= destination_dimensions.array_layers() {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    if source_top_left[0] < 0 || source_top_left[0] > source_dimensions.width() as i32 {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if source_top_left[1] < 0 || source_top_left[1] > source_dimensions.height() as i32 {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if source_top_left[2] < 0 || source_top_left[2] > source_dimensions.depth() as i32 {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if source_bottom_right[0] < 0 || source_bottom_right[0] > source_dimensions.width() as i32 {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if source_bottom_right[1] < 0 || source_bottom_right[1] > source_dimensions.height() as i32 {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if source_bottom_right[2] < 0 || source_bottom_right[2] > source_dimensions.depth() as i32 {
        return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
    }

    if destination_top_left[0] < 0 || destination_top_left[0] > destination_dimensions.width() as i32 {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    if destination_top_left[1] < 0 || destination_top_left[1] > destination_dimensions.height() as i32 {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    if destination_top_left[2] < 0 || destination_top_left[2] > destination_dimensions.depth() as i32 {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    if destination_bottom_right[0] < 0 || destination_bottom_right[0] > destination_dimensions.width() as i32 {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    if destination_bottom_right[1] < 0 || destination_bottom_right[1] > destination_dimensions.height() as i32 {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    if destination_bottom_right[2] < 0 || destination_bottom_right[2] > destination_dimensions.depth() as i32 {
        return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
    }

    match source_dimensions {
        ImageDimensions::Dim1d { .. } => {
            if source_top_left[1] != 0 || source_bottom_right[1] != 0 {
                return Err(CheckBlitImageError::IncompatibleRangeForImageType);
            }
            if source_top_left[2] != 0 || source_bottom_right[2] != 0 {
                return Err(CheckBlitImageError::IncompatibleRangeForImageType);
            }
        },
        ImageDimensions::Dim2d { .. } => {
            if source_top_left[2] != 0 || source_bottom_right[2] != 0 {
                return Err(CheckBlitImageError::IncompatibleRangeForImageType);
            }
        },
        ImageDimensions::Dim3d { .. } => {},
    }

    match destination_dimensions {
        ImageDimensions::Dim1d { .. } => {
            if destination_top_left[1] != 0 || destination_bottom_right[1] != 0 {
                return Err(CheckBlitImageError::IncompatibleRangeForImageType);
            }
            if destination_top_left[2] != 0 || destination_bottom_right[2] != 0 {
                return Err(CheckBlitImageError::IncompatibleRangeForImageType);
            }
        },
        ImageDimensions::Dim2d { .. } => {
            if destination_top_left[2] != 0 || destination_bottom_right[2] != 0 {
                return Err(CheckBlitImageError::IncompatibleRangeForImageType);
            }
        },
        ImageDimensions::Dim3d { .. } => {},
    }

    Ok(())
}

/// Error that can happen from `check_clear_color_image`.
#[derive(Debug, Copy, Clone)]
pub enum CheckBlitImageError {
    /// The source is missing the transfer source usage.
    MissingTransferSourceUsage,
    /// The destination is missing the transfer destination usage.
    MissingTransferDestinationUsage,
    /// The format of the source image doesn't support blit operations.
    SourceFormatNotSupported,
    /// The format of the destination image doesn't support blit operations.
    DestinationFormatNotSupported,
    /// You must use the nearest filter when blitting depth/stencil images.
    DepthStencilNearestMandatory,
    /// The format of the source and destination must be equal when blitting depth/stencil images.
    DepthStencilFormatMismatch,
    /// The types of the source format and the destination format aren't compatible.
    IncompatibleFormatsTypes {
        source_format_ty: FormatTy,
        destination_format_ty: FormatTy,
    },
    /// Blitting between multisampled images is forbidden.
    UnexpectedMultisampled,
    /// The offsets, array layers and/or mipmap levels are out of range in the source image.
    SourceCoordinatesOutOfRange,
    /// The offsets, array layers and/or mipmap levels are out of range in the destination image.
    DestinationCoordinatesOutOfRange,
    /// The top-left and/or bottom-right coordinates are incompatible with the image type.
    IncompatibleRangeForImageType,
}

impl error::Error for CheckBlitImageError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            CheckBlitImageError::MissingTransferSourceUsage => {
                "the source is missing the transfer source usage"
            },
            CheckBlitImageError::MissingTransferDestinationUsage => {
                "the destination is missing the transfer destination usage"
            },
            CheckBlitImageError::SourceFormatNotSupported => {
                "the format of the source image doesn't support blit operations"
            },
            CheckBlitImageError::DestinationFormatNotSupported => {
                "the format of the destination image doesn't support blit operations"
            },
            CheckBlitImageError::DepthStencilNearestMandatory => {
                "you must use the nearest filter when blitting depth/stencil images"
            },
            CheckBlitImageError::DepthStencilFormatMismatch => {
                "the format of the source and destination must be equal when blitting \
                 depth/stencil images"
            },
            CheckBlitImageError::IncompatibleFormatsTypes { .. } => {
                "the types of the source format and the destination format aren't compatible"
            },
            CheckBlitImageError::UnexpectedMultisampled => {
                "blitting between multisampled images is forbidden"
            },
            CheckBlitImageError::SourceCoordinatesOutOfRange => {
                "the offsets, array layers and/or mipmap levels are out of range in the source \
                 image"
            },
            CheckBlitImageError::DestinationCoordinatesOutOfRange => {
                "the offsets, array layers and/or mipmap levels are out of range in the \
                 destination image"
            },
            CheckBlitImageError::IncompatibleRangeForImageType => {
                "the top-left and/or bottom-right coordinates are incompatible with the image type"
            },
        }
    }
}

impl fmt::Display for CheckBlitImageError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}
<|endoftext|>


<commit_before>// 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::datatypes::ArrowPrimitiveType;

use super::{
    Array, BinaryOffsetSizeTrait, BooleanArray, GenericBinaryArray, GenericStringArray,
    PrimitiveArray, StringOffsetSizeTrait,
};

/// an iterator that returns Some(T) or None, that can be used on any PrimitiveArray
// Note: This implementation is based on std's [Vec]s' [IntoIter].
#[derive(Debug)]
pub struct PrimitiveIter<'a, T: ArrowPrimitiveType> {
    array: &'a PrimitiveArray<T>,
    current: usize,
    current_end: usize,
}

impl<'a, T: ArrowPrimitiveType> PrimitiveIter<'a, T> {
    /// create a new iterator
    pub fn new(array: &'a PrimitiveArray<T>) -> Self {
        PrimitiveIter::<T> {
            array,
            current: 0,
            current_end: array.len(),
        }
    }
}

impl<'a, T: ArrowPrimitiveType> std::iter::Iterator for PrimitiveIter<'a, T> {
    type Item = Option<T::Native>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current == self.current_end {
            None
        } else if self.array.is_null(self.current) {
            self.current += 1;
            Some(None)
        } else {
            let old = self.current;
            self.current += 1;
            Some(Some(self.array.value(old)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.array.len(), Some(self.array.len()))
    }
}

impl<'a, T: ArrowPrimitiveType> std::iter::DoubleEndedIterator for PrimitiveIter<'a, T> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current_end == self.current {
            None
        } else {
            self.current_end -= 1;
            Some(if self.array.is_null(self.current_end) {
                None
            } else {
                Some(self.array.value(self.current_end))
            })
        }
    }
}

/// all arrays have known size.
impl<'a, T: ArrowPrimitiveType> std::iter::ExactSizeIterator for PrimitiveIter<'a, T> {}

/// an iterator that returns Some(bool) or None.
// Note: This implementation is based on std's [Vec]s' [IntoIter].
#[derive(Debug)]
pub struct BooleanIter<'a> {
    array: &'a BooleanArray,
    current: usize,
    current_end: usize,
}

impl<'a> BooleanIter<'a> {
    /// create a new iterator
    pub fn new(array: &'a BooleanArray) -> Self {
        BooleanIter {
            array,
            current: 0,
            current_end: array.len(),
        }
    }
}

impl<'a> std::iter::Iterator for BooleanIter<'a> {
    type Item = Option<bool>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current == self.current_end {
            None
        } else if self.array.is_null(self.current) {
            self.current += 1;
            Some(None)
        } else {
            let old = self.current;
            self.current += 1;
            Some(Some(self.array.value(old)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.array.len(), Some(self.array.len()))
    }
}

impl<'a> std::iter::DoubleEndedIterator for BooleanIter<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current_end == self.current {
            None
        } else {
            self.current_end -= 1;
            Some(if self.array.is_null(self.current_end) {
                None
            } else {
                Some(self.array.value(self.current_end))
            })
        }
    }
}

/// all arrays have known size.
impl<'a> std::iter::ExactSizeIterator for BooleanIter<'a> {}

/// an iterator that returns `Some(&str)` or `None`, for string arrays
#[derive(Debug)]
pub struct GenericStringIter<'a, T>
where
    T: StringOffsetSizeTrait,
{
    array: &'a GenericStringArray<T>,
    i: usize,
    len: usize,
}

impl<'a, T: StringOffsetSizeTrait> GenericStringIter<'a, T> {
    /// create a new iterator
    pub fn new(array: &'a GenericStringArray<T>) -> Self {
        GenericStringIter::<T> {
            array,
            i: 0,
            len: array.len(),
        }
    }
}

impl<'a, T: StringOffsetSizeTrait> std::iter::Iterator for GenericStringIter<'a, T> {
    type Item = Option<&'a str>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        if i >= self.len {
            None
        } else if self.array.is_null(i) {
            self.i += 1;
            Some(None)
        } else {
            self.i += 1;
            Some(Some(self.array.value(i)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len, Some(self.len))
    }
}

/// all arrays have known size.
impl<'a, T: StringOffsetSizeTrait> std::iter::ExactSizeIterator
    for GenericStringIter<'a, T>
{
}

/// an iterator that returns `Some(&[u8])` or `None`, for binary arrays
#[derive(Debug)]
pub struct GenericBinaryIter<'a, T>
where
    T: BinaryOffsetSizeTrait,
{
    array: &'a GenericBinaryArray<T>,
    i: usize,
    len: usize,
}

impl<'a, T: BinaryOffsetSizeTrait> GenericBinaryIter<'a, T> {
    /// create a new iterator
    pub fn new(array: &'a GenericBinaryArray<T>) -> Self {
        GenericBinaryIter::<T> {
            array,
            i: 0,
            len: array.len(),
        }
    }
}

impl<'a, T: BinaryOffsetSizeTrait> std::iter::Iterator for GenericBinaryIter<'a, T> {
    type Item = Option<&'a [u8]>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        if i >= self.len {
            None
        } else if self.array.is_null(i) {
            self.i += 1;
            Some(None)
        } else {
            self.i += 1;
            Some(Some(self.array.value(i)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len, Some(self.len))
    }
}

/// all arrays have known size.
impl<'a, T: BinaryOffsetSizeTrait> std::iter::ExactSizeIterator
    for GenericBinaryIter<'a, T>
{
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;

    use crate::array::{ArrayRef, BinaryArray, BooleanArray, Int32Array, StringArray};

    #[test]
    fn test_primitive_array_iter_round_trip() {
        let array = Int32Array::from(vec![Some(0), None, Some(2), None, Some(4)]);
        let array = Arc::new(array) as ArrayRef;

        let array = array.as_any().downcast_ref::<Int32Array>().unwrap();

        // to and from iter, with a +1
        let result: Int32Array = array.iter().map(|e| e.map(|e| e + 1)).collect();

        let expected = Int32Array::from(vec![Some(1), None, Some(3), None, Some(5)]);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_double_ended() {
        let array = Int32Array::from(vec![Some(0), None, Some(2), None, Some(4)]);
        let mut a = array.iter();
        assert_eq!(a.next(), Some(Some(0)));
        assert_eq!(a.next(), Some(None));
        assert_eq!(a.next_back(), Some(Some(4)));
        assert_eq!(a.next_back(), Some(None));
        assert_eq!(a.next_back(), Some(Some(2)));
        // the two sides have met: None is returned by both
        assert_eq!(a.next_back(), None);
        assert_eq!(a.next(), None);
    }

    #[test]
    fn test_string_array_iter_round_trip() {
        let array =
            StringArray::from(vec![Some("a"), None, Some("aaa"), None, Some("aaaaa")]);
        let array = Arc::new(array) as ArrayRef;

        let array = array.as_any().downcast_ref::<StringArray>().unwrap();

        // to and from iter, with a +1
        let result: StringArray = array
            .iter()
            .map(|e| {
                e.map(|e| {
                    let mut a = e.to_string();
                    a.push('b');
                    a
                })
            })
            .collect();

        let expected =
            StringArray::from(vec![Some("ab"), None, Some("aaab"), None, Some("aaaaab")]);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_binary_array_iter_round_trip() {
        let array = BinaryArray::from(vec![
            Some(b"a" as &[u8]),
            None,
            Some(b"aaa"),
            None,
            Some(b"aaaaa"),
        ]);

        // to and from iter
        let result: BinaryArray = array.iter().collect();

        assert_eq!(result, array);
    }

    #[test]
    fn test_boolean_array_iter_round_trip() {
        let array = BooleanArray::from(vec![Some(true), None, Some(false)]);

        // to and from iter
        let result: BooleanArray = array.iter().collect();

        assert_eq!(result, array);
    }
}
<commit_msg>ARROW-11313: [Rust] Fixed size_hint<commit_after>// 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::datatypes::ArrowPrimitiveType;

use super::{
    Array, BinaryOffsetSizeTrait, BooleanArray, GenericBinaryArray, GenericStringArray,
    PrimitiveArray, StringOffsetSizeTrait,
};

/// an iterator that returns Some(T) or None, that can be used on any PrimitiveArray
// Note: This implementation is based on std's [Vec]s' [IntoIter].
#[derive(Debug)]
pub struct PrimitiveIter<'a, T: ArrowPrimitiveType> {
    array: &'a PrimitiveArray<T>,
    current: usize,
    current_end: usize,
}

impl<'a, T: ArrowPrimitiveType> PrimitiveIter<'a, T> {
    /// create a new iterator
    pub fn new(array: &'a PrimitiveArray<T>) -> Self {
        PrimitiveIter::<T> {
            array,
            current: 0,
            current_end: array.len(),
        }
    }
}

impl<'a, T: ArrowPrimitiveType> std::iter::Iterator for PrimitiveIter<'a, T> {
    type Item = Option<T::Native>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current == self.current_end {
            None
        } else if self.array.is_null(self.current) {
            self.current += 1;
            Some(None)
        } else {
            let old = self.current;
            self.current += 1;
            Some(Some(self.array.value(old)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (
            self.array.len() - self.current,
            Some(self.array.len() - self.current),
        )
    }
}

impl<'a, T: ArrowPrimitiveType> std::iter::DoubleEndedIterator for PrimitiveIter<'a, T> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current_end == self.current {
            None
        } else {
            self.current_end -= 1;
            Some(if self.array.is_null(self.current_end) {
                None
            } else {
                Some(self.array.value(self.current_end))
            })
        }
    }
}

/// all arrays have known size.
impl<'a, T: ArrowPrimitiveType> std::iter::ExactSizeIterator for PrimitiveIter<'a, T> {}

/// an iterator that returns Some(bool) or None.
// Note: This implementation is based on std's [Vec]s' [IntoIter].
#[derive(Debug)]
pub struct BooleanIter<'a> {
    array: &'a BooleanArray,
    current: usize,
    current_end: usize,
}

impl<'a> BooleanIter<'a> {
    /// create a new iterator
    pub fn new(array: &'a BooleanArray) -> Self {
        BooleanIter {
            array,
            current: 0,
            current_end: array.len(),
        }
    }
}

impl<'a> std::iter::Iterator for BooleanIter<'a> {
    type Item = Option<bool>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current == self.current_end {
            None
        } else if self.array.is_null(self.current) {
            self.current += 1;
            Some(None)
        } else {
            let old = self.current;
            self.current += 1;
            Some(Some(self.array.value(old)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (
            self.array.len() - self.current,
            Some(self.array.len() - self.current),
        )
    }
}

impl<'a> std::iter::DoubleEndedIterator for BooleanIter<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current_end == self.current {
            None
        } else {
            self.current_end -= 1;
            Some(if self.array.is_null(self.current_end) {
                None
            } else {
                Some(self.array.value(self.current_end))
            })
        }
    }
}

/// all arrays have known size.
impl<'a> std::iter::ExactSizeIterator for BooleanIter<'a> {}

/// an iterator that returns `Some(&str)` or `None`, for string arrays
#[derive(Debug)]
pub struct GenericStringIter<'a, T>
where
    T: StringOffsetSizeTrait,
{
    array: &'a GenericStringArray<T>,
    i: usize,
    len: usize,
}

impl<'a, T: StringOffsetSizeTrait> GenericStringIter<'a, T> {
    /// create a new iterator
    pub fn new(array: &'a GenericStringArray<T>) -> Self {
        GenericStringIter::<T> {
            array,
            i: 0,
            len: array.len(),
        }
    }
}

impl<'a, T: StringOffsetSizeTrait> std::iter::Iterator for GenericStringIter<'a, T> {
    type Item = Option<&'a str>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        if i >= self.len {
            None
        } else if self.array.is_null(i) {
            self.i += 1;
            Some(None)
        } else {
            self.i += 1;
            Some(Some(self.array.value(i)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len - self.i, Some(self.len - self.i))
    }
}

/// all arrays have known size.
impl<'a, T: StringOffsetSizeTrait> std::iter::ExactSizeIterator
    for GenericStringIter<'a, T>
{
}

/// an iterator that returns `Some(&[u8])` or `None`, for binary arrays
#[derive(Debug)]
pub struct GenericBinaryIter<'a, T>
where
    T: BinaryOffsetSizeTrait,
{
    array: &'a GenericBinaryArray<T>,
    i: usize,
    len: usize,
}

impl<'a, T: BinaryOffsetSizeTrait> GenericBinaryIter<'a, T> {
    /// create a new iterator
    pub fn new(array: &'a GenericBinaryArray<T>) -> Self {
        GenericBinaryIter::<T> {
            array,
            i: 0,
            len: array.len(),
        }
    }
}

impl<'a, T: BinaryOffsetSizeTrait> std::iter::Iterator for GenericBinaryIter<'a, T> {
    type Item = Option<&'a [u8]>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        if i >= self.len {
            None
        } else if self.array.is_null(i) {
            self.i += 1;
            Some(None)
        } else {
            self.i += 1;
            Some(Some(self.array.value(i)))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len - self.i, Some(self.len - self.i))
    }
}

/// all arrays have known size.
impl<'a, T: BinaryOffsetSizeTrait> std::iter::ExactSizeIterator
    for GenericBinaryIter<'a, T>
{
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;

    use crate::array::{ArrayRef, BinaryArray, BooleanArray, Int32Array, StringArray};

    #[test]
    fn test_primitive_array_iter_round_trip() {
        let array = Int32Array::from(vec![Some(0), None, Some(2), None, Some(4)]);
        let array = Arc::new(array) as ArrayRef;

        let array = array.as_any().downcast_ref::<Int32Array>().unwrap();

        // to and from iter, with a +1
        let result: Int32Array = array.iter().map(|e| e.map(|e| e + 1)).collect();

        let expected = Int32Array::from(vec![Some(1), None, Some(3), None, Some(5)]);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_double_ended() {
        let array = Int32Array::from(vec![Some(0), None, Some(2), None, Some(4)]);
        let mut a = array.iter();
        assert_eq!(a.next(), Some(Some(0)));
        assert_eq!(a.next(), Some(None));
        assert_eq!(a.next_back(), Some(Some(4)));
        assert_eq!(a.next_back(), Some(None));
        assert_eq!(a.next_back(), Some(Some(2)));
        // the two sides have met: None is returned by both
        assert_eq!(a.next_back(), None);
        assert_eq!(a.next(), None);
    }

    #[test]
    fn test_string_array_iter_round_trip() {
        let array =
            StringArray::from(vec![Some("a"), None, Some("aaa"), None, Some("aaaaa")]);
        let array = Arc::new(array) as ArrayRef;

        let array = array.as_any().downcast_ref::<StringArray>().unwrap();

        // to and from iter, with a +1
        let result: StringArray = array
            .iter()
            .map(|e| {
                e.map(|e| {
                    let mut a = e.to_string();
                    a.push('b');
                    a
                })
            })
            .collect();

        let expected =
            StringArray::from(vec![Some("ab"), None, Some("aaab"), None, Some("aaaaab")]);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_binary_array_iter_round_trip() {
        let array = BinaryArray::from(vec![
            Some(b"a" as &[u8]),
            None,
            Some(b"aaa"),
            None,
            Some(b"aaaaa"),
        ]);

        // to and from iter
        let result: BinaryArray = array.iter().collect();

        assert_eq!(result, array);
    }

    #[test]
    fn test_boolean_array_iter_round_trip() {
        let array = BooleanArray::from(vec![Some(true), None, Some(false)]);

        // to and from iter
        let result: BooleanArray = array.iter().collect();

        assert_eq!(result, array);
    }
}
<|endoftext|>


<commit_before>#[derive(Debug)]
struct Tree {
    enter: Node,
    left: Option<Box<Tree>>,
    right: Option<Box<Tree>>,
}

//for red-black tree
#[derive(Debug)]
enum Color {
    Black,
    Red,
    White,
}

#[derive(Debug)]
struct Node {
    val: i32,
    color: Color,
}

impl Node {
    fn new(v: &i32) -> Node {
        Node {
            val: *v,
            color: Color::White,
        }
    }
}

impl Tree {
    fn new(v: &i32) -> Tree {
        Tree {
            enter: Node::new(v),
            left: None,
            right: None,
        }
    }

    fn insert(&mut self, v: &i32) {
        let target = if *v > self.enter.val {
            &mut self.right
        } else {
            &mut self.left
        };
        //println!("target is -> {:?}", target);
        match target {
            Some(next) => {
                //println!("next is -> {:?}", &next);
                next.insert(v)
            }
            None => {
                let new_node = Node::new(v);
                let new_tree = Tree {
                    enter: new_node,
                    left: None,
                    right: None,
                };
                *target = Some(Box::new(new_tree));
            }
        }
    }

    fn look_up_recursive(&mut self, v: &i32) -> Result<&mut Self, String> {
        if *v == self.enter.val {
            return Ok(self);
        } else if *v > self.enter.val {
            if let Some(_) = self.right {
                let next = self.right.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        } else {
            if let Some(_) = self.left {
                let next = self.left.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        }
    }

    fn look_up(&mut self, v: &i32) -> Result<&mut Self, String> {
        let mut this: &mut Self = self;
        loop {
            if *v == this.enter.val {
                return Ok(this);
            } else if *v > this.enter.val {
                if let None = this.right {
                    return Err("not find".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return Err("not find".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    fn left_shift(&mut self, v: &i32) {}
}

fn main() {
    let mut a = Tree::new(&3);
    a.insert(&2);
    a.insert(&1);

    //println!("{:?}", a);
    //println!("{:?}", a.look_up(&1));
    println!("{:?}", a.look_up(&1));
    println!("{:?}", a);
}
<commit_msg>add find father node method<commit_after>#[derive(Debug, Clone)]
struct Tree {
    enter: Node,
    left: Option<Box<Tree>>,
    right: Option<Box<Tree>>,
}

//for red-black tree
#[derive(Debug, Clone)]
enum Color {
    Black,
    Red,
    White,
}

#[derive(Debug, Clone)]
struct Node {
    val: i32,
    color: Color,
}

impl Node {
    fn new(v: &i32) -> Node {
        Node {
            val: *v,
            color: Color::White,
        }
    }
}

type ReTr<'a> = Result<&'a mut Tree, String>;

impl Tree {
    fn new(v: &i32) -> Tree {
        Tree {
            enter: Node::new(v),
            left: None,
            right: None,
        }
    }

    fn insert(&mut self, v: &i32) {
        let target = if *v > self.enter.val {
            &mut self.right
        } else {
            &mut self.left
        };
        //println!("target is -> {:?}", target);
        match target {
            Some(next) => {
                //println!("next is -> {:?}", &next);
                next.insert(v)
            }
            None => {
                let new_node = Node::new(v);
                let new_tree = Tree {
                    enter: new_node,
                    left: None,
                    right: None,
                };
                *target = Some(Box::new(new_tree));
            }
        }
    }

    fn look_up_recursive(&mut self, v: &i32) -> Result<&mut Self, String> {
        if *v == self.enter.val {
            return Ok(self);
        } else if *v > self.enter.val {
            if let Some(_) = self.right {
                let next = self.right.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        } else {
            if let Some(_) = self.left {
                let next = self.left.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        }
    }

    fn look_up(&mut self, v: &i32) -> ReTr {
        let mut this: &mut Self = self;
        loop {
            if *v == this.enter.val {
                return Ok(this);
            } else if *v > this.enter.val {
                if let None = this.right {
                    return Err("not find".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return Err("not find".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    fn look_up_father(&mut self, v: &i32) -> (ReTr, String) {
        let mut this: &mut Self = self;
        loop {
            if *v == this.right.as_ref().unwrap().enter.val {
                return (Ok(this), "right".to_string());
            } else if *v == this.right.as_ref().unwrap().enter.val {
                return (Ok(this), "left".to_string());
            } else if *v > this.enter.val {
                if let None = this.right {
                    return (Err("not find".to_string()), "Error".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return (Err("not find".to_string()), "Error".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    fn left_shift(&mut self, v: &i32) {}
}

fn main() {
    let mut a = Tree::new(&3);
    a.insert(&2);
    a.insert(&1);
    a.insert(&4);
    a.insert(&5);

    //println!("{:?}", a);
    //println!("{:?}", a.look_up(&1));
    println!("{:?}", a.look_up_father(&4));
    //println!("{:?}", a);
}
<|endoftext|>


<commit_before>use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;
use syntax::source_map::Spanned;

use crate::utils::SpanlessEq;
use crate::utils::{get_parent_expr, is_allowed, match_type, paths, span_lint, span_lint_and_sugg, walk_ptrs_ty};

declare_clippy_lint! {
    /// **What it does:** Checks for string appends of the form `x = x + y` (without
    /// `let`!).
    ///
    /// **Why is this bad?** It's not really bad, but some people think that the
    /// `.push_str(_)` method is more readable.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let mut x = "Hello".to_owned();
    /// x = x + ", World";
    /// ```
    pub STRING_ADD_ASSIGN,
    pedantic,
    "using `x = x + ..` where x is a `String` instead of `push_str()`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for all instances of `x + _` where `x` is of type
    /// `String`, but only if [`string_add_assign`](#string_add_assign) does *not*
    /// match.
    ///
    /// **Why is this bad?** It's not bad in and of itself. However, this particular
    /// `Add` implementation is asymmetric (the other operand need not be `String`,
    /// but `x` does), while addition as mathematically defined is symmetric, also
    /// the `String::push_str(_)` function is a perfectly good replacement.
    /// Therefore, some dislike it and wish not to have it in their code.
    ///
    /// That said, other people think that string addition, having a long tradition
    /// in other languages is actually fine, which is why we decided to make this
    /// particular lint `allow` by default.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let x = "Hello".to_owned();
    /// x + ", World";
    /// ```
    pub STRING_ADD,
    restriction,
    "using `x + ..` where x is a `String` instead of `push_str()`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for the `as_bytes` method called on string literals
    /// that contain only ASCII characters.
    ///
    /// **Why is this bad?** Byte string literals (e.g., `b"foo"`) can be used
    /// instead. They are shorter but less discoverable than `as_bytes()`.
    ///
    /// **Known Problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let bs = "a byte string".as_bytes();
    /// ```
    pub STRING_LIT_AS_BYTES,
    style,
    "calling `as_bytes` on a string literal instead of using a byte string literal"
}

declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringAdd {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
        if let ExprKind::Binary(
            Spanned {
                node: BinOpKind::Add, ..
            },
            ref left,
            _,
        ) = e.kind
        {
            if is_string(cx, left) {
                if !is_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
                    let parent = get_parent_expr(cx, e);
                    if let Some(p) = parent {
                        if let ExprKind::Assign(ref target, _) = p.kind {
                            // avoid duplicate matches
                            if SpanlessEq::new(cx).eq_expr(target, left) {
                                return;
                            }
                        }
                    }
                }
                span_lint(
                    cx,
                    STRING_ADD,
                    e.span,
                    "you added something to a string. Consider using `String::push_str()` instead",
                );
            }
        } else if let ExprKind::Assign(ref target, ref src) = e.kind {
            if is_string(cx, target) && is_add(cx, src, target) {
                span_lint(
                    cx,
                    STRING_ADD_ASSIGN,
                    e.span,
                    "you assigned the result of adding something to this string. Consider using \
                     `String::push_str()` instead",
                );
            }
        }
    }
}

fn is_string(cx: &LateContext<'_, '_>, e: &Expr) -> bool {
    match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(e)), &paths::STRING)
}

fn is_add(cx: &LateContext<'_, '_>, src: &Expr, target: &Expr) -> bool {
    match src.kind {
        ExprKind::Binary(
            Spanned {
                node: BinOpKind::Add, ..
            },
            ref left,
            _,
        ) => SpanlessEq::new(cx).eq_expr(target, left),
        ExprKind::Block(ref block, _) => {
            block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
        },
        _ => false,
    }
}

// Max length a b"foo" string can take
const MAX_LENGTH_BYTE_STRING_LIT: usize = 32;

declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
        use crate::utils::{snippet, snippet_with_applicability};
        use syntax::ast::{LitKind, StrStyle};

        if let ExprKind::MethodCall(ref path, _, ref args) = e.kind {
            if path.ident.name == sym!(as_bytes) {
                if let ExprKind::Lit(ref lit) = args[0].kind {
                    if let LitKind::Str(ref lit_content, style) = lit.node {
                        let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#);
                        let expanded = if let StrStyle::Raw(n) = style {
                            let term = (0..n).map(|_| '#').collect::<String>();
                            format!("r{0}\"{1}\"{0}", term, lit_content.as_str())
                        } else {
                            format!("\"{}\"", lit_content.as_str())
                        };
                        let mut applicability = Applicability::MachineApplicable;
                        if callsite.starts_with("include_str!") {
                            span_lint_and_sugg(
                                cx,
                                STRING_LIT_AS_BYTES,
                                e.span,
                                "calling `as_bytes()` on `include_str!(..)`",
                                "consider using `include_bytes!(..)` instead",
                                snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen(
                                    "include_str",
                                    "include_bytes",
                                    1,
                                ),
                                applicability,
                            );
                        } else if callsite == expanded
                            && lit_content.as_str().chars().all(|c| c.is_ascii())
                            && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
                            && !args[0].span.from_expansion()
                        {
                            span_lint_and_sugg(
                                cx,
                                STRING_LIT_AS_BYTES,
                                e.span,
                                "calling `as_bytes()` on a string literal",
                                "consider using a byte string literal instead",
                                format!(
                                    "b{}",
                                    snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability)
                                ),
                                applicability,
                            );
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>use more efficient code to generate repeated string<commit_after>use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;
use syntax::source_map::Spanned;

use crate::utils::SpanlessEq;
use crate::utils::{get_parent_expr, is_allowed, match_type, paths, span_lint, span_lint_and_sugg, walk_ptrs_ty};

declare_clippy_lint! {
    /// **What it does:** Checks for string appends of the form `x = x + y` (without
    /// `let`!).
    ///
    /// **Why is this bad?** It's not really bad, but some people think that the
    /// `.push_str(_)` method is more readable.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let mut x = "Hello".to_owned();
    /// x = x + ", World";
    /// ```
    pub STRING_ADD_ASSIGN,
    pedantic,
    "using `x = x + ..` where x is a `String` instead of `push_str()`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for all instances of `x + _` where `x` is of type
    /// `String`, but only if [`string_add_assign`](#string_add_assign) does *not*
    /// match.
    ///
    /// **Why is this bad?** It's not bad in and of itself. However, this particular
    /// `Add` implementation is asymmetric (the other operand need not be `String`,
    /// but `x` does), while addition as mathematically defined is symmetric, also
    /// the `String::push_str(_)` function is a perfectly good replacement.
    /// Therefore, some dislike it and wish not to have it in their code.
    ///
    /// That said, other people think that string addition, having a long tradition
    /// in other languages is actually fine, which is why we decided to make this
    /// particular lint `allow` by default.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let x = "Hello".to_owned();
    /// x + ", World";
    /// ```
    pub STRING_ADD,
    restriction,
    "using `x + ..` where x is a `String` instead of `push_str()`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for the `as_bytes` method called on string literals
    /// that contain only ASCII characters.
    ///
    /// **Why is this bad?** Byte string literals (e.g., `b"foo"`) can be used
    /// instead. They are shorter but less discoverable than `as_bytes()`.
    ///
    /// **Known Problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let bs = "a byte string".as_bytes();
    /// ```
    pub STRING_LIT_AS_BYTES,
    style,
    "calling `as_bytes` on a string literal instead of using a byte string literal"
}

declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringAdd {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
        if let ExprKind::Binary(
            Spanned {
                node: BinOpKind::Add, ..
            },
            ref left,
            _,
        ) = e.kind
        {
            if is_string(cx, left) {
                if !is_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
                    let parent = get_parent_expr(cx, e);
                    if let Some(p) = parent {
                        if let ExprKind::Assign(ref target, _) = p.kind {
                            // avoid duplicate matches
                            if SpanlessEq::new(cx).eq_expr(target, left) {
                                return;
                            }
                        }
                    }
                }
                span_lint(
                    cx,
                    STRING_ADD,
                    e.span,
                    "you added something to a string. Consider using `String::push_str()` instead",
                );
            }
        } else if let ExprKind::Assign(ref target, ref src) = e.kind {
            if is_string(cx, target) && is_add(cx, src, target) {
                span_lint(
                    cx,
                    STRING_ADD_ASSIGN,
                    e.span,
                    "you assigned the result of adding something to this string. Consider using \
                     `String::push_str()` instead",
                );
            }
        }
    }
}

fn is_string(cx: &LateContext<'_, '_>, e: &Expr) -> bool {
    match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(e)), &paths::STRING)
}

fn is_add(cx: &LateContext<'_, '_>, src: &Expr, target: &Expr) -> bool {
    match src.kind {
        ExprKind::Binary(
            Spanned {
                node: BinOpKind::Add, ..
            },
            ref left,
            _,
        ) => SpanlessEq::new(cx).eq_expr(target, left),
        ExprKind::Block(ref block, _) => {
            block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
        },
        _ => false,
    }
}

// Max length a b"foo" string can take
const MAX_LENGTH_BYTE_STRING_LIT: usize = 32;

declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
        use crate::utils::{snippet, snippet_with_applicability};
        use syntax::ast::{LitKind, StrStyle};

        if let ExprKind::MethodCall(ref path, _, ref args) = e.kind {
            if path.ident.name == sym!(as_bytes) {
                if let ExprKind::Lit(ref lit) = args[0].kind {
                    if let LitKind::Str(ref lit_content, style) = lit.node {
                        let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#);
                        let expanded = if let StrStyle::Raw(n) = style {
                            let term = "#".repeat(n as usize);
                            format!("r{0}\"{1}\"{0}", term, lit_content.as_str())
                        } else {
                            format!("\"{}\"", lit_content.as_str())
                        };
                        let mut applicability = Applicability::MachineApplicable;
                        if callsite.starts_with("include_str!") {
                            span_lint_and_sugg(
                                cx,
                                STRING_LIT_AS_BYTES,
                                e.span,
                                "calling `as_bytes()` on `include_str!(..)`",
                                "consider using `include_bytes!(..)` instead",
                                snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen(
                                    "include_str",
                                    "include_bytes",
                                    1,
                                ),
                                applicability,
                            );
                        } else if callsite == expanded
                            && lit_content.as_str().chars().all(|c| c.is_ascii())
                            && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
                            && !args[0].span.from_expansion()
                        {
                            span_lint_and_sugg(
                                cx,
                                STRING_LIT_AS_BYTES,
                                e.span,
                                "calling `as_bytes()` on a string literal",
                                "consider using a byte string literal instead",
                                format!(
                                    "b{}",
                                    snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability)
                                ),
                                applicability,
                            );
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! ARM C Language Extensions (ACLE)
//!
//! # Developer notes
//!
//! Below is a list of built-in targets that are representative of the different ARM
//! architectures; the list includes the `target_feature`s they possess.
//!
//! - `armv4t-unknown-linux-gnueabi` - **ARMv4** - `+v4t`
//! - `armv5te-unknown-linux-gnueabi` - **ARMv5TE** - `+v4t +v5te`
//! - `arm-unknown-linux-gnueabi` - **ARMv6** - `+v4t +v5te +v6`
//! - `thumbv6m-none-eabi` - **ARMv6-M** - `+v4t +v5te +v6 +thumb-mode +mclass`
//! - `armv7-unknown-linux-gnueabihf` - **ARMv7-A** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +aclass`
//! - `armv7r-none-eabi` - **ARMv7-R** - `+v4t +v5te +v6 +v6k +v6t2  +v7 +dsp +thumb2 +rclass`
//! - `thumbv7m-none-eabi` - **ARMv7-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +thumb2 +thumb-mode +mclass`
//! - `thumbv7em-none-eabi` - **ARMv7E-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +thumb-mode +mclass`
//! - `aarch64-unknown-linux-gnu` - **ARMv8-A (AArch64)** - `+fp +neon`
//!
//! Section 10.1 of ACLE says:
//!
//! - "In the sequence of Arm architectures { v5, v5TE, v6, v6T2, v7 } each architecture includes
//! its predecessor instruction set."
//!
//! - "In the sequence of Thumb-only architectures { v6-M, v7-M, v7E-M } each architecture includes
//! its predecessor instruction set."
//!
//! From that info and from looking at how LLVM features work (using custom targets) we can identify
//! features that are subsets of others:
//!
//! Legend: `a < b` reads as "`a` is a subset of `b`"; this means that if `b` is enabled then `a` is
//! enabled as well.
//!
//! - `v4t < v5te < v6 < v6k < v6t2 < v7 < v8`
//! - `v6 < v8m < v6t2`
//! - `v7 < v8m.main`
//!
//! # References
//!
//! - [ACLE Q2 2018](https://developer.arm.com/docs/101028/latest)

// Supported arches: 8, 7, 6-M. See Section 10.1 of ACLE (e.g. DMB)
// But this is further refined within the module
#[cfg(any(
    // v8
    target_arch = "aarch64",
    // v7
    target_feature = "v7",
    // v6-M
    target_feature = "mclass"
))]
mod barrier;

#[cfg(any(
    target_arch = "aarch64",
    target_feature = "v7",
    target_feature = "mclass"
))]
pub use self::barrier::*;

mod hints;

pub use self::hints::*;

mod registers;

pub use self::registers::*;

// Supported arches: 5TE, 7E-M. See Section 10.1 of ACLE (e.g. QADD)
// But we also exclude the A profile because DSP is deprecated on that profile as of ACLE 2.0 (see
// section 5.4.7)
#[cfg(any(
    // >= v5TE but excludes v7-A
    all(target_feature = "v5te", not(target_feature = "mclass"), not(target_feature = "aclass")),
    // v7E-M
    all(target_feature = "mclass", target_feature = "dsp"),
))]
mod dsp;

#[cfg(any(
    all(
        target_feature = "v5te",
        not(target_feature = "mclass"),
        not(target_feature = "aclass")
    ),
    all(target_feature = "mclass", target_feature = "dsp"),
))]
pub use self::dsp::*;

// Deprecated in ACLE 2.0 for the A profile but fully supported on the M and R profiles, says
// Section 5.4.9 of ACLE.
#[cfg(any(
    // v7-R
    target_feature = "rclass",
    // v7E-M
    all(target_feature = "mclass", target_feature = "dsp")
))]
mod simd32;

#[cfg(any(
    target_feature = "rclass",
    all(target_feature = "mclass", target_feature = "dsp")
))]
pub use self::simd32::*;

mod sealed {
    pub trait Dmb {
        unsafe fn __dmb(&self);
    }

    pub trait Dsb {
        unsafe fn __dsb(&self);
    }

    pub trait Isb {
        unsafe fn __isb(&self);
    }

    pub trait Rsr {
        unsafe fn __rsr(&self) -> u32;
    }

    pub trait Rsr64 {
        unsafe fn __rsr64(&self) -> u64;
    }

    pub trait Rsrp {
        unsafe fn __rsrp(&self) -> *const u8;
    }

    pub trait Wsr {
        unsafe fn __wsr(&self, value: u32);
    }

    pub trait Wsr64 {
        unsafe fn __wsr64(&self, value: u64);
    }

    pub trait Wsrp {
        unsafe fn __wsrp(&self, value: *const u8);
    }
}
<commit_msg>acle/simd32: also expose on the A profile<commit_after>//! ARM C Language Extensions (ACLE)
//!
//! # Developer notes
//!
//! Below is a list of built-in targets that are representative of the different ARM
//! architectures; the list includes the `target_feature`s they possess.
//!
//! - `armv4t-unknown-linux-gnueabi` - **ARMv4** - `+v4t`
//! - `armv5te-unknown-linux-gnueabi` - **ARMv5TE** - `+v4t +v5te`
//! - `arm-unknown-linux-gnueabi` - **ARMv6** - `+v4t +v5te +v6`
//! - `thumbv6m-none-eabi` - **ARMv6-M** - `+v4t +v5te +v6 +thumb-mode +mclass`
//! - `armv7-unknown-linux-gnueabihf` - **ARMv7-A** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +aclass`
//! - `armv7r-none-eabi` - **ARMv7-R** - `+v4t +v5te +v6 +v6k +v6t2  +v7 +dsp +thumb2 +rclass`
//! - `thumbv7m-none-eabi` - **ARMv7-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +thumb2 +thumb-mode +mclass`
//! - `thumbv7em-none-eabi` - **ARMv7E-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +thumb-mode +mclass`
//! - `aarch64-unknown-linux-gnu` - **ARMv8-A (AArch64)** - `+fp +neon`
//!
//! Section 10.1 of ACLE says:
//!
//! - "In the sequence of Arm architectures { v5, v5TE, v6, v6T2, v7 } each architecture includes
//! its predecessor instruction set."
//!
//! - "In the sequence of Thumb-only architectures { v6-M, v7-M, v7E-M } each architecture includes
//! its predecessor instruction set."
//!
//! From that info and from looking at how LLVM features work (using custom targets) we can identify
//! features that are subsets of others:
//!
//! Legend: `a < b` reads as "`a` is a subset of `b`"; this means that if `b` is enabled then `a` is
//! enabled as well.
//!
//! - `v4t < v5te < v6 < v6k < v6t2 < v7 < v8`
//! - `v6 < v8m < v6t2`
//! - `v7 < v8m.main`
//!
//! # References
//!
//! - [ACLE Q2 2018](https://developer.arm.com/docs/101028/latest)

// Supported arches: 8, 7, 6-M. See Section 10.1 of ACLE (e.g. DMB)
// But this is further refined within the module
#[cfg(any(
    // v8
    target_arch = "aarch64",
    // v7
    target_feature = "v7",
    // v6-M
    target_feature = "mclass"
))]
mod barrier;

#[cfg(any(
    target_arch = "aarch64",
    target_feature = "v7",
    target_feature = "mclass"
))]
pub use self::barrier::*;

mod hints;

pub use self::hints::*;

mod registers;

pub use self::registers::*;

// Supported arches: 5TE, 7E-M. See Section 10.1 of ACLE (e.g. QADD)
// But we also exclude the A profile because DSP is deprecated on that profile as of ACLE 2.0 (see
// section 5.4.7)
#[cfg(any(
    // >= v5TE but excludes v7-A
    all(target_feature = "v5te", not(target_feature = "mclass"), not(target_feature = "aclass")),
    // v7E-M
    all(target_feature = "mclass", target_feature = "dsp"),
))]
mod dsp;

#[cfg(any(
    all(
        target_feature = "v5te",
        not(target_feature = "mclass"),
        not(target_feature = "aclass")
    ),
    all(target_feature = "mclass", target_feature = "dsp"),
))]
pub use self::dsp::*;

// Deprecated in ACLE 2.0 for the A profile but fully supported on the M and R profiles, says
// Section 5.4.9 of ACLE. We'll expose these for the A profile even if deprecated
#[cfg(any(
    // v7-A, v7-R
    all(target_feature = "v6", not(target_feature = "mclass")),
    // v7E-M
    all(target_feature = "mclass", target_feature = "dsp")
))]
mod simd32;

#[cfg(any(
    all(target_feature = "v6", not(target_feature = "mclass")),
    all(target_feature = "mclass", target_feature = "dsp")
))]
pub use self::simd32::*;

mod sealed {
    pub trait Dmb {
        unsafe fn __dmb(&self);
    }

    pub trait Dsb {
        unsafe fn __dsb(&self);
    }

    pub trait Isb {
        unsafe fn __isb(&self);
    }

    pub trait Rsr {
        unsafe fn __rsr(&self) -> u32;
    }

    pub trait Rsr64 {
        unsafe fn __rsr64(&self) -> u64;
    }

    pub trait Rsrp {
        unsafe fn __rsrp(&self) -> *const u8;
    }

    pub trait Wsr {
        unsafe fn __wsr(&self, value: u32);
    }

    pub trait Wsr64 {
        unsafe fn __wsr64(&self, value: u64);
    }

    pub trait Wsrp {
        unsafe fn __wsrp(&self, value: *const u8);
    }
}
<|endoftext|>


<commit_before>use super::btree::{BPlusTree, RTCursor as BPlusTreeCursor};
use super::sstable::*;
use super::*;
use client::AsyncClient;
use itertools::Itertools;
use parking_lot::RwLock;
use ram::segs::MAX_SEGMENT_SIZE;
use std::collections::BTreeSet;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use std::{mem, ptr};

const LEVEL_M_MAX_ELEMENTS_COUNT: usize = LEVEL_M * LEVEL_M * LEVEL_M;
const LEVEL_PAGES_MULTIPLIER: usize = 100;
const LEVEL_DIFF_MULTIPLIER: usize = 10;
const LEVEL_M: usize = super::btree::NUM_KEYS;
const LEVEL_1: usize = LEVEL_M * LEVEL_DIFF_MULTIPLIER;
const LEVEL_2: usize = LEVEL_1 * LEVEL_DIFF_MULTIPLIER;
const LEVEL_3: usize = LEVEL_2 * LEVEL_DIFF_MULTIPLIER;
const LEVEL_4: usize = LEVEL_3 * LEVEL_DIFF_MULTIPLIER;

type LevelTrees = Vec<Box<SSLevelTree>>;

macro_rules! with_levels {
    ($($sym:ident, $level_size:ident;)*) => {
        $(
            type $sym = [EntryKey; $level_size];
            impl_sspage_slice!($sym, EntryKey, $level_size);
        )*

        fn init_lsm_level_trees(neb_client: &Arc<AsyncClient>) -> (LevelTrees, Vec<usize>, Vec<usize>) {
            let mut trees = LevelTrees::new();
            let mut max_pages_list = Vec::new();
            let mut max_pages = LEVEL_M_MAX_PAGES_COUNT;
            let mut page_sizes = Vec::new();
            $(
                max_pages *= LEVEL_PAGES_MULTIPLIER;
                trees.push(box LevelTree::<$sym>::new(neb_client));
                max_pages_list.push(max_pages * $level_size);
                page_sizes.push($level_size);
                const_assert!($level_size * KEY_SIZE <= MAX_SEGMENT_SIZE);
            )*
            return (trees, max_pages_list, page_sizes);
        }
    };
}

with_levels!{
    L1, LEVEL_1;
    L2, LEVEL_2;
    L3, LEVEL_3;
    L4, LEVEL_4;
}

pub struct LSMTree {
    level_m: BPlusTree,
    trees: LevelTrees,
    // use Vec here for convenience
    max_sizes: Vec<usize>,
    page_sizes: Vec<usize>,
}

unsafe impl Send for LSMTree {}
unsafe impl Sync for LSMTree {}

impl LSMTree {
    pub fn new(neb_client: &Arc<AsyncClient>) -> Arc<Self> {
        let (trees, max_sizes, page_sizes) = init_lsm_level_trees(neb_client);
        let lsm_tree = Arc::new(LSMTree {
            level_m: BPlusTree::new(neb_client),
            trees,
            max_sizes,
            page_sizes,
        });
        let tree_clone = lsm_tree.clone();
        thread::spawn(move || {
            tree_clone.sentinel();
        });
        lsm_tree
    }

    pub fn insert(&self, mut key: EntryKey, id: &Id) -> Result<(), ()> {
        key_with_id(&mut key, id);
        self.level_m.insert(&key).map_err(|e| ())
    }

    pub fn remove(&self, mut key: EntryKey, id: &Id) -> Result<bool, ()> {
        key_with_id(&mut key, id);
        let m_deleted = self.level_m.remove(&key).map_err(|e| ())?;
        let levels_deleted = self
            .trees
            .iter()
            .map(|tree| tree.mark_deleted(&key))
            .collect_vec() // collect here to prevent short circuit
            .into_iter()
            .any(|d| d);
        Ok(m_deleted || levels_deleted)
    }

    pub fn seek(&self, mut key: EntryKey, ordering: Ordering) -> LSMTreeCursor {
        match ordering {
            Ordering::Forward => key_with_id(&mut key, &Id::unit_id()),
            Ordering::Backward => key_with_id(&mut key, &Id::new(::std::u64::MAX, ::std::u64::MAX)),
        };
        let mut cursors = vec![self.level_m.seek(&key, ordering).unwrap()];
        for tree in &self.trees {
            cursors.push(tree.seek(&key, ordering));
        }
        return LSMTreeCursor::new(
            cursors,
            self.trees.iter().map(|t| t.tombstones()).collect_vec(),
        );
    }

    fn sentinel(&self) {
        self.check_and_merge(
            LEVEL_M_MAX_ELEMENTS_COUNT,
            self.page_sizes[0],
            &mut BTreeSet::new(),
            &self.level_m,
            &*self.trees[0],
        );
        for i in 0..self.trees.len() - 1 {
            let upper = &*self.trees[i];
            let lower = &*self.trees[i + 1];
            let upper_tombstons_ref = upper.tombstones();
            let mut upper_tombstones = upper_tombstons_ref.write();
            self.check_and_merge(
                self.max_sizes[i],
                self.page_sizes[i + 1],
                &mut *upper_tombstones,
                upper,
                lower,
            );
        }
        thread::sleep(Duration::from_millis(100));
    }

    fn check_and_merge<U, L>(
        &self,
        max_elements: usize,
        upper_page_size: usize,
        upper_tombstones: &mut TombstonesInner,
        upper_level: &U,
        lower_level: &L,
    ) where
        U: MergeableTree + ?Sized,
        L: SSLevelTree + ?Sized,
    {
        let elements = upper_level.elements();
        if elements > max_elements {
            debug!("upper level have elements {} exceeds {}, start level merging", elements, max_elements);
            let entries_to_merge = upper_page_size;
            let guard = upper_level.prepare_level_merge();
            let mut pages = vec![guard.last_page()];
            let mut collected_entries = pages.last().unwrap().keys().len();
            while collected_entries < entries_to_merge {
                let next_page = pages.last().unwrap().next();
                collected_entries += next_page.keys().len();
                pages.push(next_page);
            }
            let mut entries = vec![];
            for page in &pages {
                entries.append(&mut Vec::from(page.keys()));
            }
            debug!("going to merge {} entries", entries.len());
            lower_level.merge(entries.as_mut_slice(), upper_tombstones);
            guard.remove_pages(pages.iter().map(|p| p.keys()).collect_vec().as_slice())
        }
    }
}

pub struct LSMTreeCursor {
    level_cursors: Vec<Box<Cursor>>,
    tombstones: Vec<Arc<Tombstones>>,
}

impl LSMTreeCursor {
    fn new(cursors: Vec<Box<Cursor>>, tombstones: Vec<Arc<Tombstones>>) -> Self {
        LSMTreeCursor {
            tombstones,
            level_cursors: cursors,
        }
    }

    fn next_candidate(&mut self) -> (bool, usize) {
        let min_tree = self
            .level_cursors
            .iter()
            .enumerate()
            .map(|(i, cursor)| (i, cursor.current()))
            .filter_map(|(i, current)| current.map(|current_val| (i, current_val)))
            .min_by_key(|(i, val)| *val)
            .map(|(id, _)| id);
        if let Some(id) = min_tree {
            let min_has_next = self.level_cursors[id].next();
            if !min_has_next {
                let next = self
                    .level_cursors
                    .iter()
                    .enumerate()
                    .filter_map(|(level, cursor)| cursor.current().map(|key| (id, key)))
                    .min_by_key(|(level, key)| *key);
                if let Some((id, _)) = next {
                    return (true, id);
                }
            } else {
                return (true, id);
            }
        }
        return (false, 0);
    }
}

impl Cursor for LSMTreeCursor {
    fn next(&mut self) -> bool {
        loop {
            let (has_next, candidate_level) = self.next_candidate();
            if !has_next {
                break;
            }
            if candidate_level == 0 {
                return has_next;
            }
            let candidate_key = self.level_cursors[candidate_level].current().unwrap();
            if self.tombstones[candidate_level + 1]
                .read()
                .contains(candidate_key)
            {
                // marked in tombstone, skip
                continue;
            }
            return true;
        }
        return false;
    }

    fn current(&self) -> Option<&EntryKey> {
        self.level_cursors.iter().filter_map(|c| c.current()).min()
    }
}
<commit_msg>fix level sizing<commit_after>use super::btree::{BPlusTree, RTCursor as BPlusTreeCursor};
use super::sstable::*;
use super::*;
use client::AsyncClient;
use itertools::Itertools;
use parking_lot::RwLock;
use ram::segs::MAX_SEGMENT_SIZE;
use std::collections::BTreeSet;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use std::{mem, ptr};

const LEVEL_M_MAX_ELEMENTS_COUNT: usize = LEVEL_M * LEVEL_M * LEVEL_M;
const LEVEL_ELEMENTS_MULTIPLIER: usize = 100;
const LEVEL_DIFF_MULTIPLIER: usize = 10;
const LEVEL_M: usize = super::btree::NUM_KEYS;
const LEVEL_1: usize = LEVEL_M * LEVEL_DIFF_MULTIPLIER;
const LEVEL_2: usize = LEVEL_1 * LEVEL_DIFF_MULTIPLIER;
const LEVEL_3: usize = LEVEL_2 * LEVEL_DIFF_MULTIPLIER;
const LEVEL_4: usize = LEVEL_3 * LEVEL_DIFF_MULTIPLIER;

type LevelTrees = Vec<Box<SSLevelTree>>;

macro_rules! with_levels {
    ($($sym:ident, $level_size:ident;)*) => {
        $(
            type $sym = [EntryKey; $level_size];
            impl_sspage_slice!($sym, EntryKey, $level_size);
        )*

        fn init_lsm_level_trees(neb_client: &Arc<AsyncClient>) -> (LevelTrees, Vec<usize>, Vec<usize>) {
            let mut trees = LevelTrees::new();
            let mut max_elements_list = Vec::new();
            let mut max_elements = LEVEL_M_MAX_ELEMENTS_COUNT;
            let mut page_sizes = Vec::new();
            $(
                max_elements *= LEVEL_ELEMENTS_MULTIPLIER;
                trees.push(box LevelTree::<$sym>::new(neb_client));
                max_elements_list.push(max_elements);
                page_sizes.push($level_size);
                const_assert!($level_size * KEY_SIZE <= MAX_SEGMENT_SIZE);
            )*
            return (trees, max_elements_list, page_sizes);
        }
    };
}

with_levels!{
    L1, LEVEL_1;
    L2, LEVEL_2;
    L3, LEVEL_3;
    L4, LEVEL_4;
}

pub struct LSMTree {
    level_m: BPlusTree,
    trees: LevelTrees,
    // use Vec here for convenience
    max_sizes: Vec<usize>,
    page_sizes: Vec<usize>,
}

unsafe impl Send for LSMTree {}
unsafe impl Sync for LSMTree {}

impl LSMTree {
    pub fn new(neb_client: &Arc<AsyncClient>) -> Arc<Self> {
        let (trees, max_sizes, page_sizes) = init_lsm_level_trees(neb_client);
        let lsm_tree = Arc::new(LSMTree {
            level_m: BPlusTree::new(neb_client),
            trees,
            max_sizes,
            page_sizes,
        });
        let tree_clone = lsm_tree.clone();
        thread::spawn(move || {
            tree_clone.sentinel();
        });
        lsm_tree
    }

    pub fn insert(&self, mut key: EntryKey, id: &Id) -> Result<(), ()> {
        key_with_id(&mut key, id);
        self.level_m.insert(&key).map_err(|e| ())
    }

    pub fn remove(&self, mut key: EntryKey, id: &Id) -> Result<bool, ()> {
        key_with_id(&mut key, id);
        let m_deleted = self.level_m.remove(&key).map_err(|e| ())?;
        let levels_deleted = self
            .trees
            .iter()
            .map(|tree| tree.mark_deleted(&key))
            .collect_vec() // collect here to prevent short circuit
            .into_iter()
            .any(|d| d);
        Ok(m_deleted || levels_deleted)
    }

    pub fn seek(&self, mut key: EntryKey, ordering: Ordering) -> LSMTreeCursor {
        match ordering {
            Ordering::Forward => key_with_id(&mut key, &Id::unit_id()),
            Ordering::Backward => key_with_id(&mut key, &Id::new(::std::u64::MAX, ::std::u64::MAX)),
        };
        let mut cursors = vec![self.level_m.seek(&key, ordering).unwrap()];
        for tree in &self.trees {
            cursors.push(tree.seek(&key, ordering));
        }
        return LSMTreeCursor::new(
            cursors,
            self.trees.iter().map(|t| t.tombstones()).collect_vec(),
        );
    }

    fn sentinel(&self) {
        self.check_and_merge(
            LEVEL_M_MAX_ELEMENTS_COUNT,
            self.page_sizes[0],
            &mut BTreeSet::new(),
            &self.level_m,
            &*self.trees[0],
        );
        for i in 0..self.trees.len() - 1 {
            let upper = &*self.trees[i];
            let lower = &*self.trees[i + 1];
            let upper_tombstons_ref = upper.tombstones();
            let mut upper_tombstones = upper_tombstons_ref.write();
            self.check_and_merge(
                self.max_sizes[i],
                self.page_sizes[i + 1],
                &mut *upper_tombstones,
                upper,
                lower,
            );
        }
        thread::sleep(Duration::from_millis(100));
    }

    fn check_and_merge<U, L>(
        &self,
        max_elements: usize,
        upper_page_size: usize,
        upper_tombstones: &mut TombstonesInner,
        upper_level: &U,
        lower_level: &L,
    ) where
        U: MergeableTree + ?Sized,
        L: SSLevelTree + ?Sized,
    {
        let elements = upper_level.elements();
        if elements > max_elements {
            debug!("upper level have elements {} exceeds {}, start level merging", elements, max_elements);
            let entries_to_merge = upper_page_size;
            let guard = upper_level.prepare_level_merge();
            let mut pages = vec![guard.last_page()];
            let mut collected_entries = pages.last().unwrap().keys().len();
            while collected_entries < entries_to_merge {
                let next_page = pages.last().unwrap().next();
                collected_entries += next_page.keys().len();
                pages.push(next_page);
            }
            let mut entries = vec![];
            for page in &pages {
                entries.append(&mut Vec::from(page.keys()));
            }
            debug!("going to merge {} entries", entries.len());
            lower_level.merge(entries.as_mut_slice(), upper_tombstones);
            guard.remove_pages(pages.iter().map(|p| p.keys()).collect_vec().as_slice())
        }
    }
}

pub struct LSMTreeCursor {
    level_cursors: Vec<Box<Cursor>>,
    tombstones: Vec<Arc<Tombstones>>,
}

impl LSMTreeCursor {
    fn new(cursors: Vec<Box<Cursor>>, tombstones: Vec<Arc<Tombstones>>) -> Self {
        LSMTreeCursor {
            tombstones,
            level_cursors: cursors,
        }
    }

    fn next_candidate(&mut self) -> (bool, usize) {
        let min_tree = self
            .level_cursors
            .iter()
            .enumerate()
            .map(|(i, cursor)| (i, cursor.current()))
            .filter_map(|(i, current)| current.map(|current_val| (i, current_val)))
            .min_by_key(|(i, val)| *val)
            .map(|(id, _)| id);
        if let Some(id) = min_tree {
            let min_has_next = self.level_cursors[id].next();
            if !min_has_next {
                let next = self
                    .level_cursors
                    .iter()
                    .enumerate()
                    .filter_map(|(level, cursor)| cursor.current().map(|key| (id, key)))
                    .min_by_key(|(level, key)| *key);
                if let Some((id, _)) = next {
                    return (true, id);
                }
            } else {
                return (true, id);
            }
        }
        return (false, 0);
    }
}

impl Cursor for LSMTreeCursor {
    fn next(&mut self) -> bool {
        loop {
            let (has_next, candidate_level) = self.next_candidate();
            if !has_next {
                break;
            }
            if candidate_level == 0 {
                return has_next;
            }
            let candidate_key = self.level_cursors[candidate_level].current().unwrap();
            if self.tombstones[candidate_level + 1]
                .read()
                .contains(candidate_key)
            {
                // marked in tombstone, skip
                continue;
            }
            return true;
        }
        return false;
    }

    fn current(&self) -> Option<&EntryKey> {
        self.level_cursors.iter().filter_map(|c| c.current()).min()
    }
}
<|endoftext|>