const LOWER16: u64 = 0xffff;
const FACTOR16: u64 = 1 << 16;
fn make_recover(index: usize, offset: usize) -> u64 {
index as u64 + (offset as u64) * FACTOR16
}
fn recover_index(value: u64) -> usize {
(value & LOWER16) as usize
}
fn recover_offset(value: u64) -> usize {
((value - (value & LOWER16)) / FACTOR16) as usize
}
pub const DEL_SIDE: u8 = 8;
const DEL_BEFORE: u8 = 1;
const DEL_AFTER: u8 = 2;
const DEL_ACROSS: u8 = 4;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MapResult {
pub pos: usize,
del_info: u8,
recover: Option<u64>,
}
impl MapResult {
pub fn deleted(&self) -> bool {
self.del_info & DEL_SIDE > 0
}
pub fn deleted_before(&self) -> bool {
self.del_info & (DEL_BEFORE | DEL_ACROSS) > 0
}
pub fn deleted_after(&self) -> bool {
self.del_info & (DEL_AFTER | DEL_ACROSS) > 0
}
pub fn deleted_across(&self) -> bool {
self.del_info & DEL_ACROSS > 0
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StepMap {
ranges: Vec<usize>,
inverted: bool,
}
impl StepMap {
pub fn new(ranges: Vec<usize>) -> Self {
debug_assert!(ranges.len() % 3 == 0);
StepMap {
ranges,
inverted: false,
}
}
pub fn identity() -> Self {
StepMap {
ranges: Vec::new(),
inverted: false,
}
}
pub fn invert(&self) -> StepMap {
StepMap {
ranges: self.ranges.clone(),
inverted: !self.inverted,
}
}
fn recover(&self, value: u64) -> usize {
let mut diff: i64 = 0;
let index = recover_index(value);
if !self.inverted {
for i in 0..index {
diff += self.ranges[i * 3 + 2] as i64 - self.ranges[i * 3 + 1] as i64;
}
}
(self.ranges[index * 3] as i64 + diff + recover_offset(value) as i64) as usize
}
pub fn map(&self, pos: usize, assoc: i32) -> usize {
self.map_inner(pos, assoc).pos
}
pub fn map_result(&self, pos: usize, assoc: i32) -> MapResult {
self.map_inner(pos, assoc)
}
fn map_inner(&self, pos: usize, assoc: i32) -> MapResult {
let mut diff: i64 = 0;
let mut i = 0;
while i < self.ranges.len() {
let start_raw = self.ranges[i] as i64 - if self.inverted { diff } else { 0 };
if start_raw > pos as i64 {
break;
}
let start = start_raw as usize;
let old_size = self.ranges[i + if self.inverted { 2 } else { 1 }];
let new_size = self.ranges[i + if self.inverted { 1 } else { 2 }];
let end = start + old_size;
if pos <= end {
let side = if old_size == 0 {
assoc
} else if pos == start {
-1
} else if pos == end {
1
} else {
assoc
};
let result =
(start as i64 + diff + if side < 0 { 0 } else { new_size as i64 }) as usize;
let edge = if assoc < 0 { start } else { end };
let recover = if pos == edge {
None
} else {
Some(make_recover(i / 3, pos - start))
};
let mut del_info = if pos == start {
DEL_AFTER
} else if pos == end {
DEL_BEFORE
} else {
DEL_ACROSS
};
let on_edge = if assoc < 0 { pos != start } else { pos != end };
if on_edge {
del_info |= DEL_SIDE;
}
return MapResult {
pos: result,
del_info,
recover,
};
}
diff += new_size as i64 - old_size as i64;
i += 3;
}
MapResult {
pos: (pos as i64 + diff) as usize,
del_info: 0,
recover: None,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct Mapping {
maps: Vec<StepMap>,
mirror: Vec<usize>,
}
impl Mapping {
pub fn new() -> Self {
Mapping::default()
}
pub fn len(&self) -> usize {
self.maps.len()
}
pub fn is_empty(&self) -> bool {
self.maps.is_empty()
}
pub fn maps(&self) -> &[StepMap] {
&self.maps
}
pub fn append_map(&mut self, map: StepMap) {
self.maps.push(map);
}
pub fn append_map_mirrored(&mut self, map: StepMap, mirrors: usize) {
self.maps.push(map);
let n = self.maps.len() - 1;
self.mirror.push(mirrors);
self.mirror.push(n);
}
fn get_mirror(&self, n: usize) -> Option<usize> {
let mut i = 0;
while i < self.mirror.len() {
if self.mirror[i] == n {
return Some(self.mirror[i + 1]);
}
if self.mirror[i + 1] == n {
return Some(self.mirror[i]);
}
i += 2;
}
None
}
pub fn map(&self, pos: usize, assoc: i32) -> usize {
let mut pos = pos;
let mut i = 0;
while i < self.maps.len() {
pos = self.maps[i].map(pos, assoc);
i += 1;
}
pos
}
pub fn map_result(&self, pos: usize, assoc: i32) -> MapResult {
let mut del_info = 0u8;
let mut pos = pos;
let mut i = 0;
while i < self.maps.len() {
let result = self.maps[i].map_result(pos, assoc);
if let Some(rec) = result.recover {
if let Some(corr) = self.get_mirror(i) {
if corr > i && corr < self.maps.len() {
i = corr;
pos = self.maps[corr].recover(rec);
i += 1;
continue;
}
}
}
del_info |= result.del_info;
pos = result.pos;
i += 1;
}
MapResult {
pos,
del_info,
recover: None,
}
}
}