use std::vec;
use rand::rngs::StdRng;
use crate::allocator::{Allocator, AllocatorBuilderArgument, GrantedRequests, Request};
use crate::config_parser::ConfigurationValue;
use crate::match_object_panic;
#[derive(Clone, Debug)]
struct RoundVec {
pointer : usize,
pub requested_indices : Vec<usize>,
n : usize,
}
impl RoundVec {
fn new(size : usize) -> RoundVec {
RoundVec {
pointer : 0,
requested_indices : Vec::with_capacity(size),
n : size,
}
}
fn add (&mut self, element : usize) {
self.requested_indices.push(element);
}
fn increment_pointer(&mut self) {
self.pointer = (self.pointer + 1) % self.n;
}
fn sort(&mut self) {
let pointer = self.pointer;
let size = self.size();
self.requested_indices.sort_unstable_by_key(| k|
if *k < pointer {
*k + size
} else {
*k
}
);
}
fn size (&self) -> usize {
self.n
}
fn is_empty(&self) -> bool {
self.requested_indices.is_empty()
}
fn clear(&mut self) {
self.requested_indices.clear();
}
}
pub struct ISLIPAllocator {
num_clients: usize,
num_resources: usize,
num_iterations: usize,
in_match: Vec<Option<usize>>,
out_match: Vec<Option<usize>>,
in_requests: Vec<RoundVec>,
out_requests: Vec<RoundVec>,
}
impl ISLIPAllocator {
pub fn new(args: AllocatorBuilderArgument) -> ISLIPAllocator {
if args.num_clients == 0 || args.num_resources == 0 {
panic!("Invalid arguments for ISLIPAllocator");
}
let mut num_iterations = None;
match_object_panic!(args.cv, "ISLIP", value,
"num_iter" => match value
{
&ConfigurationValue::Number(i) => num_iterations = Some(i as usize),
_ => panic!("Bad value for num_iter"),
}
);
if num_iterations.is_none() {
println!("Warning: num_iter for the iSLIP allocator is not specified in the configuration file, the default value (1) will be used");
}
let num_iterations = num_iterations.unwrap_or(1);
let in_match = vec![None; args.num_clients];
let out_match = vec![None; args.num_resources];
ISLIPAllocator {
num_clients: args.num_clients,
num_resources: args.num_resources,
num_iterations,
in_match,
out_match,
in_requests: vec![RoundVec::new(args.num_resources); args.num_clients],
out_requests: vec![RoundVec::new(args.num_clients); args.num_resources],
}
}
fn is_valid_request(&self, _request: &Request) -> bool {
if _request.client >= self.num_clients || _request.resource >= self.num_resources {
return false;
}
true
}
}
impl Allocator for ISLIPAllocator {
fn add_request(&mut self, request: Request) {
if !self.is_valid_request(&request) {
panic!("The request is not valid");
}
let client = request.client;
let resource = request.resource;
self.in_requests[client].add(resource);
self.out_requests[resource].add(client);
}
fn perform_allocation(&mut self, _rng: &mut StdRng) -> GrantedRequests {
let mut gr = GrantedRequests::default();
for client in 0..self.num_clients {
self.in_requests[client].sort();
}
for resource in 0..self.num_resources {
self.out_requests[resource].sort();
}
for client in 0..self.num_clients {
self.in_match[client] = None;
}
for resource in 0..self.num_resources {
self.out_match[resource] = None;
}
for islip_iter in 0..self.num_iterations {
let mut grants = vec![None; self.num_resources];
for resource in 0..self.num_resources {
if self.out_match[resource].is_some() || self.out_requests[resource].is_empty() {
continue;
}
for request in &self.out_requests[resource].requested_indices {
let client = *request;
if self.in_match[client].is_none() {
grants[resource] = Some(client);
break; }
}
}
for client in 0..self.num_clients {
if self.in_requests[client].is_empty() {
continue;
}
for request in &self.in_requests[client].requested_indices {
let resource = *request;
if grants[resource] == Some(client) {
self.in_match[client] = Some(resource);
self.out_match[resource] = Some(client);
let req = Request {
client,
resource,
priority: Some(0),
};
gr.add_granted_request(req);
if islip_iter == 0 {
self.in_requests[client].increment_pointer();
self.out_requests[resource].increment_pointer();
}
break;
}
}
} }
for client in 0..self.num_clients {
self.in_requests[client].clear();
}
for resource in 0..self.num_resources {
self.out_requests[resource].clear();
}
gr
}
fn support_intransit_priority(&self) -> bool {
false
}
}