summaryrefslogtreecommitdiffstats
path: root/vendor/im-rc/src/nodes/rrb.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
commit10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch)
treebdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/im-rc/src/nodes/rrb.rs
parentReleasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff)
downloadrustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz
rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/im-rc/src/nodes/rrb.rs')
-rw-r--r--vendor/im-rc/src/nodes/rrb.rs1101
1 files changed, 1101 insertions, 0 deletions
diff --git a/vendor/im-rc/src/nodes/rrb.rs b/vendor/im-rc/src/nodes/rrb.rs
new file mode 100644
index 000000000..8809b84b8
--- /dev/null
+++ b/vendor/im-rc/src/nodes/rrb.rs
@@ -0,0 +1,1101 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+use std::mem::replace;
+use std::ops::Range;
+
+use crate::nodes::chunk::{Chunk, CHUNK_SIZE};
+use crate::util::{
+ Pool, PoolRef,
+ Side::{self, Left, Right},
+};
+use crate::vector::RRBPool;
+
+use self::Entry::*;
+
+pub(crate) const NODE_SIZE: usize = CHUNK_SIZE;
+
+#[derive(Debug)]
+enum Size {
+ Size(usize),
+ Table(PoolRef<Chunk<usize>>),
+}
+
+impl Clone for Size {
+ fn clone(&self) -> Self {
+ match *self {
+ Size::Size(size) => Size::Size(size),
+ Size::Table(ref table) => Size::Table(table.clone()),
+ }
+ }
+}
+
+impl Size {
+ fn size(&self) -> usize {
+ match self {
+ Size::Size(s) => *s,
+ Size::Table(sizes) => *sizes.last().unwrap_or(&0),
+ }
+ }
+
+ fn is_size(&self) -> bool {
+ match self {
+ Size::Size(_) => true,
+ Size::Table(_) => false,
+ }
+ }
+
+ fn table_from_size(pool: &Pool<Chunk<usize>>, level: usize, size: usize) -> Self {
+ let mut chunk = Chunk::new();
+ let mut remaining = size;
+ if let Some(child_size) = NODE_SIZE.checked_pow(level as u32) {
+ while remaining > child_size {
+ let next_value = chunk.last().unwrap_or(&0) + child_size;
+ chunk.push_back(next_value);
+ remaining -= child_size;
+ }
+ }
+ if remaining > 0 {
+ let next_value = chunk.last().unwrap_or(&0) + remaining;
+ chunk.push_back(next_value);
+ }
+ Size::Table(PoolRef::new(pool, chunk))
+ }
+
+ fn push(&mut self, pool: &Pool<Chunk<usize>>, side: Side, level: usize, value: usize) {
+ let size = match self {
+ Size::Size(ref mut size) => match side {
+ Left => *size,
+ Right => {
+ *size += value;
+ return;
+ }
+ },
+ Size::Table(ref mut size_ref) => {
+ let size_table = PoolRef::make_mut(pool, size_ref);
+ debug_assert!(size_table.len() < NODE_SIZE);
+ match side {
+ Left => {
+ for entry in size_table.iter_mut() {
+ *entry += value;
+ }
+ size_table.push_front(value);
+ }
+ Right => {
+ let prev = *(size_table.last().unwrap_or(&0));
+ size_table.push_back(value + prev);
+ }
+ }
+ return;
+ }
+ };
+ *self = Size::table_from_size(pool, level, size);
+ self.push(pool, side, level, value);
+ }
+
+ fn pop(&mut self, pool: &Pool<Chunk<usize>>, side: Side, level: usize, value: usize) {
+ let size = match self {
+ Size::Size(ref mut size) => match side {
+ Left => *size,
+ Right => {
+ *size -= value;
+ return;
+ }
+ },
+ Size::Table(ref mut size_ref) => {
+ let size_table = PoolRef::make_mut(pool, size_ref);
+ match side {
+ Left => {
+ let first = size_table.pop_front();
+ debug_assert_eq!(value, first);
+ for entry in size_table.iter_mut() {
+ *entry -= value;
+ }
+ }
+ Right => {
+ let pop = size_table.pop_back();
+ let last = size_table.last().unwrap_or(&0);
+ debug_assert_eq!(value, pop - last);
+ }
+ }
+ return;
+ }
+ };
+ *self = Size::table_from_size(pool, level, size);
+ self.pop(pool, side, level, value);
+ }
+
+ fn update(&mut self, pool: &Pool<Chunk<usize>>, index: usize, level: usize, value: isize) {
+ let size = match self {
+ Size::Size(ref size) => *size,
+ Size::Table(ref mut size_ref) => {
+ let size_table = PoolRef::make_mut(pool, size_ref);
+ for entry in size_table.iter_mut().skip(index) {
+ *entry = (*entry as isize + value) as usize;
+ }
+ return;
+ }
+ };
+ *self = Size::table_from_size(pool, level, size);
+ self.update(pool, index, level, value);
+ }
+}
+
+pub(crate) enum PushResult<A> {
+ Full(A, usize),
+ Done,
+}
+
+pub(crate) enum PopResult<A> {
+ Done(A),
+ Drained(A),
+ Empty,
+}
+
+pub(crate) enum SplitResult {
+ Dropped(usize),
+ OutOfBounds,
+}
+
+// Invariants: Nodes only at level > 0, Values/Empty only at level = 0
+enum Entry<A> {
+ Nodes(Size, PoolRef<Chunk<Node<A>>>),
+ Values(PoolRef<Chunk<A>>),
+ Empty,
+}
+
+impl<A: Clone> Clone for Entry<A> {
+ fn clone(&self) -> Self {
+ match *self {
+ Nodes(ref size, ref nodes) => Nodes(size.clone(), nodes.clone()),
+ Values(ref values) => Values(values.clone()),
+ Empty => Empty,
+ }
+ }
+}
+
+impl<A: Clone> Entry<A> {
+ fn len(&self) -> usize {
+ match self {
+ Nodes(_, ref nodes) => nodes.len(),
+ Values(ref values) => values.len(),
+ Empty => 0,
+ }
+ }
+
+ fn is_full(&self) -> bool {
+ match self {
+ Nodes(_, ref nodes) => nodes.is_full(),
+ Values(ref values) => values.is_full(),
+ Empty => false,
+ }
+ }
+
+ fn unwrap_values(&self) -> &Chunk<A> {
+ match self {
+ Values(ref values) => values,
+ _ => panic!("rrb::Entry::unwrap_values: expected values, found nodes"),
+ }
+ }
+
+ fn unwrap_nodes(&self) -> &Chunk<Node<A>> {
+ match self {
+ Nodes(_, ref nodes) => nodes,
+ _ => panic!("rrb::Entry::unwrap_nodes: expected nodes, found values"),
+ }
+ }
+
+ fn unwrap_values_mut(&mut self, pool: &RRBPool<A>) -> &mut Chunk<A> {
+ match self {
+ Values(ref mut values) => PoolRef::make_mut(&pool.value_pool, values),
+ _ => panic!("rrb::Entry::unwrap_values_mut: expected values, found nodes"),
+ }
+ }
+
+ fn unwrap_nodes_mut(&mut self, pool: &RRBPool<A>) -> &mut Chunk<Node<A>> {
+ match self {
+ Nodes(_, ref mut nodes) => PoolRef::make_mut(&pool.node_pool, nodes),
+ _ => panic!("rrb::Entry::unwrap_nodes_mut: expected nodes, found values"),
+ }
+ }
+
+ fn values(self) -> Chunk<A> {
+ match self {
+ Values(values) => PoolRef::unwrap_or_clone(values),
+ _ => panic!("rrb::Entry::values: expected values, found nodes"),
+ }
+ }
+
+ fn nodes(self) -> Chunk<Node<A>> {
+ match self {
+ Nodes(_, nodes) => PoolRef::unwrap_or_clone(nodes),
+ _ => panic!("rrb::Entry::nodes: expected nodes, found values"),
+ }
+ }
+
+ fn is_empty_node(&self) -> bool {
+ matches!(self, Empty)
+ }
+}
+
+// Node
+
+pub(crate) struct Node<A> {
+ children: Entry<A>,
+}
+
+impl<A: Clone> Clone for Node<A> {
+ fn clone(&self) -> Self {
+ Node {
+ children: self.children.clone(),
+ }
+ }
+}
+
+impl<A: Clone> Default for Node<A> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl<A: Clone> Node<A> {
+ pub(crate) fn new() -> Self {
+ Node { children: Empty }
+ }
+
+ pub(crate) fn parent(pool: &RRBPool<A>, level: usize, children: Chunk<Self>) -> Self {
+ let size = {
+ let mut size = Size::Size(0);
+ let mut it = children.iter().peekable();
+ loop {
+ match it.next() {
+ None => break,
+ Some(child) => {
+ if size.is_size()
+ && !child.is_completely_dense(level - 1)
+ && it.peek().is_some()
+ {
+ size = Size::table_from_size(&pool.size_pool, level, size.size());
+ }
+ size.push(&pool.size_pool, Right, level, child.len())
+ }
+ }
+ }
+ size
+ };
+ Node {
+ children: Nodes(size, PoolRef::new(&pool.node_pool, children)),
+ }
+ }
+
+ pub(crate) fn clear_node(&mut self) {
+ self.children = Empty;
+ }
+
+ pub(crate) fn from_chunk(pool: &RRBPool<A>, level: usize, chunk: PoolRef<Chunk<A>>) -> Self {
+ let node = Node {
+ children: Values(chunk),
+ };
+ node.elevate(pool, level)
+ }
+
+ pub(crate) fn single_parent(pool: &RRBPool<A>, node: Self) -> Self {
+ let size = if node.is_dense() {
+ Size::Size(node.len())
+ } else {
+ let size_table = Chunk::unit(node.len());
+ Size::Table(PoolRef::new(&pool.size_pool, size_table))
+ };
+ let children = PoolRef::new(&pool.node_pool, Chunk::unit(node));
+ Node {
+ children: Nodes(size, children),
+ }
+ }
+
+ pub(crate) fn join_dense(pool: &RRBPool<A>, left: Self, right: Self) -> Self {
+ let left_len = left.len();
+ let right_len = right.len();
+ Node {
+ children: {
+ let children = PoolRef::new(&pool.node_pool, Chunk::pair(left, right));
+ Nodes(Size::Size(left_len + right_len), children)
+ },
+ }
+ }
+
+ pub(crate) fn elevate(self, pool: &RRBPool<A>, level_increment: usize) -> Self {
+ if level_increment > 0 {
+ Self::single_parent(pool, self.elevate(pool, level_increment - 1))
+ } else {
+ self
+ }
+ }
+
+ pub(crate) fn join_branches(self, pool: &RRBPool<A>, right: Self, level: usize) -> Self {
+ let left_len = self.len();
+ let right_len = right.len();
+ let size = if self.is_completely_dense(level) && right.is_dense() {
+ Size::Size(left_len + right_len)
+ } else {
+ let size_table = Chunk::pair(left_len, left_len + right_len);
+ Size::Table(PoolRef::new(&pool.size_pool, size_table))
+ };
+ Node {
+ children: {
+ let children = Chunk::pair(self, right);
+ Nodes(size, PoolRef::new(&pool.node_pool, children))
+ },
+ }
+ }
+
+ pub(crate) fn len(&self) -> usize {
+ match self.children {
+ Entry::Nodes(Size::Size(size), _) => size,
+ Entry::Nodes(Size::Table(ref size_table), _) => *(size_table.last().unwrap_or(&0)),
+ Entry::Values(ref values) => values.len(),
+ Entry::Empty => 0,
+ }
+ }
+
+ pub(crate) fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
+ pub(crate) fn is_single(&self) -> bool {
+ self.children.len() == 1
+ }
+
+ pub(crate) fn is_full(&self) -> bool {
+ self.children.is_full()
+ }
+
+ #[allow(dead_code)] // this is only used by tests
+ pub(crate) fn number_of_children(&self) -> usize {
+ self.children.len()
+ }
+
+ pub(crate) fn first_child(&self) -> &Self {
+ self.children.unwrap_nodes().first().unwrap()
+ }
+
+ /// True if the node is dense and so doesn't have a size table
+ fn is_dense(&self) -> bool {
+ !matches!(self.children, Entry::Nodes(Size::Table(_), _))
+ }
+
+ /// True if the node and its children are dense and at capacity
+ // TODO can use this technique to quickly test if a Size::Table
+ // should be converted back to a Size::Size
+ fn is_completely_dense(&self, level: usize) -> bool {
+ // Size of a full node is NODE_SIZE at level 0, NODE_SIZEĀ² at
+ // level 1, etc.
+ if let Some(expected_size) = NODE_SIZE.checked_pow(level as u32 + 1) {
+ self.size() == expected_size
+ } else {
+ // We overflowed a usize, there's no way we can be completely dense as we know the size
+ // fits in a usize.
+ false
+ }
+ }
+
+ #[inline]
+ fn size(&self) -> usize {
+ match self.children {
+ Entry::Nodes(ref size, _) => size.size(),
+ Entry::Values(ref values) => values.len(),
+ Entry::Empty => 0,
+ }
+ }
+
+ #[inline]
+ fn push_size(&mut self, pool: &RRBPool<A>, side: Side, level: usize, value: usize) {
+ if let Entry::Nodes(ref mut size, _) = self.children {
+ size.push(&pool.size_pool, side, level, value)
+ }
+ }
+
+ #[inline]
+ fn pop_size(&mut self, pool: &RRBPool<A>, side: Side, level: usize, value: usize) {
+ if let Entry::Nodes(ref mut size, _) = self.children {
+ size.pop(&pool.size_pool, side, level, value)
+ }
+ }
+
+ #[inline]
+ fn update_size(&mut self, pool: &RRBPool<A>, index: usize, level: usize, value: isize) {
+ if let Entry::Nodes(ref mut size, _) = self.children {
+ size.update(&pool.size_pool, index, level, value)
+ }
+ }
+
+ fn size_up_to(&self, level: usize, index: usize) -> usize {
+ if let Entry::Nodes(ref size, _) = self.children {
+ if index == 0 {
+ 0
+ } else {
+ match size {
+ Size::Table(ref size_table) => size_table[index - 1],
+ Size::Size(_) => index * NODE_SIZE.pow(level as u32),
+ }
+ }
+ } else {
+ index
+ }
+ }
+
+ fn index_in(&self, level: usize, index: usize) -> Option<usize> {
+ let mut target_idx = if let Some(child_size) = NODE_SIZE.checked_pow(level as u32) {
+ index / child_size
+ } else {
+ 0
+ };
+ if target_idx >= self.children.len() {
+ return None;
+ }
+ if let Entry::Nodes(Size::Table(ref size_table), _) = self.children {
+ while size_table[target_idx] <= index {
+ target_idx += 1;
+ if target_idx >= size_table.len() {
+ return None;
+ }
+ }
+ }
+ Some(target_idx)
+ }
+
+ pub(crate) fn index(&self, level: usize, index: usize) -> &A {
+ if level == 0 {
+ &self.children.unwrap_values()[index]
+ } else {
+ let target_idx = self.index_in(level, index).unwrap();
+ self.children.unwrap_nodes()[target_idx]
+ .index(level - 1, index - self.size_up_to(level, target_idx))
+ }
+ }
+
+ pub(crate) fn index_mut(&mut self, pool: &RRBPool<A>, level: usize, index: usize) -> &mut A {
+ if level == 0 {
+ &mut self.children.unwrap_values_mut(pool)[index]
+ } else {
+ let target_idx = self.index_in(level, index).unwrap();
+ let offset = index - self.size_up_to(level, target_idx);
+ let child = &mut self.children.unwrap_nodes_mut(pool)[target_idx];
+ child.index_mut(pool, level - 1, offset)
+ }
+ }
+
+ pub(crate) fn lookup_chunk(
+ &self,
+ level: usize,
+ base: usize,
+ index: usize,
+ ) -> (Range<usize>, *const Chunk<A>) {
+ if level == 0 {
+ (
+ base..(base + self.children.len()),
+ self.children.unwrap_values() as *const Chunk<A>,
+ )
+ } else {
+ let target_idx = self.index_in(level, index).unwrap();
+ let offset = self.size_up_to(level, target_idx);
+ let child_base = base + offset;
+ let children = self.children.unwrap_nodes();
+ let child = &children[target_idx];
+ child.lookup_chunk(level - 1, child_base, index - offset)
+ }
+ }
+
+ pub(crate) fn lookup_chunk_mut(
+ &mut self,
+ pool: &RRBPool<A>,
+ level: usize,
+ base: usize,
+ index: usize,
+ ) -> (Range<usize>, *mut Chunk<A>) {
+ if level == 0 {
+ (
+ base..(base + self.children.len()),
+ self.children.unwrap_values_mut(pool) as *mut Chunk<A>,
+ )
+ } else {
+ let target_idx = self.index_in(level, index).unwrap();
+ let offset = self.size_up_to(level, target_idx);
+ let child_base = base + offset;
+ let children = self.children.unwrap_nodes_mut(pool);
+ let child = &mut children[target_idx];
+ child.lookup_chunk_mut(pool, level - 1, child_base, index - offset)
+ }
+ }
+
+ fn push_child_node(&mut self, pool: &RRBPool<A>, side: Side, child: Node<A>) {
+ let children = self.children.unwrap_nodes_mut(pool);
+ match side {
+ Left => children.push_front(child),
+ Right => children.push_back(child),
+ }
+ }
+
+ fn pop_child_node(&mut self, pool: &RRBPool<A>, side: Side) -> Node<A> {
+ let children = self.children.unwrap_nodes_mut(pool);
+ match side {
+ Left => children.pop_front(),
+ Right => children.pop_back(),
+ }
+ }
+
+ pub(crate) fn push_chunk(
+ &mut self,
+ pool: &RRBPool<A>,
+ level: usize,
+ side: Side,
+ mut chunk: PoolRef<Chunk<A>>,
+ ) -> PushResult<PoolRef<Chunk<A>>> {
+ if chunk.is_empty() {
+ return PushResult::Done;
+ }
+ let is_full = self.is_full();
+ if level == 0 {
+ if self.children.is_empty_node() {
+ self.push_size(pool, side, level, chunk.len());
+ self.children = Values(chunk);
+ PushResult::Done
+ } else {
+ let values = self.children.unwrap_values_mut(pool);
+ if values.len() + chunk.len() <= NODE_SIZE {
+ let chunk = PoolRef::make_mut(&pool.value_pool, &mut chunk);
+ match side {
+ Side::Left => {
+ chunk.append(values);
+ values.append(chunk);
+ }
+ Side::Right => values.append(chunk),
+ }
+ PushResult::Done
+ } else {
+ PushResult::Full(chunk, 0)
+ }
+ }
+ } else if level == 1 {
+ // If rightmost existing node has any room, merge as much as
+ // possible over from the new node.
+ let num_drained = match side {
+ Side::Right => {
+ if let Entry::Nodes(ref mut size, ref mut children) = self.children {
+ let rightmost = PoolRef::make_mut(&pool.node_pool, children)
+ .last_mut()
+ .unwrap();
+ let old_size = rightmost.len();
+ let chunk = PoolRef::make_mut(&pool.value_pool, &mut chunk);
+ let values = rightmost.children.unwrap_values_mut(pool);
+ let to_drain = chunk.len().min(NODE_SIZE - values.len());
+ values.drain_from_front(chunk, to_drain);
+ size.pop(&pool.size_pool, Side::Right, level, old_size);
+ size.push(&pool.size_pool, Side::Right, level, values.len());
+ to_drain
+ } else {
+ 0
+ }
+ }
+ Side::Left => {
+ if let Entry::Nodes(ref mut size, ref mut children) = self.children {
+ let leftmost = PoolRef::make_mut(&pool.node_pool, children)
+ .first_mut()
+ .unwrap();
+ let old_size = leftmost.len();
+ let chunk = PoolRef::make_mut(&pool.value_pool, &mut chunk);
+ let values = leftmost.children.unwrap_values_mut(pool);
+ let to_drain = chunk.len().min(NODE_SIZE - values.len());
+ values.drain_from_back(chunk, to_drain);
+ size.pop(&pool.size_pool, Side::Left, level, old_size);
+ size.push(&pool.size_pool, Side::Left, level, values.len());
+ to_drain
+ } else {
+ 0
+ }
+ }
+ };
+ if is_full {
+ PushResult::Full(chunk, num_drained)
+ } else {
+ // If the chunk is empty after being drained, there might be
+ // more space in existing chunks. To keep the middle dense, we
+ // do not add it here.
+ if !chunk.is_empty() {
+ if side == Left && chunk.len() < NODE_SIZE {
+ if let Entry::Nodes(ref mut size, _) = self.children {
+ if let Size::Size(value) = *size {
+ *size = Size::table_from_size(&pool.size_pool, level, value);
+ }
+ }
+ }
+ self.push_size(pool, side, level, chunk.len());
+ self.push_child_node(pool, side, Node::from_chunk(pool, 0, chunk));
+ }
+ PushResult::Done
+ }
+ } else {
+ let chunk_size = chunk.len();
+ let index = match side {
+ Right => self.children.len() - 1,
+ Left => 0,
+ };
+ let new_child = {
+ let children = self.children.unwrap_nodes_mut(pool);
+ let child = &mut children[index];
+ match child.push_chunk(pool, level - 1, side, chunk) {
+ PushResult::Done => None,
+ PushResult::Full(chunk, num_drained) => {
+ // Our chunk was too large for `child`, so it could not
+ // be pushed there. However, exactly `num_drained`
+ // elements were added to the child. We need to reflect
+ // that change in the size field of the node.
+ match side {
+ Right => match self.children {
+ Entry::Nodes(Size::Table(ref mut sizes), _) => {
+ let sizes = PoolRef::make_mut(&pool.size_pool, sizes);
+ sizes[index] += num_drained;
+ }
+ Entry::Nodes(Size::Size(ref mut size), _) => {
+ *size += num_drained;
+ }
+ Entry::Values(_) | Entry::Empty => (),
+ },
+ Left => {
+ self.update_size(pool, 0, level, num_drained as isize);
+ }
+ }
+ if is_full {
+ return PushResult::Full(chunk, 0);
+ } else {
+ Some(Node::from_chunk(pool, level - 1, chunk))
+ }
+ }
+ }
+ };
+ match new_child {
+ None => {
+ self.update_size(pool, index, level, chunk_size as isize);
+ PushResult::Done
+ }
+ Some(child) => {
+ if side == Left && chunk_size < NODE_SIZE {
+ if let Entry::Nodes(ref mut size, _) = self.children {
+ if let Size::Size(value) = *size {
+ *size = Size::table_from_size(&pool.size_pool, level, value);
+ }
+ }
+ }
+ self.push_size(pool, side, level, child.len());
+ self.push_child_node(pool, side, child);
+ PushResult::Done
+ }
+ }
+ }
+ }
+
+ pub(crate) fn pop_chunk(
+ &mut self,
+ pool: &RRBPool<A>,
+ level: usize,
+ side: Side,
+ ) -> PopResult<PoolRef<Chunk<A>>> {
+ if self.is_empty() {
+ return PopResult::Empty;
+ }
+ if level == 0 {
+ // should only get here if the tree is just one leaf node
+ match replace(&mut self.children, Empty) {
+ Values(chunk) => PopResult::Drained(chunk),
+ Empty => panic!("rrb::Node::pop_chunk: non-empty tree with Empty leaf"),
+ Nodes(_, _) => panic!("rrb::Node::pop_chunk: branch node at leaf"),
+ }
+ } else if level == 1 {
+ let child_node = self.pop_child_node(pool, side);
+ self.pop_size(pool, side, level, child_node.len());
+ let chunk = match child_node.children {
+ Values(ref chunk) => chunk.clone(),
+ Empty => panic!("rrb::Node::pop_chunk: non-empty tree with Empty leaf"),
+ Nodes(_, _) => panic!("rrb::Node::pop_chunk: branch node at leaf"),
+ };
+ if self.is_empty() {
+ PopResult::Drained(chunk)
+ } else {
+ PopResult::Done(chunk)
+ }
+ } else {
+ let index = match side {
+ Right => self.children.len() - 1,
+ Left => 0,
+ };
+ let mut drained = false;
+ let chunk = {
+ let children = self.children.unwrap_nodes_mut(pool);
+ let child = &mut children[index];
+ match child.pop_chunk(pool, level - 1, side) {
+ PopResult::Empty => return PopResult::Empty,
+ PopResult::Done(chunk) => chunk,
+ PopResult::Drained(chunk) => {
+ drained = true;
+ chunk
+ }
+ }
+ };
+ if drained {
+ self.pop_size(pool, side, level, chunk.len());
+ self.pop_child_node(pool, side);
+ if self.is_empty() {
+ PopResult::Drained(chunk)
+ } else {
+ PopResult::Done(chunk)
+ }
+ } else {
+ self.update_size(pool, index, level, -(chunk.len() as isize));
+ PopResult::Done(chunk)
+ }
+ }
+ }
+
+ pub(crate) fn split(
+ &mut self,
+ pool: &RRBPool<A>,
+ level: usize,
+ drop_side: Side,
+ index: usize,
+ ) -> SplitResult {
+ if index == 0 && drop_side == Side::Left {
+ // Dropped nothing
+ return SplitResult::Dropped(0);
+ }
+ if level > 0 && index == 0 && drop_side == Side::Right {
+ // Dropped everything
+ let dropped = if let Entry::Nodes(ref size, _) = self.children {
+ size.size()
+ } else {
+ panic!("leaf node at non-leaf level!");
+ };
+ self.children = Entry::Empty;
+ return SplitResult::Dropped(dropped);
+ }
+ let mut dropped;
+ if level == 0 {
+ let len = self.children.len();
+ if index >= len {
+ return SplitResult::OutOfBounds;
+ }
+ let children = self.children.unwrap_values_mut(pool);
+ match drop_side {
+ Side::Left => children.drop_left(index),
+ Side::Right => children.drop_right(index),
+ }
+ SplitResult::Dropped(match drop_side {
+ Left => index,
+ Right => len - index,
+ })
+ } else if let Some(target_idx) = self.index_in(level, index) {
+ let size_up_to = self.size_up_to(level, target_idx);
+ let (size, children) =
+ if let Entry::Nodes(ref mut size, ref mut children) = self.children {
+ (size, PoolRef::make_mut(&pool.node_pool, children))
+ } else {
+ unreachable!()
+ };
+ let child_gone = 0 == {
+ let child_node = &mut children[target_idx];
+ match child_node.split(pool, level - 1, drop_side, index - size_up_to) {
+ SplitResult::OutOfBounds => return SplitResult::OutOfBounds,
+ SplitResult::Dropped(amount) => dropped = amount,
+ }
+ child_node.len()
+ };
+ match drop_side {
+ Left => {
+ let mut drop_from = target_idx;
+ if child_gone {
+ drop_from += 1;
+ }
+ children.drop_left(drop_from);
+ if let Size::Size(value) = *size {
+ *size = Size::table_from_size(&pool.size_pool, level, value);
+ }
+ let size_table = if let Size::Table(ref mut size_ref) = size {
+ PoolRef::make_mut(&pool.size_pool, size_ref)
+ } else {
+ unreachable!()
+ };
+ let dropped_size = if target_idx > 0 {
+ size_table[target_idx - 1]
+ } else {
+ 0
+ };
+ dropped += dropped_size;
+ size_table.drop_left(drop_from);
+ for i in size_table.iter_mut() {
+ *i -= dropped;
+ }
+ }
+ Right => {
+ let at_last = target_idx == children.len() - 1;
+ let mut drop_from = target_idx + 1;
+ if child_gone {
+ drop_from -= 1;
+ }
+ if drop_from < children.len() {
+ children.drop_right(drop_from);
+ }
+ match size {
+ Size::Size(ref mut size) if at_last => {
+ *size -= dropped;
+ }
+ Size::Size(ref mut size) => {
+ let size_per_child = NODE_SIZE.pow(level as u32);
+ let remainder = (target_idx + 1) * size_per_child;
+ let new_size = remainder - dropped;
+ if new_size < *size {
+ dropped = *size - new_size;
+ *size = new_size;
+ } else {
+ unreachable!(
+ "this means node is empty, should be caught at start of method"
+ );
+ }
+ }
+ Size::Table(ref mut size_ref) => {
+ let size_table = PoolRef::make_mut(&pool.size_pool, size_ref);
+ let dropped_size =
+ size_table[size_table.len() - 1] - size_table[target_idx];
+ if drop_from < size_table.len() {
+ size_table.drop_right(drop_from);
+ }
+ if !child_gone {
+ size_table[target_idx] -= dropped;
+ }
+ dropped += dropped_size;
+ }
+ }
+ }
+ }
+ SplitResult::Dropped(dropped)
+ } else {
+ SplitResult::OutOfBounds
+ }
+ }
+
+ fn merge_leaves(pool: &RRBPool<A>, mut left: Self, mut right: Self) -> Self {
+ if left.children.is_empty_node() {
+ // Left is empty, just use right
+ Self::single_parent(pool, right)
+ } else if right.children.is_empty_node() {
+ // Right is empty, just use left
+ Self::single_parent(pool, left)
+ } else {
+ {
+ let left_vals = left.children.unwrap_values_mut(pool);
+ let left_len = left_vals.len();
+ let right_vals = right.children.unwrap_values_mut(pool);
+ let right_len = right_vals.len();
+ if left_len + right_len <= NODE_SIZE {
+ left_vals.append(right_vals);
+ } else {
+ let count = right_len.min(NODE_SIZE - left_len);
+ left_vals.drain_from_front(right_vals, count);
+ }
+ }
+ if right.is_empty() {
+ Self::single_parent(pool, left)
+ } else {
+ Self::join_dense(pool, left, right)
+ }
+ }
+ }
+
+ fn merge_rebalance(
+ pool: &RRBPool<A>,
+ level: usize,
+ left: Self,
+ middle: Self,
+ right: Self,
+ ) -> Self {
+ let left_nodes = left.children.nodes().into_iter();
+ let middle_nodes = middle.children.nodes().into_iter();
+ let right_nodes = right.children.nodes().into_iter();
+ let mut subtree_still_balanced = true;
+ let mut next_leaf = Chunk::new();
+ let mut next_node = Chunk::new();
+ let mut next_subtree = Chunk::new();
+ let mut root = Chunk::new();
+
+ for subtree in left_nodes.chain(middle_nodes).chain(right_nodes) {
+ if subtree.is_empty() {
+ continue;
+ }
+ if subtree.is_completely_dense(level) && subtree_still_balanced {
+ root.push_back(subtree);
+ continue;
+ }
+ subtree_still_balanced = false;
+
+ if level == 1 {
+ for value in subtree.children.values() {
+ next_leaf.push_back(value);
+ if next_leaf.is_full() {
+ let new_node =
+ Node::from_chunk(pool, 0, PoolRef::new(&pool.value_pool, next_leaf));
+ next_subtree.push_back(new_node);
+ next_leaf = Chunk::new();
+ if next_subtree.is_full() {
+ let new_subtree = Node::parent(pool, level, next_subtree);
+ root.push_back(new_subtree);
+ next_subtree = Chunk::new();
+ }
+ }
+ }
+ } else {
+ for node in subtree.children.nodes() {
+ next_node.push_back(node);
+ if next_node.is_full() {
+ let new_node = Node::parent(pool, level - 1, next_node);
+ next_subtree.push_back(new_node);
+ next_node = Chunk::new();
+ if next_subtree.is_full() {
+ let new_subtree = Node::parent(pool, level, next_subtree);
+ root.push_back(new_subtree);
+ next_subtree = Chunk::new();
+ }
+ }
+ }
+ }
+ }
+ if !next_leaf.is_empty() {
+ let new_node = Node::from_chunk(pool, 0, PoolRef::new(&pool.value_pool, next_leaf));
+ next_subtree.push_back(new_node);
+ }
+ if !next_node.is_empty() {
+ let new_node = Node::parent(pool, level - 1, next_node);
+ next_subtree.push_back(new_node);
+ }
+ if !next_subtree.is_empty() {
+ let new_subtree = Node::parent(pool, level, next_subtree);
+ root.push_back(new_subtree);
+ }
+ Node::parent(pool, level + 1, root)
+ }
+
+ pub(crate) fn merge(pool: &RRBPool<A>, mut left: Self, mut right: Self, level: usize) -> Self {
+ if level == 0 {
+ Self::merge_leaves(pool, left, right)
+ } else {
+ let merged = {
+ if level == 1 {
+ // We're going to rebalance all the leaves anyway, there's
+ // no need for a middle at level 1
+ Node::parent(pool, 0, Chunk::new())
+ } else {
+ let left_last =
+ if let Entry::Nodes(ref mut size, ref mut children) = left.children {
+ let node = PoolRef::make_mut(&pool.node_pool, children).pop_back();
+ if !node.is_empty() {
+ size.pop(&pool.size_pool, Side::Right, level, node.len());
+ }
+ node
+ } else {
+ panic!("expected nodes, found entries or empty");
+ };
+ let right_first =
+ if let Entry::Nodes(ref mut size, ref mut children) = right.children {
+ let node = PoolRef::make_mut(&pool.node_pool, children).pop_front();
+ if !node.is_empty() {
+ size.pop(&pool.size_pool, Side::Left, level, node.len());
+ }
+ node
+ } else {
+ panic!("expected nodes, found entries or empty");
+ };
+ Self::merge(pool, left_last, right_first, level - 1)
+ }
+ };
+ Self::merge_rebalance(pool, level, left, merged, right)
+ }
+ }
+
+ #[cfg(any(test, feature = "debug"))]
+ pub(crate) fn assert_invariants(&self, level: usize) -> usize {
+ // Verifies that the size table matches reality.
+ match self.children {
+ Entry::Empty => 0,
+ Entry::Values(ref values) => {
+ // An empty value node is pointless and should never occur.
+ assert_ne!(0, values.len());
+ // Value nodes should only occur at level 0.
+ assert_eq!(0, level);
+ values.len()
+ }
+ Entry::Nodes(ref size, ref children) => {
+ // A parent node with no children should never occur.
+ assert_ne!(0, children.len());
+ // Parent nodes should never occur at level 0.
+ assert_ne!(0, level);
+ let mut lengths = Vec::new();
+ let should_be_dense = matches!(size, Size::Size(_));
+ for (index, child) in children.iter().enumerate() {
+ let len = child.assert_invariants(level - 1);
+ if should_be_dense && index < children.len() - 1 {
+ // Assert that non-end nodes without size tables are full.
+ assert_eq!(len, NODE_SIZE.pow(level as u32));
+ }
+ lengths.push(len);
+ }
+ match size {
+ Size::Size(size) => {
+ let total: usize = lengths.iter().sum();
+ assert_eq!(*size, total);
+ }
+ Size::Table(ref table) => {
+ assert_eq!(table.iter().len(), children.len());
+ for (index, current) in table.iter().enumerate() {
+ let expected: usize = lengths.iter().take(index + 1).sum();
+ assert_eq!(expected, *current);
+ }
+ }
+ }
+ lengths.iter().sum()
+ }
+ }
+ }
+
+ // pub fn print<W>(&self, f: &mut W, indent: usize, level: usize) -> Result<(), fmt::Error>
+ // where
+ // W: fmt::Write,
+ // A: fmt::Debug,
+ // {
+ // print_indent(f, indent)?;
+ // if level == 0 {
+ // if self.children.is_empty_node() {
+ // writeln!(f, "Leaf: EMPTY")
+ // } else {
+ // writeln!(f, "Leaf: {:?}", self.children.unwrap_values())
+ // }
+ // } else {
+ // match &self.children {
+ // Entry::Nodes(size, children) => {
+ // writeln!(f, "Node level {} size_table {:?}", level, size)?;
+ // for child in children.iter() {
+ // child.print(f, indent + 4, level - 1)?;
+ // }
+ // Ok(())
+ // }
+ // _ => unreachable!(),
+ // }
+ // }
+ // }
+}
+
+// fn print_indent<W>(f: &mut W, indent: usize) -> Result<(), fmt::Error>
+// where
+// W: fmt::Write,
+// {
+// for _i in 0..indent {
+// write!(f, " ")?;
+// }
+// Ok(())
+// }