From: Ian Jackson Date: Sun, 4 Oct 2020 21:48:57 +0000 (+0100) Subject: use new zcoord X-Git-Tag: otter-0.2.0~753 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=a0fc064f78c0f2f0c0e811128ce5228111bc723c;p=otter.git use new zcoord Signed-off-by: Ian Jackson --- diff --git a/src/api.rs b/src/api.rs index d218421c..1a8bebdc 100644 --- a/src/api.rs +++ b/src/api.rs @@ -278,8 +278,8 @@ impl ApiPieceOp for ApiPieceRaise { fn op(&self, gs: &mut GameState, _: PlayerId, piece: PieceId, _p: &dyn Piece, _: &dyn Lens) -> PieceUpdateFromOp { let pc = gs.pieces.byid_mut(piece).unwrap(); - pc.zlevel = ZLevel { z : self.z, zg : gs.gen }; - let update = PieceUpdateOp::SetZLevel(pc.zlevel); + pc.zlevel = ZLevel { z : self.z.clone(), zg : gs.gen }; + let update = PieceUpdateOp::SetZLevel(()); (WhatResponseToClientOp::Predictable, update, vec![]) } diff --git a/src/bigfloat.rs b/src/bigfloat.rs index dca45701..97e0fa98 100644 --- a/src/bigfloat.rs +++ b/src/bigfloat.rs @@ -42,6 +42,9 @@ mod innards { #[serde(try_from="&str")] pub struct Bigfloat(Innards); + unsafe impl Send for Bigfloat { } + unsafe impl Sync for Bigfloat { } + type Innards = NonNull; pub(in super) @@ -79,13 +82,25 @@ mod innards { impl Bigfloat { pub(in super) - fn from_parts(sign: Sign, exp: Sz, limbs: &[Limb]) -> Bigfloat { - let nlimbs : Sz = limbs.len().try_into().expect("limb count overflow"); + fn from_limbs(sign: Sign, exp: Sz, nlimbs: Sz, mut limbs: I) + -> Bigfloat + where L: Into + Debug, + I: Iterator + { unsafe { let p = alloc::alloc(layout(nlimbs)); let (p_header, p_limbs) = ptrs(p); ptr::write(p_header, Header { sign, exp, nlimbs }); - ptr::copy_nonoverlapping(limbs.as_ptr(), p_limbs, nlimbs as usize); + let mut count = 0..(nlimbs as usize); + loop { + match (limbs.next(), count.next()) { + (None, None) => break, + (Some(l), Some(i)) => { + p_limbs.add(i).write(l.into()); + }, + x => panic!("unexpected {:?}", x), + } + } Bigfloat(NonNull::new(p).unwrap()) } } @@ -102,7 +117,7 @@ mod innards { #[allow(dead_code)] // xxx pub(in super) - fn as_mut_limbs(&self) -> (&Header, &mut [Limb]) { + fn as_mut_limbs(&mut self) -> (&Header, &mut [Limb]) { unsafe { let (h, l) = ptrs(self.0.as_ptr()); let h = h.as_mut().unwrap(); @@ -110,6 +125,12 @@ mod innards { (h, limbs) } } + + pub(in super) + fn from_parts(sign: Sign, exp: Sz, limbs: &[Limb]) -> Bigfloat { + let nlimbs : Sz = limbs.len().try_into().expect("limb count overflow"); + Self::from_limbs(sign, exp, nlimbs, limbs.iter().cloned()) + } } impl Drop for Bigfloat { @@ -137,6 +158,12 @@ mod innards { } +impl Default for Bigfloat { + fn default() -> Bigfloat { + Bigfloat::from_parts(Pos, 0, &[default()]) + } +} + impl From for Limb { fn from(u: LimbVal) -> Limb { assert_eq!(0, u >> 48); @@ -224,6 +251,26 @@ impl Bigfloat { } } +#[derive(Error,Debug,Copy,Clone,Serialize,Deserialize)] +pub struct Overflow; +display_as_debug!(Overflow); + +impl From for Overflow { + fn from(_: TryFromIntError) -> Overflow { Overflow } +} + +impl TryFrom<&Mutable> for Bigfloat { + type Error = Overflow; + #[throws(Overflow)] + fn try_from(m: &Mutable) -> Bigfloat { + let exp = (-m.limbs.counter()).try_into()?; + let nlimbs = m.limbs.len().try_into()?; + let slices = m.limbs.inner().as_slices(); + let it = slices.0.iter().chain(slices.1.iter()).cloned(); + Bigfloat::from_limbs(m.sign, exp, nlimbs, it) + } +} + impl Mutable { pub fn add(&mut self, rhs: u32) { self.add_to_limb(0, rhs); diff --git a/src/cmdlistener.rs b/src/cmdlistener.rs index 075a3054..33364429 100644 --- a/src/cmdlistener.rs +++ b/src/cmdlistener.rs @@ -263,16 +263,17 @@ fn execute_game_insn(cs: &CommandStream, let mut updates = Vec::with_capacity(count as usize); let mut pos = pos.unwrap_or(DEFAULT_POS_START); - for i in 0..count { + let mut z = gs.max_z.clone_mut(); + for _ in 0..count { let p = info.load()?; let face = face.unwrap_or_default(); if p.nfaces() <= face.into() { throw!(SpecError::FaceNotFound); } - let z = gs.max_z.add(i + 1); + z.add(1); let pc = PieceState { held: None, - zlevel: ZLevel { z, zg: gs.gen }, + zlevel: ZLevel { z: (&z).try_into()?, zg: gs.gen }, lastclient: Default::default(), gen_before_lastclient: Generation(0), pinned: pinned.unwrap_or(false), @@ -325,7 +326,7 @@ fn execute_for_game(cs: &CommandStream, ig: &mut InstanceGuard, #[derive(Debug,Default)] struct UpdateHandlerBulk { - pieces : slotmap::SparseSecondaryMap>, + pieces : slotmap::SparseSecondaryMap>, logs : bool, raw : Vec, } diff --git a/src/commands.rs b/src/commands.rs index 8a09ed0e..f2bf55a6 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -92,6 +92,7 @@ pub enum MgmtError { PieceNotFound, LimitExceeded, ServerFailure(String), + ZCoordinateOverflow(#[from] bigfloat::Overflow), BadGlob { pat: String, msg: String }, BadSpec(#[from] SpecError), } diff --git a/src/gamestate.rs b/src/gamestate.rs index 06ef7162..15d5f106 100644 --- a/src/gamestate.rs +++ b/src/gamestate.rs @@ -19,11 +19,7 @@ pub struct Generation (pub u64); visible_slotmap_key!{ VisiblePieceId('.') } -#[derive(Debug,Copy,Clone,PartialEq,PartialOrd)] -#[derive(Serialize,Deserialize,Default)] -#[serde(into="f64")] -#[serde(try_from="f64")] -pub struct ZCoord(f64); +pub type ZCoord = Bigfloat; #[derive(Clone,Serialize,Deserialize,Eq,Ord,PartialEq,PartialOrd)] #[serde(transparent)] @@ -33,7 +29,7 @@ pub const DEFAULT_TABLE_SIZE : Pos = PosC([ 400, 200 ]); // ---------- general data types ---------- -#[derive(Debug,Copy,Clone,Serialize,Deserialize,Eq,PartialEq,Ord,PartialOrd)] +#[derive(Debug,Clone,Serialize,Deserialize,Eq,PartialEq,Ord,PartialOrd)] pub struct ZLevel { pub z: ZCoord, pub zg: Generation, @@ -155,35 +151,6 @@ impl Display for Generation { } } -impl TryFrom for ZCoord { - type Error = OnlineError; - #[throws(OnlineError)] - fn try_from(v: f64) -> ZCoord { - if !v.is_finite() { throw!(OnlineError::InvalidZCoord) } - ZCoord(v) - } -} -impl From for f64 { - fn from(v: ZCoord) -> f64 { v.0 } -} -impl Ord for ZCoord { - fn cmp(&self, other: &Self) -> cmp::Ordering { - self.0.partial_cmp(&other.0).unwrap() - } -} -impl Eq for ZCoord { } -impl Display for ZCoord { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - Display::fmt(&self.0,f) - } -} - -impl ZCoord { - pub fn add(&self, v: u32) -> ZCoord { - ZCoord(self.0 + (v as f64)) - } -} - pub trait ClampTable : Sized { fn clamped(self, range: Self) -> (Self, bool); } @@ -235,7 +202,7 @@ impl PieceState { pos : self.pos, held : self.held, svg : p.make_defs(pri)?, - z : self.zlevel.z, + z : self.zlevel.z.clone(), zg : self.zlevel.zg, pinned : self.pinned, uos : p.ui_operations()?, diff --git a/src/global.rs b/src/global.rs index 47d800f6..b7c62d19 100644 --- a/src/global.rs +++ b/src/global.rs @@ -393,7 +393,7 @@ impl InstanceGuard<'_> { // These parts are straightforward and correct table_size : self.c.g.gs.table_size, gen : self.c.g.gs.gen, - max_z : self.gs.max_z, + max_z : self.gs.max_z.clone(), players, // These have special handling log : Default::default(), diff --git a/src/imports.rs b/src/imports.rs index f8809df7..6d93599b 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -19,7 +19,7 @@ pub use std::str::FromStr; pub use std::iter; pub use std::iter::repeat_with; pub use std::collections::VecDeque; -pub use std::num::Wrapping; +pub use std::num::{Wrapping, TryFromIntError}; pub use std::cmp::{self,min,max,Ordering}; pub use std::error::Error; pub use std::marker::PhantomData; @@ -111,6 +111,7 @@ pub use crate::utils::*; pub use crate::spec::*; pub use crate::debugreader::DebugReader; pub use crate::shapelib; +pub use crate::bigfloat::{self, Bigfloat}; pub use nix::unistd::Uid; diff --git a/src/session.rs b/src/session.rs index e24bd370..a940e2dc 100644 --- a/src/session.rs +++ b/src/session.rs @@ -104,7 +104,7 @@ fn session(form : Json) -> Result { let for_info = SessionPieceLoadJson { held : &pr.held, - z : pr.zlevel.z, + z : pr.zlevel.z.clone(), zg : pr.zlevel.zg, pinned : pr.pinned, uos : &p.ui_operations()?, diff --git a/src/updates.rs b/src/updates.rs index 2fde6220..45113316 100644 --- a/src/updates.rs +++ b/src/updates.rs @@ -16,7 +16,7 @@ pub struct ClientSequence(u64); #[derive(Debug)] // not Default pub struct ExecuteGameChangeUpdates { - pub pcs: Vec<(PieceId,PieceUpdateOp<()>)>, + pub pcs: Vec<(PieceId,PieceUpdateOp<(),()>)>, pub log: Vec, pub raw: Option>, } @@ -44,7 +44,7 @@ pub enum PreparedUpdateEntry { Piece { by_client: IsResponseToClientOp, piece : VisiblePieceId, - op : PieceUpdateOp, + op : PieceUpdateOp, }, SetTableSize(Pos), Log (Arc), @@ -65,16 +65,16 @@ pub struct PreparedPieceState { // ---------- piece updates ---------- #[derive(Debug,Serialize)] -pub enum PieceUpdateOp { +pub enum PieceUpdateOp { Delete(), Insert(NS), Modify(NS), Move(Pos), - SetZLevel(ZLevel), + SetZLevel(ZL), } pub type PieceUpdateFromOp = (WhatResponseToClientOp, - PieceUpdateOp<()>, Vec); + PieceUpdateOp<(),()>, Vec); pub type PieceUpdateResult = Result; // ---------- for traansmission ---------- @@ -95,7 +95,7 @@ enum TransmitUpdateEntry<'u> { }, Piece { piece : VisiblePieceId, - op : PieceUpdateOp<&'u PreparedPieceState>, + op : PieceUpdateOp<&'u PreparedPieceState, &'u ZLevel>, }, RecordedUnpredictable { piece : VisiblePieceId, @@ -187,7 +187,7 @@ impl PreparedUpdateEntry { // ---------- PieceUpdatesOp ---------- -impl PieceUpdateOp { +impl PieceUpdateOp { pub fn new_state(&self) -> Option<&NS> { use PieceUpdateOp::*; match self { @@ -198,8 +198,10 @@ impl PieceUpdateOp { SetZLevel(_) => None, } } - pub fn try_map_new_state Result> - (self, f:F) -> Result,E> + pub fn try_map Result, + G: FnOnce(ZC) -> Result + > (self, f:F, g:G) -> Result,E> { use PieceUpdateOp::*; Ok(match self { @@ -207,33 +209,41 @@ impl PieceUpdateOp { Insert(ns) => Insert(f(ns)?), Modify(ns) => Modify(f(ns)?), Move(pos) => Move(pos), - SetZLevel(zl) => SetZLevel(zl), + SetZLevel(zl) => SetZLevel(g(zl)?), }) } - pub fn map_ref_new_state(&self) -> PieceUpdateOp<&NS> { + pub fn map_ref(&self) -> PieceUpdateOp<&NS,&ZC> { use PieceUpdateOp::*; match self { Delete() => Delete(), Insert(ns) => Insert(ns), Modify(ns) => Modify(ns), Move(pos) => Move(*pos), - SetZLevel(zl) => SetZLevel(*zl), + SetZLevel(zl) => SetZLevel(zl), } } - pub fn map_new_state NS2>(self, f:F) - -> PieceUpdateOp { + pub fn map NS2, + G: FnOnce(ZC) -> ZC2 + > (self, f:F, g:G) -> PieceUpdateOp + { #[derive(Error,Debug)] enum Never { } - self.try_map_new_state(|ns| >::Ok(f(ns))).unwrap() + self.try_map( + |ns| >::Ok(f(ns)), + |zc| >::Ok(g(zc)), + ).unwrap() } - pub fn new_z_generation(&self) -> Option { + pub fn new_z_generation(&self) -> Option + where ZC: Borrow + { use PieceUpdateOp::*; match self { Delete() => None, Insert(_) => None, Modify(_) => None, Move(_) => None, - SetZLevel(ZLevel{zg,..}) => Some(*zg), + SetZLevel(l) => Some(l.borrow().zg), } } } @@ -318,7 +328,7 @@ impl<'r> PrepareUpdatesBuffer<'r> { #[throws(InternalError)] fn piece_update_fallible(&mut self, piece: PieceId, - update: PieceUpdateOp<()>, + update: PieceUpdateOp<(),()>, lens: &dyn Lens) -> PreparedUpdateEntry { type WRC = WhatResponseToClientOp; @@ -330,7 +340,7 @@ impl<'r> PrepareUpdatesBuffer<'r> { self.g.pieces.get(piece), ) { (Ok(pc), Some(p)) => { - gs.max_z.update_max(pc.zlevel.z); + gs.max_z.update_max(&pc.zlevel.z); if let Some(new_lastclient) = match self.by_client { Some((WRC::Predictable,tclient,_)) | @@ -344,12 +354,15 @@ impl<'r> PrepareUpdatesBuffer<'r> { pc.gen = gen; let pri_for_all = lens.svg_pri(piece,pc,Default::default()); - let update = update.try_map_new_state( - |_|{ + let update = update.try_map( + |()|{ let mut ns = pc.prep_piecestate(p.as_ref(), &pri_for_all)?; lens.massage_prep_piecestate(&mut ns); >::Ok(ns) }, + |()|{ + Ok(pc.zlevel.clone()) + } )?; (update, pri_for_all.id) @@ -366,7 +379,7 @@ impl<'r> PrepareUpdatesBuffer<'r> { } } - pub fn piece_update(&mut self, piece: PieceId, update: PieceUpdateOp<()>, + pub fn piece_update(&mut self, piece: PieceId, update: PieceUpdateOp<(),()>, lens: &dyn Lens) { // Caller needs us to be infallible since it is too late by // this point to back out a game state change. @@ -455,7 +468,7 @@ impl PreparedUpdate { let zg = op.new_z_generation(); TUE::Recorded { piece, cseq, zg, svg: ns.map(|ns| &ns.svg) } }, - FTG::Piece => TUE::Piece { piece, op: op.map_ref_new_state() }, + FTG::Piece => TUE::Piece { piece, op: op.map_ref() }, FTG::Exactly(x) => x, } }, diff --git a/src/utils.rs b/src/utils.rs index c46dee1d..9913f4ee 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,10 +2,10 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // There is NO WARRANTY. -pub trait OrdExt : Ord + Sized { - fn update_max(&mut self, new: Self) { - if new > *self { *self = new } +pub trait OrdExt : Ord + Sized + Clone { + fn update_max(&mut self, new: &Self) { + if *new > *self { *self = new.clone() } } } -impl OrdExt for T where T : Ord + Sized { +impl OrdExt for T where T : Ord + Sized + Clone { }