otter_base/
zcoord.rs

1// Copyright 2020-2021 Ian Jackson and contributors to Otter
2// SPDX-License-Identifier: AGPL-3.0-or-later
3// There is NO WARRANTY.
4
5// This is a multiprecision sort-of-bigfloat with only a handful of
6// operations available!
7//
8// Representation, and model, ought to have these properties
9//     CBOR is binary and compact
10//  *  JSON is not lossy
11//  *  JSON is human-comprehensible
12//  *  JavaScript can compare efficiently
13//     Limb size is small for not being too full of padding
14//  *  Limb size is big so step algorithm rarely encounters limb boundaries
15//
16// Many of these are not compatible (in theory extending
17// the serde data model might help a bit, but not completely).
18// We choose those properties marked with "*".
19//
20// Main representation is a string:
21//   VVVVVVVVVV_VVVVVVVVVV ...]
22// where
23//   VVVVVVVVVV = 50 bits in lowercase base32hex ("0-9a-..."), unsigned
24// Value is a whole number of 50-bit groups ("limbs"), at least one sucb.
25// The value "0000000000" is forbidden.
26//
27// The abstract value is completed by an infinite number of zero
28// limbs to the right.  Trailing zero limbs are forbidden in the
29// representation.
30//
31// Supported operations are:
32//
33//    Total ordering
34//       Values are compared lexically.
35//
36//    Select initial value:
37//       g000000000
38//
39//    Pick a value (or "n" values) strictly in between any two
40//    existing values.
41//
42//       Find first limb that they differ.    If this
43//       leaves less than an increment of 1 per output value, do
44//       differently: choose a value halfway (rounding down) for the
45//       first differeing limb, and add a new limb, whose whole range
46//       0000000000..vvvvvvvvvv is divided evenly into n+1 (thus
47//       guaranteeing that the added limb is nonzero).
48//
49//    Pick a value later than a specified value.
50//
51//       Try to add delta to rightmost nonzero limb, with carry.  If
52//       this would overflow top limb, start again: add two limbs
53//       0000000000 and then redo (this guarantees that one of the
54//       added limbs iis nonzero).  Delta is 0001000000.
55//
56//    Pick a value earlier than a specified value.
57//
58//       Try to subtract delta from rightmost nonzero limb, with
59//       borrow.  If this would underflow, or would change leftmost
60//       limb to 0000000000, start again: decrement rightmost nonzero
61//       limb by 1, with borrow, then add two limbs vvvvvvvvvv, and
62//       redo.
63//
64//    Given a base value, and an u32 "offset multiplier", produce a value
65//
66//       The resulting values are all greater than the base, and
67//       in the same order as the provided offset multipliers.
68//       The function is deterministic
69
70use crate::prelude::*;
71
72//---------- core definitions ----------
73
74pub type RangeCount = u32;
75
76type Tail1 = u8;
77
78const BITS_PER_DIGIT: usize = 5;
79const DIGITS_PER_LIMB: usize = 10;
80
81type RawLimbVal = u64;
82#[derive(Copy,Clone,Eq,PartialEq,Ord,PartialOrd)]
83#[derive(Neg,Add,BitAnd,Sub,Shr,ShrAssign)]
84pub struct LimbVal(Wrapping<RawLimbVal>);
85
86const DELTA: LimbVal = lv(0x4000_0000);
87const ZERO: LimbVal = lv(0);
88const ONE: LimbVal = lv(1);
89const MINUS_ONE: LimbVal = lv(-1i64 as u64);
90
91const RAW_LIMB_MODULUS: RawLimbVal = 1u64 << BITS_PER_LIMB;
92
93const BITS_PER_LIMB: usize = BITS_PER_DIGIT * DIGITS_PER_LIMB;
94const DIGIT_MASK: LimbVal = lv((1u64 << BITS_PER_DIGIT) - 1);
95const TEXT_PER_LIMB: usize = DIGITS_PER_LIMB + 1;
96const LIMB_MODULUS: LimbVal = lv(RAW_LIMB_MODULUS);
97const LIMB_MASK: LimbVal = lv(RAW_LIMB_MODULUS - 1);
98
99#[derive(DeserializeFromStr,SerializeDisplay)]
100pub struct ZCoord(innards::Innards);
101
102#[derive(Error,Clone,Copy,Debug,Eq,PartialEq,Serialize,Deserialize)]
103#[error("error parsing Z coordinate")]
104pub struct ParseError;
105
106#[derive(Error,Clone,Copy,Debug,Eq,PartialEq,Serialize,Deserialize)]
107pub enum RangeImpossible {
108  #[error("Z coordinate range has end before start, cannot iterate")]
109  Backwards,
110  #[error("Z coordinate range has end equal to start, cannot iterate")]
111  Empty,
112}
113
114#[derive(Error,Clone,Copy,Debug,Eq,PartialEq,Serialize,Deserialize)]
115#[error("Z coordinate range has neither end, cannot iterate")]
116pub struct TotallyUnboundedRange;
117
118#[derive(Error,Debug,Copy,Clone,Eq,PartialEq,Serialize,Deserialize)]
119#[error("Z coordinate overflow")]
120pub struct Overflow;
121
122#[derive(Error,Clone,Copy,Debug,Eq,PartialEq,Serialize,Deserialize)]
123pub enum LogicError {
124  #[error("{0}")] RangeTotallyUnbounded(#[from] TotallyUnboundedRange),
125  #[error("{0}")] RangeImpossible      (#[from] RangeImpossible      ),
126}
127
128//---------- LimbVal ----------
129
130impl From<RawLimbVal> for LimbVal {
131  fn from(raw: RawLimbVal) -> LimbVal { lv(raw) }
132}
133
134const fn lv(raw: RawLimbVal) -> LimbVal { LimbVal(Wrapping(raw)) }
135
136impl LimbVal {
137  pub fn primitive(self) -> RawLimbVal { self.0.0 }
138  /// return value is the top bits, shifted
139  pub fn to_str_buf(self, out: &mut [Tail1; DIGITS_PER_LIMB]) -> LimbVal {
140    let mut l = self;
141    for p in out.iter_mut().rev() {
142      let v = (l & DIGIT_MASK).primitive() as u8;
143      *p = if v < 10 { b'0' + v } else { (b'a' - 10) + v };
144      l >>= BITS_PER_DIGIT;
145    }
146    l
147  }
148}
149
150impl Display for LimbVal {
151  #[throws(fmt::Error)]
152  fn fmt(&self, f: &mut fmt::Formatter) {
153    let mut buf = [0u8; DIGITS_PER_LIMB];
154    let lhs: RawLimbVal = self.to_str_buf(&mut buf).primitive();
155    if lhs != 0 {
156      write!(f, "{:#x?}_!_", lhs)?;
157    }
158    write!(f, "{}", str::from_utf8(&buf).unwrap())?;
159  }
160}
161
162impl Debug for LimbVal {
163  #[throws(fmt::Error)]
164  fn fmt(&self, f: &mut fmt::Formatter) {
165    write!(f, "lv(")?;
166    Display::fmt(self, f)?;
167    write!(f, ")")?;
168  }
169}
170
171//---------- Mutabel ----------
172
173#[derive(Clone,Debug)]
174pub struct Mutable {
175  limbs: Vec<LimbVal>,
176}
177
178impl ZCoord {
179  pub fn clone_mut(&self) -> Mutable {
180    Mutable::from_u8_unchecked(self.tail())
181  }
182}
183
184impl Mutable {
185  fn from_u8_unchecked(tail: &[u8]) -> Mutable {
186    let nlimbs = (tail.len() + 1) / TEXT_PER_LIMB;
187    let mut limbs = Vec::with_capacity(nlimbs + 2);
188    for lt in tail.chunks(TEXT_PER_LIMB) {
189      let s = str::from_utf8(&lt[0..DIGITS_PER_LIMB]).unwrap();
190      let v = RawLimbVal::from_str_radix(s, 1 << BITS_PER_DIGIT).unwrap();
191      limbs.push(v.into());
192    }
193    Mutable { limbs }
194  }
195}
196
197impl From<TryFromIntError> for Overflow {
198  fn from(_: TryFromIntError) -> Overflow { Overflow }
199}
200
201pub trait AddSubOffset {
202  fn init_delta(&self) -> LimbVal;
203  const CARRY_DELTA      : LimbVal;
204  const NEW_LIMBS        : LimbVal;
205  fn check_underflow(m: &Mutable, i: usize, nv: LimbVal) -> Option<()>;
206  #[throws(as Option)]
207  fn check_nospace(i: usize) { if i == 0 { throw!() } }
208  fn start_limb(&self, m: &Mutable) -> usize { m.limbs.len() - 1 }
209  fn final_undo_delta() -> LimbVal;
210  const SEALED_TRAIT: Sealed;
211}
212
213pub struct Sealed(());
214
215#[derive(Debug)]
216pub struct Increment;
217impl AddSubOffset for Increment {
218  fn init_delta(&self) -> LimbVal { DELTA }
219  const CARRY_DELTA      : LimbVal = ONE;
220  const NEW_LIMBS        : LimbVal = ZERO;
221  #[throws(as Option)]
222  fn check_underflow(_: &Mutable, _: usize, _: LimbVal) { }
223  fn final_undo_delta() -> LimbVal { DELTA }
224  const SEALED_TRAIT: Sealed = Sealed(());
225}
226
227#[derive(Debug)]
228pub struct Decrement;
229impl AddSubOffset for Decrement {
230  fn init_delta(&self) -> LimbVal { -DELTA }
231  const CARRY_DELTA : LimbVal = MINUS_ONE;
232  const NEW_LIMBS   : LimbVal = LIMB_MASK;
233  #[throws(as Option)]
234  fn check_underflow(_: &Mutable, i: usize, nv: LimbVal) {
235    if i == 0 && nv == ZERO { throw!() }
236  }
237  fn final_undo_delta() -> LimbVal { -DELTA + ONE }
238  const SEALED_TRAIT: Sealed = Sealed(());
239}
240
241impl Mutable {
242  #[throws(Overflow)]
243  fn addsub<ASO:AddSubOffset>(&mut self, aso: &ASO) -> ZCoord {
244    'attempt: loop {
245      let mut i = aso.start_limb(self);
246      let mut delta = aso.init_delta();
247
248      if (||{
249        loop {
250          let nv = self.limbs[i] + delta;
251          self.limbs[i] = nv & LIMB_MASK;
252          ASO::check_underflow(self, i, nv)?;
253          if nv < LIMB_MODULUS { return Some(()) }
254          ASO::check_nospace(i)?;
255          i -= 1;
256          delta = ASO::CARRY_DELTA;
257        }
258      })() == Some(()) { break 'attempt }
259
260      // undo
261      loop {
262        if i >= self.limbs.len() { break }
263        else if i == aso.start_limb(self) { delta = ASO::final_undo_delta(); }
264        let nv = self.limbs[i] - delta;
265        self.limbs[i] = nv & LIMB_MASK;
266        i += 1;
267      }
268      self.limbs.push(ASO::NEW_LIMBS);
269      self.limbs.push(ASO::NEW_LIMBS);
270    }
271    self.repack()?
272  }
273
274  #[throws(Overflow)]
275  pub fn increment(&mut self) -> ZCoord { self.addsub(&Increment)? }
276  #[throws(Overflow)]
277  pub fn decrement(&mut self) -> ZCoord { self.addsub(&Decrement)? }
278
279  #[throws(Overflow)]
280  pub fn repack(&self) -> ZCoord {
281    let mut limbs = self.limbs.as_slice();
282    while let Some(l) = limbs.strip_suffix(&[ZERO]) { limbs = l }
283
284    let taillen = (limbs.len() * TEXT_PER_LIMB - 1).try_into()?;
285    let mut bf = ZCoord::alloc(taillen);
286    let mut w = bf.tail_mut();
287
288    for l in limbs.iter().cloned() {
289      if l >= LIMB_MODULUS { throw!(Overflow) };
290      l.to_str_buf((&mut w[0..DIGITS_PER_LIMB]).try_into().unwrap());
291      if let Some(p) = w.get_mut(DIGITS_PER_LIMB) {
292        *p = b'_';
293      } else {
294        break;
295      }
296      w = &mut w[TEXT_PER_LIMB..];
297    }
298    bf
299  }
300}
301
302pub type RangeIterator = std::iter::Take<
303    IteratorCore<AddSubRangeDelta, MutateFirst>
304    >;
305
306pub trait MutateReturn: Copy {
307  fn op<T, U,
308        M: FnOnce(&mut T),
309        O: FnOnce(&T) -> U>
310    (self,
311     x: &mut T,
312     m: M,
313     o: O) -> U;
314}
315
316#[derive(Debug,Copy,Clone)]
317pub struct MutateFirst;
318impl MutateReturn for MutateFirst {
319  fn op<T, U,
320        M: FnOnce(&mut T),
321        O: FnOnce(&T) -> U>
322    (self, x: &mut T, m: M, o: O) -> U
323  {
324    m(x);
325    o(x)
326  }
327}
328
329#[derive(Debug,Copy,Clone)]
330pub struct MutateLast;
331impl MutateReturn for MutateLast {
332  fn op<T, U,
333        M: FnOnce(&mut T),
334        O: FnOnce(&T) -> U>
335    (self, x: &mut T, m: M, o: O) -> U
336  {
337    let u = o(x);
338    m(x);
339    u
340  }
341}
342
343#[derive(Debug)]
344pub struct IteratorCore<ASO, MR> {
345  current: Mutable,
346  aso: ASO,
347  mr: MR,
348}
349
350#[derive(Debug)]
351pub struct AddSubRangeDelta {
352  i: usize,
353  step: LimbVal,
354}
355impl AddSubOffset for AddSubRangeDelta {
356  fn init_delta(&self) -> LimbVal { self.step }
357  const CARRY_DELTA : LimbVal = ONE;
358  const NEW_LIMBS   : LimbVal = ZERO;
359  #[throws(as Option)]
360  fn check_underflow(_: &Mutable, _: usize, _: LimbVal) { }
361  #[throws(as Option)]
362  fn check_nospace(i: usize) { assert_ne!(i, 0) }
363  fn start_limb(&self, _: &Mutable) -> usize { self.i }
364  fn final_undo_delta() -> LimbVal { panic!() }
365  const SEALED_TRAIT: Sealed = Sealed(());
366}
367
368impl Mutable {
369  fn limb_val_lookup(&self, i: usize) -> LimbVal {
370    *self.limbs.get(i).unwrap_or(&ZERO)
371  }
372  fn extend_to_limb(&mut self, i: usize) {
373    if self.limbs.len() <= i {
374      self.limbs.resize(i+1, ZERO);
375    }
376  }
377
378  #[throws(RangeImpossible)]
379  fn range_core(a: &Mutable, b: &Mutable, count: RangeCount)
380                -> (Mutable, AddSubRangeDelta) {
381    type ASRD = AddSubRangeDelta;
382    let count = count as RawLimbVal;
383    let mut current = a.clone();
384    let mut borrowing = false;
385    let aso = 'ok: loop { for i in 0.. {
386      if i > a.limbs.len() && i > b.limbs.len() {
387	// Oh actually these numbers are equal!
388        // (We have to tolerate one limb eyond each number, because possibly
389        // we had to borrow and add a limb to the longer number.)
390	throw!(RangeImpossible::Empty);
391      }
392      //dbgc!(&a, &b, &count, i, &current, borrowing);
393
394      current.extend_to_limb(i);
395
396      let la = a.limb_val_lookup(i);
397      let lb = b.limb_val_lookup(i);
398      if la == lb && ! borrowing {
399        // We have not yet found any difference between these numbers
400        // (If we had but it wasn't enough, `borrowing` would be `true`.
401        continue
402      }
403
404      let wantgaps = count+1;
405      let avail = (lb.primitive() as i64) - (la.primitive() as i64)
406        + if borrowing { RAW_LIMB_MODULUS as i64 } else { 0};
407      if avail < 0 { throw!(RangeImpossible::Backwards) }
408      let avail = avail as u64;
409
410      if avail < 2 {
411        // Only 1 difference in this limb and the next.  We are
412        // going to have to borrow, and, later, add with carry.
413        borrowing = true;
414        continue;
415      }
416      // avail might be up to 2x limb range
417
418      let mut i = i;
419      let (step, init);
420      if avail >= wantgaps {
421        // Evenly divide intervening values for this, the first
422        // differeing limb
423	step = avail / wantgaps;
424        // ^ if count==0, wantgaps==1 and step is perhaps still too large,
425        //   but in that case our next() will never be called, so fine
426        init = la;
427      } else {
428        // Not enough space here, but we can pick a unique value for
429        // this limb, and divide the next limb evenly
430        current.limbs[i] = la + (avail/2).into();
431	i += 1;
432	step = (RAW_LIMB_MODULUS-1) / wantgaps;
433        init = ZERO;
434      }
435      current.extend_to_limb(i);
436      current.limbs[i] = init;
437      break 'ok ASRD { i, step: step.into() };
438    } };
439    (current, aso)
440  }
441
442  #[throws(RangeImpossible)]
443  /// Iterator producing a half-open range `[self, other>`
444  ///
445  /// Produces precisely `count` items.
446  pub fn range_upto(&self, other: &Mutable, count: RangeCount)
447                    -> RangeIterator {
448    let (current, aso) = Mutable::range_core(self, other, count)?;
449    IteratorCore { current, aso, mr: MutateFirst }.take(count as usize)
450  }
451}
452
453impl<ASO:AddSubOffset, MR:MutateReturn> Iterator for IteratorCore<ASO, MR> {
454  type Item = ZCoord;
455  fn next(&mut self) -> Option<ZCoord> {
456    let aso = &self.aso;
457    Some(self.mr.op(
458      &mut self.current,
459      |current| { current.addsub(aso).unwrap(); },
460      |current| { current.repack().unwrap() },
461    ))
462  }
463}
464
465pub trait BoxedIteratorTrait: Iterator<Item = ZCoord> + Debug { }
466pub type BoxedIterator = Box<dyn BoxedIteratorTrait>;
467impl<T> BoxedIteratorTrait for T where T: Iterator<Item = ZCoord> + Debug {}
468
469impl Mutable {
470  /// Iterator producing `<self, ..>`
471  pub fn iter<ASO:AddSubOffset>(self, aso: ASO)
472                                -> IteratorCore<ASO, impl MutateReturn + Debug>
473  {
474    IteratorCore { current: self, aso, mr: MutateFirst }
475  }
476  #[throws(LogicError)]
477  /// Iterator producing an open range, `<a, b>`
478  pub fn some_range(a: Option<&Mutable>, b: Option<&Mutable>,
479                    count: RangeCount) -> BoxedIterator {
480    fn mk<T:'static + Debug + Iterator<Item=ZCoord>>(x: T) -> BoxedIterator
481    { Box::new(x) }
482    let c = count as usize;
483    if c == 0 { return mk( iter::empty() ) }
484    match (a, b) {
485      (None,    None   ) => throw!(TotallyUnboundedRange),
486      (Some(a), None   ) => mk( a.clone().iter(Increment).take(c) ),
487      (Some(a), Some(b)) => mk( Mutable::range_upto(a,b,count)? ),
488      (None,    Some(b)) => mk({
489        let mut first = b.clone();
490        first.addsub(&Decrement).unwrap();
491        let (current, aso) = Mutable::range_core(&first, b, count-1)?;
492        IteratorCore { current, aso, mr: MutateLast }.take(c)
493      }),
494    }
495  }
496}
497
498impl FromStr for Mutable {
499  type Err = ParseError;
500  #[throws(ParseError)]
501  fn from_str(s: &str) -> Mutable {
502    let tail = ZCoord::checked(s)?;
503    Mutable::from_u8_unchecked(tail)
504  }
505}
506
507//---------- main features of a Zcoord ----------
508
509impl ZCoord {
510  pub fn as_str(&self) -> &str {
511    let tail = self.tail();
512    str::from_utf8(tail).unwrap()
513  }
514}
515
516impl Display for ZCoord {
517  #[throws(fmt::Error)]
518  fn fmt(&self, f: &mut Formatter) {
519    write!(f, "{}", self.as_str())?
520  }
521}
522
523impl Debug for ZCoord {
524  #[throws(fmt::Error)]
525  fn fmt(&self, f: &mut Formatter) {
526    write!(f, r#"Zc""#)?;
527    <ZCoord as Display>::fmt(self, f)?;
528    write!(f, r#"""#)?;
529  }
530}
531
532impl Ord for ZCoord {
533  fn cmp(&self, other: &ZCoord) -> Ordering {
534    let at = self.tail();
535    let bt = other.tail();
536    at.cmp(bt)
537  }
538}
539impl PartialOrd for ZCoord {
540  fn partial_cmp(&self, other: &ZCoord) -> Option<Ordering> {
541    Some(self.cmp(other))
542  }
543}
544impl Eq for ZCoord { }
545impl PartialEq for ZCoord {
546  fn eq(&self, other: &ZCoord) -> bool {
547    self.cmp(other) == Ordering::Equal
548  }
549}
550
551impl TryFrom<&str> for ZCoord {
552  type Error = ParseError;
553  #[throws(ParseError)]
554  fn try_from(s: &str) -> ZCoord { ZCoord::from_str(s)? }
555}
556
557impl FromStr for ZCoord {
558  type Err = ParseError;
559  #[throws(ParseError)]
560  fn from_str(s: &str) -> ZCoord {
561    let tail = ZCoord::checked(s)?;
562    ZCoord::alloc_copy(tail).unwrap()
563  }
564}
565
566//---------- construction of ZCoord contents ---------
567//
568// We can panic if this code is buggy, but not compromise safety.
569
570const DEFAULT_TEXT: &[u8] = b"g000000000";
571
572impl Default for ZCoord {
573  fn default() -> ZCoord {
574    ZCoord::alloc_copy(DEFAULT_TEXT).unwrap()
575  }
576}
577
578impl ZCoord {
579  #[throws(ParseError)]
580  fn checked(s: &str) -> &[u8] {
581    let s = s.as_bytes();
582    let nomlen = s.len() + 1;
583    if nomlen % TEXT_PER_LIMB !=0 { throw!(ParseError) }
584    let _: innards::Taillen = (nomlen / TEXT_PER_LIMB).try_into()
585      .map_err(|_:TryFromIntError| ParseError)?;
586    for lt in s.chunks(TEXT_PER_LIMB) {
587      if !lt[0..DIGITS_PER_LIMB].iter().all(
588        |c: &u8| {
589          (b'0'..=b'9').contains(c) ||
590          (b'a'..=b'v').contains(c)
591        }) { throw!(ParseError) }
592      match lt[DIGITS_PER_LIMB..] {
593        [] | [b'_'] => (),
594        _ => throw!(ParseError)
595      };
596    }
597    if &s[s.len() - DIGITS_PER_LIMB..] == b"0000000000" {
598      throw!(ParseError)
599    }
600    s
601  }
602
603  #[throws(ParseError)]
604  pub fn check_str(s: &str) {
605    Self::checked(s)?;
606  }
607}
608
609impl TryFrom<&Mutable> for ZCoord {
610  type Error = Overflow;
611  #[throws(Overflow)]
612  fn try_from(m: &Mutable) -> ZCoord { m.repack()? }
613}
614
615//---------- innards, unsafe ----------
616
617mod innards {
618  use std::alloc::{self, Layout};
619  use std::mem::{self, align_of, size_of};
620  use std::ptr::{self, NonNull};
621  use std::slice;
622  use super::*;
623
624  unsafe impl Send for ZCoord { }
625  unsafe impl Sync for ZCoord { }
626
627  pub(super)
628  type Innards = NonNull<u8>;
629  pub type Taillen = u16;
630
631  pub(super)
632  struct Header {
633    pub taillen: u16, // in characters
634  }
635
636  #[repr(C)]
637  #[allow(dead_code)] // this is for documentation purposes
638  struct Repr {
639    h: Header,
640    d: [Tail1],
641  }
642
643  const OFFSET: usize = {
644    let h_size = size_of::<Header>();
645    let l_align = align_of::<Tail1>();
646    l_align * ((h_size + l_align - 1) / l_align)
647  };
648
649  fn layout(len: Taillen) -> (usize, Layout) {
650    let tail_nbytes: usize = size_of::<Tail1>() * (len as usize);
651    let all_nbytes = OFFSET + tail_nbytes;
652    let align = max(align_of::<Header>(), align_of::<Tail1>());
653    (all_nbytes, Layout::from_size_align(all_nbytes, align).unwrap())
654  }
655
656  fn ptrs(p: *mut u8) -> (*mut Header, *mut Tail1) { unsafe {
657    let p_header : *mut Header = mem::transmute(p);
658    let p_tail   : *mut Tail1  = mem::transmute(p.add(OFFSET));
659    (p_header, p_tail)
660  } }
661
662  impl ZCoord {
663    unsafe fn alloc_unsafe<F>(taillen: Taillen, f:F) -> ZCoord
664    where F: FnOnce(*mut Tail1)
665    {
666      #[allow(unused_unsafe)] // unsafe block in unsafe fn
667      unsafe {
668        let p = alloc::alloc(layout(taillen).1);
669        let (p_header, p_tail) = ptrs(p);
670        ptr::write(p_header, Header { taillen });
671        f(p_tail);
672        ZCoord(NonNull::new(p).unwrap())
673      }
674    }
675  
676    pub(super)
677    fn alloc(taillen: Taillen) -> ZCoord {
678      unsafe {
679        ZCoord::alloc_unsafe(taillen, |nt: *mut Tail1| {
680          ptr::write_bytes(nt, 0, taillen as usize);
681        })
682      }
683    }
684
685    #[throws(Overflow)]
686    pub(super)
687    fn alloc_copy(tail: &[Tail1]) -> ZCoord {
688      let taillen = tail.len().try_into()?;
689      unsafe {
690        ZCoord::alloc_unsafe(taillen, |nt: *mut Tail1| {
691          ptr::copy_nonoverlapping(tail.as_ptr(), nt, taillen as usize);
692        })
693      }
694    }
695
696    pub(super) fn tail(&self) -> &[Tail1] {
697      unsafe {
698        let (h, t) = ptrs(self.0.as_ptr());
699        let h = h.as_ref().unwrap();
700        slice::from_raw_parts(t, h.taillen as usize)
701      }
702    }
703
704    pub(super)
705    fn tail_mut(&mut self) -> &mut [Tail1] {
706      unsafe {
707        let (h, t) = ptrs(self.0.as_ptr());
708        let h = h.as_ref().unwrap();
709        slice::from_raw_parts_mut(t, h.taillen as usize)
710      }
711    }
712
713    fn layout(&self) -> (usize, Layout) {
714      unsafe {
715        let (h, _) = ptrs(self.0.as_ptr());
716        let h = h.as_ref().unwrap();
717        let taillen = h.taillen;
718        layout(taillen)
719      }
720    }
721
722    #[throws(Overflow)]
723    pub fn plus_offset(&self, offset: u32) -> Self { unsafe {
724      let (old_header, old_tail) = ptrs(self.0.as_ptr());
725      let old_taillen = old_header.as_ref().unwrap().taillen;
726      let new_taillen = old_taillen
727        .checked_add(TEXT_PER_LIMB as Taillen).ok_or(Overflow)?;
728      let old_taillen: usize = old_taillen.into();
729      let new_limb = lv(
730        (offset as RawLimbVal) << (BITS_PER_LIMB - 32) |
731         1                     << (BITS_PER_LIMB - 33)
732      );
733      let mut buf: [u8; TEXT_PER_LIMB] = default();
734      buf[0] = b'_';
735      new_limb.to_str_buf((&mut buf[1..TEXT_PER_LIMB]).try_into().unwrap());
736      ZCoord::alloc_unsafe(new_taillen, |new_tail| {
737        ptr::copy_nonoverlapping(old_tail,
738                                 new_tail,
739                                 old_taillen);
740
741        ptr::copy_nonoverlapping(buf.as_ptr(),
742                                 new_tail.add(old_taillen),
743                                 TEXT_PER_LIMB);
744      })
745    } }
746  }
747
748  impl Drop for ZCoord {
749    fn drop(&mut self) {
750      let layout = self.layout().1;
751      unsafe {
752        alloc::dealloc(self.0.as_mut(), layout);
753      }
754    }
755  }
756
757  impl Clone for ZCoord {
758    fn clone(&self) -> ZCoord {
759      let (all_bytes, layout) = self.layout();
760      unsafe {
761        let p = alloc::alloc(layout);
762        ptr::copy_nonoverlapping(self.0.as_ptr(), p, all_bytes);
763        ZCoord(NonNull::new(p).unwrap())
764      }
765    }
766  }
767
768  impl Hash for ZCoord {
769    fn hash<H:Hasher>(&self, state: &mut H) {
770      self.tail().hash(state)
771    }
772  }
773
774}
775
776//---------- tests ----------
777
778#[cfg(test)]
779mod test {
780  use crate::misc::default;
781  use super::*;
782  use std::collections::hash_map::DefaultHasher;
783  use std::mem;
784
785  fn zc(s: &str) -> ZCoord { ZCoord::from_str(s).unwrap() }
786  fn mk(s: &str) -> super::Mutable { zc(s).clone_mut() }
787
788  #[test]
789  fn bfparse() {
790    let s = "gg0123abcd_0123456789";
791    let b = ZCoord::from_str(s).unwrap();
792    let b2 = b.clone();
793    assert_eq!(format!("{}", &b), s);
794    assert_eq!(format!("{}", &b.clone_mut().repack().unwrap()), s);
795    mem::drop(b);
796    assert_eq!(format!("{}", &b2), s);
797    assert_eq!(format!("{:?}", &b2),
798               format!(r#"Zc"{}""#, &b2));
799    fn bad(s: &str) { assert_eq!(Err(ParseError), ZCoord::from_str(s)); }
800    bad("");
801    bad("0");
802    bad("0000000000");
803    bad("1111111111_0000000000");
804    bad("0000000000_0000000000");
805    bad("aaaaaaaa0_aaaaaaaa00");
806    bad("aaaaaaaa0_aaaaaaaa00");
807    bad("aaaaaaaa00_aaaaaaaa0");
808    bad("#aaaaaaaa0_aaaaaaaa00");
809    bad("aaaaaaaa0#_aaaaaaaa00");
810    bad("aaaaaaaa00#aaaaaaaa00");
811    bad("aaaaaaaa00_aaaaaaaa0#");
812    bad("Zaaaaaaaa0_#aaaaaaaa0");
813    bad("Aaaaaaaaa0_#aaaaaaaa0");
814    bad("waaaaaaaa0_#aaaaaaaa0");
815    bad("/aaaaaaaa0_#aaaaaaaa0");
816    bad(":aaaaaaaa0_#aaaaaaaa0");
817    bad("`aaaaaaaa0_#aaaaaaaa0");
818  }
819
820  #[test]
821  fn limb_debug() {
822    fn chk(raw: RawLimbVal, disp: &str) {
823      let l: LimbVal = raw.into();
824      let dbg = format!("lv({})", &disp);
825      assert_eq!( &format!("{}",   &l), disp );
826      assert_eq!( &format!("{:?}", &l), &dbg );
827    }
828    chk(0x42, "0000000022");
829    chk(0x42 + RAW_LIMB_MODULUS *   0x33,   "0x33_!_0000000022");
830    chk(0x42 + RAW_LIMB_MODULUS * 0x3fae, "0x3fae_!_0000000022");
831  }
832
833  #[test]
834  fn inequality() {
835    assert!( zc("gg0123abcd_0123456789") <
836             zc("gg0123abcd_012345678a") );
837    
838    assert!( zc("gg0123abcd") <
839             zc("gg0123abcd_012345678a") );
840  }
841
842  #[test]
843  fn incdec() {
844    use core::cmp::Ordering::{Greater,Less};
845    impl Mutable {
846      fn tincdec<ASO:AddSubOffset>(mut self, exp: &str, aso: ASO,
847                                   exp_ord: Ordering) -> Self {
848        let before = self.repack().unwrap();
849        let got = self.addsub(&aso).unwrap();
850        assert_eq!(got.to_string(), exp);
851        assert_eq!(got.cmp(&before), exp_ord);
852
853        fn h(z: &ZCoord) -> u64 {
854          let mut h = DefaultHasher::new();
855          z.hash(&mut h);
856          h.finish()
857        }
858        assert_ne!(h(&got), h(&before));
859        self
860      }
861      fn tinc(self, e: &str) -> Self { self.tincdec(e, Increment, Greater) }
862      fn tdec(self, e: &str) -> Self { self.tincdec(e, Decrement, Less)    }
863    }
864    let start: ZCoord = default();
865    assert_eq!(format!("{}", &start), "g000000000");
866    start.clone_mut()
867      .tinc("g001000000");
868    start.clone_mut()
869      .tdec("fvvv000000");
870
871    mk("000000000a")
872      .tinc("000100000a")
873      .tinc("000200000a")
874      .tdec("000100000a")
875      .tdec("000000000a")
876      .tdec("0000000009_vvvvvvvvvv_vvvuvvvvvv")
877      .tdec("0000000009_vvvvvvvvvv_vvvtvvvvvv")
878      ;
879    mk("vvvvvvvvvv")
880      .tinc("vvvvvvvvvv_0000000000_0001000000")
881      .tdec("vvvvvvvvvv")
882      ;
883    mk("vvvvvvvvvv_vvvvvvvvvv_vvvvv01234")
884      .tinc("vvvvvvvvvv_vvvvvvvvvv_vvvvv01234_0000000000_0001000000")
885      ;
886    mk("0000000000_0000000000_0001012340")
887      .tdec("0000000000_0000000000_0000012340")
888      .tdec("0000000000_0000000000_000001233v_vvvvvvvvvv_vvvuvvvvvv")
889      ;
890
891    mk("vvvvvvvvvv")
892      .tinc("vvvvvvvvvv_0000000000_0001000000")
893      ;
894    mk("vvvvvvvvvv_vvvvvvvvvv_vvvvv01234")
895      .tinc("vvvvvvvvvv_vvvvvvvvvv_vvvvv01234_0000000000_0001000000")
896      ;
897
898    assert_eq!( Mutable::some_range(Some(&mk("0200000000")),
899                                    Some(&mk("0100000000")),
900                                    1).unwrap_err(),
901                LogicError::from(RangeImpossible::Backwards) );
902
903    assert_eq!( Mutable::some_range(Some(&mk("0200000000")),
904                                    Some(&mk("0200000000")),
905                                    1).unwrap_err(),
906                LogicError::from(RangeImpossible::Empty) );
907  }
908
909  #[test]
910  fn iter() {
911    let mut m = mk("000000000a").iter(Increment);
912    assert_eq!( m.next(), Some(zc("000100000a")) );
913    assert_eq!( m.next(), Some(zc("000200000a")) );
914
915    let mut m = mk("000000000a").iter(Decrement);
916    assert_eq!( m.next(), Some(zc("0000000009_vvvvvvvvvv_vvvuvvvvvv")) );
917    assert_eq!( m.next(), Some(zc("0000000009_vvvvvvvvvv_vvvtvvvvvv")) );
918  }
919
920  #[test]
921  fn range() {
922    struct It {
923      i: RangeIterator,
924      last: ZCoord,
925    }
926    impl It {
927      fn new(x: &str, y: &str, count: u32) -> Self {
928        let x = mk(x);
929        let y = mk(y);
930        let i = x.range_upto(&y, count).unwrap();
931        It { i, last: x.repack().unwrap() }
932      }
933      fn nxt(&mut self, exp: &str) {
934        let got = self.i.next().unwrap();
935        assert_eq!(got.to_string(), exp);
936        assert_eq!(got, zc(exp));
937        assert!(got > self.last, "{:?} <= {:?} !", &got, &self.last);
938        self.last = got.clone();
939      }
940    }
941    let mut it = It::new("3333333333_vvvvvvvvv0",
942                         "3333333334_0000000040", 4);
943    it.nxt("3333333334");
944    it.nxt("3333333334_0000000010");
945    it.nxt("3333333334_0000000020");
946    it.nxt("3333333334_0000000030");
947    assert_eq!(it.i.next(), None);
948
949    let mut it = It::new("3333333333_vvvvvvvvo0",
950                         "3333333334_0000000030", 4);
951    it.nxt("3333333333_vvvvvvvvq6");
952    it.nxt("3333333333_vvvvvvvvsc");
953    it.nxt("3333333333_vvvvvvvvui");
954    it.nxt("3333333334_000000000o");
955    assert_eq!(it.i.next(), None);
956
957    let mut it = It::new("aaaaaaaaaa_vvvvvvvvvv",
958                         "aaaaaaaaab"           , 2);
959    it.nxt("aaaaaaaaaa_vvvvvvvvvv_alalalalal");
960    it.nxt("aaaaaaaaaa_vvvvvvvvvv_lalalalala");
961    assert_eq!(it.i.next(), None);
962
963    let mut it = It::new("1000000000",
964                         "2000000000", 3);
965    it.nxt("1800000000");
966    it.nxt("1g00000000");
967    it.nxt("1o00000000");
968    assert_eq!(it.i.next(), None);
969
970    assert_eq!(mk             ("aaaaaaaaaa_vvvvvvvvvv")
971               .range_upto(&mk("aaaaaaaaaa_vvvvvvvvvv"), 4)
972               .unwrap_err(),
973               RangeImpossible::Empty);
974 
975    assert_eq!(mk             ("0000000001")
976               .range_upto(&mk("0000000001"), 4)
977               .unwrap_err(),
978               RangeImpossible::Empty);
979
980    assert_eq!(mk             ("0000000002")
981               .range_upto(&mk("0000000001"), 4)
982               .unwrap_err(),
983               RangeImpossible::Backwards);
984 }
985
986  #[test]
987  fn some_range() {
988    struct It {
989      i: BoxedIterator,
990      last: Option<ZCoord>,
991    }
992    #[throws(LogicError)]
993    fn mkr(a: Option<&str>, b: Option<&str>, count: RangeCount) -> It {
994      let a = a.map(|s: &str| s.parse::<ZCoord>().unwrap().clone_mut());
995      let b = b.map(|s: &str| s.parse::<ZCoord>().unwrap().clone_mut());
996      let last = a.as_ref().map(|m| m.repack().unwrap());
997      let i = Mutable::some_range(a.as_ref(), b.as_ref(), count)?;
998      It { i, last }
999    }
1000    impl It {
1001      fn nxt(&mut self, exp: Option<&str>) {
1002        let got = self.i.next();
1003        let got_s = got.as_ref().map(|s| s.to_string());
1004        let got_s = got_s.as_ref().map(|s| s.as_str());
1005        assert_eq!(got_s, exp);
1006        if let (Some(got), Some(exp)) = (&got, &exp) {
1007          assert_eq!(got, &zc(exp));
1008          if let Some(last) = &self.last { assert!(got > last); }
1009        }
1010        self.last = got.clone();
1011      }
1012    }
1013    let mut it = mkr(Some("3000000000"),Some("4000000000"),3).unwrap();
1014    it.nxt(Some("3800000000"));
1015    it.nxt(Some("3g00000000"));
1016    it.nxt(Some("3o00000000"));
1017    it.nxt(None);
1018    let mut it = mkr(Some("3000000000"),Some("4000000000"),1).unwrap();
1019    it.nxt(Some("3g00000000"));
1020    it.nxt(None);
1021    let mut it = mkr(None, Some("4000000000"),2).unwrap();
1022    it.nxt(Some("3vvv000000"));
1023    it.nxt(Some("3vvvg00000"));
1024    it.nxt(None);
1025    let mut it = mkr(Some("4000000000"),None,2).unwrap();
1026    it.nxt(Some("4001000000"));
1027    it.nxt(Some("4002000000"));
1028    it.nxt(None);
1029    let x = mkr(None,None,2);
1030    assert_eq!( x.err(), Some(
1031      LogicError::RangeTotallyUnbounded(TotallyUnboundedRange)
1032    ));
1033    let mut it = mkr(Some("fvvq000000"),Some("g026000000"),1).unwrap();
1034    it.nxt(Some("g010000000"));
1035    it.nxt(None);
1036    let mut it = mkr(None,Some("fvvq000000"),0).unwrap();
1037    it.nxt(None);
1038
1039    let mut it = mkr(Some("g0h8000000"),
1040                     Some("g0h8000000_0000004000"), 2) .unwrap();
1041    it.nxt(Some("g0h8000000_0000001ala"));
1042    it.nxt(Some("g0h8000000_0000002lak"));
1043    it.nxt(None);
1044    
1045    let mut it = mkr(None, Some("g0h8000000"), 0).unwrap();
1046    it.nxt(None);    
1047  }
1048
1049  #[test]
1050  fn plus_offset() {
1051    fn chk(off: u32, s: &str) {
1052      let z: ZCoord = "3o00000000".parse().unwrap();
1053      let p = z.plus_offset(off).unwrap();
1054      assert_eq!(s, format!("{}", &p));
1055      assert_eq!(p, s.parse().unwrap());
1056    }
1057
1058    chk(         0, "3o00000000_0000004000");
1059    chk(         1, "3o00000000_000000c000");
1060    chk(0xffffffff, "3o00000000_vvvvvvs000");
1061  }
1062}