From: Tim "S.D.Eagle" Zeitz Date: Tue, 3 Dec 2019 10:17:38 +0000 (+0100) Subject: backport some nice things from routing engine and cleanup a bit X-Git-Url: https://i11git.iti.kit.edu/anon-gitweb/?p=Mitarbeiter%2FTim-Zeitz%2Fstud-rust-base.git;a=commitdiff_plain;h=b98ead7d67d4779f4e70b47bdc08a72eb666cf9f;ds=sidebyside backport some nice things from routing engine and cleanup a bit --- diff --git a/README.md b/README.md index 7239043..59210f9 100644 --- a/README.md +++ b/README.md @@ -53,12 +53,11 @@ Die entsprechenden Funktionen sind über Traits definiert und können so direkt Das kann z.B. so aussehen: ```Rust -extern crate stud_rust_base; use stud_rust_base::io::*; -let head = Vec::::load_from("head_file_name").expect("could not read head"); -let lat = Vec::::load_from("node_latitude_file_name").expect("could not read lat"); -head.write_to("output_file").expect("could not write head"); +let head = Vec::::load_from("head_file_name")?; +let lat = Vec::::load_from("node_latitude_file_name")?; +head.write_to(&"output_file")?; ``` Die Dateien in `src/bin/` sind einmal ein Beispielprogramm sowieso Hilfsprogramme. @@ -79,12 +78,11 @@ Diese heißen `first_out`, `head` und `weight`. Um über die ausgehenden Kanten eines Knoten zu iterieren können Sie den folgenden Code verwenden: ```Rust -extern crate stud_rust_base; use stud_rust_base::{types::*, io::*}; -let first_out = Vec::::load_from("first_out_file_name").expect("could not read first_out"); -let head = Vec::::load_from("head_file_name").expect("could not read head"); -let travel_time = Vec::::load_from("weight_file_name").expect("could not read travel_time"); +let first_out = Vec::::load_from("first_out_file_name")?; +let head = Vec::::load_from("head_file_name")?; +let travel_time = Vec::::load_from("weight_file_name")?; let node_id = 42; for edge_id in first_out[node_id] .. first_out[node_id + 1] { diff --git a/src/bin/example.rs b/src/bin/example.rs index f8e9434..68056b8 100644 --- a/src/bin/example.rs +++ b/src/bin/example.rs @@ -1,28 +1,29 @@ -use stud_rust_base::{ - types::*, - io::*, - time::report_time, -}; +use stud_rust_base::{io::*, time::report_time, types::*}; -use std::{env, path::Path}; +use std::{env, error::Error, path::Path}; -fn main() { +fn main() -> Result<(), Box> { let mut args = env::args(); args.next(); let arg = &args.next().expect("No directory arg given"); let path = Path::new(arg); - let first_out = Vec::::load_from(path.join("first_out").to_str().unwrap()).expect("could not read first_out"); - let head = Vec::::load_from(path.join("head").to_str().unwrap()).expect("could not read head"); - let travel_time = Vec::::load_from(path.join("travel_time").to_str().unwrap()).expect("could not read travel_time"); + let first_out = Vec::::load_from(path.join("first_out"))?; + let head = Vec::::load_from(path.join("head"))?; + let travel_time = Vec::::load_from(path.join("travel_time"))?; report_time("iterating over arcs of some node", || { let node_id = 42; - for edge_id in first_out[node_id] .. first_out[node_id + 1] { - println!("There is an arc from {} to {} with weight {}", node_id, head[edge_id as usize], travel_time[edge_id as usize]); + for edge_id in first_out[node_id]..first_out[node_id + 1] { + println!( + "There is an arc from {} to {} with weight {}", + node_id, head[edge_id as usize], travel_time[edge_id as usize] + ); } }); - vec![42; 42].write_to(path.join("distances").to_str().unwrap()).expect("could not write distances"); + vec![42; 42].write_to(&path.join("distances"))?; + + Ok(()) } diff --git a/src/cli.rs b/src/cli.rs index e66421d..fc083d1 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,6 +1,6 @@ //! Utility module for command line interfaces -use std::{fmt, fmt::Display, error::Error}; +use std::{error::Error, fmt, fmt::Display}; /// An error struct to wrap simple static error messages #[derive(Debug)] diff --git a/src/index_heap.rs b/src/index_heap.rs index a7af9ca..477dc87 100644 --- a/src/index_heap.rs +++ b/src/index_heap.rs @@ -23,15 +23,13 @@ //! } //! } //! -//! fn main() { -//! let mut heap = IndexdMinHeap::new(3); -//! heap.push(State { node: 0, distance: 42 }); -//! heap.push(State { node: 1, distance: 23 }); -//! heap.push(State { node: 2, distance: 50000 }); -//! assert_eq!(heap.peek().cloned(), Some(State { node: 1, distance: 23 })); -//! heap.decrease_key(State { node: 0, distance: 1 }); -//! assert_eq!(heap.pop(), Some(State { node: 0, distance: 1 })); -//! } +//! let mut heap = IndexdMinHeap::new(3); +//! heap.push(State { node: 0, distance: 42 }); +//! heap.push(State { node: 1, distance: 23 }); +//! heap.push(State { node: 2, distance: 50000 }); +//! assert_eq!(heap.peek().cloned(), Some(State { node: 1, distance: 23 })); +//! heap.decrease_key(State { node: 0, distance: 1 }); +//! assert_eq!(heap.pop(), Some(State { node: 0, distance: 1 })); //! //! ``` @@ -55,7 +53,7 @@ pub trait Indexing { #[derive(Debug)] pub struct IndexdMinHeap { positions: Vec, - data: Vec + data: Vec, } const TREE_ARITY: usize = 4; @@ -68,7 +66,7 @@ impl IndexdMinHeap { pub fn new(max_index: usize) -> IndexdMinHeap { IndexdMinHeap { positions: vec![INVALID_POSITION; max_index], - data: Vec::new() + data: Vec::new(), } } @@ -170,7 +168,10 @@ impl IndexdMinHeap { let mut hole = Hole::new(&mut self.data, position); loop { - if let Some(smallest_child) = IndexdMinHeap::::children_index_range(position, heap_size).min_by_key(|&child_index| hole.get(child_index)) { + if let Some(smallest_child) = + IndexdMinHeap::::children_index_range(position, heap_size) + .min_by_key(|&child_index| hole.get(child_index)) + { if hole.get(smallest_child) >= hole.element() { self.positions[hole.element().as_index()] = position; return; // no child is smaller @@ -194,12 +195,10 @@ impl IndexdMinHeap { } } - // This is an optimization copied straight from the rust stdlib binary heap // it allows to avoid always swapping elements pairwise and rather // move each element only once. - /// Hole represents a hole in a slice i.e. an index without valid value /// (because it was moved from or duplicated). /// In drop, `Hole` will restore the slice by filling the hole diff --git a/src/io.rs b/src/io.rs index 419fa45..52057af 100644 --- a/src/io.rs +++ b/src/io.rs @@ -1,26 +1,26 @@ //! This module contains a few traits and blanket implementations -//! for (de)serializing and writing/reading numeric data to/from the disc. +//! for (de)serializing and writing/reading data to/from the disc. //! To use it you should import the `Load` and `Store` traits and use the //! `load_from` and `write_to` methods. //! //! # Example //! -//! ``` -//! use stud_rust_base::io::*; +//! ```no_run +//! # use stud_rust_base::io::*; //! -//! fn test() { -//! let head = Vec::::load_from("head_file_name").expect("could not read head"); -//! let lat = Vec::::load_from("node_latitude_file_name").expect("could not read lat"); -//! head.write_to("output_file").expect("could not write head"); -//! } +//! let head = Vec::::load_from("head_file_name")?; +//! let lat = Vec::::load_from("node_latitude_file_name")?; +//! head.write_to(&"output_file")?; +//! # Ok::<(), Box>(()) //! ``` -use std::fs; -use std::fs::File; -use std::io::prelude::*; -use std::io::Result; -use std::mem; -use std::slice; +use std::{ + fs::{metadata, File}, + io::{prelude::*, Result}, + mem, + path::Path, + slice, +}; /// A trait which allows accessing the data of an object as a slice of bytes. /// The bytes should represent a serialization of the object and allow @@ -49,6 +49,12 @@ impl DataBytes for [T] { } } +impl DataBytes for Vec { + fn data_bytes(&self) -> &[u8] { + &self[..].data_bytes() + } +} + impl DataBytesMut for [T] { fn data_bytes_mut(&mut self) -> &mut [u8] { let num_bytes = self.len() * mem::size_of::(); @@ -64,10 +70,10 @@ impl DataBytesMut for Vec { } /// A trait which extends the `DataBytes` trait and exposes a method to write objects to disk. -pub trait Store : DataBytes { - /// Writes the serialized object to the file with the given filename - fn write_to(&self, filename: &str) -> Result<()> { - File::create(filename)?.write_all(self.data_bytes()) +pub trait Store: DataBytes { + /// Writes the serialized object to the file with the given path + fn write_to(&self, path: &dyn AsRef) -> Result<()> { + File::create(path)?.write_all(self.data_bytes()) } } @@ -75,16 +81,16 @@ impl Store for T {} impl Store for [T] where [T]: DataBytes {} /// A trait to load serialized data back into objects. -pub trait Load : DataBytesMut + Sized { +pub trait Load: DataBytesMut + Sized { /// This method must create an object of the correct size for serialized data with the given number of bytes. /// It should not be necessary to call this method directly. fn new_with_bytes(num_bytes: usize) -> Self; /// This method will load serialized data from the disk, create an object of the appropriate size, /// deserialize the bytes into the object and return the object. - fn load_from(filename: &str) -> Result { - let metadata = fs::metadata(filename)?; - let mut file = File::open(filename)?; + fn load_from>(path: P) -> Result { + let metadata = metadata(path.as_ref())?; + let mut file = File::open(path)?; let mut object = Self::new_with_bytes(metadata.len() as usize); assert_eq!(metadata.len() as usize, object.data_bytes_mut().len());