use crate::op_set2::op_set::{MarkIndexBuilder, MarkIndexColumn};
use crate::op_set2::{ChangeOp, Op, OpBuilder, OpSet};
use crate::types::{ObjId, ObjType, OpId, SequenceType, TextEncoding};
use std::collections::HashMap;
pub(crate) struct IndexBuilder {
counters: HashMap<OpId, Vec<(usize, usize)>>,
succ: Vec<u32>,
top: Vec<bool>,
widths: Vec<u64>,
incs: Vec<Option<i64>>,
marks: Vec<Option<MarkIndexBuilder>>,
obj_info: ObjIndex,
last_flush: usize,
text_encoding: TextEncoding,
mark_order: MarkOrderValidator,
}
#[derive(Debug, Default, Clone)]
pub(crate) struct MarkOrderValidator {
begins: HashMap<OpId, ObjId>,
error: Option<String>,
}
impl MarkOrderValidator {
pub(crate) fn process_op(&mut self, op: &Op<'_>) {
let mark_index = op.mark_index();
self.process_mark_index(op, &mark_index);
}
pub(crate) fn process_mark_index(
&mut self,
op: &Op<'_>,
mark_index: &Option<MarkIndexBuilder>,
) {
if self.error.is_some() {
return;
}
self.check_mark_op(op, mark_index);
}
pub(crate) fn take_error(&mut self) -> Option<String> {
self.error.take()
}
fn check_mark_op(&mut self, op: &Op<'_>, mark_index: &Option<MarkIndexBuilder>) {
match mark_index {
Some(MarkIndexBuilder::Start(id, _)) => {
self.begins.insert(*id, op.obj);
}
Some(MarkIndexBuilder::End(begin)) => match self.begins.get(begin) {
Some(obj) if *obj == op.obj => {}
Some(_) => {
self.error = Some(format!(
"mark end {:?} references mark begin {:?} in a different object",
op.id, begin
));
}
None => {
self.error = Some(format!(
"mark end {:?} occurs before mark begin {:?}",
op.id, begin
));
}
},
None => {}
}
}
}
#[derive(Debug, Default, Clone)]
pub(crate) struct ObjIndex(pub(crate) HashMap<OpId, ObjInfo>);
impl ObjIndex {
pub(crate) fn object_type(&self, obj: &ObjId) -> Option<ObjType> {
if obj.is_root() {
Some(ObjType::Map)
} else {
self.0.get(&obj.0).map(|p| p.obj_type)
}
}
pub(crate) fn object_parent(&self, obj: &ObjId) -> Option<ObjId> {
if obj.is_root() {
None
} else {
self.0.get(&obj.0).map(|p| p.parent)
}
}
pub(crate) fn insert(&mut self, id: OpId, obj_info: ObjInfo) {
self.0.insert(id, obj_info);
}
pub(crate) fn remove(&mut self, id: OpId) {
self.0.remove(&id);
}
}
#[derive(Copy, Clone, Debug)]
pub(crate) struct ObjInfo {
pub(crate) parent: ObjId,
pub(crate) obj_type: ObjType,
}
impl ObjInfo {
pub(crate) fn with_new_actor(self, idx: usize) -> Self {
Self {
parent: self.parent.with_new_actor(idx),
obj_type: self.obj_type,
}
}
pub(crate) fn without_actor(self, idx: usize) -> Option<Self> {
Some(Self {
parent: self.parent.without_actor(idx)?,
obj_type: self.obj_type,
})
}
}
impl Op<'_> {
pub(crate) fn obj_info(&self) -> Option<ObjInfo> {
let obj_type = ObjType::try_from(self.action).ok()?;
let parent = self.obj;
Some(ObjInfo { parent, obj_type })
}
}
impl ChangeOp {
pub(crate) fn obj_info(&self) -> Option<ObjInfo> {
self.bld.obj_info()
}
}
impl OpBuilder<'_> {
pub(crate) fn obj_info(&self) -> Option<ObjInfo> {
let obj_type = ObjType::try_from(self.action).ok()?;
let parent = self.obj;
Some(ObjInfo { parent, obj_type })
}
}
pub(crate) struct Indexes {
pub(crate) text: hexane::PrefixColumn<Option<u32>>,
pub(crate) top: hexane::PrefixColumn<bool>,
pub(crate) visible: hexane::Column<bool>,
pub(crate) inc: hexane::Column<Option<i64>>,
pub(crate) mark: MarkIndexColumn,
pub(crate) obj_info: ObjIndex,
}
impl IndexBuilder {
pub(crate) fn new(op_set: &OpSet, encoding: TextEncoding) -> Self {
Self {
counters: HashMap::new(),
succ: Vec::with_capacity(op_set.len()),
top: Vec::with_capacity(op_set.len()),
widths: Vec::with_capacity(op_set.len()),
incs: Vec::with_capacity(op_set.sub_len()),
marks: Vec::with_capacity(op_set.len()),
obj_info: ObjIndex::default(),
last_flush: 0,
text_encoding: encoding,
mark_order: MarkOrderValidator::default(),
}
}
pub(crate) fn flush(&mut self) {
let len = self.succ.len();
for (delta, succ) in self.succ[self.last_flush..].iter().rev().enumerate() {
if *succ == 0 {
self.top[len - delta - 1] = true;
break;
}
}
self.last_flush = len;
}
pub(crate) fn process_op(&mut self, op: &Op<'_>) {
let mark_index = op.mark_index();
self.mark_order.process_mark_index(op, &mark_index);
self.marks.push(mark_index);
self.succ.push(vis_num(op));
self.top.push(false);
self.widths
.push(op.width(SequenceType::Text, self.text_encoding) as u64);
let count = self.counters.remove(&op.id);
if let Some(i) = op.get_increment_value() {
for (succ_idx, op_idx) in count.into_iter().flatten() {
self.incs[succ_idx] = Some(i);
self.succ[op_idx] -= 1;
}
}
if let Some(obj_info) = op.obj_info() {
self.obj_info.insert(op.id, obj_info);
}
}
pub(crate) fn process_succ(&mut self, op_is_counter: bool, id: OpId) {
if op_is_counter {
self.counters
.entry(id)
.or_default()
.push((self.incs.len(), self.succ.len() - 1));
}
self.incs.push(None); }
pub(crate) fn finish(mut self) -> (Indexes, MarkOrderValidator) {
self.flush();
let text = self
.widths
.iter()
.zip(self.top.iter())
.map(|(w, t)| if *t { Some(*w as u32) } else { None })
.collect();
let visible: Vec<bool> = self.succ.iter().map(|&n| n == 0).collect();
let visible = hexane::Column::from_values(visible);
let top: Vec<bool> = self.top.to_vec();
let top = hexane::PrefixColumn::from_values(top);
let inc = hexane::Column::from_values(self.incs);
let mut mark = MarkIndexColumn::new();
mark.extend(0, self.marks);
let obj_info = self.obj_info;
(
Indexes {
text,
top,
visible,
inc,
mark,
obj_info,
},
self.mark_order,
)
}
}
fn vis_num(op: &Op<'_>) -> u32 {
if op.is_inc() {
u32::MAX
} else {
op.succ().len() as u32
}
}