]> mj.ucw.cz Git - libucw.git/blob - lib/sorter/sorter.h
Remember size of the input file.
[libucw.git] / lib / sorter / sorter.h
1 /*
2  *      UCW Library -- Universal Sorter
3  *
4  *      (c) 2001--2007 Martin Mares <mj@ucw.cz>
5  *      (c) 2004 Robert Spalek <robert@ucw.cz>
6  *
7  *      This software may be freely distributed and used according to the terms
8  *      of the GNU Lesser General Public License.
9  */
10
11 /*
12  *  This is not a normal header file, but a generator of sorting
13  *  routines.  Each time you include it with parameters set in the
14  *  corresponding preprocessor macros, it generates a file sorter
15  *  with the parameters given.
16  *
17  *  FIXME: explain the basics (keys and data, callbacks etc.)
18  *
19  *  Basic parameters and callbacks:
20  *
21  *  SORT_PREFIX(x)      add a name prefix (used on all global names
22  *                      defined by the sorter)
23  *
24  *  SORT_KEY            data type capable of storing a single key.
25  *  SORT_KEY_REGULAR    data type holding a single key both in memory and on disk;
26  *                      in this case, bread() and bwrite() is used to read/write keys
27  *                      and it's also assumed that the keys are not very long.
28  *  int PREFIX_compare(SORT_KEY *a, SORT_KEY *b)
29  *                      compares two keys, result like strcmp(). Mandatory.
30  *  int PREFIX_read_key(struct fastbuf *f, SORT_KEY *k)
31  *                      reads a key from a fastbuf, returns nonzero=ok, 0=EOF.
32  *                      Mandatory unless SORT_KEY_REGULAR is defined.
33  *  void PREFIX_write_key(struct fastbuf *f, SORT_KEY *k)
34  *                      writes a key to a fastbuf. Mandatory unless SORT_KEY_REGULAR.
35  *
36  *  SORT_KEY_SIZE(key)  returns the real size of a key (a SORT_KEY type in memory
37  *                      can be truncated to this number of bytes without any harm;
38  *                      used to save memory when the keys have variable sizes).
39  *                      Default: always store the whole SORT_KEY.
40  *  SORT_DATA_SIZE(key) gets a key and returns the amount of data following it.
41  *                      Default: records consist of keys only.
42  *
43  *  Integer sorting:
44  *
45  *  SORT_INT(key)       We are sorting by an integer value. In this mode, PREFIX_compare
46  *                      is supplied automatically and the sorting function gets an extra
47  *                      parameter specifying a range of the integers. The better the range
48  *                      fits, the faster we sort. Sets up SORT_HASH_xxx automatically.
49  *
50  *  Hashing (optional, but it can speed sorting up):
51  *
52  *  SORT_HASH_BITS      signals that a monotone hashing function returning a given number of
53  *                      bits is available. Monotone hash is a function f such that f(x) < f(y)
54  *                      implies x < y and which is approximately uniformly distributed.
55  *  uns PREFIX_hash(SORT_KEY *a, SORT_KEY *b)
56  *
57  *  Unification:
58  *
59  *  SORT_UNIFY          merge items with identical keys, needs the following functions:
60  *  void PREFIX_write_merged(struct fastbuf *f, SORT_KEY **keys, void **data, uns n, void *buf)
61  *                      takes n records in memory with keys which compare equal and writes
62  *                      a single record to the given fastbuf. `buf' points to a buffer which
63  *                      is guaranteed to hold all given records.
64  *  void PREFIX_copy_merged(SORT_KEY **keys, struct fastbuf **data, uns n, struct fastbuf *dest)
65  *                      takes n records with keys in memory and data in fastbufs and writes
66  *                      a single record.
67  *
68  *  Input (choose one of these):
69  *
70  *  SORT_INPUT_FILE     file of a given name
71  *  SORT_INPUT_FB       seekable fastbuf stream
72  *  SORT_INPUT_PIPE     non-seekable fastbuf stream
73  *  SORT_INPUT_PRESORT  custom presorter. Calls function
74  *  int PREFIX_presort(struct fastbuf *dest, void *buf, size_t bufsize);
75  *                      to get successive batches of pre-sorted data.
76  *                      The function is passed a page-aligned presorting buffer.
77  *                      It returns 1 on success or 0 on EOF.
78  *
79  *  Output (chose one of these):
80  *
81  *  SORT_OUTPUT_FILE    file of a given name
82  *  SORT_OUTPUT_FB      temporary fastbuf stream
83  *  SORT_OUTPUT_THIS_FB a given fastbuf stream which can already contain a header
84  *
85  *  Other switches:
86  *
87  *  SORT_UNIQUE         all items have distinct keys (checked in debug mode)
88  *
89  *  The function generated:
90  *
91  *  <outfb> PREFIX_SORT(<in>, <out> [,<range>]), where:
92  *                      <in> = input file name/fastbuf or NULL
93  *                      <out> = output file name/fastbuf or NULL
94  *                      <range> = maximum integer value for the SORT_INT mode
95  *                      <outfb> = output fastbuf (in SORT_OUTPUT_FB mode)
96  *
97  *  After including this file, all parameter macros are automatically
98  *  undef'd.
99  */
100
101 #include "lib/sorter/common.h"
102 #include "lib/fastbuf.h"
103
104 #include <fcntl.h>
105
106 #define P(x) SORT_PREFIX(x)
107
108 #ifdef SORT_KEY_REGULAR
109 typedef SORT_KEY_REGULAR P(key);
110 static inline int P(read_key) (struct fastbuf *f, P(key) *k)
111 {
112   return breadb(f, k, sizeof(P(key)));
113 }
114 static inline void P(write_key) (struct fastbuf *f, P(key) *k)
115 {
116   bwrite(f, k, sizeof(P(key)));
117 }
118 #elif defined(SORT_KEY)
119 typedef SORT_KEY P(key);
120 #else
121 #error Missing definition of sorting key.
122 #endif
123
124 #ifdef SORT_INT
125 static inline int P(compare) (P(key) *x, P(key) *y)
126 {
127   if (SORT_INT(*x) < SORT_INT(*y))
128     return -1;
129   if (SORT_INT(*x) > SORT_INT(*y))
130     return 1;
131   return 0;
132 }
133
134 #ifndef SORT_HASH_BITS
135 static inline int P(hash) (P(key) *x)
136 {
137   return SORT_INT((*x));
138 }
139 #endif
140 #endif
141
142 #ifdef SORT_UNIFY
143 #define LESS <
144 #else
145 #define LESS <=
146 #endif
147 #define SWAP(x,y,z) do { z=x; x=y; y=z; } while(0)
148
149 #if defined(SORT_UNIQUE) && defined(DEBUG_ASSERTS)
150 #define SORT_ASSERT_UNIQUE
151 #endif
152
153 #ifdef SORT_KEY_SIZE
154 #define SORT_VAR_KEY
155 #else
156 #define SORT_KEY_SIZE(key) sizeof(key)
157 #endif
158
159 #ifdef SORT_DATA_SIZE
160 #define SORT_VAR_DATA
161 #else
162 #define SORT_DATA_SIZE(key) 0
163 #endif
164
165 static inline void P(copy_data)(P(key) *key, struct fastbuf *in, struct fastbuf *out)
166 {
167   P(write_key)(out, key);
168 #ifdef SORT_VAR_DATA
169   bbcopy(in, out, SORT_DATA_SIZE(*key));
170 #else
171   (void) in;
172 #endif
173 }
174
175 #include "lib/sorter/s-internal.h"
176 #include "lib/sorter/s-twoway.h"
177
178 static struct fastbuf *P(sort)(
179 #ifdef SORT_INPUT_FILE
180                                byte *in,
181 #else
182                                struct fastbuf *in,
183 #endif
184 #ifdef SORT_OUTPUT_FILE
185                                byte *out
186 #else
187                                struct fastbuf *out
188 #endif
189 #ifdef SORT_INT
190                                , uns int_range
191 #endif
192                                )
193 {
194   struct sort_context ctx;
195   bzero(&ctx, sizeof(ctx));
196
197 #ifdef SORT_INPUT_FILE
198   ctx.in_fb = bopen(in, O_RDONLY, sorter_stream_bufsize);
199   ctx.in_size = bfilesize(ctx.in_fb);
200 #elif defined(SORT_INPUT_FB)
201   ctx.in_fb = in;
202   ctx.in_size = bfilesize(in);
203 #elif defined(SORT_INPUT_PIPE)
204   ctx.in_fb = in;
205   ctx.in_size = ~(u64)0;
206 #elif defined(SORT_INPUT_PRESORT)
207   ASSERT(!in);
208   ctx.custom_presort = P(presort);
209   ctx.in_size = ~(u64)0;
210 #else
211 #error No input given.
212 #endif
213
214 #ifdef SORT_OUTPUT_FB
215   ASSERT(!out);
216 #elif defined(SORT_OUTPUT_THIS_FB)
217   ctx.out_fb = out;
218 #elif defined(SORT_OUTPUT_FILE)
219   /* Just assume fastbuf output and rename the fastbuf later */
220 #else
221 #error No output given.
222 #endif
223
224 #ifdef SORT_HASH_BITS
225   ctx.hash_bits = SORT_HASH_BITS;
226 #elif defined(SORT_INT)
227   ctx.hash_bits = 0;
228   while (ctx.hash_bits < 32 && (int_range >> ctx.hash_bits))
229     ctx.hash_bits++;
230 #endif
231
232   ctx.internal_sort = P(internal);
233   ctx.twoway_merge = P(twoway_merge);
234
235   sorter_run(&ctx);
236
237 #ifdef SORT_OUTPUT_FILE
238   if (rename(ctx.out_fb->name, out) < 0)
239     die("Cannot rename %s to %s: %m", ctx.out_fb->name, out);
240   bconfig(ctx.out_fb, BCONFIG_IS_TEMP_FILE, 0);
241   bclose(ctx.out_fb);
242   ctx.out_fb = NULL;
243 #endif
244   return ctx.out_fb;
245 }
246
247 #undef SORT_PREFIX
248 #undef SORT_KEY
249 #undef SORT_KEY_REGULAR
250 #undef SORT_KEY_SIZE
251 #undef SORT_DATA_SIZE
252 #undef SORT_VAR_KEY
253 #undef SORT_VAR_DATA
254 #undef SORT_INT
255 #undef SORT_HASH_BITS
256 #undef SORT_UNIFY
257 #undef SORT_INPUT_FILE
258 #undef SORT_INPUT_FB
259 #undef SORT_INPUT_PRESORT
260 #undef SORT_OUTPUT_FILE
261 #undef SORT_OUTPUT_FB
262 #undef SORT_OUTPUT_THIS_FB
263 #undef SORT_UNIQUE
264 #undef SORT_ASSERT_UNIQUE
265 #undef SWAP
266 #undef LESS
267 #undef P
268 /* FIXME: Check that we undef everything we should. */