use std::ops::Range;
use std::mem;
use std::ptr;
use std::iter;
use std::string::FromUtf8Error;
use num_traits::PrimInt;
use crate::{OclPrm, OclScl};
pub mod colors {
pub static TAB: &'static str = " ";
pub static C_DEFAULT: &'static str = "\x1b[0m";
pub static C_UNDER: &'static str = "\x1b[1m";
pub static C_RED: &'static str = "\x1b[31m";
pub static C_BRED: &'static str = "\x1b[1;31m";
pub static C_GRN: &'static str = "\x1b[32m";
pub static C_BGRN: &'static str = "\x1b[1;32m";
pub static C_ORA: &'static str = "\x1b[33m";
pub static C_DBL: &'static str = "\x1b[34m";
pub static C_PUR: &'static str = "\x1b[35m";
pub static C_CYA: &'static str = "\x1b[36m";
pub static C_LGR: &'static str = "\x1b[37m";
pub static C_DFLT: &'static str = "\x1b[39m";
pub static C_DGR: &'static str = "\x1b[90m";
pub static C_LRD: &'static str = "\x1b[91m";
pub static C_YEL: &'static str = "\x1b[93m";
pub static C_BLU: &'static str = "\x1b[94m";
pub static C_LBL: &'static str = "\x1b[94m";
pub static C_MAG: &'static str = "\x1b[95m";
pub static BGC_DEFAULT: &'static str = "\x1b[49m";
pub static BGC_GRN: &'static str = "\x1b[42m";
pub static BGC_PUR: &'static str = "\x1b[45m";
pub static BGC_LGR: &'static str = "\x1b[47m";
pub static BGC_DGR: &'static str = "\x1b[100m";
}
#[derive(Debug, Fail)]
pub enum UtilError {
#[fail(display = "The size of the source byte slice ({} bytes) does not match \
the size of the destination type ({} bytes).", src, dst)]
BytesTo { src: usize, dst: usize, },
#[fail(display = "The size of the source byte vector ({} bytes) does not match \
the size of the destination type ({} bytes).", src, dst)]
BytesInto { src: usize, dst: usize, },
#[fail(display = "The size of the source byte vector ({} bytes) is not evenly \
divisible by the size of the destination type ({} bytes).", src, dst)]
BytesIntoVec { src: usize, dst: usize, },
#[fail(display = "The size of the source byte slice ({} bytes) is not evenly \
divisible by the size of the destination type ({} bytes).", src, dst)]
BytesToVec { src: usize, dst: usize, },
#[fail(display = "Unable to convert bytes into string: {}", _0)]
BytesIntoString(#[cause] FromUtf8Error),
}
pub fn bytes_to_u32(bytes: &[u8]) -> u32 {
debug_assert!(bytes.len() == 4);
u32::from(bytes[0]) |
(u32::from(bytes[1]) << 8) |
(u32::from(bytes[2]) << 16) |
(u32::from(bytes[3]) << 24)
}
pub unsafe fn bytes_to<T>(bytes: &[u8]) -> Result<T, UtilError> {
if mem::size_of::<T>() == bytes.len() {
let mut new_val: T = mem::uninitialized();
ptr::copy(bytes.as_ptr(), &mut new_val as *mut _ as *mut u8, bytes.len());
Ok(new_val)
} else {
Err(UtilError::BytesTo { src: bytes.len(), dst: mem::size_of::<T>() })
}
}
pub unsafe fn bytes_into<T>(vec: Vec<u8>) -> Result<T, UtilError> {
if mem::size_of::<T>() == vec.len() {
let mut new_val: T = mem::uninitialized();
ptr::copy(vec.as_ptr(), &mut new_val as *mut _ as *mut u8, vec.len());
Ok(new_val)
} else {
Err(UtilError::BytesInto { src: vec.len(), dst: mem::size_of::<T>() })
}
}
pub unsafe fn bytes_into_vec<T>(mut vec: Vec<u8>) -> Result<Vec<T>, UtilError> {
if vec.len() % mem::size_of::<T>() == 0 {
let new_len = vec.len() / mem::size_of::<T>();
let new_cap = vec.capacity() / mem::size_of::<T>();
let ptr = vec.as_mut_ptr();
mem::forget(vec);
let mut new_vec: Vec<T> = Vec::from_raw_parts(ptr as *mut T, new_len, new_cap);
new_vec.shrink_to_fit();
Ok(new_vec)
} else {
Err(UtilError::BytesIntoVec { src: vec.len(), dst: mem::size_of::<T>() })
}
}
pub unsafe fn bytes_to_vec<T>(bytes: &[u8]) -> Result<Vec<T>, UtilError> {
if bytes.len() % mem::size_of::<T>() == 0 {
let new_len = bytes.len() / mem::size_of::<T>();
let mut new_vec: Vec<T> = Vec::with_capacity(new_len);
ptr::copy(bytes.as_ptr(), new_vec.as_mut_ptr() as *mut _ as *mut u8, bytes.len());
new_vec.set_len(new_len);
Ok(new_vec)
} else {
Err(UtilError::BytesToVec { src: bytes.len(), dst: mem::size_of::<T>() })
}
}
pub fn bytes_into_string(mut bytes: Vec<u8>) -> Result<String, UtilError> {
if bytes.last() == Some(&0u8) {
bytes.pop();
}
String::from_utf8(bytes)
.map(|str| String::from(str.trim()))
.map_err(UtilError::BytesIntoString)
}
pub unsafe fn into_bytes<T>(val: T) -> Vec<u8> {
let size = mem::size_of::<T>();
let mut new_vec: Vec<u8> = iter::repeat(0).take(size).collect();
ptr::copy(&val as *const _ as *const u8, new_vec.as_mut_ptr(), size);
new_vec
}
pub fn padded_len(len: usize, incr: usize) -> usize {
let len_mod = len % incr;
if len_mod == 0 {
len
} else {
let pad = incr - len_mod;
let padded_len = len + pad;
debug_assert_eq!(padded_len % incr, 0);
padded_len
}
}
#[derive(Fail, Debug)]
pub enum VecRemoveRebuildError {
#[fail(display = "Remove list is longer than source vector.")]
TooLong,
#[fail(display = "'remove_list' contains at least one out of range index: [{}] \
('orig_vec' length: {}).", idx, orig_len)]
OutOfRange { idx: usize, orig_len: usize },
}
pub fn vec_remove_rebuild<T: Clone + Copy>(orig_vec: &mut Vec<T>, remove_list: &[usize],
rebuild_threshold: usize) -> Result<(), VecRemoveRebuildError> {
if remove_list.len() > orig_vec.len() {
return Err(VecRemoveRebuildError::TooLong)
}
let orig_len = orig_vec.len();
if remove_list.len() <= rebuild_threshold {
for &idx in remove_list.iter().rev() {
if idx < orig_len {
orig_vec.remove(idx);
} else {
return Err(VecRemoveRebuildError::OutOfRange { idx, orig_len })
}
}
} else {
unsafe {
let mut remove_markers: Vec<bool> = iter::repeat(true).take(orig_len).collect();
for &idx in remove_list.iter() {
if idx < orig_len {
*remove_markers.get_unchecked_mut(idx) = false;
} else {
return Err(VecRemoveRebuildError::OutOfRange { idx, orig_len })
}
}
let mut new_len = 0usize;
for idx in 0..orig_len {
if *remove_markers.get_unchecked(idx) {
*orig_vec.get_unchecked_mut(new_len) = *orig_vec.get_unchecked(idx);
new_len += 1;
}
}
debug_assert_eq!(new_len, orig_len - remove_list.len());
orig_vec.set_len(new_len);
}
}
Ok(())
}
pub fn wrap_vals<T: OclPrm + PrimInt>(vals: &[T], val_n: T) -> Vec<T> {
vals.iter().map(|&v| v % val_n).collect()
}
pub fn print_bytes_as_hex(bytes: &[u8]) {
print!("0x");
for &byte in bytes.iter() {
print!("{:x}", byte);
}
}
#[allow(unused_assignments, unused_variables)]
pub fn print_slice<T: OclScl>(
vec: &[T],
every: usize,
val_range: Option<(T, T)>,
idx_range: Option<Range<usize>>,
show_zeros: bool,
) {
print!( "{cdgr}[{cg}{}{cdgr}/{}", vec.len(), every, cg = colors::C_GRN, cdgr = colors::C_DGR);
let (vr_start, vr_end) = match val_range {
Some(vr) => {
print!( ";({}-{})", vr.0, vr.1);
vr
},
None => (Default::default(), Default::default()),
};
let (ir_start, ir_end) = match idx_range {
Some(ref ir) => {
print!( ";[{}..{}]", ir.start, ir.end);
(ir.start, ir.end)
},
None => (0usize, 0usize),
};
print!( "]:{cd} ", cd = colors::C_DEFAULT,);
let mut ttl_nz = 0usize;
let mut ttl_ir = 0usize;
let mut within_idx_range = true;
let mut within_val_range = true;
let mut hi: T = vr_start;
let mut lo: T = vr_end;
let mut sum: i64 = 0;
let mut ttl_prntd: usize = 0;
let len = vec.len();
let mut color: &'static str = colors::C_DEFAULT;
let mut prnt: bool = false;
for (i, item) in vec.iter().enumerate() {
prnt = false;
if every != 0 {
if i % every == 0 {
prnt = true;
} else {
prnt = false;
}
}
if idx_range.is_some() {
let ir = idx_range.as_ref().expect("ocl::buffer::print_vec()");
if i < ir_start || i >= ir_end {
prnt = false;
within_idx_range = false;
} else {
within_idx_range = true;
}
} else {
within_idx_range = true;
}
if val_range.is_some() {
if *item < vr_start || *item > vr_end {
prnt = false;
within_val_range = false;
} else {
if within_idx_range {
ttl_ir += 1;
}
within_val_range = true;
}
}
if within_idx_range && within_val_range {
sum += item.to_i64().expect("ocl::buffer::print_vec(): vec[i]");
if *item > hi { hi = *item };
if *item < lo { lo = *item };
if vec[i] != Default::default() {
ttl_nz += 1usize;
color = colors::C_ORA;
} else if show_zeros {
color = colors::C_DEFAULT;
} else {
prnt = false;
}
}
if prnt {
print!( "{cg}[{cd}{}{cg}:{cc}{}{cg}]{cd}", i, vec[i], cc = color, cd = colors::C_DEFAULT, cg = colors::C_DGR);
ttl_prntd += 1;
}
}
let mut anz: f32 = 0f32;
let mut nz_pct: f32 = 0f32;
let mut ir_pct: f32 = 0f32;
let mut avg_ir: f32 = 0f32;
if ttl_nz > 0 {
anz = sum as f32 / ttl_nz as f32;
nz_pct = (ttl_nz as f32 / len as f32) * 100f32;
}
if ttl_ir > 0 {
avg_ir = sum as f32 / ttl_ir as f32;
ir_pct = (ttl_ir as f32 / len as f32) * 100f32;
}
println!("{cdgr}; (nz:{clbl}{}{cdgr}({clbl}{:.2}%{cdgr}),\
ir:{clbl}{}{cdgr}({clbl}{:.2}%{cdgr}),hi:{},lo:{},anz:{:.2},prntd:{}){cd} ",
ttl_nz, nz_pct, ttl_ir, ir_pct, hi, lo, anz, ttl_prntd, cd = colors::C_DEFAULT, clbl = colors::C_LBL, cdgr = colors::C_DGR);
}
pub fn print_simple<T: OclScl>(slice: &[T]) {
print_slice(slice, 1, None, None, true);
}
pub fn print_val_range<T: OclScl>(slice: &[T], every: usize, val_range: Option<(T, T)>) {
print_slice(slice, every, val_range, None, true);
}
#[cfg(test)]
mod tests {
#[test]
fn remove_rebuild() {
let mut primary_vals: Vec<u32> = (0..(1 << 18)).map(|v| v).collect();
let orig_len = primary_vals.len();
let mut bad_indices: Vec<usize> = Vec::<usize>::with_capacity(1 << 16);
let mut idx = 0;
for &val in primary_vals.iter() {
if (val % 19 == 0) || (val % 31 == 0) || (val % 107 == 0) {
bad_indices.push(idx);
}
idx += 1;
}
println!("util::tests::remove_rebuild(): bad_indices: {}", bad_indices.len());
super::vec_remove_rebuild(&mut primary_vals, &bad_indices[..], 3)
.expect("util::tests::remove_rebuild()");
for &val in primary_vals.iter() {
if (val % 19 == 0) || (val % 31 == 0) || (val % 107 == 0) {
panic!("util::tests::remove_rebuild(): Value: '{}' found in list!", val);
}
}
assert_eq!(orig_len, primary_vals.len() + bad_indices.len());
}
}