#![crate_name = "sum_range"]
#![warn(missing_docs)]
#![forbid(unsafe_code)]
#![no_std]
use core::ops::{Div, Mul, Rem, Sub};
use core::ops::{Range, RangeInclusive, RangeTo, RangeToInclusive};
use num::{Integer, Unsigned};
use num_convert::IntoAs;
pub trait SumRange<T> {
fn sum_range(&self) -> T;
fn sum_odd_range(&self) -> T;
fn sum_even_range(&self) -> T;
}
impl<T> SumRange<T> for Range<T>
where
T: Integer + Copy,
u8: IntoAs<T>,
{
#[inline]
fn sum_range(&self) -> T {
if self.start >= self.end {
return 0.into_as();
}
(self.end + self.start - 1.into_as()) * (self.end - self.start) / 2.into_as()
}
#[inline]
fn sum_odd_range(&self) -> T {
if self.start > self.end {
return 0.into_as();
}
let tmp_end = if self.end >= 0.into_as() {
self.end
} else {
self.end - 1.into_as()
} / 2.into_as();
let tmp_start = if self.start >= 0.into_as() {
self.start
} else {
self.start - 1.into_as()
} / 2.into_as();
tmp_end * tmp_end - tmp_start * tmp_start
}
#[inline]
fn sum_even_range(&self) -> T {
if self.start >= self.end {
return 0.into_as();
}
(if self.end % 2.into_as() == 0.into_as() {
(self.end - 1.into_as()) * (self.end - 1.into_as())
} else {
self.end * self.end
}) / 4.into_as()
- sum_even_range_to(self.start)
}
}
impl<T> SumRange<T> for RangeInclusive<T>
where
T: Integer + Copy,
u8: IntoAs<T>,
{
#[inline]
fn sum_range(&self) -> T {
if self.start() > self.end() {
return 0.into_as();
}
let start = *self.start();
let end = *self.end();
(end + start) * (end - start + 1.into_as()) / 2.into_as()
}
#[inline]
fn sum_odd_range(&self) -> T {
if self.start() > self.end() {
return 0.into_as();
}
let start = *self.start();
let end = *self.end();
let tmp_end = if end >= 0.into_as() {
end + 1.into_as()
} else {
end
} / 2.into_as();
let tmp_start = if start >= 0.into_as() {
start
} else {
start - 1.into_as()
} / 2.into_as();
(tmp_end + tmp_start) * (tmp_end - tmp_start)
}
#[inline]
fn sum_even_range(&self) -> T {
if self.start() > self.end() {
return 0.into_as();
}
let end = *self.end();
let start = *self.start();
(if end % 2.into_as() == 0.into_as() {
(end + 1.into_as()) * (end + 1.into_as())
} else {
end * end
}) / 4.into_as()
- sum_even_range_to(start)
}
}
impl<T> SumRange<T> for RangeTo<T>
where
T: Unsigned + Copy,
u8: IntoAs<T>,
{
#[inline]
fn sum_range(&self) -> T {
let start = 0.into_as();
if start == self.end {
return 0.into_as();
}
((self.end - 1.into_as()) * self.end) / 2.into_as()
}
#[inline]
fn sum_odd_range(&self) -> T {
let tmp = self.end / 2.into_as();
tmp * tmp
}
#[inline]
fn sum_even_range(&self) -> T {
sum_even_range_to(self.end)
}
}
impl<T> SumRange<T> for RangeToInclusive<T>
where
T: Unsigned + Copy,
u8: IntoAs<T>,
{
#[inline]
fn sum_range(&self) -> T {
self.end * (self.end + 1.into_as()) / 2.into_as()
}
#[inline]
fn sum_odd_range(&self) -> T {
let tmp = (self.end + 1.into_as()) / 2.into_as();
tmp * tmp
}
#[inline]
fn sum_even_range(&self) -> T {
(if self.end % 2.into_as() == 0.into_as() {
(self.end + 1.into_as()) * (self.end + 1.into_as())
} else {
self.end * self.end
}) / 4.into_as()
}
}
#[inline]
fn sum_even_range_to<T>(end: T) -> T
where
T: Div<Output = T> + Mul<Output = T> + Sub<Output = T> + Rem<Output = T> + PartialEq + Copy,
u8: IntoAs<T>,
{
let zero = 0.into_as();
if zero == end {
return zero;
}
(if end % 2.into_as() == 0.into_as() {
(end - 1.into_as()) * (end - 1.into_as())
} else {
end * end - 1.into_as()
}) / 4.into_as()
}