use std::cmp::Ordering;
use idx_sized::{
IdxSized
,IdSet
,RemoveResult
};
use various_data_file::VariousDataFile;
pub mod entity;
use entity::FieldEntity;
pub enum ConditionField{
Match(Vec<u8>)
,Range(Vec<u8>,Vec<u8>)
,Min(Vec<u8>)
,Max(Vec<u8>)
,Forward(String)
,Partial(String)
,Backward(String)
}
pub struct Field{
index: IdxSized<FieldEntity>
,strings:VariousDataFile
}
impl Field{
pub fn new(path_prefix:&str) -> Result<Field,std::io::Error>{
match IdxSized::new(&(path_prefix.to_string()+".i")){
Err(e)=>Err(e)
,Ok(index)=>{
match VariousDataFile::new(&(path_prefix.to_string()+".d")){
Ok(strings)=>Ok(Field{
index
,strings
})
,Err(e)=>Err(e)
}
}
}
}
pub fn entity<'a>(&self,id:u32)->Option<&'a FieldEntity>{
if let Some(v)=self.index.triee().entity_value(id){
Some(&v)
}else{
None
}
}
pub fn str<'a>(&self,id:u32)->Option<&'a str>{
if let Some(e)=self.entity(id){
std::str::from_utf8(unsafe{
std::slice::from_raw_parts(self.strings.offset(e.addr()) as *const u8,e.len())
}).ok()
}else{
None
}
}
pub fn num(&self,id:u32)->Option<f64>{
if let Some(e)=self.entity(id){
Some(e.num())
}else{
None
}
}
pub fn update(&mut self,id:u32,content:&[u8]) -> Option<u32>{
if let RemoveResult::Unique(data)=self.index.delete(id){
self.strings.remove(&data.data_address()); }
let cont=std::str::from_utf8(content).unwrap();
let tree=self.index.triee();
let (ord,found_id)=tree.search_cb(|data|->Ordering{
let str2=std::str::from_utf8(self.strings.slice(data.data_address())).unwrap();
if cont==str2{
Ordering::Equal
}else{
natord::compare(cont,str2)
}
});
if ord==Ordering::Equal && found_id!=0{
if let Some(_node)=self.index.triee().node(id){
self.index.triee_mut().update_same(found_id,id);
Some(id)
}else{
self.index.insert_same(found_id,id)
}
}else{
if let Some(data_address)=self.strings.insert(content){
let e=FieldEntity::new(
data_address.address()
,cont.parse().unwrap_or(0.0)
);
if let Some(_entity)=self.index.triee().node(id){
self.index.triee_mut().update_node(
found_id
,id
,e
,ord
);
Some(id)
}else{
self.index.insert_unique(e,found_id,ord,id)
}
}else{
None
}
}
}
pub fn delete(&mut self,id:u32){
self.index.delete(id);
}
pub fn search(&self,condition:&ConditionField)->IdSet{
match condition{
ConditionField::Match(v)=>{
self.search_match(&v)
}
,ConditionField::Min(min)=>{
self.search_min(&min)
}
,ConditionField::Max(max)=>{
self.search_max(&max)
}
,ConditionField::Range(min,max)=>{
self.search_range(&min,&max)
}
,ConditionField::Forward(cont)=>{
self.search_forward(&cont)
}
,ConditionField::Partial(cont)=>{
self.search_partial(&cont)
}
,ConditionField::Backward(cont)=>{
self.search_backward(&cont)
}
}
}
fn search_match(&self,cont:&[u8])->IdSet{
let mut r:IdSet=IdSet::default();
let (ord,found_id)=self.search_cb(cont);
if ord==Ordering::Equal{
r.insert(found_id);
for v in self.index.triee().sames(found_id){
r.insert(v);
}
}
r
}
fn search_min(&self,min:&[u8])->IdSet{
let mut r:IdSet=IdSet::default();
let (_,min_found_id)=self.search_cb(min);
for (_,id,_) in self.index.triee().iter_by_id_from(min_found_id){
r.insert(id);
for v in self.index.triee().sames(min_found_id){
r.insert(v);
}
}
r
}
fn search_max(&self,max:&[u8])->IdSet{
let mut r:IdSet=IdSet::default();
let (_,max_found_id)=self.search_cb(max);
for (_,id,_) in self.index.triee().iter_by_id_to(max_found_id){
r.insert(id);
for v in self.index.triee().sames(max_found_id){
r.insert(v);
}
}
r
}
fn search_range(&self,min:&[u8],max:&[u8])->IdSet{
let mut r:IdSet=IdSet::default();
let (_,min_found_id)=self.search_cb(min);
let (_,max_found_id)=self.search_cb(max);
for (_,id,_) in self.index.triee().iter_by_id_from_to(min_found_id,max_found_id){
r.insert(id);
for v in self.index.triee().sames(max_found_id){
r.insert(v);
}
}
r
}
fn search_forward(&self,cont:&str)->IdSet{
let mut r:IdSet=IdSet::default();
let len=cont.len();
for (_,id,v) in self.index.triee().iter(){
let data=v.value();
if len<=data.len(){
if let Ok(str2)=std::str::from_utf8(unsafe{
std::slice::from_raw_parts(self.strings.offset(data.addr()) as *const u8,len)
}){
if cont==str2{
r.insert(id);
}
}
}
}
r
}
fn search_partial(&self,cont:&str)->IdSet{
let mut r:IdSet=IdSet::default();
let len=cont.len();
for (_,id,v) in self.index.triee().iter(){
let data=v.value();
if len<=data.len(){
if let Ok(str2)=std::str::from_utf8(unsafe{
std::slice::from_raw_parts(self.strings.offset(data.addr()) as *const u8,data.len())
}){
if str2.contains(cont){
r.insert(id);
}
}
}
}
r
}
fn search_backward(&self,cont:&str)->IdSet{
let mut r:IdSet=IdSet::default();
let len=cont.len();
for (_,id,v) in self.index.triee().iter(){
let data=v.value();
if len<=data.len(){
if let Ok(str2)=std::str::from_utf8(unsafe{
std::slice::from_raw_parts(self.strings.offset(data.addr()) as *const u8,data.len())
}){
if str2.ends_with(cont){
r.insert(id);
}
}
}
}
r
}
fn search_cb(&self,cont:&[u8])->(Ordering,u32){
self.index.triee().search_cb(|data|->Ordering{
let str2=unsafe{
std::slice::from_raw_parts(self.strings.offset(data.addr()) as *const u8,data.len())
};
if cont==str2{
Ordering::Equal
}else{
natord::compare(
std::str::from_utf8(cont).unwrap()
,std::str::from_utf8(str2).unwrap()
)
}
})
}
}