1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use std::cmp::Ordering;

use idx_sized::{
    IdxSized
    ,Removed
    ,Avltriee
};
use various_data_file::VariousDataFile;

pub mod entity;
use entity::FieldEntity;

pub struct FieldData{
    index: IdxSized<FieldEntity>
    ,data_file:VariousDataFile
}
impl FieldData{
    pub fn new(path_prefix:&str)->Result<Self,std::io::Error>{
        let index=IdxSized::new(&(path_prefix.to_string()+".i"))?;
        let data_file=VariousDataFile::new(&(path_prefix.to_string()+".d"))?;
        Ok(FieldData{
            index
            ,data_file
        })
    }
    pub fn entity(&self,row:u32)->Option<&FieldEntity>{
        if let Some(v)=self.index.triee().value(row){
            Some(&v)
        }else{
            None
        }
    }
    pub fn get<'a>(&self,row:u32)->Option<&'a [u8]>{
        if let Some(e)=self.entity(row){
            Some(unsafe{
                std::slice::from_raw_parts(self.data_file.offset(e.addr()) as *const u8,e.len())
            })
        }else{
            None
        }
    }
    pub fn num(&self,row:u32)->Option<f64>{
        if let Some(e)=self.entity(row){
            Some(e.num())
        }else{
            None
        }
    }
    pub fn index(&self)->&IdxSized<FieldEntity>{
        &self.index
    }
    pub fn triee(&self)->&Avltriee<FieldEntity>{
        &self.index.triee()
    }
    pub fn update(&mut self,row:u32,content:&[u8])->Result<u32,std::io::Error>{
        if let Some(org)=self.index.value(row){
            //データが存在し、
            if self.data_file.bytes(org.data_address())==content{   //変更が無ければ何もしない
                return Ok(row);
            }
            //変更がある場合はまず消去
            if let Removed::Last(data)=self.index.delete(row){
                self.data_file.remove(&data.data_address());    //削除対象がユニークの場合は対象文字列を完全削除
            }
        }
    
        let cont_str=std::str::from_utf8(content).unwrap();
        let tree=self.index.triee();
        let (ord,found_row)=tree.search_cb(|data|->Ordering{
            let bytes=self.data_file.bytes(data.data_address());
            if content==bytes{
                Ordering::Equal
            }else{
                natord::compare(cont_str,std::str::from_utf8(bytes).unwrap())
            }
        });
        if ord==Ordering::Equal && found_row!=0{
           self.index.insert_same(found_row,row)
        }else{
            //新しく作る
            let data_address=self.data_file.insert(content)?;
            let e=FieldEntity::new(
                data_address.address()
                ,cont_str.parse().unwrap_or(0.0)
            );
            if let Some(_entity)=self.index.triee().node(row){
                //既存データの更新処理
                self.index.triee_mut().update_node(
                    found_row
                    ,row
                    ,e
                    ,ord
                );
                Ok(row)
            }else{
                //追加
                self.index.insert_unique(e,found_row,ord,row)
            }
        }
    }
    pub fn delete(&mut self,row:u32){
        self.index.delete(row);
    }
    
    pub(crate) fn search_cb(&self,cont:&[u8])->(Ordering,u32){
        self.index.triee().search_cb(|data|->Ordering{
            let str2=unsafe{
                std::slice::from_raw_parts(self.data_file.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()
                )
            }
        })
    }
}

#[test]
fn test(){
    let dir="./vd-test-fd/";
    if std::path::Path::new(dir).exists(){
        std::fs::remove_dir_all(dir).unwrap();
    }
    std::fs::create_dir_all(dir).unwrap();
    if let Ok(mut fd)=FieldData::new(&(dir.to_owned()+"test")){
        fd.update(1,b"Noah").unwrap();
        fd.update(2,b"Liam").unwrap();
        fd.update(3,b"Olivia").unwrap();
        fd.update(1,b"Renamed Noah").unwrap();
        fd.update(2,b"Renamed Liam").unwrap();
        fd.update(3,b"Renamed Olivia").unwrap();
        fd.update(4,b"Noah").unwrap();
        fd.update(5,b"Liam").unwrap();
        fd.update(6,b"Olivia").unwrap();
        fd.update(1,b"Renamed Renamed Noah").unwrap();
        fd.update(2,b"Renamed Renamed Liam").unwrap();
        fd.update(3,b"Renamed Renamed Olivia").unwrap();
        fd.update(4,b"Renamed Noah").unwrap();
        fd.update(5,b"Renamed Liam").unwrap();
        fd.update(6,b"Renamed Olivia").unwrap();
    }
}