middlemac 3.1.0 → 3.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +6 -0
- data/CHANGELOG.md +17 -1
- data/Rakefile +16 -5
- data/documentation_project/Contents/Resources/SharedGlobalAssets/_layouts/layout-apple-modern.haml +2 -2
- data/documentation_project/Gemfile +2 -2
- data/documentation_project/config.rb +6 -5
- data/ext/trie/darray.c +673 -0
- data/ext/trie/darray.h +233 -0
- data/ext/trie/extconf.rb +23 -0
- data/ext/trie/fileutils.c +151 -0
- data/ext/trie/fileutils.h +36 -0
- data/ext/trie/tail.c +340 -0
- data/ext/trie/tail.h +207 -0
- data/ext/trie/trie-private.c +299 -0
- data/ext/trie/trie-private.h +31 -0
- data/ext/trie/trie.c +628 -0
- data/ext/trie/trie.h +40 -0
- data/ext/trie/triedefs.h +73 -0
- data/ext/trie/typedefs.h +117 -0
- data/features/helpers_features.feature +8 -9
- data/features/main_features.feature +3 -3
- data/fixtures/middlemac_app/Gemfile +2 -2
- data/fixtures/middlemac_app/config.rb +7 -9
- data/lib/middlemac.rb +1 -1
- data/lib/middlemac/extension.rb +5 -1
- data/lib/middlemac/{trie.rb → trie-extension.rb} +0 -0
- data/lib/middlemac/version.rb +1 -1
- data/middlemac.gemspec +20 -2
- metadata +51 -34
data/ext/trie/darray.h
ADDED
@@ -0,0 +1,233 @@
|
|
1
|
+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2
|
+
/*
|
3
|
+
* darray.h - Double-array trie structure
|
4
|
+
* Created: 2006-08-11
|
5
|
+
* Author: Theppitak Karoonboonyanan <thep@linux.thai.net>
|
6
|
+
*/
|
7
|
+
|
8
|
+
#ifndef __DARRAY_H
|
9
|
+
#define __DARRAY_H
|
10
|
+
|
11
|
+
#include "triedefs.h"
|
12
|
+
|
13
|
+
/**
|
14
|
+
* @file darray.h
|
15
|
+
* @brief Double-array trie structure
|
16
|
+
*/
|
17
|
+
|
18
|
+
/**
|
19
|
+
* @brief Double-array structure type
|
20
|
+
*/
|
21
|
+
typedef struct _DArray DArray;
|
22
|
+
|
23
|
+
/**
|
24
|
+
* @brief Double-array entry enumeration function
|
25
|
+
*
|
26
|
+
* @param key : the key of the entry, up to @a sep_node
|
27
|
+
* @param sep_node : the separate node of the entry
|
28
|
+
* @param user_data : user-supplied data
|
29
|
+
*
|
30
|
+
* @return TRUE to continue enumeration, FALSE to stop
|
31
|
+
*/
|
32
|
+
typedef Bool (*DAEnumFunc) (const TrieChar *key,
|
33
|
+
TrieIndex sep_node,
|
34
|
+
void *user_data);
|
35
|
+
|
36
|
+
|
37
|
+
/**
|
38
|
+
* @brief Create a new double-array object
|
39
|
+
*
|
40
|
+
* Create a new empty doubla-array object.
|
41
|
+
*/
|
42
|
+
DArray * da_new ();
|
43
|
+
|
44
|
+
/**
|
45
|
+
* @brief Read double-array data from file
|
46
|
+
*
|
47
|
+
* @param file : the file to read
|
48
|
+
*
|
49
|
+
* @return a pointer to the openned double-array, NULL on failure
|
50
|
+
*
|
51
|
+
* Read double-array data from the opened file, starting from the current
|
52
|
+
* file pointer until the end of double array data block. On return, the
|
53
|
+
* file pointer is left at the position after the read block.
|
54
|
+
*/
|
55
|
+
DArray * da_read (FILE *file);
|
56
|
+
|
57
|
+
/**
|
58
|
+
* @brief Free double-array data
|
59
|
+
*
|
60
|
+
* @param d : the double-array data
|
61
|
+
*
|
62
|
+
* Free the given double-array data.
|
63
|
+
*/
|
64
|
+
void da_free (DArray *d);
|
65
|
+
|
66
|
+
/**
|
67
|
+
* @brief Write double-array data
|
68
|
+
*
|
69
|
+
* @param d : the double-array data
|
70
|
+
* @param file : the file to write to
|
71
|
+
*
|
72
|
+
* @return 0 on success, non-zero on failure
|
73
|
+
*
|
74
|
+
* Write double-array data to the given @a file, starting from the current
|
75
|
+
* file pointer. On return, the file pointer is left after the double-array
|
76
|
+
* data block.
|
77
|
+
*/
|
78
|
+
int da_write (const DArray *d, FILE *file);
|
79
|
+
|
80
|
+
|
81
|
+
/**
|
82
|
+
* @brief Get root state
|
83
|
+
*
|
84
|
+
* @param d : the double-array data
|
85
|
+
*
|
86
|
+
* @return root state of the @a index set, or TRIE_INDEX_ERROR on failure
|
87
|
+
*
|
88
|
+
* Get root state for stepwise walking.
|
89
|
+
*/
|
90
|
+
TrieIndex da_get_root (const DArray *d);
|
91
|
+
|
92
|
+
|
93
|
+
/**
|
94
|
+
* @brief Get BASE cell
|
95
|
+
*
|
96
|
+
* @param d : the double-array data
|
97
|
+
* @param s : the double-array state to get data
|
98
|
+
*
|
99
|
+
* @return the BASE cell value for the given state
|
100
|
+
*
|
101
|
+
* Get BASE cell value for the given state.
|
102
|
+
*/
|
103
|
+
TrieIndex da_get_base (const DArray *d, TrieIndex s);
|
104
|
+
|
105
|
+
/**
|
106
|
+
* @brief Get CHECK cell
|
107
|
+
*
|
108
|
+
* @param d : the double-array data
|
109
|
+
* @param s : the double-array state to get data
|
110
|
+
*
|
111
|
+
* @return the CHECK cell value for the given state
|
112
|
+
*
|
113
|
+
* Get CHECK cell value for the given state.
|
114
|
+
*/
|
115
|
+
TrieIndex da_get_check (const DArray *d, TrieIndex s);
|
116
|
+
|
117
|
+
|
118
|
+
/**
|
119
|
+
* @brief Set BASE cell
|
120
|
+
*
|
121
|
+
* @param d : the double-array data
|
122
|
+
* @param s : the double-array state to get data
|
123
|
+
* @param val : the value to set
|
124
|
+
*
|
125
|
+
* Set BASE cell for the given state to the given value.
|
126
|
+
*/
|
127
|
+
void da_set_base (DArray *d, TrieIndex s, TrieIndex val);
|
128
|
+
|
129
|
+
/**
|
130
|
+
* @brief Set CHECK cell
|
131
|
+
*
|
132
|
+
* @param d : the double-array data
|
133
|
+
* @param s : the double-array state to get data
|
134
|
+
* @param val : the value to set
|
135
|
+
*
|
136
|
+
* Set CHECK cell for the given state to the given value.
|
137
|
+
*/
|
138
|
+
void da_set_check (DArray *d, TrieIndex s, TrieIndex val);
|
139
|
+
|
140
|
+
/**
|
141
|
+
* @brief Walk in double-array structure
|
142
|
+
*
|
143
|
+
* @param d : the double-array structure
|
144
|
+
* @param s : current state
|
145
|
+
* @param c : the input character
|
146
|
+
*
|
147
|
+
* @return boolean indicating success
|
148
|
+
*
|
149
|
+
* Walk the double-array trie from state @a *s, using input character @a c.
|
150
|
+
* If there exists an edge from @a *s with arc labeled @a c, this function
|
151
|
+
* returns TRUE and @a *s is updated to the new state. Otherwise, it returns
|
152
|
+
* FALSE and @a *s is left unchanged.
|
153
|
+
*/
|
154
|
+
Bool da_walk (const DArray *d, TrieIndex *s, TrieChar c);
|
155
|
+
|
156
|
+
/**
|
157
|
+
* @brief Test walkability in double-array structure
|
158
|
+
*
|
159
|
+
* @param d : the double-array structure
|
160
|
+
* @param s : current state
|
161
|
+
* @param c : the input character
|
162
|
+
*
|
163
|
+
* @return boolean indicating walkability
|
164
|
+
*
|
165
|
+
* Test if there is a transition from state @a s with input character @a c.
|
166
|
+
*/
|
167
|
+
/*
|
168
|
+
Bool da_is_walkable (DArray *d, TrieIndex s, TrieChar c);
|
169
|
+
*/
|
170
|
+
#define da_is_walkable(d,s,c) \
|
171
|
+
(da_get_check ((d), da_get_base ((d), (s)) + (c)) == (s))
|
172
|
+
|
173
|
+
/**
|
174
|
+
* @brief Insert a branch from trie node
|
175
|
+
*
|
176
|
+
* @param d : the double-array structure
|
177
|
+
* @param s : the state to add branch to
|
178
|
+
* @param c : the character for the branch label
|
179
|
+
*
|
180
|
+
* @return the index of the new node
|
181
|
+
*
|
182
|
+
* Insert a new arc labelled with character @a c from the trie node
|
183
|
+
* represented by index @a s in double-array structure @a d.
|
184
|
+
* Note that it assumes that no such arc exists before inserting.
|
185
|
+
*/
|
186
|
+
TrieIndex da_insert_branch (DArray *d, TrieIndex s, TrieChar c);
|
187
|
+
|
188
|
+
/**
|
189
|
+
* @brief Prune the single branch
|
190
|
+
*
|
191
|
+
* @param d : the double-array structure
|
192
|
+
* @param s : the dangling state to prune off
|
193
|
+
*
|
194
|
+
* Prune off a non-separate path up from the final state @a s.
|
195
|
+
* If @a s still has some children states, it does nothing. Otherwise,
|
196
|
+
* it deletes the node and all its parents which become non-separate.
|
197
|
+
*/
|
198
|
+
void da_prune (DArray *d, TrieIndex s);
|
199
|
+
|
200
|
+
/**
|
201
|
+
* @brief Prune the single branch up to given parent
|
202
|
+
*
|
203
|
+
* @param d : the double-array structure
|
204
|
+
* @param p : the parent up to which to be pruned
|
205
|
+
* @param s : the dangling state to prune off
|
206
|
+
*
|
207
|
+
* Prune off a non-separate path up from the final state @a s to the
|
208
|
+
* given parent @a p. The prunning stop when either the parent @a p
|
209
|
+
* is met, or a first non-separate node is found.
|
210
|
+
*/
|
211
|
+
void da_prune_upto (DArray *d, TrieIndex p, TrieIndex s);
|
212
|
+
|
213
|
+
/**
|
214
|
+
* @brief Enumerate entries stored in double-array structure
|
215
|
+
*
|
216
|
+
* @param d : the double-array structure
|
217
|
+
* @param enum_func : the callback function to be called on each separate node
|
218
|
+
* @param user_data : user-supplied data to send as an argument to @a enum_func
|
219
|
+
*
|
220
|
+
* @return boolean value indicating whether all the keys are visited
|
221
|
+
*
|
222
|
+
* Enumerate all keys stored in double-array structure. For each entry, the
|
223
|
+
* user-supplied @a enum_func callback function is called, with the entry key,
|
224
|
+
* the separate node, and user-supplied data. Returning FALSE from such
|
225
|
+
* callback will stop enumeration and return FALSE.
|
226
|
+
*/
|
227
|
+
Bool da_enumerate (const DArray *d, DAEnumFunc enum_func, void *user_data);
|
228
|
+
|
229
|
+
#endif /* __DARRAY_H */
|
230
|
+
|
231
|
+
/*
|
232
|
+
vi:ts=4:ai:expandtab
|
233
|
+
*/
|
data/ext/trie/extconf.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
##
|
4
|
+
## Avoid warnings, since newer versions of Xcode by default try to make more and more
|
5
|
+
## warnings.
|
6
|
+
##
|
7
|
+
append_cflags("-Wno-missing-noreturn")
|
8
|
+
append_cflags("-Wno-shorten-64-to-32")
|
9
|
+
append_cflags("-Wno-return-type")
|
10
|
+
append_cflags("-Wno-sign-compare")
|
11
|
+
append_cflags("-Wno-unused-function")
|
12
|
+
append_cflags("-Wno-incompatible-pointer-types")
|
13
|
+
puts "=-=-=-=-=-=-"
|
14
|
+
puts $CFLAGS
|
15
|
+
puts "=-=-=-=-=-=-"
|
16
|
+
|
17
|
+
|
18
|
+
##
|
19
|
+
## If we want it to be installed in lib/trie, then we have to create the makefile
|
20
|
+
## in this nested format, too, otherwise lib_dir works for rake compile, but not
|
21
|
+
## for rake install.
|
22
|
+
##
|
23
|
+
create_makefile 'trie/trie'
|
@@ -0,0 +1,151 @@
|
|
1
|
+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2
|
+
/*
|
3
|
+
* fileutils.h - File utility functions
|
4
|
+
* Created: 2006-08-15
|
5
|
+
* Author: Theppitak Karoonboonyanan <thep@linux.thai.net>
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include <string.h>
|
9
|
+
#include <stdlib.h>
|
10
|
+
|
11
|
+
#include "fileutils.h"
|
12
|
+
|
13
|
+
/*--------------------------------------*
|
14
|
+
* INTERNAL FUNCTIONS DECLARATIONS *
|
15
|
+
*--------------------------------------*/
|
16
|
+
|
17
|
+
static char * make_full_path (const char *dir,
|
18
|
+
const char *name,
|
19
|
+
const char *ext);
|
20
|
+
|
21
|
+
/* ==================== BEGIN IMPLEMENTATION PART ==================== */
|
22
|
+
|
23
|
+
/*--------------------------------*
|
24
|
+
* FUNCTIONS IMPLEMENTATIONS *
|
25
|
+
*--------------------------------*/
|
26
|
+
|
27
|
+
static char *
|
28
|
+
make_full_path (const char *dir, const char *name, const char *ext)
|
29
|
+
{
|
30
|
+
char *path;
|
31
|
+
|
32
|
+
path = (char *) malloc (strlen (dir) + strlen (name) + strlen (ext) + 2);
|
33
|
+
sprintf (path, "%s/%s%s", dir, name, ext);
|
34
|
+
|
35
|
+
return path;
|
36
|
+
}
|
37
|
+
|
38
|
+
FILE *
|
39
|
+
file_open (const char *dir, const char *name, const char *ext, TrieIOMode mode)
|
40
|
+
{
|
41
|
+
const char *std_mode;
|
42
|
+
char *full_path;
|
43
|
+
FILE *file;
|
44
|
+
|
45
|
+
if (mode & TRIE_IO_WRITE)
|
46
|
+
std_mode = "r+";
|
47
|
+
else
|
48
|
+
std_mode = "r";
|
49
|
+
|
50
|
+
full_path = make_full_path (dir, name, ext);
|
51
|
+
file = fopen (full_path, std_mode);
|
52
|
+
if (!file && mode & TRIE_IO_CREATE)
|
53
|
+
file = fopen (full_path, "w+");
|
54
|
+
free (full_path);
|
55
|
+
|
56
|
+
return file;
|
57
|
+
}
|
58
|
+
|
59
|
+
long
|
60
|
+
file_length (FILE *file)
|
61
|
+
{
|
62
|
+
long cur_pos;
|
63
|
+
long size;
|
64
|
+
|
65
|
+
cur_pos = ftell (file);
|
66
|
+
|
67
|
+
fseek (file, 0L, SEEK_END);
|
68
|
+
size = ftell (file);
|
69
|
+
|
70
|
+
fseek (file, cur_pos, SEEK_SET);
|
71
|
+
|
72
|
+
return size;
|
73
|
+
}
|
74
|
+
|
75
|
+
Bool
|
76
|
+
file_read_int32 (FILE *file, int32 *o_val)
|
77
|
+
{
|
78
|
+
unsigned char buff[4];
|
79
|
+
|
80
|
+
if (fread (buff, 4, 1, file) == 1) {
|
81
|
+
*o_val = (buff[0] << 24) | (buff[1] << 16) | (buff[2] << 8) | buff[3];
|
82
|
+
return TRUE;
|
83
|
+
}
|
84
|
+
|
85
|
+
return FALSE;
|
86
|
+
}
|
87
|
+
|
88
|
+
Bool
|
89
|
+
file_write_int32 (FILE *file, int32 val)
|
90
|
+
{
|
91
|
+
unsigned char buff[4];
|
92
|
+
|
93
|
+
buff[0] = (val >> 24) & 0xff;
|
94
|
+
buff[1] = (val >> 16) & 0xff;
|
95
|
+
buff[2] = (val >> 8) & 0xff;
|
96
|
+
buff[3] = val & 0xff;
|
97
|
+
|
98
|
+
return (fwrite (buff, 4, 1, file) == 1);
|
99
|
+
}
|
100
|
+
|
101
|
+
Bool
|
102
|
+
file_read_int16 (FILE *file, int16 *o_val)
|
103
|
+
{
|
104
|
+
unsigned char buff[2];
|
105
|
+
|
106
|
+
if (fread (buff, 2, 1, file) == 1) {
|
107
|
+
*o_val = (buff[0] << 8) | buff[1];
|
108
|
+
return TRUE;
|
109
|
+
}
|
110
|
+
|
111
|
+
return FALSE;
|
112
|
+
}
|
113
|
+
|
114
|
+
Bool
|
115
|
+
file_write_int16 (FILE *file, int16 val)
|
116
|
+
{
|
117
|
+
unsigned char buff[2];
|
118
|
+
|
119
|
+
buff[0] = val >> 8;
|
120
|
+
buff[1] = val & 0xff;
|
121
|
+
|
122
|
+
return (fwrite (buff, 2, 1, file) == 1);
|
123
|
+
}
|
124
|
+
|
125
|
+
Bool
|
126
|
+
file_read_int8 (FILE *file, int8 *o_val)
|
127
|
+
{
|
128
|
+
return (fread (o_val, sizeof (int8), 1, file) == 1);
|
129
|
+
}
|
130
|
+
|
131
|
+
Bool
|
132
|
+
file_write_int8 (FILE *file, int8 val)
|
133
|
+
{
|
134
|
+
return (fwrite (&val, sizeof (int8), 1, file) == 1);
|
135
|
+
}
|
136
|
+
|
137
|
+
Bool
|
138
|
+
file_read_chars (FILE *file, char *buff, int len)
|
139
|
+
{
|
140
|
+
return (fread (buff, sizeof (char), len, file) == len);
|
141
|
+
}
|
142
|
+
|
143
|
+
Bool
|
144
|
+
file_write_chars (FILE *file, const char *buff, int len)
|
145
|
+
{
|
146
|
+
return (fwrite (buff, sizeof (char), len, file) == len);
|
147
|
+
}
|
148
|
+
|
149
|
+
/*
|
150
|
+
vi:ts=4:ai:expandtab
|
151
|
+
*/
|
@@ -0,0 +1,36 @@
|
|
1
|
+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2
|
+
/*
|
3
|
+
* fileutils.h - File utility functions
|
4
|
+
* Created: 2006-08-14
|
5
|
+
* Author: Theppitak Karoonboonyanan <thep@linux.thai.net>
|
6
|
+
*/
|
7
|
+
|
8
|
+
#ifndef __FILEUTILS_H
|
9
|
+
#define __FILEUTILS_H
|
10
|
+
|
11
|
+
#include <stdio.h>
|
12
|
+
|
13
|
+
#include "triedefs.h"
|
14
|
+
|
15
|
+
FILE * file_open (const char *dir, const char *name, const char *ext,
|
16
|
+
TrieIOMode mode);
|
17
|
+
|
18
|
+
long file_length (FILE *file);
|
19
|
+
|
20
|
+
Bool file_read_int32 (FILE *file, int32 *o_val);
|
21
|
+
Bool file_write_int32 (FILE *file, int32 val);
|
22
|
+
|
23
|
+
Bool file_read_int16 (FILE *file, int16 *o_val);
|
24
|
+
Bool file_write_int16 (FILE *file, int16 val);
|
25
|
+
|
26
|
+
Bool file_read_int8 (FILE *file, int8 *o_val);
|
27
|
+
Bool file_write_int8 (FILE *file, int8 val);
|
28
|
+
|
29
|
+
Bool file_read_chars (FILE *file, char *buff, int len);
|
30
|
+
Bool file_write_chars (FILE *file, const char *buff, int len);
|
31
|
+
|
32
|
+
#endif /* __FILEUTILS_H */
|
33
|
+
|
34
|
+
/*
|
35
|
+
vi:ts=4:ai:expandtab
|
36
|
+
*/
|
data/ext/trie/tail.c
ADDED
@@ -0,0 +1,340 @@
|
|
1
|
+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2
|
+
/*
|
3
|
+
* tail.c - trie tail for keeping suffixes
|
4
|
+
* Created: 2006-08-15
|
5
|
+
* Author: Theppitak Karoonboonyanan <thep@linux.thai.net>
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include <string.h>
|
9
|
+
#include <stdlib.h>
|
10
|
+
#include <stdio.h>
|
11
|
+
|
12
|
+
#include "tail.h"
|
13
|
+
#include "fileutils.h"
|
14
|
+
|
15
|
+
/*----------------------------------*
|
16
|
+
* INTERNAL TYPES DECLARATIONS *
|
17
|
+
*----------------------------------*/
|
18
|
+
|
19
|
+
/*-----------------------------------*
|
20
|
+
* PRIVATE METHODS DECLARATIONS *
|
21
|
+
*-----------------------------------*/
|
22
|
+
|
23
|
+
static TrieIndex tail_alloc_block (Tail *t);
|
24
|
+
static void tail_free_block (Tail *t, TrieIndex block);
|
25
|
+
|
26
|
+
/* ==================== BEGIN IMPLEMENTATION PART ==================== */
|
27
|
+
|
28
|
+
/*------------------------------------*
|
29
|
+
* INTERNAL TYPES IMPLEMENTATIONS *
|
30
|
+
*------------------------------------*/
|
31
|
+
|
32
|
+
/*------------------------------*
|
33
|
+
* PRIVATE DATA DEFINITONS *
|
34
|
+
*------------------------------*/
|
35
|
+
|
36
|
+
typedef struct {
|
37
|
+
TrieIndex next_free;
|
38
|
+
TrieData data;
|
39
|
+
TrieChar *suffix;
|
40
|
+
} TailBlock;
|
41
|
+
|
42
|
+
struct _Tail {
|
43
|
+
TrieIndex num_tails;
|
44
|
+
TailBlock *tails;
|
45
|
+
TrieIndex first_free;
|
46
|
+
};
|
47
|
+
|
48
|
+
/*-----------------------------*
|
49
|
+
* METHODS IMPLEMENTAIONS *
|
50
|
+
*-----------------------------*/
|
51
|
+
|
52
|
+
#define TAIL_SIGNATURE 0xDFFCDFFC
|
53
|
+
#define TAIL_START_BLOCKNO 1
|
54
|
+
|
55
|
+
/* Tail Header:
|
56
|
+
* INT32: signature
|
57
|
+
* INT32: pointer to first free slot
|
58
|
+
* INT32: number of tail blocks
|
59
|
+
*
|
60
|
+
* Tail Blocks:
|
61
|
+
* INT32: pointer to next free block (-1 for allocated blocks)
|
62
|
+
* INT32: data for the key
|
63
|
+
* INT16: length
|
64
|
+
* BYTES[length]: suffix string (no terminating '\0')
|
65
|
+
*/
|
66
|
+
|
67
|
+
Tail *
|
68
|
+
tail_new ()
|
69
|
+
{
|
70
|
+
Tail *t;
|
71
|
+
|
72
|
+
t = (Tail *) malloc (sizeof (Tail));
|
73
|
+
if (!t)
|
74
|
+
return NULL;
|
75
|
+
|
76
|
+
t->first_free = 0;
|
77
|
+
t->num_tails = 0;
|
78
|
+
t->tails = NULL;
|
79
|
+
|
80
|
+
return t;
|
81
|
+
}
|
82
|
+
|
83
|
+
Tail *
|
84
|
+
tail_read (FILE *file)
|
85
|
+
{
|
86
|
+
long save_pos;
|
87
|
+
Tail *t;
|
88
|
+
TrieIndex i;
|
89
|
+
uint32 sig;
|
90
|
+
|
91
|
+
/* check signature */
|
92
|
+
save_pos = ftell (file);
|
93
|
+
if (!file_read_int32 (file, (int32 *) &sig) || TAIL_SIGNATURE != sig) {
|
94
|
+
fseek (file, save_pos, SEEK_SET);
|
95
|
+
return NULL;
|
96
|
+
}
|
97
|
+
|
98
|
+
t = (Tail *) malloc (sizeof (Tail));
|
99
|
+
if (!t)
|
100
|
+
return NULL;
|
101
|
+
|
102
|
+
file_read_int32 (file, &t->first_free);
|
103
|
+
file_read_int32 (file, &t->num_tails);
|
104
|
+
t->tails = (TailBlock *) malloc (t->num_tails * sizeof (TailBlock));
|
105
|
+
if (!t->tails)
|
106
|
+
goto exit_tail_created;
|
107
|
+
for (i = 0; i < t->num_tails; i++) {
|
108
|
+
int16 length;
|
109
|
+
|
110
|
+
file_read_int32 (file, &t->tails[i].next_free);
|
111
|
+
file_read_int32 (file, &t->tails[i].data);
|
112
|
+
|
113
|
+
file_read_int16 (file, &length);
|
114
|
+
t->tails[i].suffix = (TrieChar *) malloc (length + 1);
|
115
|
+
if (length > 0)
|
116
|
+
file_read_chars (file, (char *)t->tails[i].suffix, length);
|
117
|
+
t->tails[i].suffix[length] = '\0';
|
118
|
+
}
|
119
|
+
|
120
|
+
return t;
|
121
|
+
|
122
|
+
exit_tail_created:
|
123
|
+
free (t);
|
124
|
+
return NULL;
|
125
|
+
}
|
126
|
+
|
127
|
+
void
|
128
|
+
tail_free (Tail *t)
|
129
|
+
{
|
130
|
+
TrieIndex i;
|
131
|
+
|
132
|
+
if (t->tails) {
|
133
|
+
for (i = 0; i < t->num_tails; i++)
|
134
|
+
if (t->tails[i].suffix)
|
135
|
+
free (t->tails[i].suffix);
|
136
|
+
free (t->tails);
|
137
|
+
}
|
138
|
+
free (t);
|
139
|
+
}
|
140
|
+
|
141
|
+
int
|
142
|
+
tail_write (const Tail *t, FILE *file)
|
143
|
+
{
|
144
|
+
TrieIndex i;
|
145
|
+
|
146
|
+
if (!file_write_int32 (file, TAIL_SIGNATURE) ||
|
147
|
+
!file_write_int32 (file, t->first_free) ||
|
148
|
+
!file_write_int32 (file, t->num_tails))
|
149
|
+
{
|
150
|
+
return -1;
|
151
|
+
}
|
152
|
+
for (i = 0; i < t->num_tails; i++) {
|
153
|
+
int16 length;
|
154
|
+
|
155
|
+
if (!file_write_int32 (file, t->tails[i].next_free) ||
|
156
|
+
!file_write_int32 (file, t->tails[i].data))
|
157
|
+
{
|
158
|
+
return -1;
|
159
|
+
}
|
160
|
+
|
161
|
+
length = t->tails[i].suffix ? strlen ((const char *)t->tails[i].suffix)
|
162
|
+
: 0;
|
163
|
+
if (!file_write_int16 (file, length))
|
164
|
+
return -1;
|
165
|
+
if (length > 0 &&
|
166
|
+
!file_write_chars (file, (char *)t->tails[i].suffix, length))
|
167
|
+
{
|
168
|
+
return -1;
|
169
|
+
}
|
170
|
+
}
|
171
|
+
|
172
|
+
return 0;
|
173
|
+
}
|
174
|
+
|
175
|
+
|
176
|
+
const TrieChar *
|
177
|
+
tail_get_suffix (const Tail *t, TrieIndex index)
|
178
|
+
{
|
179
|
+
index -= TAIL_START_BLOCKNO;
|
180
|
+
return (index < t->num_tails) ? t->tails[index].suffix : NULL;
|
181
|
+
}
|
182
|
+
|
183
|
+
Bool
|
184
|
+
tail_set_suffix (Tail *t, TrieIndex index, const TrieChar *suffix)
|
185
|
+
{
|
186
|
+
index -= TAIL_START_BLOCKNO;
|
187
|
+
if (index < t->num_tails) {
|
188
|
+
/* suffix and t->tails[index].suffix may overlap;
|
189
|
+
* so, dup it before it's overwritten
|
190
|
+
*/
|
191
|
+
TrieChar *tmp = NULL;
|
192
|
+
if (suffix)
|
193
|
+
tmp = (TrieChar *) strdup ((const char *)suffix);
|
194
|
+
if (t->tails[index].suffix)
|
195
|
+
free (t->tails[index].suffix);
|
196
|
+
t->tails[index].suffix = tmp;
|
197
|
+
|
198
|
+
return TRUE;
|
199
|
+
}
|
200
|
+
return FALSE;
|
201
|
+
}
|
202
|
+
|
203
|
+
TrieIndex
|
204
|
+
tail_add_suffix (Tail *t, const TrieChar *suffix)
|
205
|
+
{
|
206
|
+
TrieIndex new_block;
|
207
|
+
|
208
|
+
new_block = tail_alloc_block (t);
|
209
|
+
tail_set_suffix (t, new_block, suffix);
|
210
|
+
|
211
|
+
return new_block;
|
212
|
+
}
|
213
|
+
|
214
|
+
static TrieIndex
|
215
|
+
tail_alloc_block (Tail *t)
|
216
|
+
{
|
217
|
+
TrieIndex block;
|
218
|
+
|
219
|
+
if (0 != t->first_free) {
|
220
|
+
block = t->first_free;
|
221
|
+
t->first_free = t->tails[block].next_free;
|
222
|
+
} else {
|
223
|
+
block = t->num_tails;
|
224
|
+
t->tails = (TailBlock *) realloc (t->tails,
|
225
|
+
++t->num_tails * sizeof (TailBlock));
|
226
|
+
}
|
227
|
+
t->tails[block].next_free = -1;
|
228
|
+
t->tails[block].data = TRIE_DATA_ERROR;
|
229
|
+
t->tails[block].suffix = NULL;
|
230
|
+
|
231
|
+
return block + TAIL_START_BLOCKNO;
|
232
|
+
}
|
233
|
+
|
234
|
+
static void
|
235
|
+
tail_free_block (Tail *t, TrieIndex block)
|
236
|
+
{
|
237
|
+
TrieIndex i, j;
|
238
|
+
|
239
|
+
block -= TAIL_START_BLOCKNO;
|
240
|
+
|
241
|
+
if (block >= t->num_tails)
|
242
|
+
return;
|
243
|
+
|
244
|
+
t->tails[block].data = TRIE_DATA_ERROR;
|
245
|
+
if (NULL != t->tails[block].suffix) {
|
246
|
+
free (t->tails[block].suffix);
|
247
|
+
t->tails[block].suffix = NULL;
|
248
|
+
}
|
249
|
+
|
250
|
+
/* find insertion point */
|
251
|
+
j = 0;
|
252
|
+
for (i = t->first_free; i != 0 && i < block; i = t->tails[i].next_free)
|
253
|
+
j = i;
|
254
|
+
|
255
|
+
/* insert free block between j and i */
|
256
|
+
t->tails[block].next_free = i;
|
257
|
+
if (0 != j)
|
258
|
+
t->tails[j].next_free = block;
|
259
|
+
else
|
260
|
+
t->first_free = block;
|
261
|
+
}
|
262
|
+
|
263
|
+
TrieData
|
264
|
+
tail_get_data (const Tail *t, TrieIndex index)
|
265
|
+
{
|
266
|
+
index -= TAIL_START_BLOCKNO;
|
267
|
+
return (index < t->num_tails) ? t->tails[index].data : TRIE_DATA_ERROR;
|
268
|
+
}
|
269
|
+
|
270
|
+
Bool
|
271
|
+
tail_set_data (Tail *t, TrieIndex index, TrieData data)
|
272
|
+
{
|
273
|
+
index -= TAIL_START_BLOCKNO;
|
274
|
+
if (index < t->num_tails) {
|
275
|
+
t->tails[index].data = data;
|
276
|
+
return TRUE;
|
277
|
+
}
|
278
|
+
return FALSE;
|
279
|
+
}
|
280
|
+
|
281
|
+
void
|
282
|
+
tail_delete (Tail *t, TrieIndex index)
|
283
|
+
{
|
284
|
+
tail_free_block (t, index);
|
285
|
+
}
|
286
|
+
|
287
|
+
int
|
288
|
+
tail_walk_str (const Tail *t,
|
289
|
+
TrieIndex s,
|
290
|
+
short *suffix_idx,
|
291
|
+
const TrieChar *str,
|
292
|
+
int len)
|
293
|
+
{
|
294
|
+
const TrieChar *suffix;
|
295
|
+
int i;
|
296
|
+
short j;
|
297
|
+
|
298
|
+
suffix = tail_get_suffix (t, s);
|
299
|
+
if (!suffix)
|
300
|
+
return FALSE;
|
301
|
+
|
302
|
+
i = 0; j = *suffix_idx;
|
303
|
+
while (i < len) {
|
304
|
+
if (str[i] != suffix[j])
|
305
|
+
break;
|
306
|
+
++i;
|
307
|
+
/* stop and stay at null-terminator */
|
308
|
+
if (0 == suffix[j])
|
309
|
+
break;
|
310
|
+
++j;
|
311
|
+
}
|
312
|
+
*suffix_idx = j;
|
313
|
+
return i;
|
314
|
+
}
|
315
|
+
|
316
|
+
Bool
|
317
|
+
tail_walk_char (const Tail *t,
|
318
|
+
TrieIndex s,
|
319
|
+
short *suffix_idx,
|
320
|
+
TrieChar c)
|
321
|
+
{
|
322
|
+
const TrieChar *suffix;
|
323
|
+
TrieChar suffix_char;
|
324
|
+
|
325
|
+
suffix = tail_get_suffix (t, s);
|
326
|
+
if (!suffix)
|
327
|
+
return FALSE;
|
328
|
+
|
329
|
+
suffix_char = suffix[*suffix_idx];
|
330
|
+
if (suffix_char == c) {
|
331
|
+
if (0 != suffix_char)
|
332
|
+
++*suffix_idx;
|
333
|
+
return TRUE;
|
334
|
+
}
|
335
|
+
return FALSE;
|
336
|
+
}
|
337
|
+
|
338
|
+
/*
|
339
|
+
vi:ts=4:ai:expandtab
|
340
|
+
*/
|