Skip to content

Commit

Permalink
Merge branch 'main' into fix-ci
Browse files Browse the repository at this point in the history
ngtkana committed Oct 26, 2023
2 parents b6b771d + 8fb87a7 commit 6bfed60
Showing 3 changed files with 904 additions and 2,232 deletions.
197 changes: 24 additions & 173 deletions libs/rb/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,195 +1,46 @@
#![warn(missing_docs)]
//! Containers for storing data in a red-black tree.
use std::ops;
use std::ptr;
use std::ptr::NonNull;

/// The core implementation of a red-black tree.
mod tree;

/// Another implementation of `tree` using laef-tree.
mod leaftree;

/// A list based on a red-black tree.
mod list;

pub use list::RbList;
pub use list::RbReversibleList;

/// Iterators for a list based on a red-black tree.
pub mod list_iter {
pub use super::list::RbList;
}

/// The trait for specifying the operation of a red-black tree.
///
/// # Notation
///
/// - $xy$ denotes the multiplication of two accumulated values.
/// - $a \circ b$ denotes the composition of two lazy actions.
/// - $x \cdot a$ denotes the application of a lazy action to an accumulated value.
///
/// # Laws
///
/// For [`RbList`]:
/// - `mul` is associative. ($(xy)z = x(yz)$)
/// - `compose` is associative. ($(a \circ b) \circ c = a \circ (b \circ c)$)
/// - `apply` is an action of a semigroup on a semigroup. ($(xy) \cdot a = (x \cdot a)(y \cdot a)$, $x \cdot (a \circ b) = (x \cdot a) \cdot b$)
///
/// Furthermore, for [`RbReversibleList`]:
/// - `mul` is commutative. ($xy = yx$)
/// A trait for algebraic operations.
pub trait Op {
/// The type of the value stored in a node.
/// The type of the value stored in the leaf nodes.
type Value;
/// The type of the accumulated value of a node.
/// The type of the value stored in the internal nodes.
type Acc;
/// The type of the lazy action of a node.
type Action;
/// The type of the lazy action stored in the internal nodes.
type Lazy: PartialEq;

/// Convert a value to an accumulated value.
fn to_acc(value: &Self::Value) -> Self::Acc;
/// Convert a `Value` to an `Acc`.
fn to_acc(_: &Self::Value) -> Self::Acc;

/// Multiply two accumulated values.
fn mul(lhs: &Self::Acc, rhs: &Self::Acc) -> Self::Acc;
/// Multiply two `Acc`s.
fn mul(_: &Self::Acc, _: &Self::Acc) -> Self::Acc;

/// Apply a lazy action to a value.
fn apply(value: &mut Self::Value, lazy: &Self::Action);
/// Apply a `Lazy` action to a `Value`.
fn apply_on_value(_: &mut Self::Value, _: &Self::Lazy);

/// Apply a lazy action to an accumulated value.
fn apply_acc(acc: &mut Self::Acc, lazy: &Self::Action);
/// Apply a `Lazy` action to an `Acc`.
fn apply_on_acc(_: &mut Self::Acc, _: &Self::Lazy);

/// Compose two lazy actions.
fn compose(lhs: &Self::Action, rhs: &Self::Action) -> Self::Action;
/// Compose two `Lazy` actions.
fn compose(_: &mut Self::Lazy, _: &Self::Lazy);

/// The identity of an accumulated value.
fn identity_action() -> Self::Action;
}

/// A color of a node in a red-black tree.
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum Color {
Red,
Black,
}
/// The identity of `Lazy` actions.
fn identity() -> Self::Lazy;

/// A callback for a node in a red-black tree.
trait Callback: Sized {
/// The data stored in the node.
type Data;
/// The callback function called when it goes down the tree.
fn push(node: Ptr<Self>);
/// The callback function called when it goes up the tree.
fn update(node: Ptr<Self>);
}
/// Check if a `Lazy` action is the identity.
fn is_identity(lazy: &Self::Lazy) -> bool { *lazy == Self::identity() }

/// A trait for getting the length of a node in a red-black tree.
trait Len {
fn len(&self) -> usize;
}

/// A node in a red-black tree.
#[allow(dead_code)]
struct Node<C: Callback> {
data: C::Data,
left: Option<Ptr<C>>,
right: Option<Ptr<C>>,
parent: Option<Ptr<C>>,
color: Color,
}
fn node_ptr_eq<C: Callback>(
lhs: impl Into<Option<Ptr<C>>>,
rhs: impl Into<Option<Ptr<C>>>,
) -> bool {
ptr::eq(
lhs.into()
.map_or_else(ptr::null, |p| p.as_ref() as *const _),
rhs.into()
.map_or_else(ptr::null, |p| p.as_ref() as *const _),
)
}
/// Non-dangling pointer to a node in a red-black tree.
#[allow(dead_code)]
struct Ptr<C: Callback>(NonNull<Node<C>>);
#[allow(dead_code)]
impl<C: Callback> Ptr<C> {
/// Create a new isolated red [`Ptr`] from a [`Callback::Data`].
pub fn new(data: C::Data) -> Self {
Self(
NonNull::new(Box::into_raw(Box::new(Node {
data,
left: None,
right: None,
parent: None,
color: Color::Red,
})))
.unwrap(),
)
/// Set a `Lazy` action to the identity.
fn swap_with_identity(lazy: &mut Self::Lazy) -> Self::Lazy {
let mut tmp = Self::identity();
std::mem::swap(lazy, &mut tmp);
tmp
}

/// Give the ownership of the node to the caller.
pub fn into_box(self) -> Box<Node<C>> { unsafe { Box::from_raw(self.0.as_ptr()) } }

/// Drop the node.
pub fn drop_this(self) { unsafe { drop(Box::from_raw(self.0.as_ptr())) }; }

/// Get the node as a reference.
pub fn as_ref(&self) -> &Node<C> { unsafe { self.0.as_ref() } }

/// Get the node as a mutable reference.
pub fn as_mut(&mut self) -> &mut Node<C> { unsafe { self.0.as_mut() } }

/// Get a node as a reference with a long lifetime.
pub fn as_ref_longlife<'a>(self) -> &'a Node<C> {
unsafe { &*(self.as_ref() as *const Node<C>) }
}

/// Get a node as a mutable reference with a long lifetime.
pub fn as_mut_longlife<'a>(mut self) -> &'a mut Node<C> {
unsafe { &mut *(self.as_mut() as *mut Node<C>) }
}

/// Update the node.
pub fn update(&mut self) { C::update(*self); }

/// Update the ancestors of the node, but not the node itself.
pub fn update_ancestors(&mut self) {
let mut p = self.as_ref().parent;
while let Some(q) = p {
C::update(q);
p = q.as_ref().parent;
}
}

/// Returns `true` if the node is isolated.
pub fn is_isolated_and_red(self) -> bool {
self.as_ref().left.is_none()
&& self.as_ref().right.is_none()
&& self.as_ref().parent.is_none()
&& self.as_ref().color == Color::Red
}

/// Change the node to an isolated red node.
pub fn isolate_and_red(&mut self) {
self.as_mut().left = None;
self.as_mut().right = None;
self.as_mut().parent = None;
self.as_mut().color = Color::Red;
}
}
impl<C: Callback> Clone for Ptr<C> {
fn clone(&self) -> Self { *self }
}
impl<C: Callback> Copy for Ptr<C> {}
impl<C: Callback> ops::Deref for Ptr<C> {
type Target = Node<C>;

fn deref(&self) -> &Self::Target { self.as_ref() }
}
impl<C: Callback> ops::DerefMut for Ptr<C> {
fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut() }
}

/// Get the color of a node.
fn color<C: Callback>(p: Option<Ptr<C>>) -> Color { p.map_or(Color::Black, |p| p.as_ref().color) }
830 changes: 197 additions & 633 deletions libs/rb/src/list.rs
Original file line number Diff line number Diff line change
@@ -1,712 +1,276 @@
use crate::node_ptr_eq;
#![allow(dead_code)]
use crate::tree::BeefPtr;
use crate::tree::BeefSteak;
use crate::tree::Callback;
use crate::tree::LeafPtr;
use crate::tree::Ptr;
use crate::tree::Steak;
use crate::tree::Tree;
use crate::Callback;
use crate::Len;
use crate::Op;
use crate::Ptr;
use std::cmp::Ordering;
use std::fmt;
use std::marker::PhantomData;
use std::ops;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ops::Index;
use std::ops::RangeBounds;

// TODO: add `RbSortedList`?
// This problem:
// https://atcoder.jp/contests/arc033/tasks/arc033_3
//
// TODO: add .max_right()
// Example:
// https://atcoder.jp/contests/arc033/submissions/46249626

pub(super) struct Irreversible<O: Op> {
marker: PhantomData<O>,
}

pub(super) struct Reversible<O: Op> {
marker: PhantomData<O>,
}

#[allow(dead_code)]
pub(super) struct IrreversibleData<O: Op> {
len: usize,
value: O::Value,
acc: O::Acc,
#[allow(dead_code)]
lazy: O::Action,
}
impl<O: Op> IrreversibleData<O> {
pub(super) fn new(value: O::Value) -> Self {
let acc = O::to_acc(&value);
Self {
len: 1,
value,
acc,
lazy: O::identity_action(),
}
}
}

#[allow(dead_code)]
pub(super) struct ReversibleData<O: Op> {
len: usize,
value: O::Value,
acc: O::Acc,
lazy: O::Action,
reverse: bool,
}

#[allow(dead_code)]
impl<O: Op> Callback for Irreversible<O> {
type Data = IrreversibleData<O>;

fn push(_node: crate::Ptr<Self>) {}

fn update(mut node: crate::Ptr<Self>) {
let mut len = 1;
let mut acc = O::to_acc(&node.data.value);
if let Some(left) = node.left {
acc = O::mul(&left.data.acc, &acc);
len += left.data.len;
}
if let Some(right) = node.right {
acc = O::mul(&acc, &right.data.acc);
len += right.data.len;
}
node.data.len = len;
node.data.acc = acc;
}
}

#[allow(dead_code)]
impl<O: Op> Len for IrreversibleData<O> {
fn len(&self) -> usize { self.len }
}

#[allow(dead_code)]
impl<O: Op> Callback for Reversible<O> {
type Data = ReversibleData<O>;

fn push(_node: crate::Ptr<Self>) {}

fn update(mut node: crate::Ptr<Self>) {
let mut len = 1;
let mut acc = O::to_acc(&node.data.value);
if let Some(left) = node.left {
acc = O::mul(&left.data.acc, &acc);
len += left.data.len;
}
if let Some(right) = node.right {
acc = O::mul(&acc, &right.data.acc);
len += right.data.len;
}
node.data.len = len;
node.data.acc = acc;
}
}

/// A list based on a red-black tree.
#[allow(dead_code)]
pub struct RbList<O: Op> {
tree: Tree<Irreversible<O>>,
pub struct List<O: Op> {
tree: Tree<ListCallback<O>>,
}
impl<O: Op> RbList<O> {
/// Constructs a new, empty list.
impl<O: Op> List<O> {
/// Create a new empty list.
pub fn new() -> Self { Self::default() }

/// Returns the length of the list.
pub fn is_empty(&self) -> bool { self.tree.is_empty() }

/// Returns the length of the list.
pub fn len(&self) -> usize { self.tree.len() }

/// Provides a reference to the front element, or None if the deque is empty.
pub fn front(&self) -> Option<&O::Value> {
self.tree.front().map(|p| &p.as_ref_longlife().data.value)
}

/// Returns the last element of the list.
pub fn back(&self) -> Option<&O::Value> {
self.tree.back().map(|p| &p.as_ref_longlife().data.value)
}

/// Returns the first element of the list.
pub fn front_mut(&mut self) -> Option<&mut O::Value> {
self.tree
.front()
.map(|p| &mut p.as_mut_longlife().data.value)
}

/// Returns the last element of the list.
pub fn back_mut(&mut self) -> Option<&mut O::Value> {
self.tree
.back()
.map(|p| &mut p.as_mut_longlife().data.value)
}

/// Prepends an element to `self`.
pub fn push_front(&mut self, value: O::Value) {
self.tree.push_front(Ptr::new(IrreversibleData::new(value)));
}

/// Appends an element to `self`.
pub fn push_back(&mut self, value: O::Value) {
self.tree.push_back(Ptr::new(IrreversibleData::new(value)));
}

/// Returns a deligated entry, which is a mutable reference to the element at the given index.
pub fn entry(&mut self, index: usize) -> Entry<'_, O> {
debug_assert!(index < self.len());
Entry {
ptr: self.tree.get_at(index),
marker: PhantomData,
pub fn len(&self) -> usize {
match self.tree.root() {
Some(p) => p.len(),
None => 0,
}
}

/// Removes the first element and returns it, or `None` if the deque is empty.
pub fn pop_front(&mut self) -> Option<O::Value> {
self.tree.pop_front().map(|p| p.into_box().data.value)
}

/// Removes the last element and returns it, or `None` if the deque is empty.
pub fn pop_back(&mut self) -> Option<O::Value> {
self.tree.pop_back().map(|p| p.into_box().data.value)
}

/// Inserts an element at the given index.
pub fn insert(&mut self, index: usize, value: O::Value) {
self.tree
.insert_at(index, Ptr::new(IrreversibleData::new(value)));
}

/// Removes the element at the given index.
pub fn remove(&mut self, index: usize) -> O::Value {
self.tree.remove_at(index).into_box().data.value
}

/// Moves all elements from other into `self`, leaving `other` empty.
pub fn append(&mut self, other: &mut Self) { self.tree.append(&mut other.tree); }

/// Splits `self` into two at the given index.
pub fn split_off(&mut self, index: usize) -> Self {
let mut other = Self::new();
other.tree = self.tree.split_off_at(index);
other
}

/// Returns the index of the partition point according to the given predicate (the index of the first element of the second partition).
pub fn partition_point<P>(&self, mut pred: P) -> usize
where
P: FnMut(&O::Value) -> bool,
{
self.tree
.partition_point_index(|p| pred(&p.as_ref().data.value))
}

/// Binary searches `self` for a given element
pub fn binary_search<F>(&self, mut f: F) -> Result<usize, usize>
where
F: FnMut(&O::Value) -> Ordering,
{
self.tree.binary_search_index(|p| f(&p.as_ref().data.value))
}

/// Iterates over the list.
pub fn iter(&self) -> Range<'_, O> {
Range {
len: self.tree.len(),
start: self.tree.front(),
end: self.tree.back(),
marker: PhantomData,
}
}

/// Returns an iterator over the given range.
pub fn range(&self, range: impl RangeBounds<usize>) -> Range<'_, O> {
let Some((start, end)) = into_range_inclusive(self.len(), range) else {
return Range {
len: 0,
start: None,
end: None,
marker: PhantomData,
};
};
debug_assert!(start <= end);
assert!(end < self.len());
Range {
len: end - start + 1,
start: Some(self.tree.get_at(start)),
end: Some(self.tree.get_at(end)),
marker: PhantomData,
}
}

/// Returns the product of all the elements within the `range`.
// TODO: stop use the internal structure of `Tree` here.
pub fn fold<R: RangeBounds<usize>>(&self, range: R) -> Option<O::Acc> {
let (start, end) = into_range_inclusive(self.len(), range)?;
debug_assert!(start <= end);
assert!(
end < self.len(),
"Out of range: {}..={}, while len={}",
start,
end,
self.len()
);
// Invariants:
// * fold: [start, z]
// * len: ]z, end]
let mut z = self.tree.get_at(start);
let mut fold = O::to_acc(&z.data.value);
let mut len = end - start;
// Search up.
while len > 0 {
// 1. Try to append the right subtree.
if let Some(r) = z.right {
if len <= r.data.len {
break;
/// Returns `true` if the list is empty.
pub fn is_empty(&self) -> bool { self.tree.root().is_none() }

/// Insert a value at the `i`th position.
///
/// # Panics
///
/// Panics if `i > self.len()`.
pub fn insert(&mut self, mut i: usize, x: O::Value) {
assert!(i <= self.len(), "index out of bounds");
let position = self
.tree
.binary_search(|b| {
let left_len = b.left().len();
if i < left_len {
true
} else {
i -= left_len;
false
}
fold = O::mul(&fold, &r.data.acc);
len -= r.data.len;
}
// 2. Move to the first right ancestor.
loop {
let p = z.parent.unwrap();
if node_ptr_eq(p.left, z) {
z = p;
break;
})
.map(|l| {
(l, match i {
0 => true,
1 => false,
_ => unreachable!(),
})
});
let leaf = LeafPtr::new(LeafData {
acc: O::to_acc(&x),
value: x,
});
self.tree.insert(position, leaf, |left, right| {
BeefPtr::new(
BeefData {
len: 0,
acc: O::mul(&left.data().acc, &right.data().acc),
lazy: O::identity(),
},
left.upcast(),
right.upcast(),
)
});
}

/// Remove the `i`th value and return it.
///
/// # Panics
///
/// Panics if `i >= self.len()`.
pub fn remove(&mut self, mut i: usize) -> O::Value {
assert!(i < self.len(), "index out of bounds");
let p = self
.tree
.binary_search(|b| {
let left_len = b.left().len();
if i < left_len {
true
} else {
i -= left_len;
false
}
z = p;
}
// 3. Push back the value of the node.
fold = O::mul(&fold, &O::to_acc(&z.data.value));
len -= 1;
}
// Search down.
while len > 0 {
// 1. Move to the right.
z = z.right.unwrap();
// 2. Repeatedly move to the left.
while let Some(l) = z.left {
if l.data.len < len {
break;
}
z = l;
}
// 3. Append the left subtree and push front the value of the node.
if let Some(l) = z.left {
fold = O::mul(&fold, &l.data.acc);
len -= l.data.len;
}
fold = O::mul(&fold, &O::to_acc(&z.data.value));
len -= 1;
}
Some(fold)
})
.unwrap();
self.tree.remove(p, BeefPtr::free);
p.free().value
}
}
impl<O: Op> Drop for RbList<O> {
fn drop(&mut self) { self.tree.drop_all_nodes(); }
}
impl<O: Op> Default for RbList<O> {

impl<O: Op> Default for List<O> {
fn default() -> Self {
Self {
tree: Tree::default(),
}
}
}
impl<O: Op> fmt::Debug for RbList<O>
where
O::Value: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<O: Op> Index<usize> for RbList<O> {
type Output = O::Value;

fn index(&self, index: usize) -> &Self::Output {
&self.tree.get_at(index).as_ref_longlife().data.value
}
}
impl<O: Op> PartialEq for RbList<O>
where
O::Value: PartialEq,
{
fn eq(&self, other: &Self) -> bool { self.iter().eq(other.iter()) }
}
impl<O: Op> Eq for RbList<O> where O::Value: Eq {}
impl<O: Op> FromIterator<O::Value> for RbList<O> {
fn from_iter<T: IntoIterator<Item = O::Value>>(iter: T) -> Self {
Self {
tree: iter
.into_iter()
.map(|value| Ptr::new(IrreversibleData::new(value)))
.collect(),
}
}
}
impl<'a, O: Op> IntoIterator for &'a RbList<O> {
type IntoIter = Range<'a, O>;
type Item = &'a O::Value;

fn into_iter(self) -> Self::IntoIter { self.iter() }
}
impl<O: Op> From<Vec<O::Value>> for RbList<O> {
fn from(values: Vec<O::Value>) -> Self { values.into_iter().collect() }
}
impl<const N: usize, O: Op> From<[O::Value; N]> for RbList<O> {
fn from(values: [O::Value; N]) -> Self { values.into_iter().collect() }
}

/// An entry in a list.
/// The node and its ancestors are updated when the entry is dropped.
pub struct Entry<'a, O: Op> {
ptr: Ptr<Irreversible<O>>,
marker: PhantomData<&'a O>,
}
impl<'a, O: Op> Drop for Entry<'a, O> {
fn drop(&mut self) {
self.ptr.update();
self.ptr.update_ancestors();
}
struct LeafData<O: Op> {
value: O::Value,
acc: O::Acc,
}
impl<'a, O: Op> Deref for Entry<'a, O> {
type Target = O::Value;

fn deref(&self) -> &Self::Target { &self.ptr.as_ref_longlife().data.value }
}
impl<'a, O: Op> DerefMut for Entry<'a, O> {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.ptr.as_mut_longlife().data.value }
#[derive(Clone, Copy, Debug, PartialEq)]
struct BeefData<O: Op> {
len: usize,
acc: O::Acc,
lazy: O::Lazy,
}

/// An iterator over a list.
pub struct Range<'a, O: Op> {
len: usize,
start: Option<Ptr<Irreversible<O>>>,
end: Option<Ptr<Irreversible<O>>>,
// To make sure `O` outlives `'a`.
marker: PhantomData<&'a O>,
struct ListCallback<O> {
marker: PhantomData<O>,
}
impl<O: Op> Callback for ListCallback<O> {
type BeefData = BeefData<O>;
type LeafData = LeafData<O>;

impl<'a, O: Op> Iterator for Range<'a, O> {
type Item = &'a O::Value;
fn update(x: &mut BeefSteak<Self>) {
debug_assert!(O::is_identity(&x.data.lazy));
x.data.len = x.left.len() + x.right.len();
x.data.acc = O::mul(x.left.acc(), x.right.acc());
}

fn next(&mut self) -> Option<Self::Item> {
let start = self.start?;
self.len -= 1;
if self.len == 0 {
self.start = None;
self.end = None;
} else {
self.start = Some(start.next().unwrap());
fn push(x: &mut BeefSteak<Self>) {
if !O::is_identity(&x.data.lazy) {
let lazy = O::swap_with_identity(&mut x.data.lazy);
x.left.apply(&lazy);
x.right.apply(&lazy);
}
Some(&start.as_ref_longlife().data.value)
}
}

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

fn count(self) -> usize { self.len }

fn nth(&mut self, n: usize) -> Option<Self::Item> {
let mut start = self.start?;
if n < self.len {
start = start.advance_by(n).unwrap();
self.len -= n + 1;
if self.len == 0 {
self.start = None;
self.end = None;
} else {
self.start = start.next();
}
Some(&start.as_ref_longlife().data.value)
} else {
self.start = None;
self.end = None;
self.len = 0;
None
impl<O: Op> Ptr<ListCallback<O>> {
fn len(self) -> usize {
match &self.steak {
Steak::Leaf(_) => 1,
Steak::Beef(x) => x.data.len,
}
}
}
impl<'a, O: Op> DoubleEndedIterator for Range<'a, O> {
fn next_back(&mut self) -> Option<Self::Item> {
let end = self.end?;
self.len -= 1;
if self.len == 0 {
self.start = None;
self.end = None;
} else {
self.end = Some(end.prev().unwrap());

fn acc(&self) -> &O::Acc {
match &self.steak {
Steak::Leaf(x) => &x.acc,
Steak::Beef(x) => &x.data.acc,
}
Some(&end.as_ref_longlife().data.value)
}

fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
let mut end = self.end?;
if n < self.len {
end = end.retreat_by(n).unwrap();
self.len -= n + 1;
if self.len == 0 {
self.start = None;
self.end = None;
} else {
self.end = end.prev();
fn apply(&mut self, lazy: &O::Lazy) {
match &mut self.steak {
Steak::Leaf(x) => {
O::apply_on_acc(&mut x.acc, lazy);
O::apply_on_value(&mut x.value, lazy);
}
Some(&end.as_ref_longlife().data.value)
} else {
self.start = None;
self.end = None;
self.len = 0;
None
Steak::Beef(x) => O::apply_on_acc(&mut x.data.acc, lazy),
}
}
}

impl<'a, O: Op> ExactSizeIterator for Range<'a, O> {}

/// A list based on a red-black tree.
#[allow(dead_code)]
pub struct RbReversibleList<O: Op> {
root: Tree<Reversible<O>>,
}

/// Converts a range to a range inclusive.
/// If the range is invalid, returns `None`.
fn into_range_inclusive(len: usize, range: impl RangeBounds<usize>) -> Option<(usize, usize)> {
use ops::Bound;
let start = match range.start_bound() {
Bound::Included(&start) => start,
Bound::Excluded(&start) => start + 1,
Bound::Unbounded => 0,
};

let end = match range.end_bound() {
Bound::Included(&end) => end,
Bound::Excluded(&end) => end.checked_sub(1)?,
Bound::Unbounded => len.checked_sub(1)?,
};
(start <= end).then_some(())?;
Some((start, end))
}

#[cfg(test)]
mod tests {
use super::*;
use crate::tree::test_util;
use rand::rngs::StdRng;
use rand::Rng;
use rand::SeedableRng;
use rstest::rstest;
use std::iter::repeat_with;
use std::rc::Rc;

struct ConcatOp;
impl Op for ConcatOp {
type Acc = String;
type Action = ();
type Value = char;
const P: u64 = 998244353;

fn mul(lhs: &Self::Acc, rhs: &Self::Acc) -> Self::Acc {
lhs.chars().chain(rhs.chars()).collect()
}

fn to_acc(value: &Self::Value) -> Self::Acc { value.to_string() }

fn apply(_value: &mut Self::Value, _lazy: &Self::Action) {}

fn apply_acc(_acc: &mut Self::Acc, _lazy: &Self::Action) {}

fn compose(_lhs: &Self::Action, _rhs: &Self::Action) -> Self::Action {}

fn identity_action() -> Self::Action {}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct HashnBase {
hash: u64,
base: u64,
}
impl HashnBase {
pub fn empty() -> Self { Self { hash: 0, base: 1 } }

#[test]
fn test_drop() {
struct RcOp;
impl Op for RcOp {
type Acc = ();
type Action = ();
type Value = Rc<()>;

fn mul(_lhs: &Self::Acc, _rhs: &Self::Acc) -> Self::Acc {}

fn to_acc(_value: &Self::Value) -> Self::Acc {}

fn apply(_value: &mut Self::Value, _lazy: &Self::Action) {}

fn apply_acc(_acc: &mut Self::Acc, _lazy: &Self::Action) {}

fn compose(_lhs: &Self::Action, _rhs: &Self::Action) -> Self::Action {}

fn identity_action() -> Self::Action {}
pub fn from_value(value: u64) -> Self {
Self {
hash: value,
base: 100,
}
}

let pointer = Rc::new(());
assert_eq!(Rc::strong_count(&pointer), 1);
{
let _list = std::iter::once(Rc::clone(&pointer)).collect::<RbList<RcOp>>();
assert_eq!(Rc::strong_count(&pointer), 2);
pub fn mul(&self, other: &Self) -> Self {
Self {
hash: (self.hash * other.base + other.hash) % P,
base: self.base * other.base % P,
}
}
assert_eq!(Rc::strong_count(&pointer), 1);
}

#[test]
fn test_iterator() {
struct UsizeOp;
impl Op for UsizeOp {
type Acc = ();
type Action = ();
type Value = usize;

fn mul(_lhs: &Self::Acc, _rhs: &Self::Acc) -> Self::Acc {}

fn to_acc(_value: &Self::Value) -> Self::Acc {}

fn apply(_value: &mut Self::Value, _lazy: &Self::Action) {}

fn apply_acc(_acc: &mut Self::Acc, _lazy: &Self::Action) {}

fn compose(_lhs: &Self::Action, _rhs: &Self::Action) -> Self::Action {}
#[derive(Clone, Copy, Debug, PartialEq)]
enum RollingHash {}
impl Op for RollingHash {
type Acc = HashnBase;
type Lazy = ();
type Value = u64;

fn identity_action() -> Self::Action {}
}
fn mul(left: &Self::Acc, right: &Self::Acc) -> Self::Acc { left.mul(right) }

let mut rng = StdRng::seed_from_u64(42);
for len in 0..10 {
// Test `next()`.
let list = (0..len).collect::<RbList<UsizeOp>>();
let mut iter = list.iter();
for i in 0..len {
assert_eq!(iter.next(), Some(&i));
assert_eq!(iter.len(), len - i - 1); // Test `size_hint()`.
}
assert_eq!(iter.len(), 0); // Test `size_hint()`.
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
fn to_acc(value: &Self::Value) -> Self::Acc { HashnBase::from_value(*value) }

// Test `next_back()`.
let mut iter = list.iter();
for i in (0..len).rev() {
assert_eq!(iter.next_back(), Some(&i));
assert_eq!(iter.len(), i); // Test `size_hint()`.
}
assert_eq!(iter.len(), 0); // Test `size_hint()`.
assert_eq!(iter.next_back(), None);
assert_eq!(iter.next_back(), None);
assert_eq!(iter.next_back(), None);
fn compose(_: &mut Self::Lazy, _: &Self::Lazy) {}

// Test `nth()`.
for _ in 0..4 * len {
let mut iter = list.iter();
let n = rng.gen_range(0..=len);
assert_eq!(iter.nth(n), Some(&n).filter(|&&i| i < len));
assert_eq!(iter.len(), len.saturating_sub(n + 1)); // Test `size_hint()`.
let m = rng.gen_range(0..=len);
assert_eq!(iter.nth(m), Some(&(m + n + 1)).filter(|&&i| i < len));
assert_eq!(iter.len(), len.saturating_sub(m + n + 2)); // Test `size_hint()`.
}
fn identity() -> Self::Lazy {}

// Test `nth_back()`.
for _ in 0..4 * len {
let mut iter = list.iter();
let n = rng.gen_range(0..=len);
assert_eq!(iter.nth_back(n), len.checked_sub(n + 1).as_ref());
assert_eq!(iter.len(), len.saturating_sub(n + 1)); // Test `size_hint()`.
let m = rng.gen_range(0..=len);
assert_eq!(iter.nth_back(m), len.checked_sub(m + n + 2).as_ref());
assert_eq!(iter.len(), len.saturating_sub(m + n + 2)); // Test `size_hint()`.
}
fn apply_on_acc(_: &mut Self::Acc, _: &Self::Lazy) {}

// Test `range()`
for _ in 0..4 * len {
let start = rng.gen_range(0..=len);
let end = rng.gen_range(0..=len);
let (start, end) = (start.min(end), start.max(end));
let result = list.range(start..end).copied().collect::<Vec<_>>();
let expected = (start..end).collect::<Vec<_>>();
assert_eq!(result, expected);
}
}
fn apply_on_value(_: &mut Self::Value, _: &Self::Lazy) {}
}

#[rstest]
#[case(0.1)]
#[case(0.5)]
#[case(0.9)]
fn test_insert_remove_fold_random(#[case] remove_ratio: f64) {
let mut rng = StdRng::seed_from_u64(42);
let mut list = RbList::<ConcatOp>::new();
for _ in 0..200 {
// Remove
if rng.gen_bool(remove_ratio) && !list.is_empty() {
let index = rng.gen_range(0..list.len());
list.tree.remove_at(index);
}
// Insert
else {
let index = rng.gen_range(0..=list.len());
list.insert(index, rng.gen_range('a'..='z'));
fn to_vec<O: Op>(list: &List<O>) -> Vec<O::Value>
where
O::Value: Copy,
{
fn to_vec<O: Op>(p: Ptr<ListCallback<O>>, result: &mut Vec<O::Value>)
where
O::Value: Copy,
{
match &p.steak {
Steak::Leaf(l) => result.push(l.value),
Steak::Beef(b) => {
to_vec(b.left, result);
to_vec(b.right, result);
}
}
// Fold
let start = rng.gen_range(0..=list.len());
let end = rng.gen_range(0..=list.len());
let (start, end) = (start.min(end), start.max(end));
let expected = list.range(start..end).collect::<String>();
let result = list.fold(start..end).unwrap_or_default();
assert_eq!(result, expected, "{:?}.fold({}..{})", &list, start, end,);
}
let mut result = Vec::new();
if let Some(root) = list.tree.root() {
to_vec(root, &mut result);
}
result
}

#[test]
// https://atcoder.jp/contests/soundhound2018-summer-final-open/tasks/soundhound2018_summer_final_e
fn test_hash_swapping() {
#[rstest]
#[case(3)]
#[case(40)]
#[case(200)]
fn test_insert(#[case] max_length: usize) {
let mut rng = StdRng::seed_from_u64(42);
for _ in 0..20 {
let n = 5;
let mut s = repeat_with(|| rng.gen_range(b'a'..=b'z') as char)
.take(n)
.collect::<String>();
let mut list = s.chars().collect::<RbList<ConcatOp>>();
for _ in 0..100 {
// Rebuild
{
let mut l = rng.gen_range(0..n - 1);
let mut r = rng.gen_range(0..n);
if l >= r {
std::mem::swap(&mut l, &mut r);
r += 1;
}
// String
{
let i2 = s.split_off(r);
let i1 = s.split_off(l);
s.push_str(&i1);
s.push_str(&i2);
let mut list = List::<RollingHash>::new();
let mut vec = Vec::new();
for _ in 0..200 {
match rng.gen_range(0..=max_length) {
// Insert
x if vec.len() <= x => {
let i = rng.gen_range(0..=vec.len());
let value = rng.gen_range(0..20);
list.insert(i, value);
vec.insert(i, value);
}
// Tree
{
let mut list2 = list.split_off(r);
let mut list1 = list.split_off(l);
list.append(&mut list1);
list.append(&mut list2);
}
}
assert_eq!(list.iter().collect::<String>(), s);
// Fold
for _ in 0..10 {
let mut l = rng.gen_range(0..n - 1);
let mut r = rng.gen_range(0..n);
if l >= r {
std::mem::swap(&mut l, &mut r);
r += 1;
// Remove
x if x < vec.len() => {
if vec.is_empty() {
continue;
}
let i = rng.gen_range(0..vec.len());
let result = list.remove(i);
let expected = vec.remove(i);
assert_eq!(result, expected);
}
let ans = list.fold(l..r).unwrap_or_default();
let expected = s.chars().skip(l).take(r - l).collect::<String>();
assert_eq!(ans, expected);
_ => unreachable!(),
}
assert_eq!(&to_vec(&list), &vec);
test_util::validate(&list.tree);
}
}
}
2,109 changes: 683 additions & 1,426 deletions libs/rb/src/tree.rs

Large diffs are not rendered by default.

0 comments on commit 6bfed60

Please sign in to comment.