dvcompute 2.0.0

Discrete event simulation library (sequential simulation)
Documentation
// Copyright (c) 2020-2022  David Sorokin <davsor@mail.ru>, based in Yoshkar-Ola, Russia
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::cmp::Ordering;
use std::hash::Hash;
use std::hash::Hasher;
use std::mem;

/// Represents a finite `f64` value.
#[derive(Debug, Copy, Clone)]
pub struct FiniteF64(pub f64);

impl Hash for FiniteF64 {

    fn hash<H: Hasher>(&self, state: &mut H) {

        let x = self.0;

        if x.is_finite() {
            let key: u64 = unsafe { mem::transmute(x) };
            key.hash(state)
        } else {
            0.hash(state)
        }
    }
}

impl PartialEq for FiniteF64 {

    fn eq(&self, other: &Self) -> bool {

        let x = self.0;
        let y = other.0;

        if !x.is_nan() {
            x.eq(&y)
        } else {
            // consider all NaN to be equivalent, for we imply that this cannot be NaN
            y.is_nan()
        }
    }
}

impl Eq for FiniteF64 {}

impl PartialOrd for FiniteF64 {

    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {

        let x = self.0;
        let y = other.0;

        x.partial_cmp(&y)
    }
}

impl Ord for FiniteF64 {

    fn cmp(&self, other: &Self) -> Ordering {

        let x = self.0;
        let y = other.0;

        match x.partial_cmp(&y) {
            Some(ordering) => ordering,
            None if x.is_nan() => {
                if y.is_nan() { Ordering::Equal } else { Ordering::Less }
            },
            None if y.is_nan() => {
                if x.is_nan() { Ordering::Equal } else { Ordering::Greater }
            },
            None => {
                // we cannot go to this line!
                panic!("Illegal comparison of {} and {}", x, y)
            }
        }
    }
}