// codesnip-guard: DarySegmentTree #[cfg_attr(any(),rustfmt::skip)]pub use self::dary_segment_tree::{DarySegmentTreeAddI32,DarySegmentTreeAddI64,DarySegmentTreeMaxI32,DarySegmentTreeMaxI64,DarySegmentTreeMinI32,DarySegmentTreeMinI64};#[cfg_attr(any(),rustfmt::skip)]mod dary_segment_tree{#[cfg(target_arch="x86_64")]use super::simd;use super::{RangeBoundsExt,SimdBackend,simd_backend};use std::ops::RangeBounds;#[repr(C,align(64))]#[derive(Clone,Debug)]struct Block([T;B]);macro_rules!define_dary_segment_tree{($name:ident,$doc:literal,$value:ty,$branch:expr,$unit:expr,$operation:ident,$backend:expr,$sum:literal,$reduce_avx2:ident,$reduce_range_avx2:ident,$reduce_avx512:ident,$reduce_range_avx512:ident)=>{#[doc=$doc]#[derive(Clone,Debug)]pub struct$name{levels:Vec>>,len:usize,#[cfg(target_arch="x86_64")]backend:SimdBackend,}impl$name{pub fn new(len:usize)->Self{let mut levels=Vec::new();let mut current=len.max(1);loop{levels.push(vec![Block([$unit;$branch]);current.div_ceil($branch)]);if current==1{break;}current=current.div_ceil($branch);}Self{levels,len,#[cfg(target_arch="x86_64")]backend:$backend,}}pub fn from_vec(values:Vec<$value>)->Self{Self::build(values,$backend)}#[inline]pub fn len(&self)->usize{self.len}#[inline]pub fn is_empty(&self)->bool{self.len==0}#[inline]pub fn set(&mut self,index:usize,value:$value){assert!(index$value{assert!(index(&self,range:R)->$value where R:RangeBounds,{let range=range.to_range_bounded(0,self.len).expect("invalid range");#[cfg(target_arch="x86_64")]return match self.backend{SimdBackend::Scalar=>{self.fold_by(range.start,range.end,Self::reduce_range_scalar)}SimdBackend::Avx2=>unsafe{self.fold_avx2(range.start,range.end)},SimdBackend::Avx512=>unsafe{self.fold_avx512(range.start,range.end)},};#[cfg(not(target_arch="x86_64"))]self.fold_by(range.start,range.end,Self::reduce_range_scalar)}#[inline]pub fn fold_all(&self)->$value{self.levels.last().unwrap()[0].0[0]}fn build(values:Vec<$value>,backend:SimdBackend)->Self{let _=&backend;let len=values.len();let mut current=if values.is_empty(){vec![$unit]}else{values};let mut levels=Vec::new();loop{let blocks:Vec<_> =current.chunks($branch).map(|chunk|{let mut values=[$unit;$branch];values[..chunk.len()].copy_from_slice(chunk);Block(values)}).collect();if current.len()==1{levels.push(blocks);break;}current=blocks.iter().map(|block|Self::reduce_scalar(&block.0)).collect();levels.push(blocks);}Self{levels,len,#[cfg(target_arch="x86_64")]backend,}}#[inline]fn set_value(&mut self,index:usize,value:$value){if self.levels[0][index/$branch].0[index%$branch]==value{return;}if$sum{let delta=value.wrapping_sub(self.levels[0][index/$branch].0[index%$branch]);let mut index=index;for level in&mut self.levels{let current=&mut level[index/$branch].0[index%$branch];*current=current.wrapping_add(delta);index/=$branch;}return;}#[cfg(target_arch="x86_64")]match self.backend{SimdBackend::Scalar=>self.set_by(index,value,Self::reduce_scalar),SimdBackend::Avx2=>unsafe{self.set_avx2(index,value)},SimdBackend::Avx512=>unsafe{self.set_avx512(index,value)},}#[cfg(not(target_arch="x86_64"))]self.set_by(index,value,Self::reduce_scalar);}#[inline(always)]fn reduce_scalar(values:&[$value;$branch])->$value{let mut result=values[0];for&value in&values[1..]{result=result.$operation(value);}result}#[inline(always)]fn reduce_range_scalar(values:&[$value;$branch],start:usize,end:usize)->$value{values[start..end].iter().copied().reduce(<$value>::$operation).unwrap_or($unit)}#[inline(always)]fn set_by(&mut self,mut index:usize,value:$value,mut reduce:F)where F:FnMut(&[$value;$branch])->$value,{self.levels[0][index/$branch].0[index%$branch]=value;for level in 0..self.levels.len()-1{let block=index/$branch;let aggregate=reduce(&self.levels[level][block].0);index=block;let parent=&mut self.levels[level+1][index/$branch].0[index%$branch];if*parent==aggregate{break;}*parent=aggregate;}}#[inline(always)]fn fold_by(&self,mut left:usize,mut right:usize,mut reduce:F)->$value where F:FnMut(&[$value;$branch],usize,usize)->$value,{let mut result:$value=$unit;for level in&self.levels{if left>=right{break;}let first=left/$branch;let last=(right-1)/$branch;if first==last{return result.$operation(reduce(&level[first].0,left%$branch,(right-1)%$branch+1,));}if left%$branch!=0{result=result.$operation(reduce(&level[first].0,left%$branch,$branch));left=(first+1)*$branch;}if right%$branch!=0{result=result.$operation(reduce(&level[last].0,0,right%$branch));right=last*$branch;}left/=$branch;right/=$branch;}result}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]unsafe fn set_avx2(&mut self,index:usize,value:$value){self.set_by(index,value,|values|unsafe{simd::$reduce_avx2(values)});}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]unsafe fn fold_avx2(&self,left:usize,right:usize)->$value{self.fold_by(left,right,|values,start,end|unsafe{simd::$reduce_range_avx2(values,start,end)})}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]unsafe fn set_avx512(&mut self,index:usize,value:$value){self.set_by(index,value,|values|unsafe{simd::$reduce_avx512(values)});}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]unsafe fn fold_avx512(&self,left:usize,right:usize)->$value{self.fold_by(left,right,|values,start,end|unsafe{simd::$reduce_range_avx512(values,start,end)})}}};}define_dary_segment_tree!(DarySegmentTreeMinI32,"A cache-line-oriented d-ary point-update segment tree for range minima over `i32`.",i32,16,i32::MAX,min,simd_backend(),false,minimum_i32x16_avx2,minimum_range_i32x16_avx2,minimum_i32x16_avx512,minimum_range_i32x16_avx512);define_dary_segment_tree!(DarySegmentTreeMaxI32,"A cache-line-oriented d-ary point-update segment tree for range maxima over `i32`.",i32,16,i32::MIN,max,simd_backend(),false,maximum_i32x16_avx2,maximum_range_i32x16_avx2,maximum_i32x16_avx512,maximum_range_i32x16_avx512);define_dary_segment_tree!(DarySegmentTreeMinI64,"A cache-line-oriented d-ary point-update segment tree for range minima over `i64`.",i64,8,i64::MAX,min,simd_backend(),false,minimum_i64x8_avx2,minimum_range_i64x8_avx2,minimum_i64x8_avx512,minimum_range_i64x8_avx512);define_dary_segment_tree!(DarySegmentTreeMaxI64,"A cache-line-oriented d-ary point-update segment tree for range maxima over `i64`.",i64,8,i64::MIN,max,simd_backend(),false,maximum_i64x8_avx2,maximum_range_i64x8_avx2,maximum_i64x8_avx512,maximum_range_i64x8_avx512);define_dary_segment_tree!(DarySegmentTreeAddI32,"A cache-line-oriented d-ary point-update segment tree for wrapping range sums over `i32`.",i32,16,0,wrapping_add,simd_backend(),true,sum_i32x16_avx2,sum_range_i32x16_avx2,sum_i32x16_avx512,sum_range_i32x16_avx512);define_dary_segment_tree!(DarySegmentTreeAddI64,"A cache-line-oriented d-ary point-update segment tree for wrapping range sums over `i64`.",i64,8,0,wrapping_add,simd_backend(),true,sum_i64x8_avx2,sum_range_i64x8_avx2,sum_i64x8_avx512,sum_range_i64x8_avx512);} // codesnip-guard: _simd #[cfg_attr(any(),rustfmt::skip)]pub mod simd{#![allow(unsafe_op_in_unsafe_fn)]#[cfg(target_arch="x86_64")]use std::arch::x86_64::*;#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn first_ge_u16x32_avx2(values:&[u16;32],key:u16)->usize{let sign=_mm256_set1_epi16(i16::MIN);let key=_mm256_xor_si256(_mm256_set1_epi16(key as i16),sign);let low=_mm256_xor_si256(_mm256_loadu_si256(values.as_ptr().cast()),sign);let high=_mm256_xor_si256(_mm256_loadu_si256(values.as_ptr().add(16).cast()),sign);let low=_mm256_movemask_epi8(_mm256_cmpgt_epi16(key,low))as u32 as u64;let high=_mm256_movemask_epi8(_mm256_cmpgt_epi16(key,high))as u32 as u64;(!(low|high<<32)).trailing_zeros()as usize/2}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn first_gt_u16x32_avx2(values:&[u16;32],key:u16)->usize{let sign=_mm256_set1_epi16(i16::MIN);let key=_mm256_xor_si256(_mm256_set1_epi16(key as i16),sign);let low=_mm256_xor_si256(_mm256_loadu_si256(values.as_ptr().cast()),sign);let high=_mm256_xor_si256(_mm256_loadu_si256(values.as_ptr().add(16).cast()),sign);let low=_mm256_movemask_epi8(_mm256_cmpgt_epi16(low,key))as u32 as u64;let high=_mm256_movemask_epi8(_mm256_cmpgt_epi16(high,key))as u32 as u64;(low|high<<32).trailing_zeros()as usize/2}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn first_ge_u32x16_avx2(values:&[u32;16],key:u32)->usize{let sign=_mm256_set1_epi32(i32::MIN);let key=_mm256_xor_si256(_mm256_set1_epi32(key as i32),sign);let low=_mm256_xor_si256(_mm256_loadu_si256(values.as_ptr().cast()),sign);let high=_mm256_xor_si256(_mm256_loadu_si256(values.as_ptr().add(8).cast()),sign);let low=_mm256_movemask_ps(_mm256_castsi256_ps(_mm256_cmpgt_epi32(key,low)));let high=_mm256_movemask_ps(_mm256_castsi256_ps(_mm256_cmpgt_epi32(key,high)));let mask=((!low as u32)&0xff)|(((!high as u32)&0xff)<<8);(mask as u16).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn first_gt_u32x16_avx2(values:&[u32;16],key:u32)->usize{let sign=_mm256_set1_epi32(i32::MIN);let key=_mm256_xor_si256(_mm256_set1_epi32(key as i32),sign);let low=_mm256_xor_si256(_mm256_loadu_si256(values.as_ptr().cast()),sign);let high=_mm256_xor_si256(_mm256_loadu_si256(values.as_ptr().add(8).cast()),sign);let low=_mm256_movemask_ps(_mm256_castsi256_ps(_mm256_cmpgt_epi32(low,key)));let high=_mm256_movemask_ps(_mm256_castsi256_ps(_mm256_cmpgt_epi32(high,key)));let mask=low as u32|((high as u32)<<8);(mask as u16).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn first_ge_u64x8_avx2(values:&[u64;8],key:u64)->usize{let sign=_mm256_set1_epi64x(i64::MIN);let key=_mm256_xor_si256(_mm256_set1_epi64x(key as i64),sign);let low=_mm256_xor_si256(_mm256_loadu_si256(values.as_ptr().cast()),sign);let high=_mm256_xor_si256(_mm256_loadu_si256(values.as_ptr().add(4).cast()),sign);let low=_mm256_movemask_pd(_mm256_castsi256_pd(_mm256_cmpgt_epi64(key,low)));let high=_mm256_movemask_pd(_mm256_castsi256_pd(_mm256_cmpgt_epi64(key,high)));let mask=((!low as u32)&0x0f)|(((!high as u32)&0x0f)<<4);(mask as u8).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn first_gt_u64x8_avx2(values:&[u64;8],key:u64)->usize{let sign=_mm256_set1_epi64x(i64::MIN);let key=_mm256_xor_si256(_mm256_set1_epi64x(key as i64),sign);let low=_mm256_xor_si256(_mm256_loadu_si256(values.as_ptr().cast()),sign);let high=_mm256_xor_si256(_mm256_loadu_si256(values.as_ptr().add(4).cast()),sign);let low=_mm256_movemask_pd(_mm256_castsi256_pd(_mm256_cmpgt_epi64(low,key)));let high=_mm256_movemask_pd(_mm256_castsi256_pd(_mm256_cmpgt_epi64(high,key)));let mask=low as u32|((high as u32)<<4);(mask as u8).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f,avx512bw")]#[inline]pub unsafe fn first_ge_u16x32_avx512(values:&[u16;32],key:u16)->usize{let values=_mm512_loadu_si512(values.as_ptr().cast());let key=_mm512_set1_epi16(key as i16);(!_mm512_cmplt_epu16_mask(values,key)).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f,avx512bw")]#[inline]pub unsafe fn first_gt_u16x32_avx512(values:&[u16;32],key:u16)->usize{let values=_mm512_loadu_si512(values.as_ptr().cast());let key=_mm512_set1_epi16(key as i16);_mm512_cmpgt_epu16_mask(values,key).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn first_ge_u32x16_avx512(values:&[u32;16],key:u32)->usize{let values=_mm512_loadu_si512(values.as_ptr().cast());let key=_mm512_set1_epi32(key as i32);(!_mm512_cmplt_epu32_mask(values,key)).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn first_gt_u32x16_avx512(values:&[u32;16],key:u32)->usize{let values=_mm512_loadu_si512(values.as_ptr().cast());let key=_mm512_set1_epi32(key as i32);_mm512_cmpgt_epu32_mask(values,key).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn first_ge_u64x8_avx512(values:&[u64;8],key:u64)->usize{let values=_mm512_loadu_si512(values.as_ptr().cast());let key=_mm512_set1_epi64(key as i64);(!_mm512_cmplt_epu64_mask(values,key)).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn first_gt_u64x8_avx512(values:&[u64;8],key:u64)->usize{let values=_mm512_loadu_si512(values.as_ptr().cast());let key=_mm512_set1_epi64(key as i64);_mm512_cmpgt_epu64_mask(values,key).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn add_suffix_u32x16_avx2(values:&mut[u32;16],index:usize,delta:u32){let index=_mm256_set1_epi32(index as i32-1);let delta=_mm256_set1_epi32(delta as i32);let low_mask=_mm256_cmpgt_epi32(_mm256_setr_epi32(0,1,2,3,4,5,6,7),index);let high_mask=_mm256_cmpgt_epi32(_mm256_setr_epi32(8,9,10,11,12,13,14,15),index);let low=_mm256_add_epi32(_mm256_loadu_si256(values.as_ptr().cast()),_mm256_and_si256(delta,low_mask));let high=_mm256_add_epi32(_mm256_loadu_si256(values.as_ptr().add(8).cast()),_mm256_and_si256(delta,high_mask));_mm256_storeu_si256(values.as_mut_ptr().cast(),low);_mm256_storeu_si256(values.as_mut_ptr().add(8).cast(),high);}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn add_suffix_u64x8_avx2(values:&mut[u64;8],index:usize,delta:u64){let index=_mm256_set1_epi64x(index as i64-1);let delta=_mm256_set1_epi64x(delta as i64);let low_mask=_mm256_cmpgt_epi64(_mm256_setr_epi64x(0,1,2,3),index);let high_mask=_mm256_cmpgt_epi64(_mm256_setr_epi64x(4,5,6,7),index);let low=_mm256_add_epi64(_mm256_loadu_si256(values.as_ptr().cast()),_mm256_and_si256(delta,low_mask));let high=_mm256_add_epi64(_mm256_loadu_si256(values.as_ptr().add(4).cast()),_mm256_and_si256(delta,high_mask));_mm256_storeu_si256(values.as_mut_ptr().cast(),low);_mm256_storeu_si256(values.as_mut_ptr().add(4).cast(),high);}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn add_suffix_u32x16_avx512(values:&mut[u32;16],index:usize,delta:u32){let values_vector=_mm512_loadu_si512(values.as_ptr().cast());let values_vector=_mm512_mask_add_epi32(values_vector,u16::MAX<usize{let low=_mm256_loadu_si256(values.as_ptr().cast());let high=_mm256_loadu_si256(values.as_ptr().add(8).cast());let mut maximum=_mm256_max_epu32(low,high);maximum=_mm256_max_epu32(maximum,_mm256_permute2x128_si256::<0x01>(maximum,maximum));maximum=_mm256_max_epu32(maximum,_mm256_shuffle_epi32::<0x4e>(maximum));maximum=_mm256_max_epu32(maximum,_mm256_shuffle_epi32::<0xb1>(maximum));let maximum=_mm256_set1_epi32(_mm256_extract_epi32::<0>(maximum));let low=_mm256_movemask_ps(_mm256_castsi256_ps(_mm256_cmpeq_epi32(low,maximum)));let high=_mm256_movemask_ps(_mm256_castsi256_ps(_mm256_cmpeq_epi32(high,maximum)));((low as u32|((high as u32)<<8))as u16).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn max_index_u32x16_avx512(values:&[u32;16])->usize{let values=_mm512_loadu_si512(values.as_ptr().cast());let maximum=_mm512_set1_epi32(_mm512_reduce_max_epu32(values)as i32);_mm512_cmpeq_epi32_mask(values,maximum).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]unsafe fn max_epu64(left:__m256i,right:__m256i)->__m256i{let sign=_mm256_set1_epi64x(i64::MIN);let greater=_mm256_cmpgt_epi64(_mm256_xor_si256(left,sign),_mm256_xor_si256(right,sign));_mm256_blendv_epi8(right,left,greater)}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn max_index_u64x8_avx2(values:&[u64;8])->usize{let sign=_mm256_set1_epi64x(i64::MIN);let low=_mm256_xor_si256(_mm256_loadu_si256(values.as_ptr().cast()),sign);let high=_mm256_xor_si256(_mm256_loadu_si256(values.as_ptr().add(4).cast()),sign);let mut maximum=max_i64x4(low,high);maximum=max_i64x4(maximum,_mm256_permute4x64_epi64::<0x4e>(maximum));maximum=max_i64x4(maximum,_mm256_permute4x64_epi64::<0xb1>(maximum));let low=_mm256_movemask_pd(_mm256_castsi256_pd(_mm256_cmpeq_epi64(low,maximum)));let high=_mm256_movemask_pd(_mm256_castsi256_pd(_mm256_cmpeq_epi64(high,maximum)));((low as u32|((high as u32)<<4))as u8).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn max_index_u64x8_avx512(values:&[u64;8])->usize{let values=_mm512_loadu_si512(values.as_ptr().cast());let maximum=_mm512_set1_epi64(_mm512_reduce_max_epu64(values)as i64);_mm512_cmpeq_epi64_mask(values,maximum).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn max_index_u128x4_avx2(low:&[u64;4],high:&[u64;4])->usize{let low=_mm256_loadu_si256(low.as_ptr().cast());let high=_mm256_loadu_si256(high.as_ptr().cast());let mut maximum_high=high;maximum_high=max_epu64(maximum_high,_mm256_permute4x64_epi64::<0x4e>(maximum_high));maximum_high=max_epu64(maximum_high,_mm256_permute4x64_epi64::<0xb1>(maximum_high));let high_equal=_mm256_cmpeq_epi64(high,maximum_high);let high_mask=_mm256_movemask_pd(_mm256_castsi256_pd(high_equal))as u32&15;if high_mask.is_power_of_two(){return high_mask.trailing_zeros()as usize;}let mut maximum_low=_mm256_and_si256(low,high_equal);maximum_low=max_epu64(maximum_low,_mm256_permute4x64_epi64::<0x4e>(maximum_low));maximum_low=max_epu64(maximum_low,_mm256_permute4x64_epi64::<0xb1>(maximum_low));let both=_mm256_and_si256(high_equal,_mm256_cmpeq_epi64(low,maximum_low));(_mm256_movemask_pd(_mm256_castsi256_pd(both))as u32&15).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2,avx512f,avx512vl")]#[inline]pub unsafe fn max_index_u128x4_avx512(low:&[u64;4],high:&[u64;4])->usize{let low=_mm256_loadu_si256(low.as_ptr().cast());let high=_mm256_loadu_si256(high.as_ptr().cast());let mut maximum_high=high;maximum_high=_mm256_max_epu64(maximum_high,_mm256_permute4x64_epi64::<0x4e>(maximum_high));maximum_high=_mm256_max_epu64(maximum_high,_mm256_permute4x64_epi64::<0xb1>(maximum_high));let high_equal=_mm256_cmpeq_epi64(high,maximum_high);let high_mask=_mm256_movemask_pd(_mm256_castsi256_pd(high_equal))as u32&15;if high_mask.is_power_of_two(){return high_mask.trailing_zeros()as usize;}let mut maximum_low=_mm256_and_si256(low,high_equal);maximum_low=_mm256_max_epu64(maximum_low,_mm256_permute4x64_epi64::<0x4e>(maximum_low));maximum_low=_mm256_max_epu64(maximum_low,_mm256_permute4x64_epi64::<0xb1>(maximum_low));let both=_mm256_and_si256(high_equal,_mm256_cmpeq_epi64(low,maximum_low));(_mm256_movemask_pd(_mm256_castsi256_pd(both))as u32&15).trailing_zeros()as usize}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]unsafe fn reduce_min_i32x8(mut values:__m256i)->i32{values=_mm256_min_epi32(values,_mm256_permute2x128_si256::<0x01>(values,values));values=_mm256_min_epi32(values,_mm256_shuffle_epi32::<0x4e>(values));values=_mm256_min_epi32(values,_mm256_shuffle_epi32::<0xb1>(values));_mm256_extract_epi32::<0>(values)}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]unsafe fn reduce_max_i32x8(mut values:__m256i)->i32{values=_mm256_max_epi32(values,_mm256_permute2x128_si256::<0x01>(values,values));values=_mm256_max_epi32(values,_mm256_shuffle_epi32::<0x4e>(values));values=_mm256_max_epi32(values,_mm256_shuffle_epi32::<0xb1>(values));_mm256_extract_epi32::<0>(values)}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]unsafe fn reduce_sum_i32x8(mut values:__m256i)->i32{values=_mm256_add_epi32(values,_mm256_permute2x128_si256::<0x01>(values,values));values=_mm256_add_epi32(values,_mm256_shuffle_epi32::<0x4e>(values));values=_mm256_add_epi32(values,_mm256_shuffle_epi32::<0xb1>(values));_mm256_extract_epi32::<0>(values)}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn minimum_i32x16_avx2(values:&[i32;16])->i32{let low=_mm256_loadu_si256(values.as_ptr().cast());let high=_mm256_loadu_si256(values.as_ptr().add(8).cast());reduce_min_i32x8(_mm256_min_epi32(low,high))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn maximum_i32x16_avx2(values:&[i32;16])->i32{let low=_mm256_loadu_si256(values.as_ptr().cast());let high=_mm256_loadu_si256(values.as_ptr().add(8).cast());reduce_max_i32x8(_mm256_max_epi32(low,high))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn sum_i32x16_avx2(values:&[i32;16])->i32{let low=_mm256_loadu_si256(values.as_ptr().cast());let high=_mm256_loadu_si256(values.as_ptr().add(8).cast());reduce_sum_i32x8(_mm256_add_epi32(low,high))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]unsafe fn range_mask_i32x8(start:usize,end:usize,offset:i32)->__m256i{let lanes=_mm256_setr_epi32(offset,offset+1,offset+2,offset+3,offset+4,offset+5,offset+6,offset+7);_mm256_and_si256(_mm256_cmpgt_epi32(lanes,_mm256_set1_epi32(start as i32-1)),_mm256_cmpgt_epi32(_mm256_set1_epi32(end as i32),lanes))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn minimum_range_i32x16_avx2(values:&[i32;16],start:usize,end:usize)->i32{let unit=_mm256_set1_epi32(i32::MAX);let low=_mm256_blendv_epi8(unit,_mm256_loadu_si256(values.as_ptr().cast()),range_mask_i32x8(start,end,0));let high=_mm256_blendv_epi8(unit,_mm256_loadu_si256(values.as_ptr().add(8).cast()),range_mask_i32x8(start,end,8));reduce_min_i32x8(_mm256_min_epi32(low,high))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn maximum_range_i32x16_avx2(values:&[i32;16],start:usize,end:usize)->i32{let unit=_mm256_set1_epi32(i32::MIN);let low=_mm256_blendv_epi8(unit,_mm256_loadu_si256(values.as_ptr().cast()),range_mask_i32x8(start,end,0));let high=_mm256_blendv_epi8(unit,_mm256_loadu_si256(values.as_ptr().add(8).cast()),range_mask_i32x8(start,end,8));reduce_max_i32x8(_mm256_max_epi32(low,high))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn sum_range_i32x16_avx2(values:&[i32;16],start:usize,end:usize)->i32{let low=_mm256_and_si256(_mm256_loadu_si256(values.as_ptr().cast()),range_mask_i32x8(start,end,0));let high=_mm256_and_si256(_mm256_loadu_si256(values.as_ptr().add(8).cast()),range_mask_i32x8(start,end,8));reduce_sum_i32x8(_mm256_add_epi32(low,high))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn minimum_i32x16_avx512(values:&[i32;16])->i32{_mm512_reduce_min_epi32(_mm512_loadu_si512(values.as_ptr().cast()))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn maximum_i32x16_avx512(values:&[i32;16])->i32{_mm512_reduce_max_epi32(_mm512_loadu_si512(values.as_ptr().cast()))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn sum_i32x16_avx512(values:&[i32;16])->i32{_mm512_reduce_add_epi32(_mm512_loadu_si512(values.as_ptr().cast()))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn minimum_range_i32x16_avx512(values:&[i32;16],start:usize,end:usize)->i32{let mask=(u16::MAX<>(16-end));_mm512_mask_reduce_min_epi32(mask,_mm512_loadu_si512(values.as_ptr().cast()))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn maximum_range_i32x16_avx512(values:&[i32;16],start:usize,end:usize)->i32{let mask=(u16::MAX<>(16-end));_mm512_mask_reduce_max_epi32(mask,_mm512_loadu_si512(values.as_ptr().cast()))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn sum_range_i32x16_avx512(values:&[i32;16],start:usize,end:usize)->i32{let mask=(u16::MAX<>(16-end));_mm512_mask_reduce_add_epi32(mask,_mm512_loadu_si512(values.as_ptr().cast()))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]unsafe fn min_i64x4(left:__m256i,right:__m256i)->__m256i{_mm256_blendv_epi8(left,right,_mm256_cmpgt_epi64(left,right))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]unsafe fn max_i64x4(left:__m256i,right:__m256i)->__m256i{_mm256_blendv_epi8(right,left,_mm256_cmpgt_epi64(left,right))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]unsafe fn reduce_min_i64x4(mut values:__m256i)->i64{values=min_i64x4(values,_mm256_permute4x64_epi64::<0x4e>(values));values=min_i64x4(values,_mm256_permute4x64_epi64::<0xb1>(values));_mm256_extract_epi64::<0>(values)}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]unsafe fn reduce_max_i64x4(mut values:__m256i)->i64{values=max_i64x4(values,_mm256_permute4x64_epi64::<0x4e>(values));values=max_i64x4(values,_mm256_permute4x64_epi64::<0xb1>(values));_mm256_extract_epi64::<0>(values)}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]unsafe fn reduce_sum_i64x4(mut values:__m256i)->i64{values=_mm256_add_epi64(values,_mm256_permute4x64_epi64::<0x4e>(values));values=_mm256_add_epi64(values,_mm256_permute4x64_epi64::<0xb1>(values));_mm256_extract_epi64::<0>(values)}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn minimum_i64x8_avx2(values:&[i64;8])->i64{let low=_mm256_loadu_si256(values.as_ptr().cast());let high=_mm256_loadu_si256(values.as_ptr().add(4).cast());reduce_min_i64x4(min_i64x4(low,high))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn maximum_i64x8_avx2(values:&[i64;8])->i64{let low=_mm256_loadu_si256(values.as_ptr().cast());let high=_mm256_loadu_si256(values.as_ptr().add(4).cast());reduce_max_i64x4(max_i64x4(low,high))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn sum_i64x8_avx2(values:&[i64;8])->i64{let low=_mm256_loadu_si256(values.as_ptr().cast());let high=_mm256_loadu_si256(values.as_ptr().add(4).cast());reduce_sum_i64x4(_mm256_add_epi64(low,high))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]unsafe fn range_mask_i64x4(start:usize,end:usize,offset:i64)->__m256i{let lanes=_mm256_setr_epi64x(offset,offset+1,offset+2,offset+3);_mm256_and_si256(_mm256_cmpgt_epi64(lanes,_mm256_set1_epi64x(start as i64-1)),_mm256_cmpgt_epi64(_mm256_set1_epi64x(end as i64),lanes))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn minimum_range_i64x8_avx2(values:&[i64;8],start:usize,end:usize)->i64{let unit=_mm256_set1_epi64x(i64::MAX);let low=_mm256_blendv_epi8(unit,_mm256_loadu_si256(values.as_ptr().cast()),range_mask_i64x4(start,end,0));let high=_mm256_blendv_epi8(unit,_mm256_loadu_si256(values.as_ptr().add(4).cast()),range_mask_i64x4(start,end,4));reduce_min_i64x4(min_i64x4(low,high))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn maximum_range_i64x8_avx2(values:&[i64;8],start:usize,end:usize)->i64{let unit=_mm256_set1_epi64x(i64::MIN);let low=_mm256_blendv_epi8(unit,_mm256_loadu_si256(values.as_ptr().cast()),range_mask_i64x4(start,end,0));let high=_mm256_blendv_epi8(unit,_mm256_loadu_si256(values.as_ptr().add(4).cast()),range_mask_i64x4(start,end,4));reduce_max_i64x4(max_i64x4(low,high))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx2")]#[inline]pub unsafe fn sum_range_i64x8_avx2(values:&[i64;8],start:usize,end:usize)->i64{let low=_mm256_and_si256(_mm256_loadu_si256(values.as_ptr().cast()),range_mask_i64x4(start,end,0));let high=_mm256_and_si256(_mm256_loadu_si256(values.as_ptr().add(4).cast()),range_mask_i64x4(start,end,4));reduce_sum_i64x4(_mm256_add_epi64(low,high))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn minimum_i64x8_avx512(values:&[i64;8])->i64{_mm512_reduce_min_epi64(_mm512_loadu_si512(values.as_ptr().cast()))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn maximum_i64x8_avx512(values:&[i64;8])->i64{_mm512_reduce_max_epi64(_mm512_loadu_si512(values.as_ptr().cast()))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn sum_i64x8_avx512(values:&[i64;8])->i64{_mm512_reduce_add_epi64(_mm512_loadu_si512(values.as_ptr().cast()))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn minimum_range_i64x8_avx512(values:&[i64;8],start:usize,end:usize)->i64{let mask=(u8::MAX<>(8-end));_mm512_mask_reduce_min_epi64(mask,_mm512_loadu_si512(values.as_ptr().cast()))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn maximum_range_i64x8_avx512(values:&[i64;8],start:usize,end:usize)->i64{let mask=(u8::MAX<>(8-end));_mm512_mask_reduce_max_epi64(mask,_mm512_loadu_si512(values.as_ptr().cast()))}#[cfg(target_arch="x86_64")]#[target_feature(enable="avx512f")]#[inline]pub unsafe fn sum_range_i64x8_avx512(values:&[i64;8],start:usize,end:usize)->i64{let mask=(u8::MAX<>(8-end));_mm512_mask_reduce_add_epi64(mask,_mm512_loadu_si512(values.as_ptr().cast()))}} // codesnip-guard: avx_helper #[cfg_attr(any(),rustfmt::skip)]pub use self::avx_helper::{SimdBackend,avx512_enabled,avx512_supported,disable_avx512,enable_avx512,simd_backend};#[cfg_attr(any(),rustfmt::skip)]mod avx_helper{use std::sync::atomic::{AtomicBool,Ordering};#[derive(Copy,Clone,Debug,Eq,PartialEq)]pub enum SimdBackend{Scalar,Avx2,Avx512}static AVX512_ENABLED:AtomicBool=AtomicBool::new(true);#[inline]pub fn disable_avx512(){AVX512_ENABLED.store(false,Ordering::Relaxed);}#[inline]pub fn enable_avx512(){AVX512_ENABLED.store(true,Ordering::Relaxed);}#[inline]pub fn avx512_enabled()->bool{AVX512_ENABLED.load(Ordering::Relaxed)}#[inline]pub fn avx512_supported()->bool{#[cfg(any(target_arch="x86",target_arch="x86_64"))]return is_x86_feature_detected!("avx512f")&&is_x86_feature_detected!("avx512dq")&&is_x86_feature_detected!("avx512cd")&&is_x86_feature_detected!("avx512bw")&&is_x86_feature_detected!("avx512vl");#[cfg(not(any(target_arch="x86",target_arch="x86_64")))]false}#[inline]pub fn simd_backend()->SimdBackend{#[cfg(any(target_arch="x86",target_arch="x86_64"))]{if avx512_enabled()&&avx512_supported(){return SimdBackend::Avx512;}if is_x86_feature_detected!("avx2"){return SimdBackend::Avx2;}}SimdBackend::Scalar}#[macro_export]macro_rules!avx_helper{(@dispatch$backend:path,$kind:ident;$avx512:expr,$avx2:expr,$scalar:expr)=>{{#[cfg(target_arch="x86_64")]{match$backend(){$kind::Avx512=>$avx512,$kind::Avx2=>$avx2,$kind::Scalar=>$scalar,}}#[cfg(not(target_arch="x86_64"))]$scalar}};(@dispatch_avx2_fma$avx2:expr,$scalar:expr)=>{{#[cfg(target_arch="x86_64")]{if is_x86_feature_detected!("avx2")&&is_x86_feature_detected!("fma"){$avx2}else{$scalar}}#[cfg(not(target_arch="x86_64"))]$scalar}};(@avx512$(#[$meta:meta])*$vis:vis fn$name:ident$(<$($T:ident),+>)?($($i:ident:$t:ty),*)->$ret:ty where[$($clauses:tt)*]$body:block)=>{$(#[$meta])*$vis fn$name$(<$($T)*>)?($($i:$t),*)->$ret where$($clauses)*{if$crate::avx512_supported(){$crate::avx_helper!(@def_avx512 fn avx512$(<$($T)*>)?($($i:$t),*)->$ret where[$($clauses)*]$body);unsafe{avx512$(::<$($T),*>)?($($i),*)}}else if is_x86_feature_detected!("avx2"){$crate::avx_helper!(@def_avx2 fn avx2$(<$($T)*>)?($($i:$t),*)->$ret where[$($clauses)*]$body);unsafe{avx2$(::<$($T),*>)?($($i),*)}}else{$body}}};(@avx2$(#[$meta:meta])*$vis:vis fn$name:ident$(<$($T:ident),+>)?($($i:ident:$t:ty),*)->$ret:ty where[$($clauses:tt)*]$body:block)=>{$(#[$meta])*$vis fn$name$(<$($T)*>)?($($i:$t),*)->$ret where$($clauses)*{if is_x86_feature_detected!("avx2"){$crate::avx_helper!(@def_avx2 fn avx2$(<$($T)*>)?($($i:$t),*)->$ret where[$($clauses)*]$body);unsafe{avx2$(::<$($T),*>)?($($i),*)}}else{$body}}};(@def_avx512 fn$name:ident$(<$($T:ident),+>)?($($args:tt)*)->$ret:ty where[$($clauses:tt)*]$body:block)=>{#[target_feature(enable="avx512f,avx512dq,avx512cd,avx512bw,avx512vl")]unsafe fn$name$(<$($T)*>)?($($args)*)->$ret where$($clauses)*$body};(@def_avx2 fn$name:ident$(<$($T:ident),+>)?($($args:tt)*)->$ret:ty where[$($clauses:tt)*]$body:block)=>{#[target_feature(enable="avx2")]unsafe fn$name$(<$($T)*>)?($($args)*)->$ret where$($clauses)*$body};(@$tag:ident$(#[$meta:meta])*$vis:vis fn$name:ident$(<$($T:ident),+>)?($($args:tt)*)->$ret:ty$body:block)=>{$crate::avx_helper!(@$tag$(#[$meta])*$vis fn$name$(<$($T)*>)?($($args)*)->$ret where[]$body);};(@$tag:ident$(#[$meta:meta])*$vis:vis fn$name:ident$(<$($T:ident),+>)?($($args:tt)*)$($t:tt)*)=>{$crate::avx_helper!(@$tag$(#[$meta])*$vis fn$name$(<$($T)*>)?($($args)*)->()$($t)*);};($($t:tt)*)=>{::std::compile_error!($($t)*);}}} // codesnip-guard: bounded #[cfg_attr(any(),rustfmt::skip)]pub use self::bounded::Bounded;#[cfg_attr(any(),rustfmt::skip)]mod bounded{#[doc=" Trait for max/min bounds"]pub trait Bounded:Sized+PartialOrd{fn maximum()->Self;fn minimum()->Self;fn is_maximum(&self)->bool{self==&Self::maximum()}fn is_minimum(&self)->bool{self==&Self::minimum()}fn set_maximum(&mut self){*self=Self::maximum()}fn set_minimum(&mut self){*self=Self::minimum()}}macro_rules!impl_bounded_num{($($t:ident)*)=>{$(impl Bounded for$t{fn maximum()->Self{$t::MAX}fn minimum()->Self{$t::MIN}})*};}impl_bounded_num!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize f32 f64);macro_rules!impl_bounded_tuple{(@impl$($T:ident)*)=>{impl<$($T:Bounded),*>Bounded for($($T,)*){fn maximum()->Self{($(<$T as Bounded>::maximum(),)*)}fn minimum()->Self{($(<$T as Bounded>::minimum(),)*)}}};(@inner$($T:ident)*,)=>{impl_bounded_tuple!(@impl$($T)*);};(@inner$($T:ident)*,$U:ident$($Rest:ident)*)=>{impl_bounded_tuple!(@impl$($T)*);impl_bounded_tuple!(@inner$($T)*$U,$($Rest)*);};($T:ident$($Rest:ident)*)=>{impl_bounded_tuple!(@inner$T,$($Rest)*);};}impl_bounded_tuple!(A B C D E F G H I J);impl Bounded for(){fn maximum()->Self{}fn minimum()->Self{}}impl Bounded for bool{fn maximum()->Self{true}fn minimum()->Self{false}}implBounded for Optionwhere T:Bounded{fn maximum()->Self{Some(::maximum())}fn minimum()->Self{None}}implBounded for std::cmp::Reversewhere T:Bounded{fn maximum()->Self{std::cmp::Reverse(::minimum())}fn minimum()->Self{std::cmp::Reverse(::maximum())}}} // codesnip-guard: discrete_steps #[cfg_attr(any(),rustfmt::skip)]pub use self::discrete_steps::{DiscreteSteps,RangeBoundsExt};#[cfg_attr(any(),rustfmt::skip)]mod discrete_steps{use super::Bounded;use std::{convert::TryFrom,ops::{Bound,Range,RangeBounds,RangeInclusive}};pub trait DiscreteSteps:Clone{fn delta()->Delta;fn steps_between(start:&Self,end:&Self)->Option;fn forward_checked(start:Self,delta:Delta)->Option;fn backward_checked(start:Self,delta:Delta)->Option;fn forward(start:Self,delta:Delta)->Self{Self::forward_checked(start,delta).expect("overflow in `DiscreteSteps::forward`")}fn backward(start:Self,delta:Delta)->Self{Self::backward_checked(start,delta).expect("overflow in `DiscreteSteps::backward`")}fn forward_delta_checked(start:Self)->Option{Self::forward_checked(start,Self::delta())}fn backward_delta_checked(start:Self)->Option{Self::backward_checked(start,Self::delta())}fn forward_delta(start:Self)->Self{Self::forward(start,Self::delta())}fn backward_delta(start:Self)->Self{Self::backward(start,Self::delta())}}macro_rules!impl_discrete_steps_integer{(@common$u_source:ident)=>{fn delta()->$u_source{1}fn forward(start:Self,delta:$u_source)->Self{assert!(Self::forward_checked(start,delta).is_some(),"attempt to add with overflow");start.wrapping_add(delta as Self)}fn backward(start:Self,delta:$u_source)->Self{assert!(Self::backward_checked(start,delta).is_some(),"attempt to subtract with overflow");start.wrapping_sub(delta as Self)}};($u_source:ident$i_source:ident;$($u_narrower:ident$i_narrower:ident),*;$($u_wider:ident$i_wider:ident),*)=>{$(impl DiscreteSteps<$u_source>for$u_narrower{impl_discrete_steps_integer!(@common$u_source);fn steps_between(start:&Self,end:&Self)->Option<$u_source>{if*start<=*end{$u_source::try_from(*end-*start).ok()}else{None}}fn forward_checked(start:Self,delta:$u_source)->Option{Self::try_from(delta).ok().and_then(|delta|start.checked_add(delta))}fn backward_checked(start:Self,delta:$u_source)->Option{Self::try_from(delta).ok().and_then(|delta|start.checked_sub(delta))}}impl DiscreteSteps<$u_source>for$i_narrower{impl_discrete_steps_integer!(@common$u_source);fn steps_between(start:&Self,end:&Self)->Option<$u_source>{if*start<=*end{$u_source::try_from(end.abs_diff(*start)).ok()}else{None}}fn forward_checked(start:Self,delta:$u_source)->Option{$u_narrower::try_from(delta).ok().and_then(|delta|{let wrapped=start.wrapping_add(delta as Self);if wrapped>=start{Some(wrapped)}else{None}})}fn backward_checked(start:Self,delta:$u_source)->Option{$u_narrower::try_from(delta).ok().and_then(|delta|{let wrapped=start.wrapping_sub(delta as Self);if wrapped<=start{Some(wrapped)}else{None}})}})*$(impl DiscreteSteps<$u_source>for$u_wider{impl_discrete_steps_integer!(@common$u_source);fn steps_between(start:&Self,end:&Self)->Option<$u_source>{if*start<=*end{$u_source::try_from(*end-*start).ok()}else{None}}fn forward_checked(start:Self,delta:$u_source)->Option{start.checked_add(delta as Self)}fn backward_checked(start:Self,delta:$u_source)->Option{start.checked_sub(delta as Self)}}impl DiscreteSteps<$u_source>for$i_wider{impl_discrete_steps_integer!(@common$u_source);fn steps_between(start:&Self,end:&Self)->Option<$u_source>{if*start<=*end{end.checked_sub(*start).and_then(|result|$u_source::try_from(result).ok())}else{None}}fn forward_checked(start:Self,delta:$u_source)->Option{start.checked_add(delta as Self)}fn backward_checked(start:Self,delta:$u_source)->Option{start.checked_sub(delta as Self)}})*};}impl_discrete_steps_integer!(u16 i16;u8 i8,u16 i16,usize isize;u32 i32,u64 i64,u128 i128);impl_discrete_steps_integer!(u32 i32;u8 i8,u16 i16,u32 i32,usize isize;u64 i64,u128 i128);impl_discrete_steps_integer!(u64 i64;u8 i8,u16 i16,u32 i32,u64 i64,usize isize;u128 i128);impl_discrete_steps_integer!(u128 i128;u8 i8,u16 i16,u32 i32,u64 i64,u128 i128,usize isize;);impl_discrete_steps_integer!(usize isize;u8 i8,u16 i16,u32 i32,u64 i64,usize isize;u128 i128);pub trait RangeBoundsExt{fn start_bound_included_checked(&self)->Option;fn start_bound_excluded_checked(&self)->Option;fn end_bound_included_checked(&self)->Option;fn end_bound_excluded_checked(&self)->Option;fn start_bound_included(&self)->T;fn start_bound_excluded(&self)->T;fn end_bound_included(&self)->T;fn end_bound_excluded(&self)->T;fn start_bound_included_bounded(&self,lb:T)->Optionwhere T:Ord;fn start_bound_excluded_bounded(&self,lb:T)->Optionwhere T:Ord;fn end_bound_included_bounded(&self,ub:T)->Optionwhere T:Ord;fn end_bound_excluded_bounded(&self,ub:T)->Optionwhere T:Ord;fn to_range_checked(&self)->Option>{match(self.start_bound_included_checked(),self.end_bound_excluded_checked()){(Some(start),Some(end))=>Some(start..end),_=>None,}}fn to_range(&self)->Range{self.start_bound_included()..self.end_bound_excluded()}fn to_range_bounded(&self,min:T,max:T)->Option>where T:Ord{Some(self.start_bound_included_bounded(min)?..self.end_bound_excluded_bounded(max)?)}fn to_range_inclusive_checked(&self)->Option>{match(self.start_bound_included_checked(),self.end_bound_included_checked()){(Some(start),Some(end))=>Some(start..=end),_=>None,}}fn to_range_inclusive(&self)->RangeInclusive{self.start_bound_included()..=self.end_bound_included()}fn to_range_inclusive_bounded(&self,min:T,max:T)->Option>where T:Ord{Some(self.start_bound_included_bounded(min)?..=self.end_bound_included_bounded(max)?)}}macro_rules!impl_range_bounds_ext{($($source:ident=>$($target:ident)+);*$(;)?)=>{$($(implRangeBoundsExt<$target>for R where R:RangeBounds<$target>,{fn start_bound_included_checked(&self)->Option<$target>{match self.start_bound(){Bound::Included(x)=>Some(*x),Bound::Excluded(x)=>DiscreteSteps::<$source>::forward_delta_checked(*x),Bound::Unbounded=>Some(Bounded::minimum()),}}fn start_bound_excluded_checked(&self)->Option<$target>{match self.start_bound(){Bound::Included(x)=>DiscreteSteps::<$source>::backward_delta_checked(*x),Bound::Excluded(x)=>Some(*x),Bound::Unbounded=>None,}}fn end_bound_included_checked(&self)->Option<$target>{match self.end_bound(){Bound::Included(x)=>Some(*x),Bound::Excluded(x)=>DiscreteSteps::<$source>::backward_delta_checked(*x),Bound::Unbounded=>Some(Bounded::maximum()),}}fn end_bound_excluded_checked(&self)->Option<$target>{match self.end_bound(){Bound::Included(x)=>DiscreteSteps::<$source>::forward_delta_checked(*x),Bound::Excluded(x)=>Some(*x),Bound::Unbounded=>None,}}fn start_bound_included(&self)->$target{match self.start_bound(){Bound::Included(x)=>*x,Bound::Excluded(x)=>DiscreteSteps::<$source>::forward_delta(*x),Bound::Unbounded=>Bounded::minimum(),}}fn start_bound_excluded(&self)->$target{match self.start_bound(){Bound::Included(x)=>DiscreteSteps::<$source>::backward_delta(*x),Bound::Excluded(x)=>*x,Bound::Unbounded=>DiscreteSteps::<$source>::backward_delta(Bounded::minimum()),}}fn end_bound_included(&self)->$target{match self.end_bound(){Bound::Included(x)=>*x,Bound::Excluded(x)=>DiscreteSteps::<$source>::backward_delta(*x),Bound::Unbounded=>Bounded::maximum(),}}fn end_bound_excluded(&self)->$target{match self.end_bound(){Bound::Included(x)=>DiscreteSteps::<$source>::forward_delta(*x),Bound::Excluded(x)=>*x,Bound::Unbounded=>DiscreteSteps::<$source>::forward_delta(Bounded::maximum()),}}fn start_bound_included_bounded(&self,lb:$target)->Option<$target>where$target:Ord{match self.start_bound(){Bound::Included(x)=>Some(*x).filter(|&x|lb<=x),Bound::Excluded(x)=>DiscreteSteps::<$source>::forward_delta_checked(*x).filter(|&x|lb<=x),Bound::Unbounded=>Some(lb),}}fn start_bound_excluded_bounded(&self,lb:$target)->Option<$target>where$target:Ord{match self.start_bound(){Bound::Included(x)=>DiscreteSteps::<$source>::backward_delta_checked(*x).filter(|&x|lb<=x),Bound::Excluded(x)=>Some(*x).filter(|&x|lb<=x),Bound::Unbounded=>Some(lb),}}fn end_bound_included_bounded(&self,ub:$target)->Option<$target>where$target:Ord{match self.end_bound(){Bound::Included(x)=>Some(*x).filter(|&x|x<=ub),Bound::Excluded(x)=>DiscreteSteps::<$source>::backward_delta_checked(*x).filter(|&x|x<=ub),Bound::Unbounded=>Some(ub),}}fn end_bound_excluded_bounded(&self,ub:$target)->Option<$target>where$target:Ord{match self.end_bound(){Bound::Included(x)=>DiscreteSteps::<$source>::forward_delta_checked(*x).filter(|&x|x<=ub),Bound::Excluded(x)=>Some(*x).filter(|&x|x<=ub),Bound::Unbounded=>Some(ub),}}})+)*};}impl_range_bounds_ext!(u16=>u8 i8 u16 i16;u32=>u32 i32;u64=>u64 i64;u128=>u128 i128;usize=>isize usize;);}