chiark / gitweb /
zcoord range in Rust
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 11 Oct 2020 00:05:54 +0000 (01:05 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 11 Oct 2020 00:05:54 +0000 (01:05 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
templates/bigfloat.ts
zcoord/zcoord.rs

index 66e733a1f0bce0e649eafbdfa961a9044f970faa..aebfc9f9a5906064b4c660d884752615df90f863 100644 (file)
@@ -68,44 +68,11 @@ namespace Bigfloats {
     }
   }
 
-  function limb_val_lookup(v: Unpacked, i: Limb): number {
-    if (i >= v.limbs.length) return 0;
-    return v.limbs[i];
   }
 
   export function iter_upto(ap: Packed, bp: Packed, count: number):
   () => Packed {
     // result can be called count times to produce values > av, < bv
-    let av = unpack(ap);
-    let bv = unpack(bp);
-    for (let i = 0;
-        ;
-        i++) {
-      if (i >= av.limbs.length && i >= bv.limbs.length) {
-       // Oh actually these numbers are equal!
-       return function(){ return pack(av); }
-      }
-      let la = limb_val_lookup(av,i);
-      let lb = limb_val_lookup(bv,i);
-      if (la == lb) continue;
-    
-      let avail = limb_mask(lb - la);
-      let current = clone(av);
-      let step : number; // actual floating point!
-      if (avail > count+1) {
-       step = avail / (count+1);
-      } else {
-       current.limbs.push(0);
-       i++;
-       step = LIMB_MODULUS / (count+1);
-      }
-      step = Math.floor(step);
-      return function() {
-       current.limbs[i] += step;
-       return pack(current);
-      }
-    }
-  }
 }
 /*
 
index ad88c882f7693e54dd8d4c36ab108a54cb2a83a2..5c8f1b3b26af9656b038ac9aac3dbb17e746f7e9 100644 (file)
@@ -97,9 +97,17 @@ const LIMB_MASK    : LimbVal = Wrapping(RAW_LIMB_MODULUS-1);
 pub struct ZCoord(innards::Innards);
 
 #[derive(Error,Clone,Copy,Debug)]
-#[error("error parsing zcoord (z value)")]
+#[error("error parsing Z coordinate")]
 pub struct ParseError;
 
+#[derive(Error,Clone,Copy,Debug)]
+#[error("Z coordinate range has end before start, cannot iterate")]
+pub struct RangeBackwards;
+
+#[derive(Error,Debug,Copy,Clone,Serialize,Deserialize)]
+#[error("Z coordinate overflow")]
+pub struct Overflow;
+
 //---------- Mutabel ----------
 
 #[derive(Clone,Debug)]
@@ -121,10 +129,6 @@ impl ZCoord {
   }
 }
 
-#[derive(Error,Debug,Copy,Clone,Serialize,Deserialize)]
-#[error("Z coordinate overflow")]
-pub struct Overflow;
-
 impl From<TryFromIntError> for Overflow {
   fn from(_: TryFromIntError) -> Overflow { Overflow }
 }
@@ -198,6 +202,70 @@ impl Mutable {
   pub fn repack(&self) -> ZCoord { self.try_into()? }
 }
 
+pub type RangeIterator = std::iter::Take<RangeIteratorCore>;
+
+pub struct RangeIteratorCore {
+  current: Mutable,
+  i: usize,
+  step: LimbVal,
+}
+
+impl Mutable {
+  fn limb_val_lookup(&self, i: usize) -> LimbVal {
+    *self.limbs.get(i).unwrap_or(&ZERO)
+  }
+
+  #[throws(RangeBackwards)]
+  fn range_core(a: &Mutable, b: &Mutable, count: u32) -> RangeIteratorCore {
+    let count = count as RawLimbVal;
+    let mut i = 0;
+    let current = a.clone();
+    loop {
+      if i >= a.limbs.len() && i >= b.limbs.len() {
+       // Oh actually these numbers are equal!
+       break RangeIteratorCore { current, i: 0, step: ZERO };
+      }
+      let la = a.limb_val_lookup(i);
+      let lb = b.limb_val_lookup(i);
+      if la == lb { continue }
+      if la > lb { throw!(RangeBackwards) }
+
+      let mut current = current;
+      let wantgaps = count+1;
+      let avail = lb.0 - la.0;
+      let (step, init);
+      if avail > wantgaps {
+       step = avail / wantgaps;
+        init = la;
+      } else {
+       i += 1;
+       step = (RAW_LIMB_MODULUS-1) / wantgaps;
+        init = ZERO;
+      }
+      current.limbs.resize(i+1, ZERO);
+      current.limbs[i] = init;
+      break RangeIteratorCore { current, i, step: Wrapping(step) };
+    }
+  }
+
+  #[throws(RangeBackwards)]
+  pub fn range(&self, other: &Mutable, count: u32) -> RangeIterator {
+    Mutable::range_core(self, other, count)?.take(count as usize)
+  }
+}
+
+impl Iterator for RangeIteratorCore {
+  type Item = ZCoord;
+  #[throws(as Option)]
+  fn next(&mut self) -> ZCoord {
+    self.current.limbs[self.i] += self.step;
+    self.current.repack().unwrap()
+  }
+}
+impl ExactSizeIterator for RangeIteratorCore {
+  fn len(&self) -> usize { return usize::MAX }
+}
+
 //---------- main features of a Zcoord ----------
 
 impl ZCoord {