<commit_before>/* diosix virtual CPU scheduler
 *
 * This is, for now, really really simple.
 * Making it fairer and adaptive to workloads is the ultimate goal.
 *
 * (c) Chris Williams, 2018-2021.
 *
 * See LICENSE for usage and copying.
 */

use super::lock::Mutex;
use alloc::collections::vec_deque::VecDeque;
use hashbrown::hash_map::HashMap;
use platform::timer::TimerValue;
use super::error::Cause;
use super::vcore::{VirtualCore, Priority};
use super::pcore::{self, PhysicalCore, PhysicalCoreID};
use super::hardware;
use super::message;
use super::capsule::{self, CapsuleState};

pub type TimesliceCount = u64;

/* prevent physical CPU time starvation: allow a normal virtual core to run after this number of timeslices
have been spent running high priority virtual cores */
const HIGH_PRIO_TIMESLICES_MAX: TimesliceCount = 10;

/* max how long a virtual core is allowed to run before a scheduling decision is made */
const TIMESLICE_LENGTH: TimerValue = TimerValue::Milliseconds(50);

/* define the shortest time between now and another interrupt and rescheduling decision.
this is to stop supervisor kernels spamming the scheduling system with lots of short reschedulings */
const TIMESLICE_MIN_LENGTH: TimerValue = TimerValue::Milliseconds(5);

/* duration a system maintence core (one that can't run supervisor code) must wait
before looking for fixed work to do. also the length in between application cores can
attempt to perform housekeeping */
const MAINTENANCE_LENGTH: TimerValue = TimerValue::Seconds(5);

/* these are the global wait queues. while each physical CPU core gets its own pair
of high-normal wait queues, virtual cores waiting to be assigned to a physical CPU sit in these global queues.
when a physical CPU runs out of queued virtual cores, it pulls one from these global queues.
a physical CPU core can ask fellow CPUs to push virtual cores onto the global queues via messages */
lazy_static!
{
    static ref GLOBAL_QUEUES: Mutex<ScheduleQueues> = Mutex::new("global scheduler queue", ScheduleQueues::new());
    static ref WORKLOAD: Mutex<HashMap<PhysicalCoreID, usize>> = Mutex::new("workload balancer", HashMap::new());
    static ref LAST_HOUSEKEEP_CHECK: Mutex<TimerValue> = Mutex::new("housekeeper tracking", TimerValue::Exact(0));
}

#[derive(PartialEq, Clone, Copy, Debug)]
pub enum SearchMode
{
    MustFind, /* when searching for something to run, keep looping until successful */
    CheckOnce /* search just once for something else to run, return to environment otherwise */
}

/* queue a virtual core in global wait list */
pub fn queue(to_queue: VirtualCore)
{
    GLOBAL_QUEUES.lock().queue(to_queue);
}

/* activate preemptive multitasking. each physical CPU core should call this
   to start running workloads - be them user/supervisor or management tasks
   <= returns OK, or error code on failure */
pub fn start() -> Result<(), Cause>
{
    hardware::scheduler_timer_start();
    Ok(())
}

/* make a decision on whether to run another virtual core,
   or return to the currently running core (if possible).
   ping() is called when a scheduler timer IRQ comes in */
pub fn ping()
{
    let time_now = hardware::scheduler_get_timer_now();
    let frequency = hardware::scheduler_get_timer_frequency();
    if time_now.is_none() || frequency.is_none()
    {
        /* check to see if anything needs to run and bail out if
        no timer hardware can be found (and yet we're still getting IRQs?) */
        run_next(SearchMode::CheckOnce);
        return;
    }

    /* get down to the exact timer values */
    let frequency = frequency.unwrap();
    let time_now = time_now.unwrap().to_exact(frequency);

    /* if the virtual core we're running is doomed, skip straight
       to forcing a reschedule of another vcore */
    match (pcore::PhysicalCore::this().get_timer_sched_last(),
           pcore::PhysicalCore::this().is_vcore_doomed())
    {
        (Some(v), false) =>
        {
            let timeslice_length = TIMESLICE_LENGTH.to_exact(frequency);
            let mut last_scheduled_at = v.to_exact(frequency);

            /* if the capsule we're running in is valid then perform a time slice check.
               if it's not valid, ensure the capsule is torn down or restarted for this
               virtual core. when all vcores are removed from the capsule, it will either
               be deleted or restarted, depending on its state */
            let capsule_state = capsule::get_current_state();
            match capsule_state
            {
                Some(CapsuleState::Valid) =>
                {
                    /* check to see if we've reached the end of this physical CPU core's
                    time slice. a virtual code has the pcore for TIMESLICE_LENGTH of time
                    before a mandatory scheduling decision is made */
                    if time_now - last_scheduled_at >= timeslice_length
                    {
                        /* it's been a while since we last made a decision, so force one now */
                        run_next(SearchMode::CheckOnce);
                        pcore::PhysicalCore::this().set_timer_sched_last(Some(TimerValue::Exact(time_now)));
                        last_scheduled_at = time_now;
                    }
                },
                _ =>
                {
                    /* it is safe to call destroy_current() and restart_current() multiple times
                       per vcore until the capsule is dead or restarted */
                    if let Err(_e) = match capsule_state
                    {
                        Some(CapsuleState::Dying) => capsule::destroy_current(),
                        Some(CapsuleState::Restarting) => capsule::restart_current(),
                        _ => Ok(())
                    }
                    {
                        hvalert!("BUG: Capsule update failure {:?} in scheduler ({:?})", _e, capsule_state)
                    }

                    /* capsule we're running in is no longer valid so force a reschedule */
                    run_next(SearchMode::MustFind);
                    pcore::PhysicalCore::this().set_timer_sched_last(Some(TimerValue::Exact(time_now)));
                    last_scheduled_at = time_now;
                }
            }

            /* check to make sure timer target is correct for whatever virtual core we're about
            to run. run_next() may have set a new timer irq target, or changed the virtual core
            we're running. there may be a supervisor-level timer IRQ upcoming.
            make sure the physical core timer target value is appropriate. */
            if let Some(timer_target) = hardware::scheduler_get_timer_next_at()
            {
                let mut timer_target = timer_target.to_exact(frequency);

                /* avoid skipping over any pending supervisor timer IRQ: reduce latency between
                capsule timer interrupts being raised and capsule cores scheduled to pick up said IRQs */
                if let Some(supervisor_target) = pcore::PhysicalCore::get_virtualcore_timer_target()
                {
                    timer_target = supervisor_target.to_exact(frequency);
                }

                /* if the target is already behind us, discard it and interrupt at end of this timeslice.
                   if the target is too far ahead, curtail it to the end of this timeslice */
                if timer_target <= time_now || timer_target > last_scheduled_at + timeslice_length
                {
                    timer_target = last_scheduled_at + timeslice_length;
                }

                hardware::scheduler_timer_at(TimerValue::Exact(timer_target));
            }
        },

        /* if not we've not scheduled anything yet, or whatever we were running
           is now invalid, we must find something (else) to run */
        (None, _) | (_, true) =>
        {
            run_next(SearchMode::MustFind);
            pcore::PhysicalCore::this().set_timer_sched_last(Some(TimerValue::Exact(time_now)));
        }
    }
}

/* find something else to run, or return to whatever we were running if allowed.
   call this function when a virtual core's timeslice has expired, or it has crashed
   or stopped running and we can't return to it. this function will return regardless
   if this physical CPU core is unable to run virtual cores.
   => search_mode = define whether or not to continue searching for another
   virtual core to run, or check once to see if something else is waiting */
fn run_next(search_mode: SearchMode)
{
    /* check for housekeeping */
    housekeeping();

    /* if this core can run supervisor-level code then find it some work to do */
    if pcore::PhysicalCore::smode_supported()
    {
        loop
        {
            let mut something_found = true;

            /* check to see if there's anything waiting to be picked up for this
            physical CPU from a global queue. if so, then adopt it so it can get a chance to run */
            match GLOBAL_QUEUES.lock().dequeue()
            {
                /* we've found a virtual CPU core to run, so switch to that */
                Some(orphan) =>
                {
                    let mut workloads = WORKLOAD.lock();
                    let pcore_id = PhysicalCore::get_id();

                    /* increment counter of how many virtual cores this physical CPU core
                    has taken from the global queue */
                    if let Some(count) = workloads.get_mut(&pcore_id)
                    {
                        *count = *count + 1;
                    }
                    else
                    {
                        workloads.insert(pcore_id, 1);
                    }

                    pcore::context_switch(orphan);
                },

                /* otherwise, try to take a virtual CPU core waiting for this physical CPU core and run it */
                _ => match PhysicalCore::dequeue()
                {
                    Some(virtcore) => pcore::context_switch(virtcore), /* waiting virtual CPU core found, queuing now */
                    _ => something_found = false /* nothing else to run */
                }
            }

            /* if we've found something, or only searching once, exit the search loop */
            if something_found == true || search_mode == SearchMode::CheckOnce
            {
                break;
            }

            /* still here? see if there's a capsule waiting to be restarted and give us something to do */
            capsulehousekeeper!();
        }

        /* we've got a virtual core to run. tell the timer system to call us back soon */
        hardware::scheduler_timer_next_in(TIMESLICE_LENGTH);
    }
    else
    {
        hardware::scheduler_timer_next_in(MAINTENANCE_LENGTH); /* we'll be back some time later */
    }
}

/* perform any housekeeping duties defined by the various parts of the system */
fn housekeeping()
{
    /* perform integrity checks */
    #[cfg(feature = "integritychecks")]
    {
        if let Err(val) = pcore::PhysicalCore::integrity_check()
        {
            hvalert!("CPU private stack overflowed (0x{:x}). Halting!", val);
            loop {}
        }
    }

    /* avoid blocking on the house keeping lock */
    if LAST_HOUSEKEEP_CHECK.is_locked() == true
    {
        return;
    }

    let mut last_check = LAST_HOUSEKEEP_CHECK.lock();

    /* only perform housekeeping once every MAINTENANCE_LENGTH-long period */
    match (hardware::scheduler_get_timer_now(), hardware::scheduler_get_timer_frequency())
    {
        (Some(time_now), Some(frequency)) =>
        {
            let time_now = time_now.to_exact(frequency);
            let last_check_value = (*last_check).to_exact(frequency);
            let maintence_length = MAINTENANCE_LENGTH.to_exact(frequency);

            /* wait until we're at least MAINTENANCE_LENGTH into boot */
            if time_now > maintence_length
            {
                if time_now - last_check_value < maintence_length
                {
                    /* not enough MAINTENANCE_LENGTH time has passed */
                    return;
                }
                /* mark when we last performed housekeeping */
                *last_check = TimerValue::Exact(time_now);
            }
            else
            {
                /* flush debug and bail out */
                debughousekeeper!();
                return;
            }
        },
        (_, _) =>
        {
            /* no timer. output debug and bail out */
            debughousekeeper!();
            return;
        }
    }

    debughousekeeper!(); /* drain the debug logs to the debug hardware port */
    heaphousekeeper!(); /* return any unused regions of physical memory */
    physmemhousekeeper!(); /* tidy up any physical memory structures */
    capsulehousekeeper!(); /* restart capsules that crashed or rebooted */

    /* if the global queues are empty then work out which physical CPU core
    has the most number of virtual cores and is therefore the busiest */
    let global_queue_lock = GLOBAL_QUEUES.lock();
    if global_queue_lock.total_queued() > 0
    {
        let mut highest_count = 0;
        let mut busiest_pcore: Option<PhysicalCoreID> = None;
        let workloads = WORKLOAD.lock();
        for (&pcoreid, &vcore_count) in workloads.iter()
        {
            if vcore_count > highest_count
            {
                highest_count = vcore_count;
                busiest_pcore = Some(pcoreid);
            }
        }

        /* ask the busiest core to send one virtual core back to the global queue
        but only if it has enough to share: it must have more than one virtual core */
        if highest_count > 1
        {
            if let Some(pid) = busiest_pcore
            {
                let m = message::Message::new(message::Recipient::send_to_pcore(pid),
                                                message::MessageContent::DisownQueuedVirtualCore);
                match message::send(m)
                {
                    Err(e) => hvalert!("Failed to message physical CPU {} during load balancing: {:?}", pid, e),
                    Ok(()) => ()
                };
            }
        }
    }
}

/* maintain a simple two-level round-robin scheduler per physical CPU core. we can make it more fancy later.
the hypervisor tries to dish out physical CPU time fairly among capsules, and let the
capsule supervisors work out how best to allocate their time to userspace code.
picking the next virtual CPU core to run should be O(1) or as close as possible to it. */
pub struct ScheduleQueues
{
    high: VecDeque<VirtualCore>,
    low: VecDeque<VirtualCore>,
    high_timeslices: TimesliceCount
}

impl ScheduleQueues
{
    /* initialize a new set of scheduler queues */
    pub fn new() -> ScheduleQueues
    {
        ScheduleQueues
        {
            high: VecDeque::<VirtualCore>::new(),
            low: VecDeque::<VirtualCore>::new(),
            high_timeslices: 0
        }
    }

    /* run the given virtual core by switching to its supervisor context.
    this also updates NORM_PRIO_TICKS. if the current physical CPU was already running a
    virtual core, that virtual core is queued up in the waiting list by context_switch() */
    pub fn run(&mut self, to_run: VirtualCore)
    {
        /* if we're about to run a normal virtual core, then reset counter since a normal virtual core ran.
        if we're running a non-normal virtual core, then increase the count. */
        match to_run.get_priority()
        {
            Priority::Normal => self.high_timeslices = 0,
            Priority::High => self.high_timeslices = self.high_timeslices + 1
        };

        pcore::context_switch(to_run);
    }

    /* add the given virtual core to the appropriate waiting queue. put it to the back
    so that other virtual cores get a chance to run */
    pub fn queue(&mut self, to_queue: VirtualCore)
    {
        match to_queue.get_priority()
        {
            Priority::High => self.high.push_back(to_queue),
            Priority::Normal => self.low.push_back(to_queue)
        }
    }

    /* remove a virtual core from the waiting list queues, selected by priority with safeguards to
    prevent CPU time starvation. Returns selected virtual core or None for no other virtual cores waiting */
    pub fn dequeue(&mut self) -> Option<VirtualCore>
    {
        /* has a normal virtual core been waiting for ages? */
        if self.high_timeslices > HIGH_PRIO_TIMESLICES_MAX
        {
            match self.low.pop_front()
            {
                Some(t) => return Some(t),
                None => ()
            };
        }

        /* check the high priority queue for anything waiting.
        if not, then try the normal priority queue */
        match self.high.pop_front()
        {
            Some(t) => Some(t),
            None => self.low.pop_front()
        }
    }

    /* return the total number of virtual cores queued */
    pub fn total_queued(&self) -> usize
    {
        self.high.len() + self.low.len()
    }
}
<commit_msg>Added error checking on message creation<commit_after>/* diosix virtual CPU scheduler
 *
 * This is, for now, really really simple.
 * Making it fairer and adaptive to workloads is the ultimate goal.
 *
 * (c) Chris Williams, 2018-2021.
 *
 * See LICENSE for usage and copying.
 */

use super::lock::Mutex;
use alloc::collections::vec_deque::VecDeque;
use hashbrown::hash_map::HashMap;
use platform::timer::TimerValue;
use super::error::Cause;
use super::vcore::{VirtualCore, Priority};
use super::pcore::{self, PhysicalCore, PhysicalCoreID};
use super::hardware;
use super::message;
use super::capsule::{self, CapsuleState};

pub type TimesliceCount = u64;

/* prevent physical CPU time starvation: allow a normal virtual core to run after this number of timeslices
have been spent running high priority virtual cores */
const HIGH_PRIO_TIMESLICES_MAX: TimesliceCount = 10;

/* max how long a virtual core is allowed to run before a scheduling decision is made */
const TIMESLICE_LENGTH: TimerValue = TimerValue::Milliseconds(50);

/* define the shortest time between now and another interrupt and rescheduling decision.
this is to stop supervisor kernels spamming the scheduling system with lots of short reschedulings */
const TIMESLICE_MIN_LENGTH: TimerValue = TimerValue::Milliseconds(5);

/* duration a system maintence core (one that can't run supervisor code) must wait
before looking for fixed work to do. also the length in between application cores can
attempt to perform housekeeping */
const MAINTENANCE_LENGTH: TimerValue = TimerValue::Seconds(5);

/* these are the global wait queues. while each physical CPU core gets its own pair
of high-normal wait queues, virtual cores waiting to be assigned to a physical CPU sit in these global queues.
when a physical CPU runs out of queued virtual cores, it pulls one from these global queues.
a physical CPU core can ask fellow CPUs to push virtual cores onto the global queues via messages */
lazy_static!
{
    static ref GLOBAL_QUEUES: Mutex<ScheduleQueues> = Mutex::new("global scheduler queue", ScheduleQueues::new());
    static ref WORKLOAD: Mutex<HashMap<PhysicalCoreID, usize>> = Mutex::new("workload balancer", HashMap::new());
    static ref LAST_HOUSEKEEP_CHECK: Mutex<TimerValue> = Mutex::new("housekeeper tracking", TimerValue::Exact(0));
}

#[derive(PartialEq, Clone, Copy, Debug)]
pub enum SearchMode
{
    MustFind, /* when searching for something to run, keep looping until successful */
    CheckOnce /* search just once for something else to run, return to environment otherwise */
}

/* queue a virtual core in global wait list */
pub fn queue(to_queue: VirtualCore)
{
    GLOBAL_QUEUES.lock().queue(to_queue);
}

/* activate preemptive multitasking. each physical CPU core should call this
   to start running workloads - be them user/supervisor or management tasks
   <= returns OK, or error code on failure */
pub fn start() -> Result<(), Cause>
{
    hardware::scheduler_timer_start();
    Ok(())
}

/* make a decision on whether to run another virtual core,
   or return to the currently running core (if possible).
   ping() is called when a scheduler timer IRQ comes in */
pub fn ping()
{
    let time_now = hardware::scheduler_get_timer_now();
    let frequency = hardware::scheduler_get_timer_frequency();
    if time_now.is_none() || frequency.is_none()
    {
        /* check to see if anything needs to run and bail out if
        no timer hardware can be found (and yet we're still getting IRQs?) */
        run_next(SearchMode::CheckOnce);
        return;
    }

    /* get down to the exact timer values */
    let frequency = frequency.unwrap();
    let time_now = time_now.unwrap().to_exact(frequency);

    /* if the virtual core we're running is doomed, skip straight
       to forcing a reschedule of another vcore */
    match (pcore::PhysicalCore::this().get_timer_sched_last(),
           pcore::PhysicalCore::this().is_vcore_doomed())
    {
        (Some(v), false) =>
        {
            let timeslice_length = TIMESLICE_LENGTH.to_exact(frequency);
            let mut last_scheduled_at = v.to_exact(frequency);

            /* if the capsule we're running in is valid then perform a time slice check.
               if it's not valid, ensure the capsule is torn down or restarted for this
               virtual core. when all vcores are removed from the capsule, it will either
               be deleted or restarted, depending on its state */
            let capsule_state = capsule::get_current_state();
            match capsule_state
            {
                Some(CapsuleState::Valid) =>
                {
                    /* check to see if we've reached the end of this physical CPU core's
                    time slice. a virtual code has the pcore for TIMESLICE_LENGTH of time
                    before a mandatory scheduling decision is made */
                    if time_now - last_scheduled_at >= timeslice_length
                    {
                        /* it's been a while since we last made a decision, so force one now */
                        run_next(SearchMode::CheckOnce);
                        pcore::PhysicalCore::this().set_timer_sched_last(Some(TimerValue::Exact(time_now)));
                        last_scheduled_at = time_now;
                    }
                },
                _ =>
                {
                    /* it is safe to call destroy_current() and restart_current() multiple times
                       per vcore until the capsule is dead or restarted */
                    if let Err(_e) = match capsule_state
                    {
                        Some(CapsuleState::Dying) => capsule::destroy_current(),
                        Some(CapsuleState::Restarting) => capsule::restart_current(),
                        _ => Ok(())
                    }
                    {
                        hvalert!("BUG: Capsule update failure {:?} in scheduler ({:?})", _e, capsule_state)
                    }

                    /* capsule we're running in is no longer valid so force a reschedule */
                    run_next(SearchMode::MustFind);
                    pcore::PhysicalCore::this().set_timer_sched_last(Some(TimerValue::Exact(time_now)));
                    last_scheduled_at = time_now;
                }
            }

            /* check to make sure timer target is correct for whatever virtual core we're about
            to run. run_next() may have set a new timer irq target, or changed the virtual core
            we're running. there may be a supervisor-level timer IRQ upcoming.
            make sure the physical core timer target value is appropriate. */
            if let Some(timer_target) = hardware::scheduler_get_timer_next_at()
            {
                let mut timer_target = timer_target.to_exact(frequency);

                /* avoid skipping over any pending supervisor timer IRQ: reduce latency between
                capsule timer interrupts being raised and capsule cores scheduled to pick up said IRQs */
                if let Some(supervisor_target) = pcore::PhysicalCore::get_virtualcore_timer_target()
                {
                    timer_target = supervisor_target.to_exact(frequency);
                }

                /* if the target is already behind us, discard it and interrupt at end of this timeslice.
                   if the target is too far ahead, curtail it to the end of this timeslice */
                if timer_target <= time_now || timer_target > last_scheduled_at + timeslice_length
                {
                    timer_target = last_scheduled_at + timeslice_length;
                }

                hardware::scheduler_timer_at(TimerValue::Exact(timer_target));
            }
        },

        /* if not we've not scheduled anything yet, or whatever we were running
           is now invalid, we must find something (else) to run */
        (None, _) | (_, true) =>
        {
            run_next(SearchMode::MustFind);
            pcore::PhysicalCore::this().set_timer_sched_last(Some(TimerValue::Exact(time_now)));
        }
    }
}

/* find something else to run, or return to whatever we were running if allowed.
   call this function when a virtual core's timeslice has expired, or it has crashed
   or stopped running and we can't return to it. this function will return regardless
   if this physical CPU core is unable to run virtual cores.
   => search_mode = define whether or not to continue searching for another
   virtual core to run, or check once to see if something else is waiting */
fn run_next(search_mode: SearchMode)
{
    /* check for housekeeping */
    housekeeping();

    /* if this core can run supervisor-level code then find it some work to do */
    if pcore::PhysicalCore::smode_supported()
    {
        loop
        {
            let mut something_found = true;

            /* check to see if there's anything waiting to be picked up for this
            physical CPU from a global queue. if so, then adopt it so it can get a chance to run */
            match GLOBAL_QUEUES.lock().dequeue()
            {
                /* we've found a virtual CPU core to run, so switch to that */
                Some(orphan) =>
                {
                    let mut workloads = WORKLOAD.lock();
                    let pcore_id = PhysicalCore::get_id();

                    /* increment counter of how many virtual cores this physical CPU core
                    has taken from the global queue */
                    if let Some(count) = workloads.get_mut(&pcore_id)
                    {
                        *count = *count + 1;
                    }
                    else
                    {
                        workloads.insert(pcore_id, 1);
                    }

                    pcore::context_switch(orphan);
                },

                /* otherwise, try to take a virtual CPU core waiting for this physical CPU core and run it */
                _ => match PhysicalCore::dequeue()
                {
                    Some(virtcore) => pcore::context_switch(virtcore), /* waiting virtual CPU core found, queuing now */
                    _ => something_found = false /* nothing else to run */
                }
            }

            /* if we've found something, or only searching once, exit the search loop */
            if something_found == true || search_mode == SearchMode::CheckOnce
            {
                break;
            }

            /* still here? see if there's a capsule waiting to be restarted and give us something to do */
            capsulehousekeeper!();
        }

        /* we've got a virtual core to run. tell the timer system to call us back soon */
        hardware::scheduler_timer_next_in(TIMESLICE_LENGTH);
    }
    else
    {
        hardware::scheduler_timer_next_in(MAINTENANCE_LENGTH); /* we'll be back some time later */
    }
}

/* perform any housekeeping duties defined by the various parts of the system */
fn housekeeping()
{
    /* perform integrity checks */
    #[cfg(feature = "integritychecks")]
    {
        if let Err(val) = pcore::PhysicalCore::integrity_check()
        {
            hvalert!("CPU private stack overflowed (0x{:x}). Halting!", val);
            loop {}
        }
    }

    /* avoid blocking on the house keeping lock */
    if LAST_HOUSEKEEP_CHECK.is_locked() == true
    {
        return;
    }

    let mut last_check = LAST_HOUSEKEEP_CHECK.lock();

    /* only perform housekeeping once every MAINTENANCE_LENGTH-long period */
    match (hardware::scheduler_get_timer_now(), hardware::scheduler_get_timer_frequency())
    {
        (Some(time_now), Some(frequency)) =>
        {
            let time_now = time_now.to_exact(frequency);
            let last_check_value = (*last_check).to_exact(frequency);
            let maintence_length = MAINTENANCE_LENGTH.to_exact(frequency);

            /* wait until we're at least MAINTENANCE_LENGTH into boot */
            if time_now > maintence_length
            {
                if time_now - last_check_value < maintence_length
                {
                    /* not enough MAINTENANCE_LENGTH time has passed */
                    return;
                }
                /* mark when we last performed housekeeping */
                *last_check = TimerValue::Exact(time_now);
            }
            else
            {
                /* flush debug and bail out */
                debughousekeeper!();
                return;
            }
        },
        (_, _) =>
        {
            /* no timer. output debug and bail out */
            debughousekeeper!();
            return;
        }
    }

    debughousekeeper!(); /* drain the debug logs to the debug hardware port */
    heaphousekeeper!(); /* return any unused regions of physical memory */
    physmemhousekeeper!(); /* tidy up any physical memory structures */
    capsulehousekeeper!(); /* restart capsules that crashed or rebooted */

    /* if the global queues are empty then work out which physical CPU core
    has the most number of virtual cores and is therefore the busiest */
    let global_queue_lock = GLOBAL_QUEUES.lock();
    if global_queue_lock.total_queued() > 0
    {
        let mut highest_count = 0;
        let mut busiest_pcore: Option<PhysicalCoreID> = None;
        let workloads = WORKLOAD.lock();
        for (&pcoreid, &vcore_count) in workloads.iter()
        {
            if vcore_count > highest_count
            {
                highest_count = vcore_count;
                busiest_pcore = Some(pcoreid);
            }
        }

        /* ask the busiest core to send one virtual core back to the global queue
        but only if it has enough to share: it must have more than one virtual core */
        if highest_count > 1
        {
            if let Some(pid) = busiest_pcore
            {
                if let Ok(m) = message::Message::new(message::Recipient::send_to_pcore(pid),
                                                        message::MessageContent::DisownQueuedVirtualCore)
                {
                    match message::send(m)
                    {
                        Err(e) => hvalert!("Failed to message physical CPU {} during load balancing: {:?}", pid, e),
                        Ok(()) => ()
                    };
                }
            }
        }
    }
}

/* maintain a simple two-level round-robin scheduler per physical CPU core. we can make it more fancy later.
the hypervisor tries to dish out physical CPU time fairly among capsules, and let the
capsule supervisors work out how best to allocate their time to userspace code.
picking the next virtual CPU core to run should be O(1) or as close as possible to it. */
pub struct ScheduleQueues
{
    high: VecDeque<VirtualCore>,
    low: VecDeque<VirtualCore>,
    high_timeslices: TimesliceCount
}

impl ScheduleQueues
{
    /* initialize a new set of scheduler queues */
    pub fn new() -> ScheduleQueues
    {
        ScheduleQueues
        {
            high: VecDeque::<VirtualCore>::new(),
            low: VecDeque::<VirtualCore>::new(),
            high_timeslices: 0
        }
    }

    /* run the given virtual core by switching to its supervisor context.
    this also updates NORM_PRIO_TICKS. if the current physical CPU was already running a
    virtual core, that virtual core is queued up in the waiting list by context_switch() */
    pub fn run(&mut self, to_run: VirtualCore)
    {
        /* if we're about to run a normal virtual core, then reset counter since a normal virtual core ran.
        if we're running a non-normal virtual core, then increase the count. */
        match to_run.get_priority()
        {
            Priority::Normal => self.high_timeslices = 0,
            Priority::High => self.high_timeslices = self.high_timeslices + 1
        };

        pcore::context_switch(to_run);
    }

    /* add the given virtual core to the appropriate waiting queue. put it to the back
    so that other virtual cores get a chance to run */
    pub fn queue(&mut self, to_queue: VirtualCore)
    {
        match to_queue.get_priority()
        {
            Priority::High => self.high.push_back(to_queue),
            Priority::Normal => self.low.push_back(to_queue)
        }
    }

    /* remove a virtual core from the waiting list queues, selected by priority with safeguards to
    prevent CPU time starvation. Returns selected virtual core or None for no other virtual cores waiting */
    pub fn dequeue(&mut self) -> Option<VirtualCore>
    {
        /* has a normal virtual core been waiting for ages? */
        if self.high_timeslices > HIGH_PRIO_TIMESLICES_MAX
        {
            match self.low.pop_front()
            {
                Some(t) => return Some(t),
                None => ()
            };
        }

        /* check the high priority queue for anything waiting.
        if not, then try the normal priority queue */
        match self.high.pop_front()
        {
            Some(t) => Some(t),
            None => self.low.pop_front()
        }
    }

    /* return the total number of virtual cores queued */
    pub fn total_queued(&self) -> usize
    {
        self.high.len() + self.low.len()
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
The Finally trait provides a method, `finally` on
stack closures that emulates Java-style try/finally blocks.

# Example

~~~
do || {
    ...
}.finally {
    alway_run_this();
}
~~~
*/

use ops::Drop;

#[cfg(test)] use task::failing;

pub trait Finally<T> {
    fn finally(&self, dtor: &fn()) -> T;
}

impl<'self,T> Finally<T> for &'self fn() -> T {
    fn finally(&self, dtor: &fn()) -> T {
        let _d = Finallyalizer {
            dtor: dtor
        };

        (*self)()
    }
}

struct Finallyalizer<'self> {
    dtor: &'self fn()
}

#[unsafe_destructor]
impl<'self> Drop for Finallyalizer<'self> {
    fn finalize(&self) {
        (self.dtor)();
    }
}

#[test]
fn test_success() {
    let mut i = 0;
    do (|| {
        i = 10;
    }).finally {
        assert!(!failing());
        assert!(i == 10);
        i = 20;
    }
    assert!(i == 20);
}

#[test]
#[ignore(cfg(windows))]
#[should_fail]
fn test_fail() {
    let mut i = 0;
    do (|| {
        i = 10;
        fail!();
    }).finally {
        assert!(failing());
        assert!(i == 10);
    }
}

#[test]
fn test_retval() {
    let closure: &fn() -> int = || 10;
    let i = do closure.finally { };
    assert!(i == 10);
}

#[test]
fn test_compact() {
    // FIXME #4727: Should be able to use a fn item instead
    // of a closure for do_some_fallible_work,
    // but it's a type error.
    let do_some_fallible_work: &fn() = || { };
    fn but_always_run_this_function() { }
    do_some_fallible_work.finally(
        but_always_run_this_function);
}
<commit_msg>Implement Finally for ~fn and @fn types<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
The Finally trait provides a method, `finally` on
stack closures that emulates Java-style try/finally blocks.

# Example

~~~
do || {
    ...
}.finally {
    alway_run_this();
}
~~~
*/

use ops::Drop;

#[cfg(test)] use task::{failing, spawn};

pub trait Finally<T> {
    fn finally(&self, dtor: &fn()) -> T;
}

impl<'self,T> Finally<T> for &'self fn() -> T {
    fn finally(&self, dtor: &fn()) -> T {
        let _d = Finallyalizer {
            dtor: dtor
        };

        (*self)()
    }
}

impl<T> Finally<T> for ~fn() -> T {
    fn finally(&self, dtor: &fn()) -> T {
        let _d = Finallyalizer {
            dtor: dtor
        };

        (*self)()
    }
}

impl<T> Finally<T> for @fn() -> T {
    fn finally(&self, dtor: &fn()) -> T {
        let _d = Finallyalizer {
            dtor: dtor
        };

        (*self)()
    }
}

struct Finallyalizer<'self> {
    dtor: &'self fn()
}

#[unsafe_destructor]
impl<'self> Drop for Finallyalizer<'self> {
    fn finalize(&self) {
        (self.dtor)();
    }
}

#[test]
fn test_success() {
    let mut i = 0;
    do (|| {
        i = 10;
    }).finally {
        assert!(!failing());
        assert!(i == 10);
        i = 20;
    }
    assert!(i == 20);
}

#[test]
#[ignore(cfg(windows))]
#[should_fail]
fn test_fail() {
    let mut i = 0;
    do (|| {
        i = 10;
        fail!();
    }).finally {
        assert!(failing());
        assert!(i == 10);
    }
}

#[test]
fn test_retval() {
    let closure: &fn() -> int = || 10;
    let i = do closure.finally { };
    assert!(i == 10);
}

#[test]
fn test_compact() {
    // FIXME #4727: Should be able to use a fn item instead
    // of a closure for do_some_fallible_work,
    // but it's a type error.
    let do_some_fallible_work: &fn() = || { };
    fn but_always_run_this_function() { }
    do_some_fallible_work.finally(
        but_always_run_this_function);
}

#[test]
fn test_owned() {
    fn spawn_with_finalizer(f: ~fn()) {
        do spawn { do f.finally { } }
    }
    let owned: ~fn() = || { };
    spawn_with_finalizer(owned);
}

#[test]
fn test_managed() {
    let i = @mut 10;
    let managed: @fn() -> int = || {
        let r = *i;
        *i += 10;
        r
    };
    assert!(do managed.finally {} == 10);
    assert!(*i == 20);
}<|endoftext|>


<commit_before>// Copyright 2018 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Parse the output of a cargo build.rs script and generate a list of flags and
//! environment variable for the build.
use std::io::{BufRead, BufReader, Read};
use std::process::{Command, Output};

#[derive(Debug, PartialEq, Eq)]
pub struct CompileAndLinkFlags {
    pub compile_flags: String,
    pub link_flags: String,
}

/// Enum containing all the considered return value from the script
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BuildScriptOutput {
    /// cargo:rustc-link-lib
    LinkLib(String),
    /// cargo:rustc-link-search
    LinkSearch(String),
    /// cargo:rustc-cfg
    Cfg(String),
    /// cargo:rustc-flags
    Flags(String),
    /// cargo:rustc-env
    Env(String),
    /// cargo:VAR=VALUE
    DepEnv(String),
}

impl BuildScriptOutput {
    /// Converts a line into a [BuildScriptOutput] enum.
    ///
    /// Examples
    /// ```rust
    /// assert_eq!(BuildScriptOutput::new("cargo:rustc-link-lib=lib"), Some(BuildScriptOutput::LinkLib("lib".to_owned())));
    /// ```
    fn new(line: &str) -> Option<BuildScriptOutput> {
        let split = line.splitn(2, '=').collect::<Vec<_>>();
        if split.len() <= 1 {
            // Not a cargo directive.
            return None;
        }
        let param = split[1].trim().to_owned();
        let key_split = split[0].splitn(2, ':').collect::<Vec<_>>();
        if key_split.len() <= 1 || key_split[0] != "cargo" {
            // Not a cargo directive.
            return None;
        }
        match key_split[1] {
            "rustc-link-lib" => Some(BuildScriptOutput::LinkLib(param)),
            "rustc-link-search" => Some(BuildScriptOutput::LinkSearch(param)),
            "rustc-cfg" => Some(BuildScriptOutput::Cfg(param)),
            "rustc-flags" => Some(BuildScriptOutput::Flags(param)),
            "rustc-env" => Some(BuildScriptOutput::Env(param)),
            "rerun-if-changed" | "rerun-if-env-changed" =>
            // Ignored because Bazel will re-run if those change all the time.
            {
                None
            }
            "warning" => {
                eprint!("Build Script Warning: {}", split[1]);
                None
            }
            "rustc-cdylib-link-arg" => {
                // cargo:rustc-cdylib-link-arg=FLAG — Passes custom flags to a linker for cdylib crates.
                eprint!(
                    "Warning: build script returned unsupported directive `{}`",
                    split[0]
                );
                None
            }
            _ => {
                // cargo:KEY=VALUE — Metadata, used by links scripts.
                Some(BuildScriptOutput::DepEnv(format!(
                    "{}={}",
                    key_split[1].to_uppercase(),
                    param
                )))
            }
        }
    }

    /// Converts a [BufReader] into a vector of [BuildScriptOutput] enums.
    fn outputs_from_reader<T: Read>(mut reader: BufReader<T>) -> Vec<BuildScriptOutput> {
        let mut result = Vec::<BuildScriptOutput>::new();
        let mut line = String::new();
        while reader.read_line(&mut line).expect("Cannot read line") != 0 {
            if let Some(bso) = BuildScriptOutput::new(&line) {
                result.push(bso);
            }
            line.clear();
        }
        result
    }

    /// Take a [Command], execute it and converts its input into a vector of [BuildScriptOutput]
    pub fn outputs_from_command(
        cmd: &mut Command,
    ) -> Result<(Vec<BuildScriptOutput>, Output), Output> {
        let child_output = cmd.output().expect("Unable to start binary");
        if child_output.status.success() {
            let reader = BufReader::new(child_output.stdout.as_slice());
            let output = Self::outputs_from_reader(reader);
            Ok((output, child_output))
        } else {
            Err(child_output)
        }
    }

    /// Convert a vector of [BuildScriptOutput] into a list of environment variables.
    pub fn outputs_to_env(outputs: &[BuildScriptOutput], exec_root: &str) -> String {
        outputs
            .iter()
            .filter_map(|x| {
                if let BuildScriptOutput::Env(env) = x {
                    Some(Self::escape_for_serializing(Self::redact_exec_root(
                        env, exec_root,
                    )))
                } else {
                    None
                }
            })
            .collect::<Vec<_>>()
            .join("\n")
    }

    /// Convert a vector of [BuildScriptOutput] into a list of dependencies environment variables.
    pub fn outputs_to_dep_env(
        outputs: &[BuildScriptOutput],
        crate_links: &str,
        exec_root: &str,
    ) -> String {
        let prefix = format!("DEP_{}_", crate_links.replace("-", "_").to_uppercase());
        outputs
            .iter()
            .filter_map(|x| {
                if let BuildScriptOutput::DepEnv(env) = x {
                    Some(format!(
                        "{}{}",
                        prefix,
                        Self::escape_for_serializing(Self::redact_exec_root(env, exec_root))
                    ))
                } else {
                    None
                }
            })
            .collect::<Vec<_>>()
            .join("\n")
    }

    /// Convert a vector of [BuildScriptOutput] into a flagfile.
    pub fn outputs_to_flags(outputs: &[BuildScriptOutput], exec_root: &str) -> CompileAndLinkFlags {
        let mut compile_flags = Vec::new();
        let mut link_flags = Vec::new();

        for flag in outputs {
            match flag {
                BuildScriptOutput::Cfg(e) => compile_flags.push(format!("--cfg={}", e)),
                BuildScriptOutput::Flags(e) => compile_flags.push(e.to_owned()),
                BuildScriptOutput::LinkLib(e) => link_flags.push(format!("-l{}", e)),
                BuildScriptOutput::LinkSearch(e) => link_flags.push(format!("-L{}", e)),
                _ => {}
            }
        }
        CompileAndLinkFlags {
            compile_flags: compile_flags.join("\n"),
            link_flags: Self::redact_exec_root(&link_flags.join("\n"), exec_root),
        }
    }

    fn redact_exec_root(value: &str, exec_root: &str) -> String {
        value.replace(exec_root, "${pwd}")
    }

    // The process-wrapper treats trailing backslashes as escapes for following newlines.
    // If the env var ends with a backslash (and accordingly doesn't have a following newline),
    // escape it so that it doesn't get turned into a newline by the process-wrapper.
    //
    // Note that this code doesn't handle newlines in strings - that's because Cargo treats build
    // script output as single-line-oriented, so stops processing at the end of a line regardless.
    fn escape_for_serializing(mut value: String) -> String {
        if value.ends_with('\\') {
            value.push('\\');
        }
        value
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;

    #[test]
    fn test_from_read_buffer_to_env_and_flags() {
        let buff = Cursor::new(
            "
cargo:rustc-link-lib=sdfsdf
cargo:rustc-env=FOO=BAR
cargo:rustc-link-search=/some/absolute/path/bleh
cargo:rustc-env=BAR=FOO
cargo:rustc-flags=-Lblah
cargo:rerun-if-changed=ignored
cargo:rustc-cfg=feature=awesome
cargo:version=123
cargo:version_number=1010107f
cargo:include_path=/some/absolute/path/include
cargo:rustc-env=SOME_PATH=/some/absolute/path/beep
",
        );
        let reader = BufReader::new(buff);
        let result = BuildScriptOutput::outputs_from_reader(reader);
        assert_eq!(result.len(), 10);
        assert_eq!(result[0], BuildScriptOutput::LinkLib("sdfsdf".to_owned()));
        assert_eq!(result[1], BuildScriptOutput::Env("FOO=BAR".to_owned()));
        assert_eq!(
            result[2],
            BuildScriptOutput::LinkSearch("/some/absolute/path/bleh".to_owned())
        );
        assert_eq!(result[3], BuildScriptOutput::Env("BAR=FOO".to_owned()));
        assert_eq!(result[4], BuildScriptOutput::Flags("-Lblah".to_owned()));
        assert_eq!(
            result[5],
            BuildScriptOutput::Cfg("feature=awesome".to_owned())
        );
        assert_eq!(
            result[6],
            BuildScriptOutput::DepEnv("VERSION=123".to_owned())
        );
        assert_eq!(
            result[7],
            BuildScriptOutput::DepEnv("VERSION_NUMBER=1010107f".to_owned())
        );
        assert_eq!(
            result[9],
            BuildScriptOutput::Env("SOME_PATH=/some/absolute/path/beep".to_owned())
        );

        assert_eq!(
            BuildScriptOutput::outputs_to_dep_env(&result, "ssh2", "/some/absolute/path"),
            "DEP_SSH2_VERSION=123\nDEP_SSH2_VERSION_NUMBER=1010107f\nDEP_SSH2_INCLUDE_PATH=${pwd}/include".to_owned()
        );
        assert_eq!(
            BuildScriptOutput::outputs_to_env(&result, "/some/absolute/path"),
            "FOO=BAR\nBAR=FOO\nSOME_PATH=${pwd}/beep".to_owned()
        );
        assert_eq!(
            BuildScriptOutput::outputs_to_flags(&result, "/some/absolute/path"),
            CompileAndLinkFlags {
                // -Lblah was output as a rustc-flags, so even though it probably _should_ be a link
                // flag, we don't treat it like one.
                compile_flags: "-Lblah\n--cfg=feature=awesome".to_owned(),
                link_flags: "-lsdfsdf\n-L${pwd}/bleh".to_owned(),
            }
        );
    }
}
<commit_msg>Support `cargo:rustc-link-arg=FLAG` in build script runner (#1061)<commit_after>// Copyright 2018 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Parse the output of a cargo build.rs script and generate a list of flags and
//! environment variable for the build.
use std::io::{BufRead, BufReader, Read};
use std::process::{Command, Output};

#[derive(Debug, PartialEq, Eq)]
pub struct CompileAndLinkFlags {
    pub compile_flags: String,
    pub link_flags: String,
}

/// Enum containing all the considered return value from the script
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BuildScriptOutput {
    /// cargo:rustc-link-lib
    LinkLib(String),
    /// cargo:rustc-link-search
    LinkSearch(String),
    /// cargo:rustc-cfg
    Cfg(String),
    /// cargo:rustc-flags
    Flags(String),
    /// cargo:rustc-link-arg
    LinkArg(String),
    /// cargo:rustc-env
    Env(String),
    /// cargo:VAR=VALUE
    DepEnv(String),
}

impl BuildScriptOutput {
    /// Converts a line into a [BuildScriptOutput] enum.
    ///
    /// Examples
    /// ```rust
    /// assert_eq!(BuildScriptOutput::new("cargo:rustc-link-lib=lib"), Some(BuildScriptOutput::LinkLib("lib".to_owned())));
    /// ```
    fn new(line: &str) -> Option<BuildScriptOutput> {
        let split = line.splitn(2, '=').collect::<Vec<_>>();
        if split.len() <= 1 {
            // Not a cargo directive.
            return None;
        }
        let param = split[1].trim().to_owned();
        let key_split = split[0].splitn(2, ':').collect::<Vec<_>>();
        if key_split.len() <= 1 || key_split[0] != "cargo" {
            // Not a cargo directive.
            return None;
        }

        match key_split[1] {
            "rustc-link-lib" => Some(BuildScriptOutput::LinkLib(param)),
            "rustc-link-search" => Some(BuildScriptOutput::LinkSearch(param)),
            "rustc-cfg" => Some(BuildScriptOutput::Cfg(param)),
            "rustc-flags" => Some(BuildScriptOutput::Flags(param)),
            "rustc-link-arg" => Some(BuildScriptOutput::LinkArg(param)),
            "rustc-env" => Some(BuildScriptOutput::Env(param)),
            "rerun-if-changed" | "rerun-if-env-changed" =>
            // Ignored because Bazel will re-run if those change all the time.
            {
                None
            }
            "warning" => {
                eprint!("Build Script Warning: {}", split[1]);
                None
            }
            "rustc-cdylib-link-arg" | "rustc-link-arg-bin" | "rustc-link-arg-bins" => {
                // cargo:rustc-cdylib-link-arg=FLAG — Passes custom flags to a linker for cdylib crates.
                // cargo:rustc-link-arg-bin=BIN=FLAG – Passes custom flags to a linker for the binary BIN.
                // cargo:rustc-link-arg-bins=FLAG – Passes custom flags to a linker for binaries.
                eprint!(
                    "Warning: build script returned unsupported directive `{}`",
                    split[0]
                );
                None
            }
            _ => {
                // cargo:KEY=VALUE — Metadata, used by links scripts.
                Some(BuildScriptOutput::DepEnv(format!(
                    "{}={}",
                    key_split[1].to_uppercase(),
                    param
                )))
            }
        }
    }

    /// Converts a [BufReader] into a vector of [BuildScriptOutput] enums.
    fn outputs_from_reader<T: Read>(mut reader: BufReader<T>) -> Vec<BuildScriptOutput> {
        let mut result = Vec::<BuildScriptOutput>::new();
        let mut line = String::new();
        while reader.read_line(&mut line).expect("Cannot read line") != 0 {
            if let Some(bso) = BuildScriptOutput::new(&line) {
                result.push(bso);
            }
            line.clear();
        }
        result
    }

    /// Take a [Command], execute it and converts its input into a vector of [BuildScriptOutput]
    pub fn outputs_from_command(
        cmd: &mut Command,
    ) -> Result<(Vec<BuildScriptOutput>, Output), Output> {
        let child_output = cmd.output().expect("Unable to start binary");
        if child_output.status.success() {
            let reader = BufReader::new(child_output.stdout.as_slice());
            let output = Self::outputs_from_reader(reader);
            Ok((output, child_output))
        } else {
            Err(child_output)
        }
    }

    /// Convert a vector of [BuildScriptOutput] into a list of environment variables.
    pub fn outputs_to_env(outputs: &[BuildScriptOutput], exec_root: &str) -> String {
        outputs
            .iter()
            .filter_map(|x| {
                if let BuildScriptOutput::Env(env) = x {
                    Some(Self::escape_for_serializing(Self::redact_exec_root(
                        env, exec_root,
                    )))
                } else {
                    None
                }
            })
            .collect::<Vec<_>>()
            .join("\n")
    }

    /// Convert a vector of [BuildScriptOutput] into a list of dependencies environment variables.
    pub fn outputs_to_dep_env(
        outputs: &[BuildScriptOutput],
        crate_links: &str,
        exec_root: &str,
    ) -> String {
        let prefix = format!("DEP_{}_", crate_links.replace("-", "_").to_uppercase());
        outputs
            .iter()
            .filter_map(|x| {
                if let BuildScriptOutput::DepEnv(env) = x {
                    Some(format!(
                        "{}{}",
                        prefix,
                        Self::escape_for_serializing(Self::redact_exec_root(env, exec_root))
                    ))
                } else {
                    None
                }
            })
            .collect::<Vec<_>>()
            .join("\n")
    }

    /// Convert a vector of [BuildScriptOutput] into a flagfile.
    pub fn outputs_to_flags(outputs: &[BuildScriptOutput], exec_root: &str) -> CompileAndLinkFlags {
        let mut compile_flags = Vec::new();
        let mut link_flags = Vec::new();

        for flag in outputs {
            match flag {
                BuildScriptOutput::Cfg(e) => compile_flags.push(format!("--cfg={}", e)),
                BuildScriptOutput::Flags(e) => compile_flags.push(e.to_owned()),
                BuildScriptOutput::LinkArg(e) => compile_flags.push(format!("-Clink-arg={}", e)),
                BuildScriptOutput::LinkLib(e) => link_flags.push(format!("-l{}", e)),
                BuildScriptOutput::LinkSearch(e) => link_flags.push(format!("-L{}", e)),
                _ => {}
            }
        }
        CompileAndLinkFlags {
            compile_flags: compile_flags.join("\n"),
            link_flags: Self::redact_exec_root(&link_flags.join("\n"), exec_root),
        }
    }

    fn redact_exec_root(value: &str, exec_root: &str) -> String {
        value.replace(exec_root, "${pwd}")
    }

    // The process-wrapper treats trailing backslashes as escapes for following newlines.
    // If the env var ends with a backslash (and accordingly doesn't have a following newline),
    // escape it so that it doesn't get turned into a newline by the process-wrapper.
    //
    // Note that this code doesn't handle newlines in strings - that's because Cargo treats build
    // script output as single-line-oriented, so stops processing at the end of a line regardless.
    fn escape_for_serializing(mut value: String) -> String {
        if value.ends_with('\\') {
            value.push('\\');
        }
        value
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;

    #[test]
    fn test_from_read_buffer_to_env_and_flags() {
        let buff = Cursor::new(
            "
cargo:rustc-link-lib=sdfsdf
cargo:rustc-env=FOO=BAR
cargo:rustc-link-search=/some/absolute/path/bleh
cargo:rustc-env=BAR=FOO
cargo:rustc-flags=-Lblah
cargo:rerun-if-changed=ignored
cargo:rustc-cfg=feature=awesome
cargo:version=123
cargo:version_number=1010107f
cargo:include_path=/some/absolute/path/include
cargo:rustc-env=SOME_PATH=/some/absolute/path/beep
cargo:rustc-link-arg=-weak_framework
cargo:rustc-link-arg=Metal
",
        );
        let reader = BufReader::new(buff);
        let result = BuildScriptOutput::outputs_from_reader(reader);
        assert_eq!(result.len(), 12);
        assert_eq!(result[0], BuildScriptOutput::LinkLib("sdfsdf".to_owned()));
        assert_eq!(result[1], BuildScriptOutput::Env("FOO=BAR".to_owned()));
        assert_eq!(
            result[2],
            BuildScriptOutput::LinkSearch("/some/absolute/path/bleh".to_owned())
        );
        assert_eq!(result[3], BuildScriptOutput::Env("BAR=FOO".to_owned()));
        assert_eq!(result[4], BuildScriptOutput::Flags("-Lblah".to_owned()));
        assert_eq!(
            result[5],
            BuildScriptOutput::Cfg("feature=awesome".to_owned())
        );
        assert_eq!(
            result[6],
            BuildScriptOutput::DepEnv("VERSION=123".to_owned())
        );
        assert_eq!(
            result[7],
            BuildScriptOutput::DepEnv("VERSION_NUMBER=1010107f".to_owned())
        );
        assert_eq!(
            result[9],
            BuildScriptOutput::Env("SOME_PATH=/some/absolute/path/beep".to_owned())
        );
        assert_eq!(
            result[10],
            BuildScriptOutput::LinkArg("-weak_framework".to_owned())
        );
        assert_eq!(result[11], BuildScriptOutput::LinkArg("Metal".to_owned()));

        assert_eq!(
            BuildScriptOutput::outputs_to_dep_env(&result, "ssh2", "/some/absolute/path"),
            "DEP_SSH2_VERSION=123\nDEP_SSH2_VERSION_NUMBER=1010107f\nDEP_SSH2_INCLUDE_PATH=${pwd}/include".to_owned()
        );
        assert_eq!(
            BuildScriptOutput::outputs_to_env(&result, "/some/absolute/path"),
            "FOO=BAR\nBAR=FOO\nSOME_PATH=${pwd}/beep".to_owned()
        );
        assert_eq!(
            BuildScriptOutput::outputs_to_flags(&result, "/some/absolute/path"),
            CompileAndLinkFlags {
                // -Lblah was output as a rustc-flags, so even though it probably _should_ be a link
                // flag, we don't treat it like one.
                compile_flags:
                    "-Lblah\n--cfg=feature=awesome\n-Clink-arg=-weak_framework\n-Clink-arg=Metal"
                        .to_owned(),
                link_flags: "-lsdfsdf\n-L${pwd}/bleh".to_owned(),
            }
        );
    }
}
<|endoftext|>


<commit_before>#![doc="Implements the triangular matrix data-type
"]

// std imports
use std::ptr;
use std::mem;
use std::num::{Zero, One};
use std::rt::heap::allocate;

// local imports

use matrix::element::{Number};

use matrix::error::*;

use matrix::traits::{MatrixType, Introspection,
    MatrixBuffer, Extraction, ERO, ECO, Updates};

// complex numbers
use external::complex::Complex32;
use external::complex::Complex64;

use util;

#[doc = "
Represents a triangular square matrix of numbers.

The matrix can be either upper triangular or
lower triangular (but not both off course).

For an upper triangular matrix, the
numbers are stored in column major order.

For a lower triangular matrix, the numbers
are stored in row major order.

The difference in ordering is to simplify
cell index to cell offset calculations.

The half of the matrix which is full of zeros,
is not stored in memory. Thus, all calculations
are done smartly.

This design is not too flexible. The memory allocation
is done in the beginning and never changed afterwards.
Thus, the size of the matrix remains same.
"]
pub struct TriangularMatrix<T:Number> {
    /// Number of rows and columns in the matrix
    size : uint,
    /// The pointer to raw data array of the matrix
    ptr : *mut T,
    /// Indicates whether the matrix is upper or lower triangular
    ut_flag : bool
}

/// A matrix of 8-bit signed integers
pub type TriangularMatrixI8 = TriangularMatrix<i8>;
/// A matrix of 16-bit signed integers
pub type TriangularMatrixI16 = TriangularMatrix<i16>;
/// A matrix of 32-bit signed integers
pub type TriangularMatrixI32 = TriangularMatrix<i32>;
/// A matrix of 64-bit signed integers
pub type TriangularMatrixI64 = TriangularMatrix<i64>;
/// A matrix of 8-bit unsigned integers
pub type TriangularMatrixU8 = TriangularMatrix<u8>;
/// A matrix of 16-bit unsigned integers
pub type TriangularMatrixU16 = TriangularMatrix<u16>;
/// A matrix of 32-bit unsigned integers
pub type TriangularMatrixU32 = TriangularMatrix<u32>;
/// A matrix of 64-bit unsigned integers
pub type TriangularMatrixU64 = TriangularMatrix<u64>;
/// A matrix of  unsigned integers
pub type TriangularMatrixUInt = TriangularMatrix<uint>;
/// A matrix of 32-bit floating point numbers.
pub type TriangularMatrixF32 = TriangularMatrix<f32>;
/// A matrix of 64-bit floating point numbers.
pub type TriangularMatrixF64 = TriangularMatrix<f64>;
/// A matrix of 32-bit complex numbers numbers.
pub type TriangularMatrixC32 = TriangularMatrix<Complex32>;
/// A matrix of 64-bit complex numbers numbers.
pub type TriangularMatrixC64 = TriangularMatrix<Complex64>;

/// Static functions for creating  a triangular matrix
impl<T:Number> TriangularMatrix<T> {

#[doc = "Constructs a new matrix of given size (uninitialized).
"]
    pub fn new(size: uint,
        ut_flag : bool )-> TriangularMatrix<T> {
        let capacity = size * (size + 1) / 2;
        if capacity == 0 {
            // Support for empty matrices.
            // The buffer remains a null pointer.
            return TriangularMatrix{
                size : size,
                ut_flag : ut_flag,
                ptr : ptr::null_mut()
            };
        }
        let bytes = capacity * mem::size_of::<T>();
        let raw = unsafe {
            allocate(bytes, mem::min_align_of::<T>())
        };
        let ptr = raw as *mut T;
        TriangularMatrix {size : size,
                ut_flag : ut_flag,
                ptr : ptr}
    }

    /// Constructs a triangular matrix of all zeros
    pub fn zeros(size: uint,
        ut : bool)-> TriangularMatrix<T> {
        let m : TriangularMatrix<T> = TriangularMatrix::new(size, ut);
        // zero out the memory
        unsafe { ptr::zero_memory(m.ptr, m.capacity())};
        m
    }
}

/// Core methods for all matrix types
impl<T:Number> MatrixType<T> for TriangularMatrix<T> {

    /// Returns the number of rows in the matrix
    fn num_rows(&self) -> uint {
        self.size
    }

    /// Returns the number of columns in the matrix
    fn num_cols(&self) -> uint {
        self.size
    }

    /// Returns the size of matrix in an (r, c) tuple
    fn size (&self)-> (uint, uint){
        (self.size, self.size)
    }

    /// Returns the number of cells in matrix
    fn num_cells(&self)->uint {
        self.size * self.size
    }

    /// Returns if the matrix is an identity matrix
    fn is_identity(&self) -> bool {
        let o : T = One::one();
        let z  : T = Zero::zero();
        let ptr = self.ptr;
        // Check the 0, 0 element
        if unsafe{*ptr} != o {
            return false;
        }
        let mut offset = 1;
        for i in range(1, self.size){
            for _ in range (0, i){
                let v = unsafe {*ptr.offset(offset)};
                if v != z {
                    return false;
                }
                // Move on to next element in the row (l t)
                // or column (u t).
                offset += 1;
            }
            // Check the diagonal element
            if unsafe {*ptr.offset(offset)} != o {
                return false;
            }
            // Skip the diagonal element
            offset += 1;
        }
        true
    }

    /// Returns if the matrix is a diagonal matrix
    fn is_diagonal(&self) -> bool {
        let z  : T = Zero::zero();
        let ptr = self.ptr;
        // We ignore the a[0,0] position.
        // We start working with 2nd row (l t) or column (u t)
        let mut offset = 1;
        for i in range(1, self.size){
            for _ in range (0, i){
                let v = unsafe {*ptr.offset(offset)};
                if v != z {
                    return false;
                }
                // Move on to next element in the row (l t)
                // or column (u t).
                offset += 1;
            }
            // Skip the diagonal element
            offset += 1;
        }
        true
    }

    /// Returns if the matrix is lower triangular
    fn is_lt(&self) -> bool {
        ! self.ut_flag
    }

    /// Returns if the matrix is upper triangular
    fn is_ut(&self) -> bool {
        self.ut_flag
    }

    /// Returns if the matrix is triangular
    fn is_triangular(&self) -> bool {
        true
    }

    fn get(&self, r : uint, c : uint) -> T  {
        // These assertions help in checking matrix boundaries
        debug_assert!(r < self.size);
        debug_assert!(c < self.size);
        unsafe {
            *self.ptr.offset(self.cell_to_offset(r, c) as int)
        }
    }

    fn set(&mut self, r : uint, c : uint, value : T) {
        // These assertions help in checking matrix boundaries
        debug_assert!(r < self.size);
        debug_assert!(c < self.size);
        unsafe {
            *self.ptr.offset(self.cell_to_offset(r, c) as int) = value;
        }
    }

}

/// Introspection support
impl<T:Number> Introspection for TriangularMatrix<T> {
    /// Indicates if the matrix is a triangular matrix
    fn is_triangular_matrix_type(&self) -> bool {
        true
    }
}

/// Buffer access
impl<T:Number> MatrixBuffer<T> for TriangularMatrix<T> {
    /// Fake implementation
    fn stride (&self)->uint {
        -1 as uint
    }

    /// Returns an unsafe pointer to the matrix's
    /// buffer.
    #[inline]
    fn as_ptr(&self)-> *const T{
        self.ptr as *const T
    }

    /// Returns a mutable unsafe pointer to
    /// the matrix's underlying buffer
    #[inline]
    fn as_mut_ptr(&mut self) -> *mut T{
        self.ptr
    }

    /// Maps a cell index to actual offset in the internal buffer
    #[inline]
    fn cell_to_offset(&self, r : uint,  c: uint)-> int {
        debug_assert!(if self.ut_flag {
            r <= c && c < self.size
        }
        else {
            c <= r && r < self.size
        });
        let offset = if self.ut_flag {
            c * (c + 1) / 2 + r

        }
        else {
            r * (r + 1) /2 + c
        };
        offset as int
    }

}

/// Main methods of a triangular matrix
impl<T:Number> TriangularMatrix<T> {

    /// Returns the capacity of the matrix
    /// i.e. the number of elements it can hold
    pub fn capacity(&self)-> uint {
        let n = self.size;
        n * (n + 1) / 2
    }

}

#[unsafe_destructor]
impl<T:Number> Drop for TriangularMatrix<T> {
    fn drop(&mut self) {
        if self.num_cells() != 0 {
            unsafe {
                util::memory::dealloc(self.ptr, self.capacity())
            }
        }
    }
}

<commit_msg>Initial unit tests for triangular matrices.<commit_after>#![doc="Implements the triangular matrix data-type
"]

// std imports
use std::ptr;
use std::mem;
use std::fmt;
use std::num::{Zero, One};
use std::rt::heap::allocate;

// local imports

use matrix::element::{Number};
use matrix::matrix::Matrix;
use matrix::error::*;

use matrix::traits::{MatrixType, Introspection,
    MatrixBuffer, Extraction, ERO, ECO, Updates};

// complex numbers
use external::complex::Complex32;
use external::complex::Complex64;

use util;
use discrete::mod_n;

#[doc = "
Represents a triangular square matrix of numbers.

The matrix can be either upper triangular or
lower triangular (but not both off course).

For an upper triangular matrix, the
numbers are stored in column major order.

For a lower triangular matrix, the numbers
are stored in row major order.

The difference in ordering is to simplify
cell index to cell offset calculations.

The half of the matrix which is full of zeros,
is not stored in memory. Thus, all calculations
are done smartly.

This design is not too flexible. The memory allocation
is done in the beginning and never changed afterwards.
Thus, the size of the matrix remains same.
"]
pub struct TriangularMatrix<T:Number> {
    /// Number of rows and columns in the matrix
    size : uint,
    /// The pointer to raw data array of the matrix
    ptr : *mut T,
    /// Indicates whether the matrix is upper or lower triangular
    ut_flag : bool
}

/// A matrix of 8-bit signed integers
pub type TriangularMatrixI8 = TriangularMatrix<i8>;
/// A matrix of 16-bit signed integers
pub type TriangularMatrixI16 = TriangularMatrix<i16>;
/// A matrix of 32-bit signed integers
pub type TriangularMatrixI32 = TriangularMatrix<i32>;
/// A matrix of 64-bit signed integers
pub type TriangularMatrixI64 = TriangularMatrix<i64>;
/// A matrix of 8-bit unsigned integers
pub type TriangularMatrixU8 = TriangularMatrix<u8>;
/// A matrix of 16-bit unsigned integers
pub type TriangularMatrixU16 = TriangularMatrix<u16>;
/// A matrix of 32-bit unsigned integers
pub type TriangularMatrixU32 = TriangularMatrix<u32>;
/// A matrix of 64-bit unsigned integers
pub type TriangularMatrixU64 = TriangularMatrix<u64>;
/// A matrix of  unsigned integers
pub type TriangularMatrixUInt = TriangularMatrix<uint>;
/// A matrix of 32-bit floating point numbers.
pub type TriangularMatrixF32 = TriangularMatrix<f32>;
/// A matrix of 64-bit floating point numbers.
pub type TriangularMatrixF64 = TriangularMatrix<f64>;
/// A matrix of 32-bit complex numbers numbers.
pub type TriangularMatrixC32 = TriangularMatrix<Complex32>;
/// A matrix of 64-bit complex numbers numbers.
pub type TriangularMatrixC64 = TriangularMatrix<Complex64>;

/// Static functions for creating  a triangular matrix
impl<T:Number> TriangularMatrix<T> {

#[doc = "Constructs a new matrix of given size (uninitialized).
"]
    pub fn new(size: uint,
        ut_flag : bool )-> TriangularMatrix<T> {
        let capacity = size * (size + 1) / 2;
        if capacity == 0 {
            // Support for empty matrices.
            // The buffer remains a null pointer.
            return TriangularMatrix{
                size : size,
                ut_flag : ut_flag,
                ptr : ptr::null_mut()
            };
        }
        let bytes = capacity * mem::size_of::<T>();
        let raw = unsafe {
            allocate(bytes, mem::min_align_of::<T>())
        };
        let ptr = raw as *mut T;
        TriangularMatrix {size : size,
                ut_flag : ut_flag,
                ptr : ptr}
    }

    /// Constructs a triangular matrix of all zeros
    pub fn zeros(size: uint,
        ut : bool)-> TriangularMatrix<T> {
        let m : TriangularMatrix<T> = TriangularMatrix::new(size, ut);
        // zero out the memory
        unsafe { ptr::zero_memory(m.ptr, m.capacity())};
        m
    }

    /// Constructs a matrix of all ones.
    pub fn ones(size: uint, ut : bool)-> TriangularMatrix<T> {
        let m : TriangularMatrix<T> = TriangularMatrix::new(size, ut);
        // fill with ones
        let ptr = m.ptr;
        let o : T = One::one();
        let n = m.capacity() as int;
        for i in range(0i, n){
            unsafe{
                *ptr.offset(i) = o;
            }
        }
        m
    }
}

/// Core methods for all matrix types
impl<T:Number> MatrixType<T> for TriangularMatrix<T> {

    /// Returns the number of rows in the matrix
    fn num_rows(&self) -> uint {
        self.size
    }

    /// Returns the number of columns in the matrix
    fn num_cols(&self) -> uint {
        self.size
    }

    /// Returns the size of matrix in an (r, c) tuple
    fn size (&self)-> (uint, uint){
        (self.size, self.size)
    }

    /// Returns the number of cells in matrix
    fn num_cells(&self)->uint {
        self.size * self.size
    }

    /// Returns if the matrix is an identity matrix
    fn is_identity(&self) -> bool {
        let o : T = One::one();
        let z  : T = Zero::zero();
        let ptr = self.ptr;
        // Check the 0, 0 element
        if unsafe{*ptr} != o {
            return false;
        }
        let mut offset = 1;
        for i in range(1, self.size){
            for _ in range (0, i){
                let v = unsafe {*ptr.offset(offset)};
                if v != z {
                    return false;
                }
                // Move on to next element in the row (l t)
                // or column (u t).
                offset += 1;
            }
            // Check the diagonal element
            if unsafe {*ptr.offset(offset)} != o {
                return false;
            }
            // Skip the diagonal element
            offset += 1;
        }
        true
    }

    /// Returns if the matrix is a diagonal matrix
    fn is_diagonal(&self) -> bool {
        let z  : T = Zero::zero();
        let ptr = self.ptr;
        // We ignore the a[0,0] position.
        // We start working with 2nd row (l t) or column (u t)
        let mut offset = 1;
        for i in range(1, self.size){
            for _ in range (0, i){
                let v = unsafe {*ptr.offset(offset)};
                if v != z {
                    return false;
                }
                // Move on to next element in the row (l t)
                // or column (u t).
                offset += 1;
            }
            // Skip the diagonal element
            offset += 1;
        }
        true
    }

    /// Returns if the matrix is lower triangular
    fn is_lt(&self) -> bool {
        ! self.ut_flag
    }

    /// Returns if the matrix is upper triangular
    fn is_ut(&self) -> bool {
        self.ut_flag
    }

    /// Returns if the matrix is triangular
    fn is_triangular(&self) -> bool {
        true
    }

    fn get(&self, r : uint, c : uint) -> T  {
        // These assertions help in checking matrix boundaries
        debug_assert!(r < self.size);
        debug_assert!(c < self.size);
        if (self.ut_flag && r > c) || (!self.ut_flag && r < c) {
            let v : T = Zero::zero();
            return v;
        }
        unsafe {
            *self.ptr.offset(self.cell_to_offset(r, c) as int)
        }
    }

    fn set(&mut self, r : uint, c : uint, value : T) {
        // These assertions help in checking matrix boundaries
        debug_assert!(r < self.size);
        debug_assert!(c < self.size);
        unsafe {
            *self.ptr.offset(self.cell_to_offset(r, c) as int) = value;
        }
    }

}

/// Introspection support
impl<T:Number> Introspection for TriangularMatrix<T> {
    /// Indicates if the matrix is a triangular matrix
    fn is_triangular_matrix_type(&self) -> bool {
        true
    }
}

/// Buffer access
impl<T:Number> MatrixBuffer<T> for TriangularMatrix<T> {
    /// Fake implementation
    fn stride (&self)->uint {
        -1 as uint
    }

    /// Returns an unsafe pointer to the matrix's
    /// buffer.
    #[inline]
    fn as_ptr(&self)-> *const T{
        self.ptr as *const T
    }

    /// Returns a mutable unsafe pointer to
    /// the matrix's underlying buffer
    #[inline]
    fn as_mut_ptr(&mut self) -> *mut T{
        self.ptr
    }

    /// Maps a cell index to actual offset in the internal buffer
    #[inline]
    fn cell_to_offset(&self, r : uint,  c: uint)-> int {
        debug_assert!(if self.ut_flag {
            r <= c && c < self.size
        }
        else {
            c <= r && r < self.size
        });
        let offset = if self.ut_flag {
            c * (c + 1) / 2 + r

        }
        else {
            r * (r + 1) /2 + c
        };
        offset as int
    }

}

/// Main methods of a triangular matrix
impl<T:Number> TriangularMatrix<T> {

    /// Returns the capacity of the matrix
    /// i.e. the number of elements it can hold
    pub fn capacity(&self)-> uint {
        let n = self.size;
        n * (n + 1) / 2
    }

}

#[unsafe_destructor]
impl<T:Number> Drop for TriangularMatrix<T> {
    fn drop(&mut self) {
        if self.num_cells() != 0 {
            unsafe {
                util::memory::dealloc(self.ptr, self.capacity())
            }
        }
    }
}

/// Implement extraction API for triangular matrix
impl <T:Number> Extraction<T> for TriangularMatrix<T> {

    /// Returns the r'th row vector
    fn row(&self, r : int) -> Matrix<T> {
        // Lets ensure that the row value is mapped to
        // a value in the range [0, rows - 1]
        let r = mod_n(r, self.num_rows() as int);
        let mut result : Matrix<T> = Matrix::new(1, self.num_cols());
        let pd = result.as_mut_ptr();
        let ps = self.as_ptr();
        let z : T  = Zero::zero();
        let mut dst_offset = 0i;
        let n = self.size;
        if self.ut_flag {
            // The triangle is stored in column major order.
            // We have zeros in the beginning r zeros
            for _ in range(0, r) {
                unsafe{
                    *pd.offset(dst_offset) = z;
                }
                dst_offset += 1;
            }
            for c in range(r, n){
                let src_offset = self.cell_to_offset(r, c);
                unsafe{
                    *pd.offset(dst_offset) = *ps.offset(src_offset);
                }
                dst_offset += 1;
            }
        }
        else {
            // the lower triangle is stored in row major order.
            // r-th row contains r + 1 entries. Rest are zero.
            for c in range(0, r + 1) {
                let src_offset = self.cell_to_offset(r, c);
                unsafe{
                    *pd.offset(dst_offset) = *ps.offset(src_offset);
                }
                dst_offset += 1;
            }
            for _ in range(r + 1, n){
                unsafe{
                    *pd.offset(dst_offset) = z;
                }
                dst_offset += 1;
            }
       }
        result
    }

    /// Returns the c'th column vector
    fn col(&self, c : int) -> Matrix<T>{
        // Lets ensure that the col value is mapped to
        // a value in the range [0, cols - 1]
        let c = mod_n(c, self.num_cols() as int);
        let mut result : Matrix<T> = Matrix::new(self.num_rows(), 1);
        let pd = result.as_mut_ptr();
        let ps = self.as_ptr();
        for r in range(0, self.num_rows()){
            let src_offset = self.cell_to_offset(r, c);
            let dst_offset = result.cell_to_offset(r, 0);
            unsafe{
                *pd.offset(dst_offset) = *ps.offset(src_offset);
            }
        }
        result
    }

    /// Extract a submatrix from the matrix
    /// rows can easily repeat if the number of requested rows is higher than actual rows
    /// cols can easily repeat if the number of requested cols is higher than actual cols
    fn sub_matrix(&self, start_row : int,
        start_col : int ,
        num_rows: uint,
        num_cols : uint) -> Matrix<T>{
        let r = mod_n(start_row, self.num_rows() as int);
        let c = mod_n(start_col, self.num_cols() as int);
        let mut result : Matrix<T> = Matrix::new(num_rows, num_cols);
        let pd = result.as_mut_ptr();
        let ps = self.as_ptr();
        let mut dc = 0;
        for c in range(c, c + num_cols).map(|x | x % self.num_cols()) {
            let mut dr = 0;
            for r in range(r , r + num_rows).map(|x|  x % self.num_rows()) {
                let src_offset = self.cell_to_offset(r, c);
                let dst_offset = result.cell_to_offset(dr, dc);
                unsafe{
                    *pd.offset(dst_offset) = *ps.offset(src_offset);
                }
                dr += 1;
            }
            dc += 1;
        }
        result
    }

}

/// Formatting of the triangular matrix on screen
impl <T:Number> fmt::Show for TriangularMatrix<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // We need to find out the number of characters needed
        // to show each value.
        // maximum value
        let cap = self.capacity();
        let mut strings : Vec<String> = Vec::with_capacity(cap);
        let mut max_len : uint = 0;
        let ptr = self.ptr;
        for i in range(0i, cap as int){
            let v = unsafe {*ptr.offset(i)};
            let s = v.to_string();
            let slen = s.len();
            strings.push(s);
            if slen > max_len {
                max_len = slen;
            }
        }
        try!(write!(f, "["));
        // Here we print row by row
        let n = self.size;
        for r in range (0, n) {
           try!(write!(f, "\n  "));
            for c in range (0, n){
                if self.ut_flag {
                    if r > c {
                        for _ in range(0, max_len + 1){
                            try!(write!(f, " "));
                        }
                        try!(write!(f, "0"));
                        continue;
                    }
                }
                else {
                    if r < c {
                        for _ in range(0, max_len + 1){
                            try!(write!(f, " "));
                        }
                        try!(write!(f, "0"));
                        continue;
                    }
                }
                // This is something from within the matrix.
                let offset = self.cell_to_offset(r, c);
                let ref s = strings[offset as uint];
                let extra = max_len + 2 - s.len();
                for _ in range(0, extra){
                    try!(write!(f, " "));
                }
                try!(write!(f, "{}", s));
            }
        }
        try!(write!(f, "\n]"));
        Ok(())
    }
}

/******************************************************
 *
 *   Unit tests follow.
 *
 *******************************************************/

#[cfg(test)]
mod tests {

    use super::*;
    use matrix::*;

    #[test]
    fn test_create_0(){
        let m : TriangularMatrixI64 = TriangularMatrix::new(4, true);
        println!("{}", m);
        assert_eq!(m.size(), (4, 4));
    }

    #[test]
    fn test_create_ones(){
        let n = 4;
        let m : TriangularMatrixI64 = TriangularMatrix::ones(n, true);
        println!("{}", m);
        for r in range(0, n) {
            for c in range(0, n){
                if r > c {
                    assert_eq!(m.get(r, c), 0);
                }
                else {
                    assert_eq!(m.get(r, c), 1);
                }
            }
        }
        let m : TriangularMatrixI64 = TriangularMatrix::ones(n, false);
        println!("{}", m);
        for r in range(0, n) {
            for c in range(0, n){
                if r < c {
                    assert_eq!(m.get(r, c), 0);
                }
                else {
                    assert_eq!(m.get(r, c), 1);
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>//! lint when there is a large size difference between variants on an enum

use rustc::lint::*;
use rustc::hir::*;
use utils::{span_lint_and_then, snippet_opt};
use rustc::ty::layout::TargetDataLayout;
use rustc::ty::TypeFoldable;
use rustc::traits::Reveal;

/// **What it does:** Checks for large size differences between variants on `enum`s.
///
/// **Why is this bad?** Enum size is bounded by the largest variant. Having a large variant
/// can penalize the memory layout of that enum.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// enum Test {
///    A(i32),
///    B([i32; 8000]),
/// }
/// ```
declare_lint! {
    pub LARGE_ENUM_VARIANT,
    Warn,
    "large size difference between variants on an enum"
}

#[derive(Copy,Clone)]
pub struct LargeEnumVariant {
    maximum_size_difference_allowed: u64,
}

impl LargeEnumVariant {
    pub fn new(maximum_size_difference_allowed: u64) -> Self {
        LargeEnumVariant { maximum_size_difference_allowed: maximum_size_difference_allowed }
    }
}

impl LintPass for LargeEnumVariant {
    fn get_lints(&self) -> LintArray {
        lint_array!(LARGE_ENUM_VARIANT)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant {
    fn check_item(&mut self, cx: &LateContext, item: &Item) {
        let did = cx.tcx.hir.local_def_id(item.id);
        if let ItemEnum(ref def, _) = item.node {
            let ty = cx.tcx.item_type(did);
            let adt = ty.ty_adt_def().expect("already checked whether this is an enum");

            let mut sizes = Vec::new();
            let mut variants = Vec::new();

            for variant in &adt.variants {
                let data_layout = TargetDataLayout::parse(cx.sess());
                cx.tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
                    let size: u64 = variant.fields
                        .iter()
                        .map(|f| {
                            let ty = cx.tcx.item_type(f.did);
                            if ty.needs_subst() {
                                0 // we can't reason about generics, so we treat them as zero sized
                            } else {
                                ty.layout(&infcx)
                                    .expect("layout should be computable for concrete type")
                                    .size(&data_layout)
                                    .bytes()
                            }
                        })
                        .sum();

                    sizes.push(size);
                    variants.push(variant);
                });
            }

            let mut grouped = sizes.into_iter().zip(variants.into_iter().enumerate()).collect::<Vec<_>>();

            grouped.sort_by_key(|g| g.0);

            let smallest_variant = grouped.first();
            let largest_variant = grouped.last();

            if let (Some(smallest), Some(largest)) = (smallest_variant, largest_variant) {
                let difference = largest.0 - smallest.0;

                if difference > self.maximum_size_difference_allowed {
                    let (i, variant) = largest.1;

                    span_lint_and_then(cx,
                                       LARGE_ENUM_VARIANT,
                                       def.variants[i].span,
                                       "large size difference between variants",
                                       |db| {
                        if variant.fields.len() == 1 {
                            let span = match def.variants[i].node.data {
                                VariantData::Struct(ref fields, _) |
                                VariantData::Tuple(ref fields, _) => fields[0].ty.span,
                                VariantData::Unit(_) => unreachable!(),
                            };
                            if let Some(snip) = snippet_opt(cx, span) {
                                db.span_suggestion(span,
                                                   "consider boxing the large fields to reduce the total size of the \
                                                    enum",
                                                   format!("Box<{}>", snip));
                                return;
                            }
                        }
                        db.span_help(def.variants[i].span,
                                     "consider boxing the large fields to reduce the total size of the enum");
                    });
                }
            }

        }
    }
}
<commit_msg>Search directly for the largest and smallest variants instead of sorting<commit_after>//! lint when there is a large size difference between variants on an enum

use rustc::lint::*;
use rustc::hir::*;
use utils::{span_lint_and_then, snippet_opt};
use rustc::ty::layout::TargetDataLayout;
use rustc::ty::TypeFoldable;
use rustc::traits::Reveal;

/// **What it does:** Checks for large size differences between variants on `enum`s.
///
/// **Why is this bad?** Enum size is bounded by the largest variant. Having a large variant
/// can penalize the memory layout of that enum.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// enum Test {
///    A(i32),
///    B([i32; 8000]),
/// }
/// ```
declare_lint! {
    pub LARGE_ENUM_VARIANT,
    Warn,
    "large size difference between variants on an enum"
}

#[derive(Copy,Clone)]
pub struct LargeEnumVariant {
    maximum_size_difference_allowed: u64,
}

impl LargeEnumVariant {
    pub fn new(maximum_size_difference_allowed: u64) -> Self {
        LargeEnumVariant { maximum_size_difference_allowed: maximum_size_difference_allowed }
    }
}

impl LintPass for LargeEnumVariant {
    fn get_lints(&self) -> LintArray {
        lint_array!(LARGE_ENUM_VARIANT)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant {
    fn check_item(&mut self, cx: &LateContext, item: &Item) {
        let did = cx.tcx.hir.local_def_id(item.id);
        if let ItemEnum(ref def, _) = item.node {
            let ty = cx.tcx.item_type(did);
            let adt = ty.ty_adt_def().expect("already checked whether this is an enum");

            let mut smallest_variant: Option<(_, _)> = None;
            let mut largest_variant: Option<(_, _)> = None;

            for (i, variant) in adt.variants.iter().enumerate() {
                let data_layout = TargetDataLayout::parse(cx.sess());
                cx.tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
                    let size: u64 = variant.fields
                        .iter()
                        .map(|f| {
                            let ty = cx.tcx.item_type(f.did);
                            if ty.needs_subst() {
                                0 // we can't reason about generics, so we treat them as zero sized
                            } else {
                                ty.layout(&infcx)
                                    .expect("layout should be computable for concrete type")
                                    .size(&data_layout)
                                    .bytes()
                            }
                        })
                        .sum();

                    let grouped = (size, (i, variant));

                    update_if(&mut smallest_variant, grouped, |a, b| b.0 <= a.0);
                    update_if(&mut largest_variant, grouped, |a, b| b.0 >= a.0);
                });
            }

            if let (Some(smallest), Some(largest)) = (smallest_variant, largest_variant) {
                let difference = largest.0 - smallest.0;

                if difference > self.maximum_size_difference_allowed {
                    let (i, variant) = largest.1;

                    span_lint_and_then(cx,
                                       LARGE_ENUM_VARIANT,
                                       def.variants[i].span,
                                       "large size difference between variants",
                                       |db| {
                        if variant.fields.len() == 1 {
                            let span = match def.variants[i].node.data {
                                VariantData::Struct(ref fields, _) |
                                VariantData::Tuple(ref fields, _) => fields[0].ty.span,
                                VariantData::Unit(_) => unreachable!(),
                            };
                            if let Some(snip) = snippet_opt(cx, span) {
                                db.span_suggestion(span,
                                                   "consider boxing the large fields to reduce the total size of the \
                                                    enum",
                                                   format!("Box<{}>", snip));
                                return;
                            }
                        }
                        db.span_help(def.variants[i].span,
                                     "consider boxing the large fields to reduce the total size of the enum");
                    });
                }
            }

        }
    }
}

fn update_if<T, F>(old: &mut Option<T>, new: T, f: F) where F: Fn(&T, &T) -> bool {
    if let Some(ref mut val) = *old {
        if f(val, &new) {
            *val = new;
        }
    } else {
        *old = Some(new);
    }
}
<|endoftext|>