1use std::cell::RefCell;
44use std::collections::VecDeque;
45
46use yo_common::Small;
47
48use crate::chunk::{CHUNK_BYTES, Chunk};
49use crate::frozen::{self, Broken};
50use crate::listpack::{Entry, Listpack};
51
52const HITS: usize = 8;
58
59const FORM_PACKED: u8 = 1;
61const FORM_CHUNKS: u8 = 2;
63
64pub type Element<'a> = Entry<'a>;
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub struct Limits {
75 pub max_packed_bytes: usize,
77 pub max_packed_entries: Option<usize>,
85}
86
87impl Default for Limits {
88 fn default() -> Limits {
92 Limits {
93 max_packed_bytes: CHUNK_BYTES,
94 max_packed_entries: None,
95 }
96 }
97}
98
99impl Limits {
100 #[must_use]
107 pub fn of(fill: i32) -> Limits {
108 if fill >= 0 {
109 return Limits {
110 max_packed_bytes: CHUNK_BYTES,
111 max_packed_entries: Some((fill as usize).max(1)),
112 };
113 }
114 const SIZES: [usize; 5] = [4096, 8192, 16384, 32768, 65536];
116 let at = ((-fill) as usize - 1).min(SIZES.len() - 1);
117 Limits {
118 max_packed_bytes: SIZES[at],
119 max_packed_entries: None,
120 }
121 }
122
123 #[must_use]
125 fn exceeded(&self, bytes: usize, entries: usize) -> bool {
126 match self.max_packed_entries {
127 Some(cap) => bytes > CHUNK_BYTES || entries > cap,
128 None => bytes > self.max_packed_bytes,
129 }
130 }
131
132 #[must_use]
134 fn exceeded_halved(&self, bytes: usize, entries: usize) -> bool {
135 match self.max_packed_entries {
136 Some(cap) => bytes > CHUNK_BYTES / 2 || entries > cap / 2,
137 None => bytes > self.max_packed_bytes / 2,
138 }
139 }
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
144pub enum Encoding {
145 Listpack,
147 Quicklist,
149}
150
151impl Encoding {
152 #[must_use]
154 pub const fn name(self) -> &'static str {
155 match self {
156 Encoding::Listpack => "listpack",
157 Encoding::Quicklist => "quicklist",
158 }
159 }
160}
161
162#[derive(Debug, Clone, PartialEq, Eq)]
164enum Body {
165 Packed(Listpack),
166 Chunks(Deque),
167}
168
169#[derive(Debug, Clone, PartialEq, Eq)]
171pub struct List {
172 body: Body,
173}
174
175impl Default for List {
176 fn default() -> List {
177 List::new()
178 }
179}
180
181impl List {
182 #[must_use]
184 pub fn new() -> List {
185 List {
186 body: Body::Packed(Listpack::new()),
187 }
188 }
189
190 #[must_use]
192 #[inline]
193 pub fn len(&self) -> usize {
194 match &self.body {
195 Body::Packed(lp) => lp.len(),
196 Body::Chunks(d) => d.len(),
197 }
198 }
199
200 #[must_use]
206 #[inline]
207 pub fn is_empty(&self) -> bool {
208 self.len() == 0
209 }
210
211 pub fn freeze(&self, out: &mut Vec<u8>) {
230 match &self.body {
231 Body::Packed(lp) => {
232 out.push(FORM_PACKED);
233 out.extend_from_slice(lp.as_bytes());
234 }
235 Body::Chunks(d) => {
236 out.push(FORM_CHUNKS);
237 frozen::put_uint(out, d.chunks.len() as u64);
238 for c in &d.chunks {
239 frozen::put_uint(out, c.len() as u64);
240 frozen::put_bytes(out, c.entries());
241 }
242 }
243 }
244 }
245
246 pub fn thaw(bytes: &[u8]) -> Result<List, Broken> {
253 let mut cut = frozen::Cut::new(bytes);
254 match cut.byte()? {
255 FORM_PACKED => Ok(List {
256 body: Body::Packed(Listpack::from_bytes(cut.rest()).map_err(|_| Broken::Body)?),
257 }),
258 FORM_CHUNKS => {
259 let n = usize::try_from(cut.uint()?).map_err(|_| Broken::Short)?;
260 if n > cut.rest().len() {
263 return Err(Broken::Body);
264 }
265 let mut d = Deque::new();
266 d.chunks.reserve(n);
267 for _ in 0..n {
268 let count = usize::try_from(cut.uint()?).map_err(|_| Broken::Short)?;
269 let entries = cut.bytes()?;
270 if count > entries.len() {
271 return Err(Broken::Body);
274 }
275 d.len += count;
276 d.chunks.push_back(Chunk::adopt(entries, count));
277 }
278 Ok(List {
279 body: Body::Chunks(d),
280 })
281 }
282 _ => Err(Broken::Form),
283 }
284 }
285
286 #[must_use]
288 pub const fn encoding(&self) -> Encoding {
289 match &self.body {
290 Body::Packed(_) => Encoding::Listpack,
291 Body::Chunks(_) => Encoding::Quicklist,
292 }
293 }
294
295 #[must_use]
297 pub fn memory_bytes(&self) -> usize {
298 match &self.body {
299 Body::Packed(lp) => lp.byte_len(),
300 Body::Chunks(d) => d.memory_bytes(),
301 }
302 }
303
304 #[must_use]
306 pub fn get(&self, index: usize) -> Option<Element<'_>> {
307 match &self.body {
308 Body::Packed(lp) => lp.get(index),
309 Body::Chunks(d) => d.get(index),
310 }
311 }
312
313 #[must_use]
315 pub fn front(&self) -> Option<Element<'_>> {
316 match &self.body {
317 Body::Packed(lp) => lp.get(0),
318 Body::Chunks(d) => d.front(),
319 }
320 }
321
322 #[must_use]
327 pub fn back(&self) -> Option<Element<'_>> {
328 match &self.body {
329 Body::Packed(lp) => lp.get_back(0),
330 Body::Chunks(d) => d.back(),
331 }
332 }
333
334 pub fn iter(&self) -> impl Iterator<Item = Element<'_>> {
336 let (packed, chunks) = match &self.body {
339 Body::Packed(lp) => (Some(lp.iter()), None),
340 Body::Chunks(d) => (None, Some(d.iter())),
341 };
342 packed
343 .into_iter()
344 .flatten()
345 .chain(chunks.into_iter().flatten())
346 }
347
348 pub fn iter_back(&self) -> impl Iterator<Item = Element<'_>> {
353 let (packed, chunks) = match &self.body {
354 Body::Packed(lp) => (Some(lp.iter_back()), None),
355 Body::Chunks(d) => (None, Some(d.iter_back())),
356 };
357 packed
358 .into_iter()
359 .flatten()
360 .chain(chunks.into_iter().flatten())
361 }
362
363 pub fn range(&self, start: usize, count: usize) -> impl Iterator<Item = Element<'_>> {
376 let (packed, chunks) = match &self.body {
377 Body::Packed(lp) => (Some(lp.iter_from(start).take(count)), None),
378 Body::Chunks(d) => (None, Some(d.range(start, count))),
379 };
380 packed
381 .into_iter()
382 .flatten()
383 .chain(chunks.into_iter().flatten())
384 }
385
386 pub fn push_front(&mut self, value: &[u8], limits: &Limits) {
388 self.grow_by(value, limits);
389 match &mut self.body {
390 Body::Packed(lp) => lp.insert(0, value),
391 Body::Chunks(d) => d.push_front(value),
392 }
393 }
394
395 pub fn push_back(&mut self, value: &[u8], limits: &Limits) {
397 self.grow_by(value, limits);
398 match &mut self.body {
399 Body::Packed(lp) => lp.push(value),
400 Body::Chunks(d) => d.push_back(value),
401 }
402 }
403
404 pub fn insert(&mut self, index: usize, value: &[u8], limits: &Limits) -> bool {
409 if index > self.len() {
410 return false;
411 }
412 self.grow_by(value, limits);
413 match &mut self.body {
414 Body::Packed(lp) => {
415 lp.insert(index, value);
416 true
417 }
418 Body::Chunks(d) => d.insert_at(index, value),
419 }
420 }
421
422 pub fn insert_at_pivot(
427 &mut self,
428 pivot: &[u8],
429 value: &[u8],
430 before: bool,
431 limits: &Limits,
432 ) -> Option<usize> {
433 let at = self.find(pivot)?;
434 let at = if before { at } else { at + 1 };
435 self.insert(at, value, limits).then(|| self.len())
436 }
437
438 pub fn set(&mut self, index: usize, value: &[u8], limits: &Limits) -> bool {
440 if index >= self.len() {
441 return false;
442 }
443 if let Body::Packed(lp) = &self.body {
448 let old = lp.get(index).map_or(0, |e| e.byte_len());
449 let after = lp.byte_len() + crate::listpack::entry_len(value) - old;
450 self.grow_to(after, self.len(), limits);
451 }
452 match &mut self.body {
453 Body::Packed(lp) => lp.replace(index, value),
454 Body::Chunks(d) => d.replace_at(index, value),
455 }
456 }
457
458 #[must_use]
466 pub fn find(&self, value: &[u8]) -> Option<usize> {
467 let as_int = yo_common::num::parse_i64(value);
468 match &self.body {
469 Body::Packed(lp) => lp.find_parsed(value, as_int, 1),
470 Body::Chunks(d) => d.find(value, as_int),
471 }
472 }
473
474 pub fn positions(
501 &self,
502 value: &[u8],
503 rank: i64,
504 count: usize,
505 maxlen: usize,
506 found: &mut dyn FnMut(usize),
507 ) -> usize {
508 if rank == 0 {
509 return 0;
510 }
511 let as_int = yo_common::num::parse_i64(value);
512 let len = self.len();
513 let mut skip = rank.unsigned_abs() as usize - 1;
514 let mut hits = 0usize;
515 {
516 let mut take = |at: usize| -> bool {
520 if skip > 0 {
521 skip -= 1;
522 return true;
523 }
524 found(at);
525 hits += 1;
526 count == 0 || hits < count
527 };
528 if rank > 0 {
529 match &self.body {
530 Body::Packed(lp) => lp.find_each(value, as_int, maxlen, &mut take),
531 Body::Chunks(d) => d.find_each(value, as_int, maxlen, &mut take),
532 };
533 } else {
534 let mut back = |at: usize| take(len - at - 1);
538 match &self.body {
539 Body::Packed(lp) => lp.find_each_back(value, as_int, maxlen, &mut back),
540 Body::Chunks(d) => d.find_each_back(value, as_int, maxlen, &mut back),
541 };
542 }
543 }
544 hits
545 }
546
547 pub fn remove(&mut self, count: i64, value: &[u8], limits: &Limits) -> usize {
552 let as_int = yo_common::num::parse_i64(value);
553 let want = if count == 0 {
554 usize::MAX
555 } else {
556 count.unsigned_abs() as usize
557 };
558 let mut hits: Small<usize, HITS> = Small::new();
567 if count >= 0 {
568 match &self.body {
569 Body::Packed(lp) => lp.find_each(value, as_int, 0, &mut |at| {
570 hits.push(at);
571 hits.len() < want
572 }),
573 Body::Chunks(d) => d.find_each(value, as_int, 0, &mut |at| {
574 hits.push(at);
575 hits.len() < want
576 }),
577 };
578 hits.reverse();
579 } else {
580 let len = self.len();
581 match &self.body {
582 Body::Packed(lp) => lp.find_each_back(value, as_int, 0, &mut |at| {
583 hits.push(len - at - 1);
584 hits.len() < want
585 }),
586 Body::Chunks(d) => d.find_each_back(value, as_int, 0, &mut |at| {
587 hits.push(len - at - 1);
588 hits.len() < want
589 }),
590 };
591 }
592 for at in &hits {
593 self.remove_at(*at);
594 }
595 self.shrunk(limits);
596 hits.len()
597 }
598
599 fn remove_at(&mut self, index: usize) -> bool {
605 match &mut self.body {
606 Body::Packed(lp) => lp.delete(index, 1),
607 Body::Chunks(d) => d.remove_at(index),
608 }
609 }
610
611 pub fn trim(&mut self, start: usize, count: usize, limits: &Limits) {
617 let len = self.len();
618 let start = start.min(len);
619 let keep = count.min(len - start);
620 match &mut self.body {
621 Body::Packed(lp) => {
622 lp.delete(start + keep, len - start - keep);
623 lp.delete(0, start);
624 }
625 Body::Chunks(d) => d.trim(start, keep),
626 }
627 self.shrunk(limits);
628 }
629
630 pub fn drop_front(&mut self, limits: &Limits) -> bool {
636 let gone = match &mut self.body {
637 Body::Packed(lp) => lp.delete(0, 1),
638 Body::Chunks(d) => d.drop_front(),
639 };
640 self.shrunk(limits);
641 gone
642 }
643
644 pub fn drop_back(&mut self, limits: &Limits) -> bool {
646 let gone = match &mut self.body {
647 Body::Packed(lp) => {
648 let last = lp.len().checked_sub(1);
649 last.is_some_and(|at| lp.delete(at, 1))
650 }
651 Body::Chunks(d) => d.drop_back(),
652 };
653 self.shrunk(limits);
654 gone
655 }
656
657 pub fn pop_front(&mut self, limits: &Limits) -> Option<Vec<u8>> {
662 let out = self.front()?.to_vec();
663 self.drop_front(limits);
664 Some(out)
665 }
666
667 pub fn pop_back(&mut self, limits: &Limits) -> Option<Vec<u8>> {
669 let out = self.back()?.to_vec();
670 self.drop_back(limits);
671 Some(out)
672 }
673
674 fn shrunk(&mut self, limits: &Limits) {
681 let Body::Chunks(d) = &self.body else {
682 return;
683 };
684 if d.chunks.len() != 1 {
685 return;
686 }
687 let only = &d.chunks[0];
688 if limits.exceeded_halved(only.live_bytes(), only.len()) {
689 return;
690 }
691 let mut lp = Listpack::new();
692 for e in only.iter() {
693 match e {
694 Entry::Int(n) => {
695 let mut digits = Vec::new();
696 Entry::Int(n).write_to(&mut digits);
697 lp.push(&digits);
698 }
699 Entry::Str(s) => lp.push(s),
700 }
701 }
702 self.body = Body::Packed(lp);
703 }
704
705 fn grow_by(&mut self, value: &[u8], limits: &Limits) {
711 let Body::Packed(lp) = &self.body else {
712 return;
713 };
714 let after = lp.byte_len() + crate::listpack::entry_len(value);
715 self.grow_to(after, lp.len() + 1, limits);
716 }
717
718 fn grow_to(&mut self, bytes: usize, entries: usize, limits: &Limits) {
720 if !matches!(self.body, Body::Packed(_)) || !limits.exceeded(bytes, entries) {
721 return;
722 }
723 let Body::Packed(lp) = std::mem::replace(&mut self.body, Body::Chunks(Deque::new())) else {
724 unreachable!("just matched a packed body");
725 };
726 let Body::Chunks(d) = &mut self.body else {
727 unreachable!("just put a chunked body there");
728 };
729 d.adopt(&lp);
730 }
731}
732
733fn lone(value: &[u8], front: bool) -> Chunk {
740 if crate::listpack::entry_len(value) > CHUNK_BYTES {
741 return Chunk::plain(value);
742 }
743 let mut c = if front {
744 Chunk::for_front()
745 } else {
746 Chunk::for_back()
747 };
748 let put = if front {
749 c.push_front(value)
750 } else {
751 c.push_back(value)
752 };
753 debug_assert!(put, "an empty chunk refused the only element in it");
754 c
755}
756
757#[derive(Debug, Clone)]
763struct Deque {
764 chunks: VecDeque<Chunk>,
765 len: usize,
766 starts: RefCell<VecDeque<i64>>,
773}
774
775impl PartialEq for Deque {
780 fn eq(&self, other: &Deque) -> bool {
781 self.len == other.len && self.chunks == other.chunks
782 }
783}
784
785impl Eq for Deque {}
786
787impl Deque {
788 fn new() -> Deque {
790 Deque {
791 chunks: VecDeque::new(),
792 len: 0,
793 starts: RefCell::new(VecDeque::new()),
794 }
795 }
796
797 #[inline]
799 const fn len(&self) -> usize {
800 self.len
801 }
802
803 fn adopt(&mut self, lp: &Listpack) {
805 self.len = lp.len();
806 self.chunks.push_back(Chunk::adopt(lp.entries(), lp.len()));
807 self.tail_added();
808 }
809
810 fn memory_bytes(&self) -> usize {
819 let spare = self.chunks.capacity() - self.chunks.len();
820 self.chunks.iter().map(Chunk::memory_bytes).sum::<usize>()
821 + spare * size_of::<Chunk>()
822 + self.starts.borrow().capacity() * size_of::<i64>()
823 }
824
825 fn front(&self) -> Option<Element<'_>> {
827 self.chunks.front()?.front()
828 }
829
830 fn back(&self) -> Option<Element<'_>> {
832 self.chunks.back()?.back()
833 }
834
835 fn get(&self, index: usize) -> Option<Element<'_>> {
837 let (i, within) = self.locate(index)?;
838 self.chunks[i].get(within)
839 }
840
841 fn iter(&self) -> impl Iterator<Item = Element<'_>> {
843 self.chunks.iter().flat_map(Chunk::iter)
844 }
845
846 fn find(&self, value: &[u8], as_int: Option<i64>) -> Option<usize> {
853 let mut base = 0usize;
854 for c in &self.chunks {
855 if let Some(at) = c.find(value, as_int) {
856 return Some(base + at);
857 }
858 base += c.len();
859 }
860 None
861 }
862
863 fn find_each(
869 &self,
870 value: &[u8],
871 as_int: Option<i64>,
872 limit: usize,
873 hit: &mut dyn FnMut(usize) -> bool,
874 ) -> usize {
875 let mut base = 0usize;
876 let mut looked = 0usize;
877 for c in &self.chunks {
878 if limit != 0 && looked >= limit {
879 break;
880 }
881 let at = base;
882 let mut on = true;
883 looked += c.find_each(value, as_int, limit.saturating_sub(looked), &mut |i| {
884 on = hit(at + i);
885 on
886 });
887 base += c.len();
888 if !on {
889 break;
890 }
891 }
892 looked
893 }
894
895 fn find_each_back(
897 &self,
898 value: &[u8],
899 as_int: Option<i64>,
900 limit: usize,
901 hit: &mut dyn FnMut(usize) -> bool,
902 ) -> usize {
903 let mut base = 0usize;
904 let mut looked = 0usize;
905 for c in self.chunks.iter().rev() {
906 if limit != 0 && looked >= limit {
907 break;
908 }
909 let at = base;
910 let mut on = true;
911 looked += c.find_each_back(value, as_int, limit.saturating_sub(looked), &mut |i| {
912 on = hit(at + i);
913 on
914 });
915 base += c.len();
916 if !on {
917 break;
918 }
919 }
920 looked
921 }
922
923 fn range(&self, start: usize, count: usize) -> impl Iterator<Item = Element<'_>> {
932 let (chunk, within) = self.locate(start).unwrap_or((self.chunks.len(), 0));
933 let first = self.chunks.get(chunk).map(|c| c.iter_from(within));
934 first
935 .into_iter()
936 .flatten()
937 .chain(self.chunks.iter().skip(chunk + 1).flat_map(Chunk::iter))
938 .take(count)
939 }
940
941 fn iter_back(&self) -> impl Iterator<Item = Element<'_>> {
943 self.chunks.iter().rev().flat_map(Chunk::iter_back)
944 }
945
946 fn locate(&self, index: usize) -> Option<(usize, usize)> {
972 if index >= self.len {
973 return None;
974 }
975 let head = self.chunks.front()?.len();
982 if index < head {
983 return Some((0, index));
984 }
985 let last = self.chunks.len() - 1;
986 let before_tail = self.len - self.chunks[last].len();
987 if index >= before_tail {
988 return Some((last, index - before_tail));
989 }
990 let mut starts = self.starts.borrow_mut();
991 if starts.is_empty() {
992 starts.push_back(0);
993 }
994 let want = starts[0] + index as i64;
999 loop {
1000 let last = starts.len() - 1;
1001 let end = starts[last] + self.chunks[last].len() as i64;
1002 if end > want || starts.len() == self.chunks.len() {
1003 break;
1004 }
1005 starts.push_back(end);
1006 }
1007 let at = starts.partition_point(|&s| s <= want) - 1;
1011 Some((at, (want - starts[at]) as usize))
1012 }
1013
1014 #[inline]
1019 fn cut(&mut self, from: usize) {
1020 let keep = from.min(self.chunks.len());
1021 let starts = self.starts.get_mut();
1022 if starts.len() > keep {
1023 starts.truncate(keep);
1024 }
1025 }
1026
1027 #[inline]
1032 fn head_moved(&mut self, by: i64) {
1033 if let Some(first) = self.starts.get_mut().front_mut() {
1034 *first += by;
1035 }
1036 }
1037
1038 #[inline]
1040 fn head_added(&mut self, len: usize) {
1041 let starts = self.starts.get_mut();
1042 if let Some(&first) = starts.front() {
1043 starts.push_front(first - len as i64);
1044 }
1045 }
1046
1047 #[inline]
1049 fn head_dropped(&mut self) {
1050 self.starts.get_mut().pop_front();
1051 }
1052
1053 #[inline]
1060 fn tail_added(&mut self) {
1061 let n = self.chunks.len();
1062 let before = if n >= 2 { self.chunks[n - 2].len() } else { 0 };
1063 let starts = self.starts.get_mut();
1064 if n == 1 && starts.is_empty() {
1065 starts.push_back(0);
1066 } else if starts.len() + 1 == n {
1067 let last = starts[n - 2];
1068 starts.push_back(last + before as i64);
1069 }
1070 }
1071
1072 fn push_front(&mut self, value: &[u8]) {
1074 if let Some(head) = self.chunks.front_mut()
1075 && head.push_front(value)
1076 {
1077 self.len += 1;
1078 self.head_moved(-1);
1079 return;
1080 }
1081 if self.chunks.front().is_some_and(Chunk::is_empty) {
1085 self.chunks.pop_front();
1086 self.head_dropped();
1087 } else if let Some(head) = self.chunks.front_mut() {
1088 head.seal();
1089 }
1090 self.chunks.push_front(lone(value, true));
1091 self.len += 1;
1092 self.head_added(1);
1093 }
1094
1095 fn push_back(&mut self, value: &[u8]) {
1097 if let Some(tail) = self.chunks.back_mut()
1098 && tail.push_back(value)
1099 {
1100 self.len += 1;
1101 return;
1102 }
1103 if self.chunks.back().is_some_and(Chunk::is_empty) {
1104 self.chunks.pop_back();
1105 self.cut(self.chunks.len());
1106 } else if let Some(tail) = self.chunks.back_mut() {
1107 tail.seal();
1108 }
1109 self.chunks.push_back(lone(value, false));
1110 self.len += 1;
1111 self.tail_added();
1112 }
1113
1114 fn insert_at(&mut self, index: usize, value: &[u8]) -> bool {
1121 if index > self.len {
1122 return false;
1123 }
1124 if index == 0 {
1125 self.push_front(value);
1126 return true;
1127 }
1128 if index == self.len {
1129 self.push_back(value);
1130 return true;
1131 }
1132 let Some((i, within)) = self.locate(index) else {
1133 return false;
1134 };
1135 if self.chunks[i].insert_at(within, value) {
1136 self.len += 1;
1137 self.cut(i + 1);
1139 return true;
1140 }
1141 let mut rest = self.chunks[i].split_off(within);
1142 let put = self.chunks[i].push_back(value) || rest.push_front(value);
1144 self.chunks.insert(i + 1, rest);
1145 if !put {
1146 self.chunks.insert(i + 1, lone(value, false));
1147 }
1148 self.len += 1;
1149 self.cut(i + 1);
1150 true
1151 }
1152
1153 fn remove_at(&mut self, index: usize) -> bool {
1155 let Some((i, within)) = self.locate(index) else {
1156 return false;
1157 };
1158 if !self.chunks[i].remove_at(within) {
1159 return false;
1160 }
1161 self.len -= 1;
1162 if self.chunks[i].is_empty() && self.chunks.len() > 1 {
1163 self.chunks.remove(i);
1164 self.cut(i);
1168 } else {
1169 self.cut(i + 1);
1170 }
1171 true
1172 }
1173
1174 fn replace_at(&mut self, index: usize, value: &[u8]) -> bool {
1179 let Some((i, within)) = self.locate(index) else {
1180 return false;
1181 };
1182 if self.chunks[i].replace_at(within, value) {
1183 return true;
1186 }
1187 let mut rest = self.chunks[i].split_off(within);
1188 rest.drop_front();
1189 let put = self.chunks[i].push_back(value) || rest.push_front(value);
1190 if !rest.is_empty() {
1191 self.chunks.insert(i + 1, rest);
1192 }
1193 if !put {
1194 self.chunks.insert(i + 1, lone(value, false));
1195 }
1196 if self.chunks[i].is_empty() && self.chunks.len() > 1 {
1197 self.chunks.remove(i);
1198 }
1199 self.cut(i);
1200 true
1201 }
1202
1203 fn trim(&mut self, start: usize, keep: usize) {
1210 let mut front = start;
1211 while front > 0 {
1212 let Some(held) = self.chunks.front().map(Chunk::len) else {
1213 break;
1214 };
1215 if held <= front && self.chunks.len() > 1 {
1216 front -= held;
1217 self.len -= held;
1218 self.chunks.pop_front();
1219 self.head_dropped();
1220 } else {
1221 let took = self.chunks[0].drop_front_n(front);
1222 self.len -= took;
1223 front -= took;
1224 self.head_moved(took as i64);
1225 if took == 0 {
1226 break;
1227 }
1228 }
1229 }
1230 let mut back = self.len - keep.min(self.len);
1231 while back > 0 {
1232 let Some(held) = self.chunks.back().map(Chunk::len) else {
1233 break;
1234 };
1235 if held <= back && self.chunks.len() > 1 {
1236 back -= held;
1237 self.len -= held;
1238 self.chunks.pop_back();
1239 self.cut(self.chunks.len());
1240 } else {
1241 let last = self.chunks.len() - 1;
1242 let took = self.chunks[last].drop_back_n(back);
1243 self.len -= took;
1244 back -= took;
1245 if took == 0 {
1246 break;
1247 }
1248 }
1249 }
1250 }
1251
1252 fn drop_front(&mut self) -> bool {
1254 let Some(head) = self.chunks.front_mut() else {
1255 return false;
1256 };
1257 if !head.drop_front() {
1258 return false;
1259 }
1260 let gone = head.is_empty();
1261 self.len -= 1;
1262 self.head_moved(1);
1263 if gone && self.chunks.len() > 1 {
1264 self.chunks.pop_front();
1265 self.head_dropped();
1266 }
1267 true
1268 }
1269
1270 fn drop_back(&mut self) -> bool {
1272 let Some(tail) = self.chunks.back_mut() else {
1273 return false;
1274 };
1275 if !tail.drop_back() {
1276 return false;
1277 }
1278 let gone = tail.is_empty();
1279 self.len -= 1;
1280 if gone && self.chunks.len() > 1 {
1281 self.chunks.pop_back();
1282 self.cut(self.chunks.len());
1283 }
1284 true
1285 }
1286
1287 #[cfg(test)]
1294 fn index_is_true(&self) {
1295 let starts = self.starts.borrow();
1296 assert!(
1297 starts.len() <= self.chunks.len(),
1298 "the index describes {} chunks and the ring holds {}",
1299 starts.len(),
1300 self.chunks.len()
1301 );
1302 let Some(&base) = starts.front() else {
1303 return;
1304 };
1305 let mut real = 0usize;
1306 for (i, &s) in starts.iter().enumerate() {
1307 assert_eq!(
1308 s - base,
1309 real as i64,
1310 "chunk {i} is indexed at {} and starts at {real}",
1311 s - base
1312 );
1313 real += self.chunks[i].len();
1314 }
1315 }
1316}
1317
1318#[cfg(test)]
1319mod tests {
1320 use super::*;
1321
1322 fn all(l: &List) -> Vec<Vec<u8>> {
1323 l.iter().map(|e| e.to_vec()).collect()
1324 }
1325
1326 fn both_bands(n: usize) -> [List; 2] {
1333 let limits = Limits::default();
1334 let mut packed = List::new();
1335 let mut chunks = List::new();
1336 for i in 0..n {
1337 packed.push_back(format!("e{i}").as_bytes(), &limits);
1338 chunks.push_back(format!("e{i}:{}", "p".repeat(400)).as_bytes(), &limits);
1339 }
1340 assert_eq!(packed.encoding(), Encoding::Listpack);
1341 assert_eq!(chunks.encoding(), Encoding::Quicklist);
1342 [packed, chunks]
1343 }
1344
1345 fn chunked(n: usize) -> List {
1348 let mut l = List::new();
1349 let limits = Limits::default();
1350 for i in 0..n {
1351 l.push_back(format!("value:{i:0>60}").as_bytes(), &limits);
1352 }
1353 assert_eq!(l.encoding(), Encoding::Quicklist, "{n} did not promote");
1354 l
1355 }
1356
1357 #[test]
1358 fn a_new_list_is_empty_and_packed() {
1359 let l = List::new();
1360 assert!(l.is_empty());
1361 assert_eq!(l.len(), 0);
1362 assert_eq!(l.encoding(), Encoding::Listpack);
1363 assert!(l.front().is_none());
1364 assert!(l.back().is_none());
1365 assert!(l.get(0).is_none());
1366 }
1367
1368 #[test]
1369 fn pushing_at_both_ends_puts_the_elements_in_order() {
1370 let mut l = List::new();
1371 let limits = Limits::default();
1372 l.push_back(b"b", &limits);
1373 l.push_back(b"c", &limits);
1374 l.push_front(b"a", &limits);
1375 assert_eq!(all(&l), vec![b"a".to_vec(), b"b".to_vec(), b"c".to_vec()]);
1376 assert_eq!(l.front().unwrap().to_vec(), b"a");
1377 assert_eq!(l.back().unwrap().to_vec(), b"c");
1378 assert_eq!(l.get(1).unwrap().to_vec(), b"b");
1379 assert_eq!(l.len(), 3);
1380 }
1381
1382 #[test]
1383 fn popping_takes_from_the_end_it_says() {
1384 let mut l = List::new();
1385 let limits = Limits::default();
1386 for m in [b"a", b"b", b"c"] {
1387 l.push_back(m, &limits);
1388 }
1389 assert_eq!(l.pop_front(&limits).unwrap(), b"a");
1390 assert_eq!(l.pop_back(&limits).unwrap(), b"c");
1391 assert_eq!(all(&l), vec![b"b".to_vec()]);
1392 assert_eq!(l.pop_front(&limits).unwrap(), b"b");
1393 assert!(l.pop_front(&limits).is_none());
1394 assert!(l.pop_back(&limits).is_none());
1395 assert!(l.is_empty());
1396 }
1397
1398 #[test]
1401 fn a_thousand_short_elements_stay_packed() {
1402 let mut l = List::new();
1403 let limits = Limits::default();
1404 for i in 0..1000 {
1405 l.push_back(i.to_string().as_bytes(), &limits);
1406 }
1407 assert_eq!(l.encoding(), Encoding::Listpack);
1408 assert_eq!(l.len(), 1000);
1409 }
1410
1411 #[test]
1412 fn enough_bytes_promotes_and_keeps_every_element() {
1413 let l = chunked(300);
1414 assert_eq!(l.len(), 300);
1415 for i in 0..300 {
1416 assert_eq!(
1417 l.get(i).unwrap().to_vec(),
1418 format!("value:{i:0>60}").into_bytes(),
1419 "element {i} after promotion"
1420 );
1421 }
1422 }
1423
1424 #[test]
1425 fn a_chunked_list_pushes_and_pops_at_both_ends() {
1426 let mut l = chunked(300);
1427 let limits = Limits::default();
1428 l.push_front(b"first", &limits);
1429 l.push_back(b"last", &limits);
1430 assert_eq!(l.len(), 302);
1431 assert_eq!(l.front().unwrap().to_vec(), b"first");
1432 assert_eq!(l.back().unwrap().to_vec(), b"last");
1433 assert_eq!(l.pop_front(&limits).unwrap(), b"first");
1434 assert_eq!(l.pop_back(&limits).unwrap(), b"last");
1435 assert_eq!(l.len(), 300);
1436 assert_eq!(
1437 l.front().unwrap().to_vec(),
1438 format!("value:{:0>60}", 0).into_bytes()
1439 );
1440 }
1441
1442 #[test]
1446 fn a_queue_drains_in_the_order_it_filled() {
1447 let mut l = List::new();
1448 let limits = Limits::default();
1449 for i in 0..5000 {
1450 l.push_back(format!("job:{i:0>40}").as_bytes(), &limits);
1451 }
1452 for i in 0..5000 {
1453 assert_eq!(
1454 l.pop_front(&limits).unwrap(),
1455 format!("job:{i:0>40}").into_bytes(),
1456 "job {i} came back in the wrong place"
1457 );
1458 }
1459 assert!(l.is_empty());
1460 }
1461
1462 #[test]
1465 fn a_stack_comes_back_in_reverse() {
1466 let mut l = List::new();
1467 let limits = Limits::default();
1468 for i in 0..2000 {
1469 l.push_front(format!("frame:{i:0>40}").as_bytes(), &limits);
1470 }
1471 for i in (0..2000).rev() {
1472 assert_eq!(
1473 l.pop_front(&limits).unwrap(),
1474 format!("frame:{i:0>40}").into_bytes()
1475 );
1476 }
1477 assert!(l.is_empty());
1478 }
1479
1480 #[test]
1481 fn indexing_agrees_with_the_walk_from_both_ends() {
1482 let l = chunked(1000);
1483 let walked = all(&l);
1484 for (i, want) in walked.iter().enumerate() {
1485 assert_eq!(&l.get(i).unwrap().to_vec(), want, "at {i}");
1486 }
1487 assert!(l.get(walked.len()).is_none());
1488 }
1489
1490 #[test]
1493 fn a_list_that_shrinks_far_enough_goes_back_to_one_blob() {
1494 let mut l = chunked(300);
1495 let limits = Limits::default();
1496 while l.len() > 200 {
1497 l.drop_back(&limits);
1498 }
1499 assert_eq!(
1500 l.encoding(),
1501 Encoding::Quicklist,
1502 "under the limit is not under half of it"
1503 );
1504 while l.len() > 50 {
1505 l.drop_back(&limits);
1506 }
1507 assert_eq!(l.encoding(), Encoding::Listpack);
1508 assert_eq!(l.len(), 50);
1509 for i in 0..50 {
1510 assert_eq!(
1511 l.get(i).unwrap().to_vec(),
1512 format!("value:{i:0>60}").into_bytes(),
1513 "element {i} survived the demotion"
1514 );
1515 }
1516 }
1517
1518 #[test]
1521 fn a_demoted_list_promotes_again() {
1522 let mut l = chunked(300);
1523 let limits = Limits::default();
1524 while l.len() > 20 {
1525 l.drop_back(&limits);
1526 }
1527 assert_eq!(l.encoding(), Encoding::Listpack);
1528 for i in 0..300 {
1529 l.push_back(format!("again:{i:0>60}").as_bytes(), &limits);
1530 }
1531 assert_eq!(l.encoding(), Encoding::Quicklist);
1532 assert_eq!(l.len(), 320);
1533 assert_eq!(
1534 l.get(19).unwrap().to_vec(),
1535 format!("value:{:0>60}", 19).into_bytes(),
1536 "the last of the elements that survived the demotion"
1537 );
1538 assert_eq!(
1539 l.get(20).unwrap().to_vec(),
1540 format!("again:{:0>60}", 0).into_bytes(),
1541 "the first of the elements pushed after it"
1542 );
1543 }
1544
1545 #[test]
1548 fn integers_stay_integers_across_the_band_change() {
1549 let mut l = List::new();
1550 let limits = Limits::default();
1551 for i in 0..300 {
1552 l.push_back(i.to_string().as_bytes(), &limits);
1553 l.push_back(vec![b'x'; 100].as_slice(), &limits);
1554 }
1555 assert_eq!(l.encoding(), Encoding::Quicklist);
1556 assert_eq!(l.get(0), Some(Entry::Int(0)));
1557 assert_eq!(l.get(2), Some(Entry::Int(1)));
1558 assert_eq!(l.len(), 600);
1559 }
1560
1561 #[test]
1565 fn a_count_limit_promotes_on_the_count() {
1566 let limits = Limits::of(4);
1567 let mut l = List::new();
1568 for i in 0..4 {
1569 l.push_back(i.to_string().as_bytes(), &limits);
1570 }
1571 assert_eq!(l.encoding(), Encoding::Listpack);
1572 l.push_back(b"5", &limits);
1573 assert_eq!(l.encoding(), Encoding::Quicklist);
1574 assert_eq!(l.len(), 5);
1575 }
1576
1577 #[test]
1578 fn the_limits_are_redis_node_limits() {
1579 assert_eq!(Limits::of(-1).max_packed_bytes, 4096);
1580 assert_eq!(Limits::of(-2).max_packed_bytes, 8192);
1581 assert_eq!(Limits::of(-5).max_packed_bytes, 65536);
1582 assert_eq!(Limits::of(-9).max_packed_bytes, 65536);
1583 assert_eq!(Limits::of(128).max_packed_entries, Some(128));
1584 assert_eq!(Limits::of(0).max_packed_entries, Some(1));
1585 assert_eq!(Limits::of(-2), Limits::default());
1586 }
1587
1588 #[test]
1589 fn memory_is_counted_in_both_bands() {
1590 let mut l = List::new();
1591 let limits = Limits::default();
1592 assert!(l.memory_bytes() > 0);
1593 for i in 0..300 {
1594 l.push_back(format!("value:{i:0>60}").as_bytes(), &limits);
1595 }
1596 let held = l.memory_bytes();
1599 assert!(held > 300 * 66, "{held} is less than the elements");
1600 assert!(held < 300 * 66 * 3, "{held} is three times the elements");
1601 }
1602
1603 #[test]
1613 #[ignore = "a measurement, run it by name"]
1614 fn measure_bytes_per_element() {
1615 let limits = Limits::default();
1616 for len in [8usize, 16, 64] {
1617 for n in [128usize, 10_000, 1_000_000] {
1618 let (l, payload) = weighed(n, len, &limits);
1619 let total = l.memory_bytes();
1620 println!(
1621 "n={n:<9} elem={len:<4} band={:<9} total={total:<11} payload={payload:<11} over_per_element={:.2}",
1622 l.encoding().name(),
1623 (total as f64 - payload as f64) / n as f64
1624 );
1625 }
1626 }
1627 }
1628
1629 fn weighed(n: usize, len: usize, limits: &Limits) -> (List, usize) {
1631 let mut l = List::new();
1632 let mut payload = 0usize;
1633 for i in 0..n {
1634 let v = format!("e{i:0>w$}", w = len - 1);
1638 debug_assert_eq!(v.len(), len);
1639 payload += v.len();
1640 l.push_back(v.as_bytes(), limits);
1641 }
1642 (l, payload)
1643 }
1644
1645 #[test]
1652 fn a_long_list_does_not_hold_much_more_than_it_stores() {
1653 let limits = Limits::default();
1654 let n = 100_000;
1655 let (l, payload) = weighed(n, 16, &limits);
1656 assert_eq!(l.encoding(), Encoding::Quicklist);
1657 let total = l.memory_bytes();
1658 assert!(
1659 total < payload + n * 4,
1660 "{total} bytes for {payload} of elements, which is {:.2} an element over",
1661 (total as f64 - payload as f64) / n as f64
1662 );
1663 }
1664
1665 #[test]
1669 fn an_element_too_big_for_a_chunk_gets_one_of_its_own() {
1670 let mut l = List::new();
1671 let limits = Limits::default();
1672 let huge = vec![b'h'; 20_000];
1673 l.push_back(&huge, &limits);
1674 assert_eq!(l.len(), 1);
1675 assert_eq!(l.encoding(), Encoding::Quicklist);
1676 assert_eq!(l.front().unwrap().to_vec(), huge);
1677 l.push_back(b"after", &limits);
1678 l.push_front(b"before", &limits);
1679 assert_eq!(l.len(), 3);
1680 assert_eq!(l.get(1).unwrap().to_vec(), huge);
1681 assert_eq!(l.back().unwrap().to_vec(), b"after");
1682 assert_eq!(l.front().unwrap().to_vec(), b"before");
1683 assert_eq!(l.pop_front(&limits).unwrap(), b"before");
1684 assert_eq!(l.pop_front(&limits).unwrap(), huge);
1685 }
1686
1687 #[test]
1688 fn the_walk_backward_is_the_walk_forward_reversed() {
1689 for mut l in [List::new(), chunked(400)] {
1690 let limits = Limits::default();
1691 l.push_back(b"tail", &limits);
1692 let mut want = all(&l);
1693 want.reverse();
1694 let got: Vec<Vec<u8>> = l.iter_back().map(|e| e.to_vec()).collect();
1695 assert_eq!(got, want, "{:?}", l.encoding());
1696 }
1697 }
1698
1699 #[test]
1700 fn a_range_is_the_window_it_was_asked_for() {
1701 for l in both_bands(50) {
1702 let all_of_it = all(&l);
1703 for (start, count) in [(0, 0), (0, 5), (3, 4), (48, 9), (50, 3), (0, 50)] {
1704 let got: Vec<Vec<u8>> = l.range(start, count).map(|e| e.to_vec()).collect();
1705 let want = &all_of_it[start.min(50)..(start + count).min(50)];
1706 assert_eq!(got, want, "{start} for {count} in {:?}", l.encoding());
1707 }
1708 }
1709 }
1710
1711 #[test]
1716 fn a_window_lands_in_the_right_place_whatever_chunk_it_starts_in() {
1717 let limits = Limits::default();
1718 let mut l = List::new();
1719 for i in 0..500 {
1723 l.push_back(format!("e{i}:{}", "p".repeat(200)).as_bytes(), &limits);
1724 }
1725 assert_eq!(l.encoding(), Encoding::Quicklist);
1726 let all_of_it = all(&l);
1727
1728 for start in 0..=500 {
1729 for count in [0usize, 1, 7, 130, 500] {
1730 let got: Vec<Vec<u8>> = l.range(start, count).map(|e| e.to_vec()).collect();
1731 let want = &all_of_it[start.min(500)..(start + count).min(500)];
1732 assert_eq!(got, want, "{count} from {start}");
1733 }
1734 }
1735 }
1736
1737 #[test]
1744 fn a_packed_window_lands_in_the_right_place_from_either_end() {
1745 let limits = Limits::default();
1746 let mut l = List::new();
1747 for i in 0..400 {
1748 l.push_back(format!("e{i:0>9}").as_bytes(), &limits);
1749 }
1750 assert_eq!(l.encoding(), Encoding::Listpack);
1751 let all_of_it = all(&l);
1752
1753 for start in 0..=400 {
1754 assert_eq!(
1755 l.get(start).map(|e| e.to_vec()).as_ref(),
1756 all_of_it.get(start),
1757 "element {start}"
1758 );
1759 for count in [0usize, 1, 7, 130, 400] {
1760 let got: Vec<Vec<u8>> = l.range(start, count).map(|e| e.to_vec()).collect();
1761 let want = &all_of_it[start.min(400)..(start + count).min(400)];
1762 assert_eq!(got, want, "{count} from {start}");
1763 }
1764 }
1765 }
1766
1767 #[test]
1774 fn reading_the_middle_survives_a_head_that_keeps_moving() {
1775 let limits = Limits::default();
1776 let mut l = List::new();
1777 let mut want: Vec<Vec<u8>> = Vec::new();
1778 for i in 0..2000 {
1779 let v = format!("e{i}:{}", "p".repeat(100)).into_bytes();
1780 l.push_back(&v, &limits);
1781 want.push(v);
1782 }
1783 assert_eq!(l.encoding(), Encoding::Quicklist);
1784
1785 for round in 0..400 {
1786 if round % 3 == 0 {
1789 for k in 0..7 {
1790 let v = format!("h{round}:{k}:{}", "q".repeat(100)).into_bytes();
1791 l.push_front(&v, &limits);
1792 want.insert(0, v);
1793 }
1794 } else {
1795 for _ in 0..5 {
1796 assert_eq!(l.pop_front(&limits), Some(want.remove(0)));
1797 }
1798 }
1799 assert_eq!(l.len(), want.len(), "length after round {round}");
1800 for at in [0, 1, want.len() / 3, want.len() / 2, want.len() - 1] {
1801 assert_eq!(
1802 l.get(at).map(|e| e.to_vec()).as_ref(),
1803 Some(&want[at]),
1804 "element {at} after round {round}"
1805 );
1806 }
1807 let mid = want.len() / 2;
1808 let got: Vec<Vec<u8>> = l.range(mid, 30).map(|e| e.to_vec()).collect();
1809 assert_eq!(got, want[mid..mid + 30], "the window after round {round}");
1810 let Body::Chunks(d) = &l.body else {
1811 panic!("the list left the chunked band");
1812 };
1813 d.index_is_true();
1814 }
1815 }
1816
1817 #[test]
1818 fn setting_an_element_replaces_only_that_one() {
1819 for mut l in both_bands(50) {
1820 let limits = Limits::default();
1821 let before = all(&l);
1822 let band = l.encoding();
1823 for at in [0usize, 1, 25, 49] {
1824 let mut want = before.clone();
1825 for value in [
1826 &b"z"[..],
1827 &b"a much longer element than the one there"[..],
1828 b"42",
1829 ] {
1830 assert!(l.set(at, value, &limits), "setting {at} in {band:?}");
1831 want[at] = value.to_vec();
1832 assert_eq!(all(&l), want, "setting {at} to {value:?} in {band:?}");
1833 }
1834 l.set(at, &before[at], &limits);
1835 }
1836 assert!(!l.set(50, b"z", &limits), "past the end is not a set");
1837 assert_eq!(all(&l), before);
1838 }
1839 }
1840
1841 #[test]
1853 fn a_pivot_is_found_at_the_right_position_across_a_ring_of_chunks() {
1854 let limits = Limits::default();
1855 let mut l = List::new();
1856 let mut want: Vec<Vec<u8>> = Vec::new();
1857 for i in 0..4_000usize {
1858 let v = match i % 4 {
1862 0 => i.to_string().into_bytes(),
1863 1 => (i64::MAX - i as i64).to_string().into_bytes(),
1864 2 => format!("v{i:0width$}", width = 1 + i % 30).into_bytes(),
1865 _ => format!("value:{i}:{}", "x".repeat(40 + i % 90)).into_bytes(),
1866 };
1867 l.push_back(&v, &limits);
1868 want.push(v);
1869 }
1870 assert_eq!(l.encoding(), Encoding::Quicklist, "this needs the ring");
1871 assert_eq!(l.len(), want.len());
1872 for (at, v) in want.iter().enumerate() {
1873 assert_eq!(l.find(v), Some(at), "element {at} is not where it is");
1874 }
1875 assert_eq!(l.find(b"not in here at all"), None);
1876 assert_eq!(l.find(b"v2000000000000000000000000000002"), None);
1880 }
1881
1882 #[test]
1889 fn positions_agree_with_the_element_walk_across_a_ring_of_chunks() {
1890 let limits = Limits::default();
1891 let mut l = List::new();
1892 for i in 0..4_000usize {
1893 let v = if i % 7 == 0 {
1894 b"wanted".to_vec()
1895 } else {
1896 format!("element:{i:0width$}", width = 8 + i % 40).into_bytes()
1897 };
1898 l.push_back(&v, &limits);
1899 }
1900 assert_eq!(l.encoding(), Encoding::Quicklist, "this needs the ring");
1901 let want: Vec<usize> = (0..4_000).filter(|i| i % 7 == 0).collect();
1902
1903 let mut got = Vec::new();
1904 assert_eq!(
1905 l.positions(b"wanted", 1, 0, 0, &mut |at| got.push(at)),
1906 want.len()
1907 );
1908 assert_eq!(got, want);
1909
1910 let mut got = Vec::new();
1913 l.positions(b"wanted", -1, 0, 0, &mut |at| got.push(at));
1914 got.reverse();
1915 assert_eq!(got, want, "the same matches, found the other way round");
1916
1917 let mut got = Vec::new();
1920 l.positions(b"wanted", 4, 3, 0, &mut |at| got.push(at));
1921 assert_eq!(got, want[3..6].to_vec());
1922 let mut got = Vec::new();
1923 l.positions(b"wanted", -4, 3, 0, &mut |at| got.push(at));
1924 let mut tail = want[want.len() - 6..want.len() - 3].to_vec();
1925 tail.reverse();
1926 assert_eq!(got, tail);
1927
1928 let mut got = Vec::new();
1931 l.positions(b"wanted", 1, 0, 1_000, &mut |at| got.push(at));
1932 assert_eq!(
1933 got,
1934 want.iter()
1935 .copied()
1936 .filter(|&i| i < 1_000)
1937 .collect::<Vec<_>>()
1938 );
1939 let mut got = Vec::new();
1940 l.positions(b"wanted", -1, 0, 1_000, &mut |at| got.push(at));
1941 got.reverse();
1942 assert_eq!(
1943 got,
1944 want.iter()
1945 .copied()
1946 .filter(|&i| i >= 3_000)
1947 .collect::<Vec<_>>()
1948 );
1949 }
1950
1951 #[test]
1955 fn removing_across_a_ring_takes_out_exactly_what_was_asked_for() {
1956 let limits = Limits::default();
1957 let build = || {
1958 let mut l = List::new();
1959 for i in 0..3_000usize {
1960 let v = if i % 5 == 0 {
1961 b"gone".to_vec()
1962 } else {
1963 format!("element:{i:0width$}", width = 8 + i % 30).into_bytes()
1964 };
1965 l.push_back(&v, &limits);
1966 }
1967 assert_eq!(l.encoding(), Encoding::Quicklist, "this needs the ring");
1968 l
1969 };
1970 let kept: Vec<Vec<u8>> = (0..3_000usize)
1971 .filter(|i| i % 5 != 0)
1972 .map(|i| format!("element:{i:0width$}", width = 8 + i % 30).into_bytes())
1973 .collect();
1974
1975 let mut l = build();
1976 assert_eq!(l.remove(0, b"gone", &limits), 600);
1977 assert_eq!(all(&l), kept);
1978
1979 let mut l = build();
1981 assert_eq!(l.remove(10, b"gone", &limits), 10);
1982 assert_eq!(l.len(), 2_990);
1983 assert_eq!(l.find(b"gone"), Some(40), "the eleventh was at 50");
1984
1985 let mut l = build();
1987 assert_eq!(l.remove(-10, b"gone", &limits), 10);
1988 assert_eq!(l.len(), 2_990);
1989 let mut last = 0usize;
1990 l.positions(b"gone", -1, 1, 0, &mut |at| last = at);
1991 assert_eq!(last, 2_945);
1994 }
1995
1996 #[test]
1997 fn an_insert_goes_where_the_pivot_is() {
1998 for mut l in both_bands(50) {
1999 let limits = Limits::default();
2000 let before = all(&l);
2001 let band = l.encoding();
2002 let pivot = before[25].clone();
2003 assert_eq!(
2004 l.insert_at_pivot(&pivot, b"before", true, &limits),
2005 Some(51)
2006 );
2007 assert_eq!(
2008 l.insert_at_pivot(&pivot, b"after", false, &limits),
2009 Some(52)
2010 );
2011 assert_eq!(l.get(25).unwrap().to_vec(), b"before", "{band:?}");
2012 assert_eq!(l.get(26).unwrap().to_vec(), pivot, "{band:?}");
2013 assert_eq!(l.get(27).unwrap().to_vec(), b"after", "{band:?}");
2014 assert_eq!(l.len(), 52);
2015 assert_eq!(
2016 l.insert_at_pivot(b"nothing like it", b"x", true, &limits),
2017 None
2018 );
2019 assert_eq!(l.len(), 52);
2020 }
2021 }
2022
2023 #[test]
2024 fn an_insert_by_index_takes_both_ends_and_the_middle() {
2025 for at in [0usize, 1, 200, 399, 400] {
2026 let mut l = chunked(400);
2027 let limits = Limits::default();
2028 let mut want = all(&l);
2029 assert!(l.insert(at, b"new", &limits), "inserting at {at}");
2030 want.insert(at, b"new".to_vec());
2031 assert_eq!(all(&l), want, "inserting at {at}");
2032 assert_eq!(l.len(), 401);
2033 }
2034 let mut l = chunked(400);
2035 assert!(!l.insert(401, b"new", &Limits::default()));
2036 }
2037
2038 #[test]
2039 fn removing_by_value_counts_from_the_end_it_was_told_to() {
2040 let build = || {
2041 let mut l = List::new();
2042 let limits = Limits::default();
2043 for i in 0..40 {
2044 l.push_back(
2045 if i % 3 == 0 {
2046 b"x".to_vec()
2047 } else {
2048 format!("e{i}").into_bytes()
2049 }
2050 .as_slice(),
2051 &limits,
2052 );
2053 }
2054 l
2055 };
2056 let limits = Limits::default();
2057
2058 let mut l = build();
2059 assert_eq!(l.remove(0, b"x", &limits), 14, "every one of them");
2060 assert!(!all(&l).contains(&b"x".to_vec()));
2061 assert_eq!(l.len(), 26);
2062
2063 let mut l = build();
2064 assert_eq!(l.remove(2, b"x", &limits), 2);
2065 assert_eq!(l.len(), 38);
2066 assert_eq!(l.get(0).unwrap().to_vec(), b"e1", "the first two went");
2067
2068 let mut l = build();
2069 assert_eq!(l.remove(-2, b"x", &limits), 2);
2070 assert_eq!(l.get(0).unwrap().to_vec(), b"x", "the last two went");
2071 assert_eq!(l.back().unwrap().to_vec(), b"e38");
2072
2073 let mut l = build();
2074 assert_eq!(l.remove(99, b"x", &limits), 14, "more than there are");
2075 assert_eq!(l.remove(1, b"nothing like it", &limits), 0);
2076 }
2077
2078 #[test]
2079 fn a_trim_keeps_the_window_and_nothing_else() {
2080 for (start, count) in [
2081 (0usize, 400usize),
2082 (0, 10),
2083 (390, 10),
2084 (100, 200),
2085 (0, 0),
2086 (399, 1),
2087 ] {
2088 let mut l = chunked(400);
2089 let limits = Limits::default();
2090 let want = all(&l)[start..start + count].to_vec();
2091 l.trim(start, count, &limits);
2092 assert_eq!(all(&l), want, "keeping {count} from {start}");
2093 assert_eq!(l.len(), count);
2094 }
2095 }
2096
2097 #[test]
2100 fn a_trim_that_leaves_a_handful_goes_back_to_one_blob() {
2101 let mut l = chunked(400);
2102 let limits = Limits::default();
2103 l.trim(10, 5, &limits);
2104 assert_eq!(l.encoding(), Encoding::Listpack);
2105 assert_eq!(l.len(), 5);
2106 assert_eq!(
2107 l.get(0).unwrap().to_vec(),
2108 format!("value:{:0>60}", 10).into_bytes()
2109 );
2110 }
2111
2112 #[test]
2113 fn a_position_is_counted_from_the_end_the_rank_asked_for() {
2114 for mut l in [List::new(), chunked(300)] {
2115 let limits = Limits::default();
2116 let band = l.encoding();
2117 for m in [b"a", b"b", b"a", b"c", b"a"] {
2118 l.push_back(m, &limits);
2119 }
2120 let base = l.len() - 5;
2121 let mut out = Vec::new();
2122
2123 l.positions(b"a", 1, 1, 0, &mut |at| out.push(at));
2124 assert_eq!(out, vec![base], "{band:?}");
2125
2126 out.clear();
2127 l.positions(b"a", 2, 1, 0, &mut |at| out.push(at));
2128 assert_eq!(out, vec![base + 2], "the second from the front");
2129
2130 out.clear();
2131 l.positions(b"a", -1, 1, 0, &mut |at| out.push(at));
2132 assert_eq!(out, vec![base + 4], "the first from the back");
2133
2134 out.clear();
2135 l.positions(b"a", -2, 1, 0, &mut |at| out.push(at));
2136 assert_eq!(out, vec![base + 2], "the second from the back");
2137
2138 out.clear();
2139 l.positions(b"a", 1, 0, 0, &mut |at| out.push(at));
2140 assert_eq!(out, vec![base, base + 2, base + 4], "all of them");
2141
2142 out.clear();
2143 l.positions(b"a", -1, 0, 0, &mut |at| out.push(at));
2144 assert_eq!(out, vec![base + 4, base + 2, base], "all of them backward");
2145
2146 out.clear();
2147 l.positions(b"a", 1, 2, 0, &mut |at| out.push(at));
2148 assert_eq!(out, vec![base, base + 2], "two of them");
2149
2150 out.clear();
2151 l.positions(b"nothing like it", 1, 0, 0, &mut |at| out.push(at));
2152 assert!(out.is_empty());
2153
2154 out.clear();
2155 l.positions(b"a", 0, 0, 0, &mut |at| out.push(at));
2156 assert!(out.is_empty(), "a rank of zero is not a rank");
2157 }
2158 }
2159
2160 #[test]
2163 fn maxlen_stops_the_walk_rather_than_the_answers() {
2164 let mut l = List::new();
2165 let limits = Limits::default();
2166 for i in 0..20 {
2167 l.push_back(
2168 if i == 15 {
2169 b"x".to_vec()
2170 } else {
2171 format!("e{i}").into_bytes()
2172 }
2173 .as_slice(),
2174 &limits,
2175 );
2176 }
2177 let mut out = Vec::new();
2178 l.positions(b"x", 1, 0, 10, &mut |at| out.push(at));
2179 assert!(out.is_empty(), "ten comparisons do not reach the sixteenth");
2180 out.clear();
2181 l.positions(b"x", 1, 0, 16, &mut |at| out.push(at));
2182 assert_eq!(out, vec![15]);
2183 out.clear();
2184 l.positions(b"x", -1, 0, 5, &mut |at| out.push(at));
2185 assert_eq!(out, vec![15], "five from the back does reach it");
2186 }
2187
2188 #[test]
2193 fn a_long_run_of_operations_agrees_with_a_vec() {
2194 let (_, chunked) = model_run(&Limits::default());
2200 assert_eq!(chunked, 0, "the default limits should not chunk this list");
2201 let (packed, chunked) = model_run(&Limits::of(8));
2202 assert!(packed > 200, "{packed} rounds packed");
2203 assert!(chunked > 200, "{chunked} rounds chunked");
2204 }
2205
2206 fn model_run(limits: &Limits) -> (usize, usize) {
2209 let mut l = List::new();
2210 let mut want: Vec<Vec<u8>> = Vec::new();
2211 let mut seed = 0x2064_u64;
2214 let mut next = move || {
2215 seed = seed.wrapping_mul(6_364_136_223_846_793_005).wrapping_add(1);
2216 (seed >> 33) as usize
2217 };
2218 let (mut packed, mut chunked) = (0, 0);
2219 for round in 0..4000 {
2220 let n = next();
2221 let value = match n % 4 {
2222 0 => format!("{}", n % 97).into_bytes(),
2223 1 => vec![b'a' + (n % 26) as u8; 1 + n % 40],
2224 2 => vec![b'z'; 200 + n % 400],
2225 _ => format!("e{round}").into_bytes(),
2226 };
2227 match n % 9 {
2228 0 => {
2229 l.push_front(&value, limits);
2230 want.insert(0, value);
2231 }
2232 1 | 2 => {
2233 l.push_back(&value, limits);
2234 want.push(value);
2235 }
2236 3 if !want.is_empty() => {
2237 let at = n % want.len();
2238 assert!(l.insert(at, &value, limits));
2239 want.insert(at, value);
2240 }
2241 4 if !want.is_empty() => {
2242 let at = n % want.len();
2243 assert!(l.set(at, &value, limits));
2244 want[at] = value;
2245 }
2246 5 if !want.is_empty() => {
2247 assert_eq!(l.pop_front(limits), Some(want.remove(0)));
2248 }
2249 6 if !want.is_empty() => {
2250 assert_eq!(l.pop_back(limits), want.pop());
2251 }
2252 7 if want.len() > 4 => {
2253 let start = n % (want.len() - 2);
2254 let keep = 1 + n % (want.len() - start);
2255 l.trim(start, keep, limits);
2256 want = want[start..start + keep].to_vec();
2257 }
2258 8 if !want.is_empty() => {
2259 let needle = want[n % want.len()].clone();
2260 let count = [0i64, 1, -1, 3][n % 4];
2261 let gone = l.remove(count, &needle, limits);
2262 let mut hits: Vec<usize> = want
2263 .iter()
2264 .enumerate()
2265 .filter(|(_, m)| **m == needle)
2266 .map(|(i, _)| i)
2267 .collect();
2268 if count < 0 {
2269 hits.reverse();
2270 }
2271 if count != 0 {
2272 hits.truncate(count.unsigned_abs() as usize);
2273 }
2274 assert_eq!(gone, hits.len(), "round {round}");
2275 hits.sort_unstable();
2276 for at in hits.iter().rev() {
2277 want.remove(*at);
2278 }
2279 }
2280 _ => {}
2281 }
2282 assert_eq!(l.len(), want.len(), "length after round {round}");
2283 if !want.is_empty() {
2289 for at in [0, want.len() / 2, want.len() - 1] {
2290 assert_eq!(
2291 l.get(at).map(|e| e.to_vec()).as_ref(),
2292 Some(&want[at]),
2293 "element {at} after round {round}"
2294 );
2295 }
2296 }
2297 if let Body::Chunks(d) = &l.body {
2298 d.index_is_true();
2299 }
2300 match l.encoding() {
2301 Encoding::Listpack => packed += 1,
2302 Encoding::Quicklist => chunked += 1,
2303 }
2304 if round % 25 == 0 {
2305 assert_eq!(all(&l), want, "contents after round {round}");
2306 let mut back = all(&l);
2307 back.reverse();
2308 let walked: Vec<Vec<u8>> = l.iter_back().map(|e| e.to_vec()).collect();
2309 assert_eq!(walked, back, "the backward walk after round {round}");
2310 if let Some(first) = want.first() {
2311 assert_eq!(l.front().unwrap().to_vec(), *first);
2312 assert_eq!(l.back().unwrap().to_vec(), *want.last().unwrap());
2313 assert_eq!(l.find(first), Some(0));
2314 }
2315 }
2316 }
2317 assert_eq!(all(&l), want);
2318 (packed, chunked)
2319 }
2320
2321 fn round_trip(l: &List) -> List {
2323 let mut out = Vec::new();
2324 l.freeze(&mut out);
2325 let back = List::thaw(&out).expect("it came back");
2326 assert_eq!(back.len(), l.len(), "the length");
2327 assert_eq!(back.encoding(), l.encoding(), "the band");
2328 assert_eq!(all(&back), all(l), "the elements");
2329 let mut backward: Vec<Vec<u8>> = back.iter_back().map(|e| e.to_vec()).collect();
2330 backward.reverse();
2331 assert_eq!(backward, all(l), "and the walk the other way");
2332 back
2333 }
2334
2335 #[test]
2336 fn a_frozen_list_comes_back_in_the_band_it_left() {
2337 round_trip(&List::new());
2338 for l in both_bands(40) {
2339 round_trip(&l);
2340 }
2341 for l in both_bands(200) {
2342 round_trip(&l);
2343 }
2344 }
2345
2346 #[test]
2352 fn a_ring_comes_back_with_the_same_chunk_boundaries() {
2353 let l = chunked(2000);
2354 let Body::Chunks(before) = &l.body else {
2355 unreachable!("chunked built a ring");
2356 };
2357 let want: Vec<usize> = before.chunks.iter().map(Chunk::len).collect();
2358 assert!(want.len() > 2, "{} chunks is not a ring", want.len());
2359
2360 let back = round_trip(&l);
2361 let Body::Chunks(after) = &back.body else {
2362 unreachable!("it came back a ring");
2363 };
2364 let got: Vec<usize> = after.chunks.iter().map(Chunk::len).collect();
2365 assert_eq!(got, want);
2366 }
2367
2368 #[test]
2369 fn a_list_that_came_back_takes_more_elements_at_both_ends() {
2370 let limits = Limits::default();
2371 for l in both_bands(200) {
2372 let mut back = round_trip(&l);
2373 back.push_front(b"first", &limits);
2374 back.push_back(b"last", &limits);
2375 assert_eq!(back.len(), l.len() + 2);
2376 assert_eq!(back.front().expect("a front").to_vec(), b"first".to_vec());
2377 assert_eq!(back.back().expect("a back").to_vec(), b"last".to_vec());
2378 assert_eq!(back.get(1).expect("the old front").to_vec(), all(&l)[0]);
2379 }
2380 }
2381
2382 #[test]
2383 fn an_element_too_big_for_a_chunk_survives_the_trip() {
2384 let limits = Limits::default();
2385 let mut l = List::new();
2386 l.push_back(b"before", &limits);
2387 l.push_back(&vec![b'x'; CHUNK_BYTES * 2], &limits);
2388 l.push_back(b"after", &limits);
2389 assert_eq!(l.encoding(), Encoding::Quicklist);
2390 let back = round_trip(&l);
2391 assert_eq!(
2392 back.get(1).expect("the big one").to_vec().len(),
2393 CHUNK_BYTES * 2
2394 );
2395 }
2396
2397 #[test]
2398 fn a_frozen_list_that_arrives_damaged_is_an_error_and_not_a_panic() {
2399 for l in both_bands(40) {
2400 let mut out = Vec::new();
2401 l.freeze(&mut out);
2402 for cut in 0..out.len() {
2403 let _ = List::thaw(&out[..cut]);
2404 }
2405 }
2406 assert_eq!(List::thaw(&[]).err(), Some(Broken::Short));
2407 assert_eq!(List::thaw(&[9]).err(), Some(Broken::Form));
2408 assert_eq!(List::thaw(&[FORM_PACKED, 1, 2]).err(), Some(Broken::Body));
2409 assert_eq!(
2412 List::thaw(&[FORM_CHUNKS, 0xff, 0xff, 0x7f, 0]).err(),
2413 Some(Broken::Body)
2414 );
2415 assert_eq!(
2416 List::thaw(&[FORM_CHUNKS, 1, 9, 2, b'a', b'b']).err(),
2417 Some(Broken::Body)
2418 );
2419 }
2420}