<commit_before>use crate::*;

use async_std::{net::SocketAddr, prelude::*};

use futures::{
    self,
    sink::SinkExt,
    stream::{self, select, SelectAll, StreamExt},
};
use futures_timer::Delay;

use serde::Serialize;
use std::str::FromStr;
use std::{
    collections::HashMap,
    iter::FromIterator,
    time::{Duration, Instant},
};
use structopt::StructOpt;

#[derive(Clone, Copy, Debug, Serialize)]
pub struct TripReport {
    stream_id: StreamId,
    index: u64,
    round_trip: u128,
}

#[derive(Clone)]
pub struct Summary {
    pub mean_ms: f64,
    pub deviation_ms: f64,
    pub trip_reports: Vec<TripReport>,
}

impl FromIterator<Summary> for Summary {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = Summary>,
    {
        let (trip_reports, count, mean_sum, deviation_sum) =
            iter.into_iter().fold(
                (vec![], 0, 0.0, 0.0),
                |(
                    mut trip_reports,
                    mut count,
                    mut mean_sum,
                    mut deviation_sum,
                ),
                 mut result| {
                    mean_sum += result.mean_ms;
                    deviation_sum += result.deviation_ms;
                    count += 1;
                    trip_reports.append(&mut result.trip_reports);

                    (trip_reports, count, mean_sum, deviation_sum)
                },
            );

        Summary {
            mean_ms: mean_sum / count as f64,
            deviation_ms: deviation_sum / count as f64,
            trip_reports,
        }
    }
}

impl std::fmt::Debug for Summary {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("Summary")
            .field("Mean", &self.mean_ms)
            .field("Deviation", &self.deviation_ms)
            .finish()
    }
}

impl From<Vec<TripReport>> for Summary {
    fn from(src: Vec<TripReport>) -> Self {
        let sum: u128 = src.iter().map(|r| r.round_trip).sum();
        let n = src.len() as u128;
        let mean = sum / n;

        let square_difference = |r: &TripReport| (r.round_trip - mean).pow(2);
        let sum_of_squares: u128 = src.iter().map(square_difference).sum();
        let variance = sum_of_squares / (n - 1);
        let deviation = (variance as f64).sqrt();

        let mean = Duration::from_nanos(mean as u64);
        let deviation = Duration::from_nanos(deviation as u64);

        Summary {
            mean_ms: mean.as_secs_f64() * 1e3,
            deviation_ms: deviation.as_secs_f64() * 1e3,
            trip_reports: src,
        }
    }
}

/// Returns a stream that yields `()` `hertz` times per second.
fn ticker(hertz: u32) -> impl Stream<Item = ()> {
    let tick_rate = Duration::from_secs(1) / hertz;
    stream::repeat(0u8).then(move |_| Delay::new(tick_rate))
}

#[derive(Debug)]
struct TransferTracker {
    stream_id: StreamId,
    total_expected: usize,
    live: HashMap<u64, Instant>,
    returned: Vec<TripReport>,
}

impl TransferTracker {
    fn track_send(&mut self, id: u64) {
        self.live.insert(id, Instant::now());
    }

    fn track_return(&mut self, id: u64) {
        if let Some(sent_time) = self.live.remove(&id) {
            self.returned.push(TripReport {
                stream_id: self.stream_id,
                index: id,
                round_trip: Instant::now().duration_since(sent_time).as_nanos(),
            });
        }
    }

    fn done(&self) -> bool {
        self.returned.len() >= self.total_expected
    }
}

async fn run(
    options: Options,
    client: impl Connection + Unpin,
) -> Result<Summary> {
    enum Input {
        Transfer(TransferCmd),
        Wire(Result<Datagram>),
    }

    let (mut client_sink, client_stream) = client.split();
    let returned_datagrams = client_stream.map(Input::Wire);

    let mut tracking = options
        .transfers
        .iter()
        .filter_map(|tx| {
            tx.return_count.map(|total_expected| {
                (
                    tx.stream_id,
                    TransferTracker {
                        stream_id: tx.stream_id,
                        total_expected,
                        live: HashMap::new(),
                        returned: vec![],
                    },
                )
            })
        })
        .collect::<HashMap<StreamId, TransferTracker>>();
    let transfers: SelectAll<_> = options
        .transfers
        .into_iter()
        .map(Transfer::stream)
        .collect();

    let mut input_stream =
        select(transfers.map(Input::Transfer), returned_datagrams);

    loop {
        let input = input_stream.next().await.unwrap();
        match input {
            Input::Wire(returned_datagram) => {
                let returned_datagram: Datagram =
                    returned_datagram.expect("datagram");
                let stream = returned_datagram
                    .stream_position
                    .expect("stream position")
                    .stream_id;
                let benchmark_datagram =
                    bincode::deserialize::<BenchmarkDatagram>(
                        returned_datagram.data.as_slice(),
                    )?;

                if let Some(tracker) = tracking.get_mut(&stream) {
                    tracker.track_return(benchmark_datagram.id);
                }

                if tracking.values().all(TransferTracker::done) {
                    return Ok(tracking
                        .into_iter()
                        .map(|(_, tracker)| tracker.returned)
                        .map(Summary::from)
                        .collect());
                }
            }
            Input::Transfer(transfer_cmd) => {
                client_sink.send(transfer_cmd.send_cmd).await?;
                if let Some((cumulative_tracking, cmd_tracking)) =
                    transfer_cmd.tracking.and_then(|cmd_tracking| {
                        let cumulative_tracking =
                            tracking.get_mut(&cmd_tracking.stream_id)?;
                        Some((cumulative_tracking, cmd_tracking))
                    })
                {
                    cumulative_tracking.track_send(cmd_tracking.id);
                }
            }
        }
    }
}

#[derive(Clone, Debug, StructOpt)]
pub struct Options {
    /// Address of the server to run the benchmark against;
    #[structopt(short = "a", default_value = "127.0.0.1:33333")]
    pub address: SocketAddr,
    /// Periodic transfers, specified in terms of
    /// `stream_id:size:hertz:[return_count]`.
    #[structopt(short = "b", long)]
    pub transfers: Vec<Transfer>,
    #[structopt(subcommand)]
    pub protocol: Protocol,
}

struct TransferCmd {
    send_cmd: SendCmd,
    tracking: Option<TransferMessageTracking>,
}

/// Tracking information for a transfer message on the wire.
struct TransferMessageTracking {
    stream_id: StreamId,
    id: u64,
}

#[derive(Clone, Debug, Copy)]
pub struct Transfer {
    pub stream_id: StreamId,
    pub size: usize,
    pub hertz: u32,
    pub return_count: Option<usize>,
}

impl Transfer {
    fn stream(self) -> impl Stream<Item = TransferCmd> {
        let ticker = ticker(self.hertz);
        let mut id = 0;
        ticker.map(move |_| {
            id += 1;
            match self.return_count {
                Some(_) => TransferCmd {
                    send_cmd: self.send_cmd(id),
                    tracking: Some(TransferMessageTracking {
                        stream_id: self.stream_id,
                        id,
                    }),
                },
                None => TransferCmd {
                    send_cmd: self.send_cmd(ID_DO_NOT_RETURN),
                    tracking: None,
                },
            }
        })
    }

    fn send_cmd(&self, id: u64) -> SendCmd {
        let delivery_mode = DeliveryMode::ReliableOrdered(self.stream_id);
        SendCmd {
            delivery_mode,
            data: bincode::serialize(&BenchmarkDatagram {
                id,
                delivery_mode,
                data: vec![0; self.size],
            })
            .expect("to serialize bulk transfer"),
            ..SendCmd::default()
        }
    }
}

impl FromStr for Transfer {
    type Err = std::num::ParseIntError;
    fn from_str(src: &str) -> std::result::Result<Self, Self::Err> {
        let args: Vec<&str> = src.split(":").collect();

        let stream_id = args[0].parse::<u8>()?;
        let size = args[1].parse::<usize>()?;
        let hertz = args[2].parse::<u32>()?;
        let return_count =
            args.get(3).map(|a| a.parse::<usize>()).transpose()?;

        Ok(Self {
            stream_id: StreamId(stream_id),
            size,
            hertz,
            return_count,
        })
    }
}

pub async fn client_main(options: Options) -> Result<Summary> {
    let address = options.address;
    match options.protocol {
        Protocol::Tcp => {
            run(
                options,
                loop {
                    let result = tcp::TcpConnection::connect(address).await;

                    let error = match result {
                        Ok(results) => break results,
                        Err(e) => e,
                    };

                    // The server port is not yet open; give it time.
                    if error.is::<std::io::Error>()
                        && error
                            .downcast_ref::<std::io::Error>()
                            .map(std::io::Error::kind)
                            == Some(std::io::ErrorKind::ConnectionRefused)
                    {
                        continue;
                    }

                    panic!(
                        "Failed to connect to benchmark server: {:?}",
                        error
                    );
                },
            )
            .await
        }
        Protocol::Enet => {
            run(options, enet::EnetConnection::connect(address).await).await
        }
    }
}
<commit_msg>Use f64 for intermediate values<commit_after>use crate::*;

use async_std::{net::SocketAddr, prelude::*};

use futures::{
    self,
    sink::SinkExt,
    stream::{self, select, SelectAll, StreamExt},
};
use futures_timer::Delay;

use serde::Serialize;
use std::str::FromStr;
use std::{
    collections::HashMap,
    iter::FromIterator,
    time::{Duration, Instant},
};
use structopt::StructOpt;

#[derive(Clone, Copy, Debug, Serialize)]
pub struct TripReport {
    stream_id: StreamId,
    index: u64,
    round_trip: f64,
}

#[derive(Clone)]
pub struct Summary {
    pub mean_ms: f64,
    pub deviation_ms: f64,
    pub trip_reports: Vec<TripReport>,
}

impl FromIterator<Summary> for Summary {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = Summary>,
    {
        let (trip_reports, count, mean_sum, deviation_sum) =
            iter.into_iter().fold(
                (vec![], 0, 0.0, 0.0),
                |(
                    mut trip_reports,
                    mut count,
                    mut mean_sum,
                    mut deviation_sum,
                ),
                 mut result| {
                    mean_sum += result.mean_ms;
                    deviation_sum += result.deviation_ms;
                    count += 1;
                    trip_reports.append(&mut result.trip_reports);

                    (trip_reports, count, mean_sum, deviation_sum)
                },
            );

        Summary {
            mean_ms: mean_sum / count as f64,
            deviation_ms: deviation_sum / count as f64,
            trip_reports,
        }
    }
}

impl std::fmt::Debug for Summary {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("Summary")
            .field("Mean", &self.mean_ms)
            .field("Deviation", &self.deviation_ms)
            .finish()
    }
}

impl From<Vec<TripReport>> for Summary {
    fn from(src: Vec<TripReport>) -> Self {
        let sum: f64 = src.iter().map(|r| r.round_trip).sum();
        let n = src.len() as f64;
        let mean = sum / n;

        let square_difference = |r: &TripReport| (r.round_trip - mean).powi(2);
        let sum_of_squares: f64 = src.iter().map(square_difference).sum();
        let variance = sum_of_squares / (n - 1.0);
        let deviation = variance.sqrt();

        Summary {
            mean_ms: mean,
            deviation_ms: deviation,
            trip_reports: src,
        }
    }
}

/// Returns a stream that yields `()` `hertz` times per second.
fn ticker(hertz: u32) -> impl Stream<Item = ()> {
    let tick_rate = Duration::from_secs(1) / hertz;
    stream::repeat(0u8).then(move |_| Delay::new(tick_rate))
}

#[derive(Debug)]
struct TransferTracker {
    stream_id: StreamId,
    total_expected: usize,
    live: HashMap<u64, Instant>,
    returned: Vec<TripReport>,
}

impl TransferTracker {
    fn track_send(&mut self, id: u64) {
        self.live.insert(id, Instant::now());
    }

    fn track_return(&mut self, id: u64) {
        if let Some(sent_time) = self.live.remove(&id) {
            self.returned.push(TripReport {
                stream_id: self.stream_id,
                index: id,
                round_trip: Instant::now().duration_since(sent_time).as_secs_f64() * 1e3,
            });
        }
    }

    fn done(&self) -> bool {
        self.returned.len() >= self.total_expected
    }
}

async fn run(
    options: Options,
    client: impl Connection + Unpin,
) -> Result<Summary> {
    enum Input {
        Transfer(TransferCmd),
        Wire(Result<Datagram>),
    }

    let (mut client_sink, client_stream) = client.split();
    let returned_datagrams = client_stream.map(Input::Wire);

    let mut tracking = options
        .transfers
        .iter()
        .filter_map(|tx| {
            tx.return_count.map(|total_expected| {
                (
                    tx.stream_id,
                    TransferTracker {
                        stream_id: tx.stream_id,
                        total_expected,
                        live: HashMap::new(),
                        returned: vec![],
                    },
                )
            })
        })
        .collect::<HashMap<StreamId, TransferTracker>>();
    let transfers: SelectAll<_> = options
        .transfers
        .into_iter()
        .map(Transfer::stream)
        .collect();

    let mut input_stream =
        select(transfers.map(Input::Transfer), returned_datagrams);

    loop {
        let input = input_stream.next().await.unwrap();
        match input {
            Input::Wire(returned_datagram) => {
                let returned_datagram: Datagram =
                    returned_datagram.expect("datagram");
                let stream = returned_datagram
                    .stream_position
                    .expect("stream position")
                    .stream_id;
                let benchmark_datagram =
                    bincode::deserialize::<BenchmarkDatagram>(
                        returned_datagram.data.as_slice(),
                    )?;

                if let Some(tracker) = tracking.get_mut(&stream) {
                    tracker.track_return(benchmark_datagram.id);
                }

                if tracking.values().all(TransferTracker::done) {
                    return Ok(tracking
                        .into_iter()
                        .map(|(_, tracker)| tracker.returned)
                        .map(Summary::from)
                        .collect());
                }
            }
            Input::Transfer(transfer_cmd) => {
                client_sink.send(transfer_cmd.send_cmd).await?;
                if let Some((cumulative_tracking, cmd_tracking)) =
                    transfer_cmd.tracking.and_then(|cmd_tracking| {
                        let cumulative_tracking =
                            tracking.get_mut(&cmd_tracking.stream_id)?;
                        Some((cumulative_tracking, cmd_tracking))
                    })
                {
                    cumulative_tracking.track_send(cmd_tracking.id);
                }
            }
        }
    }
}

#[derive(Clone, Debug, StructOpt)]
pub struct Options {
    /// Address of the server to run the benchmark against;
    #[structopt(short = "a", default_value = "127.0.0.1:33333")]
    pub address: SocketAddr,
    /// Periodic transfers, specified in terms of
    /// `stream_id:size:hertz:[return_count]`.
    #[structopt(short = "b", long)]
    pub transfers: Vec<Transfer>,
    #[structopt(subcommand)]
    pub protocol: Protocol,
}

struct TransferCmd {
    send_cmd: SendCmd,
    tracking: Option<TransferMessageTracking>,
}

/// Tracking information for a transfer message on the wire.
struct TransferMessageTracking {
    stream_id: StreamId,
    id: u64,
}

#[derive(Clone, Debug, Copy)]
pub struct Transfer {
    pub stream_id: StreamId,
    pub size: usize,
    pub hertz: u32,
    pub return_count: Option<usize>,
}

impl Transfer {
    fn stream(self) -> impl Stream<Item = TransferCmd> {
        let ticker = ticker(self.hertz);
        let mut id = 0;
        ticker.map(move |_| {
            id += 1;
            match self.return_count {
                Some(_) => TransferCmd {
                    send_cmd: self.send_cmd(id),
                    tracking: Some(TransferMessageTracking {
                        stream_id: self.stream_id,
                        id,
                    }),
                },
                None => TransferCmd {
                    send_cmd: self.send_cmd(ID_DO_NOT_RETURN),
                    tracking: None,
                },
            }
        })
    }

    fn send_cmd(&self, id: u64) -> SendCmd {
        let delivery_mode = DeliveryMode::ReliableOrdered(self.stream_id);
        SendCmd {
            delivery_mode,
            data: bincode::serialize(&BenchmarkDatagram {
                id,
                delivery_mode,
                data: vec![0; self.size],
            })
            .expect("to serialize bulk transfer"),
            ..SendCmd::default()
        }
    }
}

impl FromStr for Transfer {
    type Err = std::num::ParseIntError;
    fn from_str(src: &str) -> std::result::Result<Self, Self::Err> {
        let args: Vec<&str> = src.split(":").collect();

        let stream_id = args[0].parse::<u8>()?;
        let size = args[1].parse::<usize>()?;
        let hertz = args[2].parse::<u32>()?;
        let return_count =
            args.get(3).map(|a| a.parse::<usize>()).transpose()?;

        Ok(Self {
            stream_id: StreamId(stream_id),
            size,
            hertz,
            return_count,
        })
    }
}

pub async fn client_main(options: Options) -> Result<Summary> {
    let address = options.address;
    match options.protocol {
        Protocol::Tcp => {
            run(
                options,
                loop {
                    let result = tcp::TcpConnection::connect(address).await;

                    let error = match result {
                        Ok(results) => break results,
                        Err(e) => e,
                    };

                    // The server port is not yet open; give it time.
                    if error.is::<std::io::Error>()
                        && error
                            .downcast_ref::<std::io::Error>()
                            .map(std::io::Error::kind)
                            == Some(std::io::ErrorKind::ConnectionRefused)
                    {
                        continue;
                    }

                    panic!(
                        "Failed to connect to benchmark server: {:?}",
                        error
                    );
                },
            )
            .await
        }
        Protocol::Enet => {
            run(options, enet::EnetConnection::connect(address).await).await
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::arch::x86_64::{__cpuid, __cpuid_count};
use std::fmt::{self, Display};
use std::result;

use devices::{IrqChipCap, IrqChipX86_64};
use hypervisor::{HypervisorX86_64, VcpuX86_64};

#[derive(Debug, PartialEq)]
pub enum Error {
    GetSupportedCpusFailed(base::Error),
    SetSupportedCpusFailed(base::Error),
}
pub type Result<T> = result::Result<T, Error>;

impl std::error::Error for Error {}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            GetSupportedCpusFailed(e) => write!(f, "GetSupportedCpus ioctl failed: {}", e),
            SetSupportedCpusFailed(e) => write!(f, "SetSupportedCpus ioctl failed: {}", e),
        }
    }
}

// CPUID bits in ebx, ecx, and edx.
const EBX_CLFLUSH_CACHELINE: u32 = 8; // Flush a cache line size.
const EBX_CLFLUSH_SIZE_SHIFT: u32 = 8; // Bytes flushed when executing CLFLUSH.
const EBX_CPU_COUNT_SHIFT: u32 = 16; // Index of this CPU.
const EBX_CPUID_SHIFT: u32 = 24; // Index of this CPU.
const ECX_EPB_SHIFT: u32 = 3; // "Energy Performance Bias" bit.
const ECX_X2APIC_SHIFT: u32 = 21; // APIC supports extended xAPIC (x2APIC) standard.
const ECX_TSC_DEADLINE_TIMER_SHIFT: u32 = 24; // TSC deadline mode of APIC timer.
const ECX_HYPERVISOR_SHIFT: u32 = 31; // Flag to be set when the cpu is running on a hypervisor.
const EDX_HTT_SHIFT: u32 = 28; // Hyper Threading Enabled.
const ECX_TOPO_TYPE_SHIFT: u32 = 8; // Topology Level type.
const ECX_TOPO_SMT_TYPE: u32 = 1; // SMT type.
const ECX_TOPO_CORE_TYPE: u32 = 2; // CORE type.

fn filter_cpuid(
    vcpu_id: usize,
    cpu_count: usize,
    cpuid: &mut hypervisor::CpuId,
    irq_chip: &dyn IrqChipX86_64,
    no_smt: bool,
) -> Result<()> {
    let entries = &mut cpuid.cpu_id_entries;

    for entry in entries {
        match entry.function {
            1 => {
                // X86 hypervisor feature
                if entry.index == 0 {
                    entry.ecx |= 1 << ECX_HYPERVISOR_SHIFT;
                }
                if irq_chip.check_capability(IrqChipCap::X2Apic) {
                    entry.ecx |= 1 << ECX_X2APIC_SHIFT;
                } else {
                    entry.ecx &= !(1 << ECX_X2APIC_SHIFT);
                }
                if irq_chip.check_capability(IrqChipCap::TscDeadlineTimer) {
                    entry.ecx |= 1 << ECX_TSC_DEADLINE_TIMER_SHIFT;
                }
                entry.ebx = (vcpu_id << EBX_CPUID_SHIFT) as u32
                    | (EBX_CLFLUSH_CACHELINE << EBX_CLFLUSH_SIZE_SHIFT);
                if cpu_count > 1 {
                    entry.ebx |= (cpu_count as u32) << EBX_CPU_COUNT_SHIFT;
                    entry.edx |= 1 << EDX_HTT_SHIFT;
                }
            }
            2 | 0x80000005 | 0x80000006 => unsafe {
                let result = __cpuid(entry.function);
                entry.eax = result.eax;
                entry.ebx = result.ebx;
                entry.ecx = result.ecx;
                entry.edx = result.edx;
            },
            4 => {
                unsafe {
                    let result = __cpuid_count(entry.function, entry.index);
                    entry.eax = result.eax;
                    entry.ebx = result.ebx;
                    entry.ecx = result.ecx;
                    entry.edx = result.edx;
                }
                entry.eax &= !0xFC000000;
            }
            6 => {
                // Clear X86 EPB feature.  No frequency selection in the hypervisor.
                entry.ecx &= !(1 << ECX_EPB_SHIFT);
            }
            0xB | 0x1F => {
                // Extended topology enumeration / V2 Extended topology enumeration
                // NOTE: these will need to be split if any of the fields that differ between
                // the two versions are to be set.
                entry.edx = vcpu_id as u32; // x2APIC ID
                if no_smt {
                    // Make it so that all VCPUs appear as different,
                    // non-hyperthreaded cores on the same package.
                    if entry.index == 0 {
                        entry.eax = 0; // Shift to get id of next level
                        entry.ebx = 1; // Number of logical cpus at this level
                        entry.ecx = (ECX_TOPO_SMT_TYPE << ECX_TOPO_TYPE_SHIFT) | entry.index;
                    } else if entry.index == 1 {
                        entry.eax = 4;
                        entry.ebx = (cpu_count as u32) & 0xffff;
                        entry.ecx = (ECX_TOPO_CORE_TYPE << ECX_TOPO_TYPE_SHIFT) | entry.index;
                    } else {
                        entry.eax = 0;
                        entry.ebx = 0;
                        entry.ecx = 0;
                    }
                }
            }
            _ => (),
        }
    }

    Ok(())
}

/// Sets up the cpuid entries for the given vcpu.  Can fail if there are too many CPUs specified or
/// if an ioctl returns an error.
///
/// # Arguments
///
/// * `hypervisor` - `HypervisorX86_64` impl for getting supported CPU IDs.
/// * `vcpu` - `VcpuX86_64` for setting CPU ID.
/// * `vcpu_id` - The vcpu index of `vcpu`.
/// * `nrcpus` - The number of vcpus being used by this VM.
pub fn setup_cpuid(
    hypervisor: &dyn HypervisorX86_64,
    irq_chip: &dyn IrqChipX86_64,
    vcpu: &dyn VcpuX86_64,
    vcpu_id: usize,
    nrcpus: usize,
    no_smt: bool,
) -> Result<()> {
    let mut cpuid = hypervisor
        .get_supported_cpuid()
        .map_err(Error::GetSupportedCpusFailed)?;

    filter_cpuid(vcpu_id, nrcpus, &mut cpuid, irq_chip, no_smt)?;

    vcpu.set_cpuid(&cpuid)
        .map_err(Error::SetSupportedCpusFailed)
}

/// get host cpu max physical address bits
pub fn phy_max_address_bits() -> u32 {
    let mut phys_bits: u32 = 36;

    let highest_ext_function = unsafe { __cpuid(0x80000000) };
    if highest_ext_function.eax >= 0x80000008 {
        let addr_size = unsafe { __cpuid(0x80000008) };
        phys_bits = addr_size.eax & 0xff;
    }

    phys_bits
}

#[cfg(test)]
mod tests {
    use super::*;
    use hypervisor::CpuIdEntry;

    #[test]
    fn feature_and_vendor_name() {
        let mut cpuid = hypervisor::CpuId::new(2);
        let guest_mem =
            vm_memory::GuestMemory::new(&[(vm_memory::GuestAddress(0), 0x10000)]).unwrap();
        let kvm = hypervisor::kvm::Kvm::new().unwrap();
        let vm = hypervisor::kvm::KvmVm::new(&kvm, guest_mem).unwrap();
        let irq_chip = devices::KvmKernelIrqChip::new(vm, 1).unwrap();

        let entries = &mut cpuid.cpu_id_entries;
        entries.push(CpuIdEntry {
            function: 0,
            ..Default::default()
        });
        entries.push(CpuIdEntry {
            function: 1,
            ecx: 0x10,
            edx: 0,
            ..Default::default()
        });
        assert_eq!(Ok(()), filter_cpuid(1, 2, &mut cpuid, &irq_chip, false));

        let entries = &mut cpuid.cpu_id_entries;
        assert_eq!(entries[0].function, 0);
        assert_eq!(1, (entries[1].ebx >> EBX_CPUID_SHIFT) & 0x000000ff);
        assert_eq!(2, (entries[1].ebx >> EBX_CPU_COUNT_SHIFT) & 0x000000ff);
        assert_eq!(
            EBX_CLFLUSH_CACHELINE,
            (entries[1].ebx >> EBX_CLFLUSH_SIZE_SHIFT) & 0x000000ff
        );
        assert_ne!(0, entries[1].ecx & (1 << ECX_HYPERVISOR_SHIFT));
        assert_ne!(0, entries[1].edx & (1 << EDX_HTT_SHIFT));
    }
}
<commit_msg>x86_64/cpuid.rs: Add cpu topology when no_smt isn't set<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::arch::x86_64::{__cpuid, __cpuid_count};
use std::fmt::{self, Display};
use std::result;

use devices::{IrqChipCap, IrqChipX86_64};
use hypervisor::{HypervisorX86_64, VcpuX86_64};

#[derive(Debug, PartialEq)]
pub enum Error {
    GetSupportedCpusFailed(base::Error),
    SetSupportedCpusFailed(base::Error),
}
pub type Result<T> = result::Result<T, Error>;

impl std::error::Error for Error {}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            GetSupportedCpusFailed(e) => write!(f, "GetSupportedCpus ioctl failed: {}", e),
            SetSupportedCpusFailed(e) => write!(f, "SetSupportedCpus ioctl failed: {}", e),
        }
    }
}

// CPUID bits in ebx, ecx, and edx.
const EBX_CLFLUSH_CACHELINE: u32 = 8; // Flush a cache line size.
const EBX_CLFLUSH_SIZE_SHIFT: u32 = 8; // Bytes flushed when executing CLFLUSH.
const EBX_CPU_COUNT_SHIFT: u32 = 16; // Index of this CPU.
const EBX_CPUID_SHIFT: u32 = 24; // Index of this CPU.
const ECX_EPB_SHIFT: u32 = 3; // "Energy Performance Bias" bit.
const ECX_X2APIC_SHIFT: u32 = 21; // APIC supports extended xAPIC (x2APIC) standard.
const ECX_TSC_DEADLINE_TIMER_SHIFT: u32 = 24; // TSC deadline mode of APIC timer.
const ECX_HYPERVISOR_SHIFT: u32 = 31; // Flag to be set when the cpu is running on a hypervisor.
const EDX_HTT_SHIFT: u32 = 28; // Hyper Threading Enabled.
const ECX_TOPO_TYPE_SHIFT: u32 = 8; // Topology Level type.
const ECX_TOPO_SMT_TYPE: u32 = 1; // SMT type.
const ECX_TOPO_CORE_TYPE: u32 = 2; // CORE type.
const EAX_CPU_CORES_SHIFT: u32 = 26; // Index of cpu cores in the same physical package.

fn filter_cpuid(
    vcpu_id: usize,
    cpu_count: usize,
    cpuid: &mut hypervisor::CpuId,
    irq_chip: &dyn IrqChipX86_64,
    no_smt: bool,
) -> Result<()> {
    let entries = &mut cpuid.cpu_id_entries;

    for entry in entries {
        match entry.function {
            1 => {
                // X86 hypervisor feature
                if entry.index == 0 {
                    entry.ecx |= 1 << ECX_HYPERVISOR_SHIFT;
                }
                if irq_chip.check_capability(IrqChipCap::X2Apic) {
                    entry.ecx |= 1 << ECX_X2APIC_SHIFT;
                } else {
                    entry.ecx &= !(1 << ECX_X2APIC_SHIFT);
                }
                if irq_chip.check_capability(IrqChipCap::TscDeadlineTimer) {
                    entry.ecx |= 1 << ECX_TSC_DEADLINE_TIMER_SHIFT;
                }
                entry.ebx = (vcpu_id << EBX_CPUID_SHIFT) as u32
                    | (EBX_CLFLUSH_CACHELINE << EBX_CLFLUSH_SIZE_SHIFT);
                if cpu_count > 1 {
                    entry.ebx |= (cpu_count as u32) << EBX_CPU_COUNT_SHIFT;
                    entry.edx |= 1 << EDX_HTT_SHIFT;
                }
            }
            2 | 0x80000005 | 0x80000006 => unsafe {
                let result = __cpuid(entry.function);
                entry.eax = result.eax;
                entry.ebx = result.ebx;
                entry.ecx = result.ecx;
                entry.edx = result.edx;
            },
            4 => {
                unsafe {
                    let result = __cpuid_count(entry.function, entry.index);
                    entry.eax = result.eax;
                    entry.ebx = result.ebx;
                    entry.ecx = result.ecx;
                    entry.edx = result.edx;
                }
                entry.eax &= !0xFC000000;
                if cpu_count > 1 {
                    let cpu_cores = if no_smt {
                        cpu_count as u32
                    } else if cpu_count % 2 == 0 {
                        (cpu_count >> 1) as u32
                    } else {
                        1
                    };
                    entry.eax |= (cpu_cores - 1) << EAX_CPU_CORES_SHIFT;
                }
            }
            6 => {
                // Clear X86 EPB feature.  No frequency selection in the hypervisor.
                entry.ecx &= !(1 << ECX_EPB_SHIFT);
            }
            0xB | 0x1F => {
                // Extended topology enumeration / V2 Extended topology enumeration
                // NOTE: these will need to be split if any of the fields that differ between
                // the two versions are to be set.
                entry.edx = vcpu_id as u32; // x2APIC ID
                if entry.index == 0 {
                    if no_smt || (cpu_count == 1) {
                        // Make it so that all VCPUs appear as different,
                        // non-hyperthreaded cores on the same package.
                        entry.eax = 0; // Shift to get id of next level
                        entry.ebx = 1; // Number of logical cpus at this level
                    } else if cpu_count % 2 == 0 {
                        // Each core has 2 hyperthreads
                        entry.eax = 1; // Shift to get id of next level
                        entry.ebx = 2; // Number of logical cpus at this level
                    } else {
                        // One core contain all the cpu_count hyperthreads
                        let cpu_bits: u32 = 32 - ((cpu_count - 1) as u32).leading_zeros();
                        entry.eax = cpu_bits; // Shift to get id of next level
                        entry.ebx = cpu_count as u32; // Number of logical cpus at this level
                    }
                    entry.ecx = (ECX_TOPO_SMT_TYPE << ECX_TOPO_TYPE_SHIFT) | entry.index;
                } else if entry.index == 1 {
                    let cpu_bits: u32 = 32 - ((cpu_count - 1) as u32).leading_zeros();
                    entry.eax = cpu_bits;
                    entry.ebx = (cpu_count as u32) & 0xffff; // Number of logical cpus at this level
                    entry.ecx = (ECX_TOPO_CORE_TYPE << ECX_TOPO_TYPE_SHIFT) | entry.index;
                } else {
                    entry.eax = 0;
                    entry.ebx = 0;
                    entry.ecx = 0;
                }
            }
            _ => (),
        }
    }

    Ok(())
}

/// Sets up the cpuid entries for the given vcpu.  Can fail if there are too many CPUs specified or
/// if an ioctl returns an error.
///
/// # Arguments
///
/// * `hypervisor` - `HypervisorX86_64` impl for getting supported CPU IDs.
/// * `vcpu` - `VcpuX86_64` for setting CPU ID.
/// * `vcpu_id` - The vcpu index of `vcpu`.
/// * `nrcpus` - The number of vcpus being used by this VM.
pub fn setup_cpuid(
    hypervisor: &dyn HypervisorX86_64,
    irq_chip: &dyn IrqChipX86_64,
    vcpu: &dyn VcpuX86_64,
    vcpu_id: usize,
    nrcpus: usize,
    no_smt: bool,
) -> Result<()> {
    let mut cpuid = hypervisor
        .get_supported_cpuid()
        .map_err(Error::GetSupportedCpusFailed)?;

    filter_cpuid(vcpu_id, nrcpus, &mut cpuid, irq_chip, no_smt)?;

    vcpu.set_cpuid(&cpuid)
        .map_err(Error::SetSupportedCpusFailed)
}

/// get host cpu max physical address bits
pub fn phy_max_address_bits() -> u32 {
    let mut phys_bits: u32 = 36;

    let highest_ext_function = unsafe { __cpuid(0x80000000) };
    if highest_ext_function.eax >= 0x80000008 {
        let addr_size = unsafe { __cpuid(0x80000008) };
        phys_bits = addr_size.eax & 0xff;
    }

    phys_bits
}

#[cfg(test)]
mod tests {
    use super::*;
    use hypervisor::CpuIdEntry;

    #[test]
    fn feature_and_vendor_name() {
        let mut cpuid = hypervisor::CpuId::new(2);
        let guest_mem =
            vm_memory::GuestMemory::new(&[(vm_memory::GuestAddress(0), 0x10000)]).unwrap();
        let kvm = hypervisor::kvm::Kvm::new().unwrap();
        let vm = hypervisor::kvm::KvmVm::new(&kvm, guest_mem).unwrap();
        let irq_chip = devices::KvmKernelIrqChip::new(vm, 1).unwrap();

        let entries = &mut cpuid.cpu_id_entries;
        entries.push(CpuIdEntry {
            function: 0,
            ..Default::default()
        });
        entries.push(CpuIdEntry {
            function: 1,
            ecx: 0x10,
            edx: 0,
            ..Default::default()
        });
        assert_eq!(Ok(()), filter_cpuid(1, 2, &mut cpuid, &irq_chip, false));

        let entries = &mut cpuid.cpu_id_entries;
        assert_eq!(entries[0].function, 0);
        assert_eq!(1, (entries[1].ebx >> EBX_CPUID_SHIFT) & 0x000000ff);
        assert_eq!(2, (entries[1].ebx >> EBX_CPU_COUNT_SHIFT) & 0x000000ff);
        assert_eq!(
            EBX_CLFLUSH_CACHELINE,
            (entries[1].ebx >> EBX_CLFLUSH_SIZE_SHIFT) & 0x000000ff
        );
        assert_ne!(0, entries[1].ecx & (1 << ECX_HYPERVISOR_SHIFT));
        assert_ne!(0, entries[1].edx & (1 << EDX_HTT_SHIFT));
    }
}
<|endoftext|>


<commit_before>struct BufferManager;

struct BufferFrame;

impl BufferManager {
	pub fn new(size: uint) -> BufferManager {
		BufferManager
	}

	pub fn fixPage(pageId: u64, exclusive: bool) -> Option<BufferFrame> {
		None
	}

	pub fn unfixPage(frame: BufferFrame, isDirty: bool) {
	}
}

impl BufferFrame {
	pub fn getData() -> ~[u8] {
		~[0_u8, ..1024]
	}
}

fn main() {
	println!("Rewrite me into a test");
}
<commit_msg>Added some member variables<commit_after>extern crate collections;
use collections::HashMap;

struct BufferManager {
	size: uint,
	frames: HashMap<u64, BufferFrame>,
}

struct BufferFrame;

impl BufferManager {
	pub fn new(size: uint) -> BufferManager {
		let h = HashMap::with_capacity(size);
		BufferManager {size: size, frames: h}
	}

	pub fn fixPage(pageId: u64, exclusive: bool) -> Option<BufferFrame> {
		None
	}

	pub fn unfixPage(frame: BufferFrame, isDirty: bool) {
	}
}

impl BufferFrame {
	pub fn getData() -> ~[u8] {
		~[0_u8, ..1024]
	}
}

fn main() {
	println!("Rewrite me into a test");
}
<|endoftext|>


<commit_before>use input::ScanCode;
use platform;

/// Represents an open window on the host machine.
#[derive(Debug)]
pub struct Window(platform::window::Window);

impl Window {
    /// Creates a new window named `name`.
    pub fn new(name: &str) -> Result<Window, CreateWindowError> {
        Ok(Window(platform::window::Window::new(name)))
    }

    /// Removes and returns the next pending message from the message queue.
    ///
    /// If no messages are pending returns `None` and does not block.
    pub fn next_message(&mut self) -> Option<Message> {
        self.0.next_message()
    }

    /// Removes and returns the next pending message, blocking until one is available.
    ///
    /// If there are no pending messages in the message queue this method blocks until
    /// the next one is available. This method may still return `None` if it is not
    /// possible for the window to yield more messages (e.g. if the window is closed).
    pub fn wait_message(&mut self) -> Option<Message> {
        self.0.wait_message()
    }

    /// Gets the bounds describing the position/size of the window.
    // TODO: Return more structured, less platform-specific data.
    pub fn get_rect(&self) -> (i32, i32, i32, i32) {
        self.0.get_rect()
    }

    /// Creates a message pump for the window.
    ///
    /// A message pump allows message processing for a window to be offloaded to a worker thread
    /// without having to give away ownership of the window.
    pub fn message_pump(&mut self) -> MessagePump {
        MessagePump(self.0.inner())
    }

    /// Gets a reference to the platform-specific implementation of the window.
    pub fn platform(&self) -> &platform::window::Window {
        &self.0
    }
}

#[derive(Debug)]
pub enum CreateWindowError {
}

/// An iterator that does message processing for `Window`.
pub struct MessagePump(platform::window::WindowInner);

impl MessagePump {
    /// Pumps all messages for the window, blocking until there are no more messages to be pumped.
    pub fn run(&mut self) {
        self.0.pump_forever();
    }
}

impl Iterator for MessagePump {
    type Item = Message;

    fn next(&mut self) -> Option<Message> {
        self.0.wait_message()
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Message {
    Activate,
    Close,
    Destroy,
    Paint,
    KeyUp(ScanCode),
    KeyDown(ScanCode),

    /// The x movement and y movement in pixels.
    MouseMove(i32, i32),

    /// The x and y coordinates in pixels.
    ///
    /// These coordinates are relative to the window, with the upper-left corner
    /// of the window being (0, 0).
    MousePos(i32, i32),

    /// Message signaling a mouse button has been pressed.
    ///
    /// This message is sent any time a mouse button has been pressed. The wrapped
    /// value is the index of button on the mouse: 0 is LMB, 1 is RMB, 2 is LMB, with
    /// other button assignments being driver dependent (I assume).
    MouseButtonPressed(u8),

    /// Message signaling a mouse button has been released.
    ///
    /// This message is sent any time a mouse button has been released. The wrapped
    /// value is the index of button on the mouse: 0 is LMB, 1 is RMB, 2 is LMB, with
    /// other button assignments being driver dependent (I assume).
    MouseButtonReleased(u8),

    /// Message signalling how much the mouse wheel has been scrolled.
    ///
    /// This message is sent any time the mouse wheel is scrolled. The wrapped value
    /// is the amount the mouse wheel was scrolled, though the scale of this value
    /// is platform/driver dependent (I assume).
    MouseWheel(i32),
}
<commit_msg>Add Iterator implementation for Window<commit_after>use input::ScanCode;
use platform;

/// Represents an open window on the host machine.
#[derive(Debug)]
pub struct Window(platform::window::Window);

impl Window {
    /// Creates a new window named `name`.
    pub fn new(name: &str) -> Result<Window, CreateWindowError> {
        Ok(Window(platform::window::Window::new(name)))
    }

    /// Removes and returns the next pending message from the message queue.
    ///
    /// If no messages are pending returns `None` and does not block.
    pub fn next_message(&mut self) -> Option<Message> {
        self.0.next_message()
    }

    /// Removes and returns the next pending message, blocking until one is available.
    ///
    /// If there are no pending messages in the message queue this method blocks until
    /// the next one is available. This method may still return `None` if it is not
    /// possible for the window to yield more messages (e.g. if the window is closed).
    pub fn wait_message(&mut self) -> Option<Message> {
        self.0.wait_message()
    }

    /// Gets the bounds describing the position/size of the window.
    // TODO: Return more structured, less platform-specific data.
    pub fn get_rect(&self) -> (i32, i32, i32, i32) {
        self.0.get_rect()
    }

    /// Creates a message pump for the window.
    ///
    /// A message pump allows message processing for a window to be offloaded to a worker thread
    /// without having to give away ownership of the window.
    pub fn message_pump(&mut self) -> MessagePump {
        MessagePump(self.0.inner())
    }

    /// Gets a reference to the platform-specific implementation of the window.
    pub fn platform(&self) -> &platform::window::Window {
        &self.0
    }
}

impl<'a> Iterator for &'a mut Window {
    type Item = Message;

    fn next(&mut self) -> Option<Message> {
        self.next_message()
    }
}

#[derive(Debug)]
pub enum CreateWindowError {
}

/// An iterator that does message processing for `Window`.
pub struct MessagePump(platform::window::WindowInner);

impl MessagePump {
    /// Pumps all messages for the window, blocking until there are no more messages to be pumped.
    pub fn run(&mut self) {
        self.0.pump_forever();
    }
}

impl Iterator for MessagePump {
    type Item = Message;

    fn next(&mut self) -> Option<Message> {
        self.0.wait_message()
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Message {
    Activate,
    Close,
    Destroy,
    Paint,
    KeyUp(ScanCode),
    KeyDown(ScanCode),

    /// The x movement and y movement in pixels.
    MouseMove(i32, i32),

    /// The x and y coordinates in pixels.
    ///
    /// These coordinates are relative to the window, with the upper-left corner
    /// of the window being (0, 0).
    MousePos(i32, i32),

    /// Message signaling a mouse button has been pressed.
    ///
    /// This message is sent any time a mouse button has been pressed. The wrapped
    /// value is the index of button on the mouse: 0 is LMB, 1 is RMB, 2 is LMB, with
    /// other button assignments being driver dependent (I assume).
    MouseButtonPressed(u8),

    /// Message signaling a mouse button has been released.
    ///
    /// This message is sent any time a mouse button has been released. The wrapped
    /// value is the index of button on the mouse: 0 is LMB, 1 is RMB, 2 is LMB, with
    /// other button assignments being driver dependent (I assume).
    MouseButtonReleased(u8),

    /// Message signalling how much the mouse wheel has been scrolled.
    ///
    /// This message is sent any time the mouse wheel is scrolled. The wrapped value
    /// is the amount the mouse wheel was scrolled, though the scale of this value
    /// is platform/driver dependent (I assume).
    MouseWheel(i32),
}
<|endoftext|>


<commit_before>//! Sparse mapping of entity references to larger value types.
//!
//! This module provides a `SparseMap` data structure which implements a sparse mapping from an
//! `EntityRef` key to a value type that may be on the larger side. This implementation is based on
//! the paper:
//!
//! > Briggs, Torczon, *An efficient representation for sparse sets*,
//!   ACM Letters on Programming Languages and Systems, Volume 2, Issue 1-4, March-Dec. 1993.
//!
//! A `SparseMap<K, V>` map provides:
//!
//! - Memory usage equivalent to `EntityMap<K, u32>` + `Vec<V>`, so much smaller than
//!   `EntityMap<K, V>` for sparse mappings of larger `V` types.
//! - Constant time lookup, slightly slower than `EntityMap`.
//! - A very fast, constant time `clear()` operation.
//! - Fast insert and erase operations.
//! - Stable iteration that is as fast as a `Vec<V>`.
//!
//! # Compared to `EntityMap`
//!
//! When should we use a `SparseMap` instead of a secondary `EntityMap`? First of all, `SparseMap`
//! does not provide the functionality of a primary `EntityMap` which can allocate and assign
//! entity references to objects as they are pushed onto the map. It is only the secondary
//! entity maps that can be replaced with a `SparseMap`.
//!
//! - A secondary entity map requires its values to implement `Default`, and it is a bit loose
//!   about creating new mappings to the default value. It doesn't distinguish clearly between an
//!   unmapped key and one that maps to the default value. `SparseMap` does not require `Default`
//!   values, and it tracks accurately if a key has been mapped or not.
//! - Iterating over the contants of an `EntityMap` is linear in the size of the *key space*, while
//!   iterating over a `SparseMap` is linear in the number of elements in the mapping. This is an
//!   advantage precisely when the mapping is sparse.
//! - `SparseMap::clear()` is constant time and super-fast. `EntityMap::clear()` is linear in the
//!   size of the key space. (Or, rather the required `resize()` call following the `clear()` is).
//! - `SparseMap` requires the values to implement `SparseMapValue<K>` which means that they must
//!   contain their own key.

use entity_map::{EntityRef, EntityMap};
use std::mem;
use std::u32;

/// Trait for extracting keys from values stored in a `SparseMap`.
///
/// All values stored in a `SparseMap` must keep track of their own key in the map and implement
/// this trait to provide access to the key.
pub trait SparseMapValue<K> {
    /// Get the key of this sparse map value. This key is not alowed to change while the value
    /// is a member of the map.
    fn key(&self) -> K;
}

/// A sparse mapping of entity references.
pub struct SparseMap<K, V>
    where K: EntityRef,
          V: SparseMapValue<K>
{
    sparse: EntityMap<K, u32>,
    dense: Vec<V>,
}

impl<K, V> SparseMap<K, V>
    where K: EntityRef,
          V: SparseMapValue<K>
{
    /// Create a new empty mapping.
    pub fn new() -> Self {
        SparseMap {
            sparse: EntityMap::new(),
            dense: Vec::new(),
        }
    }

    /// Returns the number of elements in the map.
    pub fn len(&self) -> usize {
        self.dense.len()
    }

    /// Returns true is the map contains no elements.
    pub fn is_empty(&self) -> bool {
        self.dense.is_empty()
    }

    /// Returns a reference to the value corresponding to the key.
    pub fn get(&self, key: K) -> Option<&V> {
        if let Some(idx) = self.sparse.get(key).cloned() {
            if let Some(entry) = self.dense.get(idx as usize) {
                if entry.key() == key {
                    return Some(entry);
                }
            }
        }
        None
    }

    /// Returns a mutable reference to the value corresponding to the key.
    ///
    /// Note that the returned value must not be mutated in a way that would change its key. This
    /// would invalidate the sparse set data structure.
    pub fn get_mut(&mut self, key: K) -> Option<&mut V> {
        if let Some(idx) = self.sparse.get(key).cloned() {
            if let Some(entry) = self.dense.get_mut(idx as usize) {
                if entry.key() == key {
                    return Some(entry);
                }
            }
        }
        None
    }

    /// Return the index into `dense` of the value corresponding to `key`.
    fn index(&self, key: K) -> Option<usize> {
        if let Some(idx) = self.sparse.get(key).cloned() {
            let idx = idx as usize;
            if let Some(entry) = self.dense.get(idx) {
                if entry.key() == key {
                    return Some(idx);
                }
            }
        }
        None
    }

    /// Insert a value into the map.
    ///
    /// If the map did not have this key present, `None` is returned.
    ///
    /// If the map did have this key present, the value is updated, and the old value is returned.
    ///
    /// It is not necessary to provide a key since the value knows its own key already.
    pub fn insert(&mut self, value: V) -> Option<V> {
        let key = value.key();

        // Replace the existing entry for `key` if there is one.
        if let Some(entry) = self.get_mut(key) {
            return Some(mem::replace(entry, value));
        }

        // There was no previous entry for `key`. Add it to the end of `dense`.
        let idx = self.dense.len();
        assert!(idx <= u32::MAX as usize, "SparseMap overflow");
        self.dense.push(value);
        *self.sparse.ensure(key) = idx as u32;
        None
    }

    /// Remove a value from the map and return it.
    pub fn remove(&mut self, key: K) -> Option<V> {
        if let Some(idx) = self.index(key) {
            let back = self.dense.pop().unwrap();

            // Are we popping the back of `dense`?
            if idx == self.dense.len() {
                return Some(back);
            }

            // We're removing an element from the middle of `dense`.
            // Replace the element at `idx` with the back of `dense`.
            // Repair `sparse` first.
            self.sparse[back.key()] = idx as u32;
            return Some(mem::replace(&mut self.dense[idx], back));
        }

        // Nothing to remove.
        None
    }
}

/// Any `EntityRef` can be used as a sparse map value representing itself.
impl<T> SparseMapValue<T> for T
    where T: EntityRef
{
    fn key(&self) -> T {
        *self
    }
}

/// A sparse set of entity references.
///
/// Any type that implements `EntityRef` can be used as a sparse set value too.
pub type SparseSet<T> = SparseMap<T, T>;

#[cfg(test)]
mod tests {
    use super::*;
    use entity_map::EntityRef;
    use ir::Inst;

    // Mock key-value object for testing.
    #[derive(PartialEq, Eq, Debug)]
    struct Obj(Inst, &'static str);

    impl SparseMapValue<Inst> for Obj {
        fn key(&self) -> Inst {
            self.0
        }
    }

    #[test]
    fn empty_immutable_map() {
        let i1 = Inst::new(1);
        let map: SparseMap<Inst, Obj> = SparseMap::new();

        assert!(map.is_empty());
        assert_eq!(map.len(), 0);
        assert_eq!(map.get(i1), None);
    }

    #[test]
    fn single_entry() {
        let i0 = Inst::new(0);
        let i1 = Inst::new(1);
        let i2 = Inst::new(2);
        let mut map = SparseMap::new();

        assert!(map.is_empty());
        assert_eq!(map.len(), 0);
        assert_eq!(map.get(i1), None);
        assert_eq!(map.get_mut(i1), None);
        assert_eq!(map.remove(i1), None);

        assert_eq!(map.insert(Obj(i1, "hi")), None);
        assert!(!map.is_empty());
        assert_eq!(map.len(), 1);
        assert_eq!(map.get(i0), None);
        assert_eq!(map.get(i1), Some(&Obj(i1, "hi")));
        assert_eq!(map.get(i2), None);
        assert_eq!(map.get_mut(i0), None);
        assert_eq!(map.get_mut(i1), Some(&mut Obj(i1, "hi")));
        assert_eq!(map.get_mut(i2), None);

        assert_eq!(map.remove(i0), None);
        assert_eq!(map.remove(i2), None);
        assert_eq!(map.remove(i1), Some(Obj(i1, "hi")));
        assert_eq!(map.len(), 0);
        assert_eq!(map.get(i1), None);
        assert_eq!(map.get_mut(i1), None);
        assert_eq!(map.remove(i0), None);
        assert_eq!(map.remove(i1), None);
        assert_eq!(map.remove(i2), None);
    }

    #[test]
    fn multiple_entries() {
        let i0 = Inst::new(0);
        let i1 = Inst::new(1);
        let i2 = Inst::new(2);
        let i3 = Inst::new(3);
        let mut map = SparseMap::new();

        assert_eq!(map.insert(Obj(i2, "foo")), None);
        assert_eq!(map.insert(Obj(i1, "bar")), None);
        assert_eq!(map.insert(Obj(i0, "baz")), None);

        assert_eq!(map.len(), 3);
        assert_eq!(map.get(i0), Some(&Obj(i0, "baz")));
        assert_eq!(map.get(i1), Some(&Obj(i1, "bar")));
        assert_eq!(map.get(i2), Some(&Obj(i2, "foo")));
        assert_eq!(map.get(i3), None);

        // Remove front object, causing back to be swapped down.
        assert_eq!(map.remove(i1), Some(Obj(i1, "bar")));
        assert_eq!(map.len(), 2);
        assert_eq!(map.get(i0), Some(&Obj(i0, "baz")));
        assert_eq!(map.get(i1), None);
        assert_eq!(map.get(i2), Some(&Obj(i2, "foo")));
        assert_eq!(map.get(i3), None);

        // Reinsert something at a previously used key.
        assert_eq!(map.insert(Obj(i1, "barbar")), None);
        assert_eq!(map.len(), 3);
        assert_eq!(map.get(i0), Some(&Obj(i0, "baz")));
        assert_eq!(map.get(i1), Some(&Obj(i1, "barbar")));
        assert_eq!(map.get(i2), Some(&Obj(i2, "foo")));
        assert_eq!(map.get(i3), None);

        // Replace an entry.
        assert_eq!(map.insert(Obj(i0, "bazbaz")), Some(Obj(i0, "baz")));
        assert_eq!(map.len(), 3);
        assert_eq!(map.get(i0), Some(&Obj(i0, "bazbaz")));
        assert_eq!(map.get(i1), Some(&Obj(i1, "barbar")));
        assert_eq!(map.get(i2), Some(&Obj(i2, "foo")));
        assert_eq!(map.get(i3), None);
    }

    #[test]
    fn entity_set() {
        let i0 = Inst::new(0);
        let i1 = Inst::new(1);
        let mut set = SparseSet::new();

        assert_eq!(set.insert(i0), None);
        assert_eq!(set.insert(i0), Some(i0));
        assert_eq!(set.insert(i1), None);
        assert_eq!(set.get(i0), Some(&i0));
        assert_eq!(set.get(i1), Some(&i1));
    }
}
<commit_msg>Add iteration support to SparseMap.<commit_after>//! Sparse mapping of entity references to larger value types.
//!
//! This module provides a `SparseMap` data structure which implements a sparse mapping from an
//! `EntityRef` key to a value type that may be on the larger side. This implementation is based on
//! the paper:
//!
//! > Briggs, Torczon, *An efficient representation for sparse sets*,
//!   ACM Letters on Programming Languages and Systems, Volume 2, Issue 1-4, March-Dec. 1993.
//!
//! A `SparseMap<K, V>` map provides:
//!
//! - Memory usage equivalent to `EntityMap<K, u32>` + `Vec<V>`, so much smaller than
//!   `EntityMap<K, V>` for sparse mappings of larger `V` types.
//! - Constant time lookup, slightly slower than `EntityMap`.
//! - A very fast, constant time `clear()` operation.
//! - Fast insert and erase operations.
//! - Stable iteration that is as fast as a `Vec<V>`.
//!
//! # Compared to `EntityMap`
//!
//! When should we use a `SparseMap` instead of a secondary `EntityMap`? First of all, `SparseMap`
//! does not provide the functionality of a primary `EntityMap` which can allocate and assign
//! entity references to objects as they are pushed onto the map. It is only the secondary
//! entity maps that can be replaced with a `SparseMap`.
//!
//! - A secondary entity map requires its values to implement `Default`, and it is a bit loose
//!   about creating new mappings to the default value. It doesn't distinguish clearly between an
//!   unmapped key and one that maps to the default value. `SparseMap` does not require `Default`
//!   values, and it tracks accurately if a key has been mapped or not.
//! - Iterating over the contants of an `EntityMap` is linear in the size of the *key space*, while
//!   iterating over a `SparseMap` is linear in the number of elements in the mapping. This is an
//!   advantage precisely when the mapping is sparse.
//! - `SparseMap::clear()` is constant time and super-fast. `EntityMap::clear()` is linear in the
//!   size of the key space. (Or, rather the required `resize()` call following the `clear()` is).
//! - `SparseMap` requires the values to implement `SparseMapValue<K>` which means that they must
//!   contain their own key.

use entity_map::{EntityRef, EntityMap};
use std::mem;
use std::slice;
use std::u32;

/// Trait for extracting keys from values stored in a `SparseMap`.
///
/// All values stored in a `SparseMap` must keep track of their own key in the map and implement
/// this trait to provide access to the key.
pub trait SparseMapValue<K> {
    /// Get the key of this sparse map value. This key is not alowed to change while the value
    /// is a member of the map.
    fn key(&self) -> K;
}

/// A sparse mapping of entity references.
pub struct SparseMap<K, V>
    where K: EntityRef,
          V: SparseMapValue<K>
{
    sparse: EntityMap<K, u32>,
    dense: Vec<V>,
}

impl<K, V> SparseMap<K, V>
    where K: EntityRef,
          V: SparseMapValue<K>
{
    /// Create a new empty mapping.
    pub fn new() -> Self {
        SparseMap {
            sparse: EntityMap::new(),
            dense: Vec::new(),
        }
    }

    /// Returns the number of elements in the map.
    pub fn len(&self) -> usize {
        self.dense.len()
    }

    /// Returns true is the map contains no elements.
    pub fn is_empty(&self) -> bool {
        self.dense.is_empty()
    }

    /// Returns a reference to the value corresponding to the key.
    pub fn get(&self, key: K) -> Option<&V> {
        if let Some(idx) = self.sparse.get(key).cloned() {
            if let Some(entry) = self.dense.get(idx as usize) {
                if entry.key() == key {
                    return Some(entry);
                }
            }
        }
        None
    }

    /// Returns a mutable reference to the value corresponding to the key.
    ///
    /// Note that the returned value must not be mutated in a way that would change its key. This
    /// would invalidate the sparse set data structure.
    pub fn get_mut(&mut self, key: K) -> Option<&mut V> {
        if let Some(idx) = self.sparse.get(key).cloned() {
            if let Some(entry) = self.dense.get_mut(idx as usize) {
                if entry.key() == key {
                    return Some(entry);
                }
            }
        }
        None
    }

    /// Return the index into `dense` of the value corresponding to `key`.
    fn index(&self, key: K) -> Option<usize> {
        if let Some(idx) = self.sparse.get(key).cloned() {
            let idx = idx as usize;
            if let Some(entry) = self.dense.get(idx) {
                if entry.key() == key {
                    return Some(idx);
                }
            }
        }
        None
    }

    /// Insert a value into the map.
    ///
    /// If the map did not have this key present, `None` is returned.
    ///
    /// If the map did have this key present, the value is updated, and the old value is returned.
    ///
    /// It is not necessary to provide a key since the value knows its own key already.
    pub fn insert(&mut self, value: V) -> Option<V> {
        let key = value.key();

        // Replace the existing entry for `key` if there is one.
        if let Some(entry) = self.get_mut(key) {
            return Some(mem::replace(entry, value));
        }

        // There was no previous entry for `key`. Add it to the end of `dense`.
        let idx = self.dense.len();
        assert!(idx <= u32::MAX as usize, "SparseMap overflow");
        self.dense.push(value);
        *self.sparse.ensure(key) = idx as u32;
        None
    }

    /// Remove a value from the map and return it.
    pub fn remove(&mut self, key: K) -> Option<V> {
        if let Some(idx) = self.index(key) {
            let back = self.dense.pop().unwrap();

            // Are we popping the back of `dense`?
            if idx == self.dense.len() {
                return Some(back);
            }

            // We're removing an element from the middle of `dense`.
            // Replace the element at `idx` with the back of `dense`.
            // Repair `sparse` first.
            self.sparse[back.key()] = idx as u32;
            return Some(mem::replace(&mut self.dense[idx], back));
        }

        // Nothing to remove.
        None
    }

    /// Get an iterator over the values in the map.
    ///
    /// The iteration order is entirely determined by the preceding sequence of `insert` and
    /// `remove` operations. In particular, if no elements were removed, this is the insertion
    /// order.
    pub fn values(&self) -> slice::Iter<V> {
        self.dense.iter()
    }
}

/// Iterating over the elements of a set.
impl<'a, K, V> IntoIterator for &'a SparseMap<K, V>
    where K: EntityRef,
          V: SparseMapValue<K>
{
    type Item = &'a V;
    type IntoIter = slice::Iter<'a, V>;

    fn into_iter(self) -> Self::IntoIter {
        self.values()
    }
}

/// Any `EntityRef` can be used as a sparse map value representing itself.
impl<T> SparseMapValue<T> for T
    where T: EntityRef
{
    fn key(&self) -> T {
        *self
    }
}

/// A sparse set of entity references.
///
/// Any type that implements `EntityRef` can be used as a sparse set value too.
pub type SparseSet<T> = SparseMap<T, T>;

#[cfg(test)]
mod tests {
    use super::*;
    use entity_map::EntityRef;
    use ir::Inst;

    // Mock key-value object for testing.
    #[derive(PartialEq, Eq, Debug)]
    struct Obj(Inst, &'static str);

    impl SparseMapValue<Inst> for Obj {
        fn key(&self) -> Inst {
            self.0
        }
    }

    #[test]
    fn empty_immutable_map() {
        let i1 = Inst::new(1);
        let map: SparseMap<Inst, Obj> = SparseMap::new();

        assert!(map.is_empty());
        assert_eq!(map.len(), 0);
        assert_eq!(map.get(i1), None);
        assert_eq!(map.values().count(), 0);
    }

    #[test]
    fn single_entry() {
        let i0 = Inst::new(0);
        let i1 = Inst::new(1);
        let i2 = Inst::new(2);
        let mut map = SparseMap::new();

        assert!(map.is_empty());
        assert_eq!(map.len(), 0);
        assert_eq!(map.get(i1), None);
        assert_eq!(map.get_mut(i1), None);
        assert_eq!(map.remove(i1), None);

        assert_eq!(map.insert(Obj(i1, "hi")), None);
        assert!(!map.is_empty());
        assert_eq!(map.len(), 1);
        assert_eq!(map.get(i0), None);
        assert_eq!(map.get(i1), Some(&Obj(i1, "hi")));
        assert_eq!(map.get(i2), None);
        assert_eq!(map.get_mut(i0), None);
        assert_eq!(map.get_mut(i1), Some(&mut Obj(i1, "hi")));
        assert_eq!(map.get_mut(i2), None);

        assert_eq!(map.remove(i0), None);
        assert_eq!(map.remove(i2), None);
        assert_eq!(map.remove(i1), Some(Obj(i1, "hi")));
        assert_eq!(map.len(), 0);
        assert_eq!(map.get(i1), None);
        assert_eq!(map.get_mut(i1), None);
        assert_eq!(map.remove(i0), None);
        assert_eq!(map.remove(i1), None);
        assert_eq!(map.remove(i2), None);
    }

    #[test]
    fn multiple_entries() {
        let i0 = Inst::new(0);
        let i1 = Inst::new(1);
        let i2 = Inst::new(2);
        let i3 = Inst::new(3);
        let mut map = SparseMap::new();

        assert_eq!(map.insert(Obj(i2, "foo")), None);
        assert_eq!(map.insert(Obj(i1, "bar")), None);
        assert_eq!(map.insert(Obj(i0, "baz")), None);

        // Iteration order = insertion order when nothing has been removed yet.
        assert_eq!(map.values().map(|obj| obj.1).collect::<Vec<_>>(),
                   ["foo", "bar", "baz"]);

        assert_eq!(map.len(), 3);
        assert_eq!(map.get(i0), Some(&Obj(i0, "baz")));
        assert_eq!(map.get(i1), Some(&Obj(i1, "bar")));
        assert_eq!(map.get(i2), Some(&Obj(i2, "foo")));
        assert_eq!(map.get(i3), None);

        // Remove front object, causing back to be swapped down.
        assert_eq!(map.remove(i1), Some(Obj(i1, "bar")));
        assert_eq!(map.len(), 2);
        assert_eq!(map.get(i0), Some(&Obj(i0, "baz")));
        assert_eq!(map.get(i1), None);
        assert_eq!(map.get(i2), Some(&Obj(i2, "foo")));
        assert_eq!(map.get(i3), None);

        // Reinsert something at a previously used key.
        assert_eq!(map.insert(Obj(i1, "barbar")), None);
        assert_eq!(map.len(), 3);
        assert_eq!(map.get(i0), Some(&Obj(i0, "baz")));
        assert_eq!(map.get(i1), Some(&Obj(i1, "barbar")));
        assert_eq!(map.get(i2), Some(&Obj(i2, "foo")));
        assert_eq!(map.get(i3), None);

        // Replace an entry.
        assert_eq!(map.insert(Obj(i0, "bazbaz")), Some(Obj(i0, "baz")));
        assert_eq!(map.len(), 3);
        assert_eq!(map.get(i0), Some(&Obj(i0, "bazbaz")));
        assert_eq!(map.get(i1), Some(&Obj(i1, "barbar")));
        assert_eq!(map.get(i2), Some(&Obj(i2, "foo")));
        assert_eq!(map.get(i3), None);

        // Check the reference `IntoIter` impl.
        let mut v = Vec::new();
        for i in &map {
            v.push(i.1);
        }
        assert_eq!(v.len(), map.len());
    }

    #[test]
    fn entity_set() {
        let i0 = Inst::new(0);
        let i1 = Inst::new(1);
        let mut set = SparseSet::new();

        assert_eq!(set.insert(i0), None);
        assert_eq!(set.insert(i0), Some(i0));
        assert_eq!(set.insert(i1), None);
        assert_eq!(set.get(i0), Some(&i0));
        assert_eq!(set.get(i1), Some(&i1));
    }
}
<|endoftext|>


<commit_before>/* 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 http://mozilla.org/MPL/2.0/. */

use eutil::fptr_is_null;
use libc::{c_int};
use std::collections::TreeMap;
use std::mem;
use std::slice;
use std::str;
use std::string::String;
use string::{cef_string_userfree_utf8_alloc,cef_string_userfree_utf8_free,cef_string_utf8_set};
use types::{cef_string_map_t,cef_string_t};

fn string_map_to_treemap(sm: *mut cef_string_map_t) -> *mut TreeMap<String, *mut cef_string_t> {
    sm as *mut TreeMap<String, *mut cef_string_t>
}

//cef_string_map

#[no_mangle]
pub extern "C" fn cef_string_map_alloc() -> *mut cef_string_map_t {
    unsafe {
         let sm: Box<TreeMap<String, *mut cef_string_t>> = box TreeMap::new();
         mem::transmute(sm)
    }
}

#[no_mangle]
pub extern "C" fn cef_string_map_size(sm: *mut cef_string_map_t) -> c_int {
    unsafe {
        if fptr_is_null(mem::transmute(sm)) { return 0; }
        let v = string_map_to_treemap(sm);
        (*v).len() as c_int
    }
}

#[no_mangle]
pub extern "C" fn cef_string_map_append(sm: *mut cef_string_map_t, key: *const cef_string_t, value: *const cef_string_t) -> c_int {
    unsafe {
        if fptr_is_null(mem::transmute(sm)) { return 0; }
        let v = string_map_to_treemap(sm);
        slice::raw::buf_as_slice(mem::transmute((*key).str), (*key).length as uint, |result| {
            match str::from_utf8(result) {
                Some(k) => {
                    let s = String::from_str(k);
                    let csv = cef_string_userfree_utf8_alloc();
                    cef_string_utf8_set(mem::transmute((*value).str), (*value).length, csv, 1);
                    (*v).insert(s, csv);
                    1
                },
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_map_find(sm: *mut cef_string_map_t, key: *const cef_string_t, value: *mut cef_string_t) -> c_int {
    unsafe {
        if fptr_is_null(mem::transmute(sm)) { return 0; }
        let v = string_map_to_treemap(sm);
        slice::raw::buf_as_slice(mem::transmute((*key).str), (*key).length as uint, |result| {
            match str::from_utf8(result) {
                Some(k) => {
                    match (*v).find(&String::from_str(k)) {
                        Some(s) => {
                            cef_string_utf8_set(mem::transmute((**s).str), (**s).length, value, 1);
                            1
                        }
                        None => 0
                    }
                },
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_map_key(sm: *mut cef_string_map_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || fptr_is_null(mem::transmute(sm)) { return 0; }
        let v = string_map_to_treemap(sm);
        if index as uint > (*v).len() - 1 { return 0; }

        for (i, k) in (*v).keys().enumerate() {
            if i == index as uint {
                cef_string_utf8_set(k.as_bytes().as_ptr(), k.len() as u64, value, 1);
                return 1;
            }
        }
    }
    0
}

#[no_mangle]
pub extern "C" fn cef_string_map_value(sm: *mut cef_string_map_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || fptr_is_null(mem::transmute(sm)) { return 0; }
        let v = string_map_to_treemap(sm);
        if index as uint > (*v).len() - 1 { return 0; }

        for (i, val) in (*v).values().enumerate() {
            if i == index as uint {
                cef_string_utf8_set(mem::transmute((**val).str), (**val).length, value, 1);
                return 1;
            }
        }
    }
    0
}

#[no_mangle]
pub extern "C" fn cef_string_map_clear(sm: *mut cef_string_map_t) {
    unsafe {
        if fptr_is_null(mem::transmute(sm)) { return; }
        let v = string_map_to_treemap(sm);
        if (*v).len() == 0 { return; }
        for val in (*v).values() {
            cef_string_userfree_utf8_free((*val));
        }
        (*v).clear();
    }
}
<commit_msg>embedding: cef_string_map_free()<commit_after>/* 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 http://mozilla.org/MPL/2.0/. */

use eutil::fptr_is_null;
use libc::{c_int};
use std::collections::TreeMap;
use std::mem;
use std::slice;
use std::str;
use std::string::String;
use string::{cef_string_userfree_utf8_alloc,cef_string_userfree_utf8_free,cef_string_utf8_set};
use types::{cef_string_map_t,cef_string_t};

fn string_map_to_treemap(sm: *mut cef_string_map_t) -> *mut TreeMap<String, *mut cef_string_t> {
    sm as *mut TreeMap<String, *mut cef_string_t>
}

//cef_string_map

#[no_mangle]
pub extern "C" fn cef_string_map_alloc() -> *mut cef_string_map_t {
    unsafe {
         let sm: Box<TreeMap<String, *mut cef_string_t>> = box TreeMap::new();
         mem::transmute(sm)
    }
}

#[no_mangle]
pub extern "C" fn cef_string_map_size(sm: *mut cef_string_map_t) -> c_int {
    unsafe {
        if fptr_is_null(mem::transmute(sm)) { return 0; }
        let v = string_map_to_treemap(sm);
        (*v).len() as c_int
    }
}

#[no_mangle]
pub extern "C" fn cef_string_map_append(sm: *mut cef_string_map_t, key: *const cef_string_t, value: *const cef_string_t) -> c_int {
    unsafe {
        if fptr_is_null(mem::transmute(sm)) { return 0; }
        let v = string_map_to_treemap(sm);
        slice::raw::buf_as_slice(mem::transmute((*key).str), (*key).length as uint, |result| {
            match str::from_utf8(result) {
                Some(k) => {
                    let s = String::from_str(k);
                    let csv = cef_string_userfree_utf8_alloc();
                    cef_string_utf8_set(mem::transmute((*value).str), (*value).length, csv, 1);
                    (*v).insert(s, csv);
                    1
                },
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_map_find(sm: *mut cef_string_map_t, key: *const cef_string_t, value: *mut cef_string_t) -> c_int {
    unsafe {
        if fptr_is_null(mem::transmute(sm)) { return 0; }
        let v = string_map_to_treemap(sm);
        slice::raw::buf_as_slice(mem::transmute((*key).str), (*key).length as uint, |result| {
            match str::from_utf8(result) {
                Some(k) => {
                    match (*v).find(&String::from_str(k)) {
                        Some(s) => {
                            cef_string_utf8_set(mem::transmute((**s).str), (**s).length, value, 1);
                            1
                        }
                        None => 0
                    }
                },
                None => 0
            }
        })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_map_key(sm: *mut cef_string_map_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || fptr_is_null(mem::transmute(sm)) { return 0; }
        let v = string_map_to_treemap(sm);
        if index as uint > (*v).len() - 1 { return 0; }

        for (i, k) in (*v).keys().enumerate() {
            if i == index as uint {
                cef_string_utf8_set(k.as_bytes().as_ptr(), k.len() as u64, value, 1);
                return 1;
            }
        }
    }
    0
}

#[no_mangle]
pub extern "C" fn cef_string_map_value(sm: *mut cef_string_map_t, index: c_int, value: *mut cef_string_t) -> c_int {
    unsafe {
        if index < 0 || fptr_is_null(mem::transmute(sm)) { return 0; }
        let v = string_map_to_treemap(sm);
        if index as uint > (*v).len() - 1 { return 0; }

        for (i, val) in (*v).values().enumerate() {
            if i == index as uint {
                cef_string_utf8_set(mem::transmute((**val).str), (**val).length, value, 1);
                return 1;
            }
        }
    }
    0
}

#[no_mangle]
pub extern "C" fn cef_string_map_clear(sm: *mut cef_string_map_t) {
    unsafe {
        if fptr_is_null(mem::transmute(sm)) { return; }
        let v = string_map_to_treemap(sm);
        if (*v).len() == 0 { return; }
        for val in (*v).values() {
            cef_string_userfree_utf8_free((*val));
        }
        (*v).clear();
    }
}

#[no_mangle]
pub extern "C" fn cef_string_map_free(sm: *mut cef_string_map_t) {
    unsafe {
        if fptr_is_null(mem::transmute(sm)) { return; }
        let v: Box<TreeMap<String, *mut cef_string_t>> = mem::transmute(sm);
        cef_string_map_clear(sm);
        drop(v);
    }
}
<|endoftext|>


<commit_before>#![feature(core)]
extern crate core;

#[cfg(test)]
mod tests {
    use core::panicking::panic_fmt;

    use core::fmt;

    // pub fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
    //     #[allow(improper_ctypes)]
    //     extern {
    //         #[lang = "panic_fmt"]
    //         fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32) -> !;
    //     }
    //     let (file, line) = *file_line;
    //     unsafe { panic_impl(fmt, file, line) }
    // }

    #[test]
    #[should_panic]
    fn panic_fmt_test1() {
	let expr: &'static str = "Hello, World!";
	let pieces: &[&'static str]  = &[expr];
	let args: &[fmt::ArgumentV1] = &[];
	let fmt: fmt::Arguments = fmt::Arguments::new_v1(pieces, args);

	let file: &'static str = "FILENAME";
	let line: u32 = 68;
	let file_line: (&'static str, u32) = (file, line);

	panic_fmt(fmt, &file_line); // panicked at 'Hello, World!', FILENAME:68
    }

    #[test]
    #[should_panic]
    fn panic_fmt_test2() {
	let pieces: &[&'static str]  = &["", ", ", "!"];

	let x1: String = "Hello".to_string();
	let x2: String = "World".to_string();
	let args: &[fmt::ArgumentV1] = &[
	    fmt::ArgumentV1::new(&x1, fmt::Display::fmt),
	    fmt::ArgumentV1::new(&x2, fmt::Display::fmt)
	];

	let fmt: fmt::Arguments = fmt::Arguments::new_v1(pieces, args);

	let file: &'static str = "FILENAME";
	let line: u32 = 68;
	let file_line: (&'static str, u32) = (file, line);

	panic_fmt(fmt, &file_line); // panicked at 'Hello, World!', FILENAME:68
    }

    #[test]
    #[should_panic]
    fn panic_fmt_test3() {
	let pieces: &[&'static str]  = &["arg1 = [", "], arg2 = [", "]"];

	let x1: usize = 500;
	let x2: usize = 999;
	let args: &[fmt::ArgumentV1] = &[
	    fmt::ArgumentV1::new(&x1, fmt::Display::fmt),
	    fmt::ArgumentV1::new(&x2, fmt::Display::fmt)
	];

	let fmt: fmt::Arguments = fmt::Arguments::new_v1(pieces, args);

	let file: &'static str = "FILENAME";
	let line: u32 = 68;
	let file_line: (&'static str, u32) = (file, line);

	panic_fmt(fmt, &file_line); // panicked at 'arg1 = [500], arg2 = [999]', FILENAME:68
    }
}
<commit_msg>using `&'static str` instead of `String`<commit_after>#![feature(core)]
extern crate core;

#[cfg(test)]
mod tests {
    use core::panicking::panic_fmt;

    use core::fmt;

    // pub fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
    //     #[allow(improper_ctypes)]
    //     extern {
    //         #[lang = "panic_fmt"]
    //         fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32) -> !;
    //     }
    //     let (file, line) = *file_line;
    //     unsafe { panic_impl(fmt, file, line) }
    // }

    #[test]
    #[should_panic]
    fn panic_fmt_test1() {
	let expr: &'static str = "Hello, World!";
	let pieces: &[&'static str]  = &[expr];
	let args: &[fmt::ArgumentV1] = &[];
	let fmt: fmt::Arguments = fmt::Arguments::new_v1(pieces, args);

	let file: &'static str = "FILENAME";
	let line: u32 = 68;
	let file_line: (&'static str, u32) = (file, line);

	panic_fmt(fmt, &file_line); // panicked at 'Hello, World!', FILENAME:68
    }

    #[test]
    #[should_panic]
    fn panic_fmt_test2() {
	let pieces: &[&'static str]  = &["", ", ", "!"];

	let x1: &'static str = "Hello";
	let x2: &'static str = "World";
	let args: &[fmt::ArgumentV1] = &[
	    fmt::ArgumentV1::new(&x1, fmt::Display::fmt),
	    fmt::ArgumentV1::new(&x2, fmt::Display::fmt)
	];

	let fmt: fmt::Arguments = fmt::Arguments::new_v1(pieces, args);

	let file: &'static str = "FILENAME";
	let line: u32 = 68;
	let file_line: (&'static str, u32) = (file, line);

	panic_fmt(fmt, &file_line); // panicked at 'Hello, World!', FILENAME:68
    }

    #[test]
    #[should_panic]
    fn panic_fmt_test3() {
	let pieces: &[&'static str]  = &["arg1 = [", "], arg2 = [", "]"];

	let x1: usize = 500;
	let x2: usize = 999;
	let args: &[fmt::ArgumentV1] = &[
	    fmt::ArgumentV1::new(&x1, fmt::Display::fmt),
	    fmt::ArgumentV1::new(&x2, fmt::Display::fmt)
	];

	let fmt: fmt::Arguments = fmt::Arguments::new_v1(pieces, args);

	let file: &'static str = "FILENAME";
	let line: u32 = 68;
	let file_line: (&'static str, u32) = (file, line);

	panic_fmt(fmt, &file_line); // panicked at 'arg1 = [500], arg2 = [999]', FILENAME:68
    }
}
<|endoftext|>