dictionary.c
Go to the documentation of this file.
1 /******************************************************************************/
35 /******************************************************************************/
36 
37 #include "dictionary.h"
39 
40 int
43  char *ext,
44  char *filename
45 ) {
46  return snprintf(filename, ION_MAX_FILENAME_LENGTH, "%d.%s", id, ext);
47 }
48 
60 char
62  ion_key_t first_key,
63  ion_key_t second_key,
64  ion_key_size_t key_size
65 ) {
66  return strncmp((char *) first_key, (char *) second_key, key_size);
67 }
68 
79 char
81  ion_key_t first_key,
82  ion_key_t second_key,
83  ion_key_size_t key_size
84 ) {
85  return strncmp((char *) first_key, (char *) second_key, key_size);
86 }
87 
90  ion_key_type_t key_type
91 ) {
93 
94  switch (key_type) {
97  break;
98  }
99 
102  break;
103  }
104 
105  case key_type_char_array: {
107  break;
108  }
109 
112  break;
113  }
114 
115  default: {
116  /* do something - you must bind the correct comparison function */
117  break;
118  }
119  }
120 
121  return compare;
122 }
123 
124 ion_err_t
126  ion_dictionary_handler_t *handler,
129  ion_key_type_t key_type,
130  ion_key_size_t key_size,
131  ion_value_size_t value_size,
132  ion_dictionary_size_t dictionary_size
133 ) {
134  ion_err_t err;
136 
137  err = handler->create_dictionary(id, key_type, key_size, value_size, dictionary_size, compare, handler, dictionary);
138 
139  if (err_ok == err) {
140  dictionary->instance->id = id;
141  dictionary->status = ion_dictionary_status_ok;
142  }
143  else {
144  dictionary->status = ion_dictionary_status_error;
145  }
146 
147  return err;
148 }
149 
153  ion_key_t key,
154  ion_value_t value
155 ) {
156  return dictionary->handler->insert(dictionary, key, value);
157 }
158 
162  ion_key_t key,
163  ion_value_t value
164 ) {
165  return dictionary->handler->get(dictionary, key, value);
166 }
167 
171  ion_key_t key,
172  ion_value_t value
173 ) {
174  return dictionary->handler->update(dictionary, key, value);
175 }
176 
177 ion_err_t
180 ) {
181  return dictionary->handler->delete_dictionary(dictionary);
182 }
183 
184 ion_err_t
186  ion_dictionary_handler_t *handler,
188 ) {
189  ion_err_t error = handler->destroy_dictionary(id);
190 
191  if (err_not_implemented == error) {
192  error = ffdict_destroy_dictionary(id);
193  }
194 
195  return error;
196 }
197 
201  ion_key_t key
202 ) {
203  return dictionary->handler->remove(dictionary, key);
204 }
205 
206 char
208  ion_key_t first_key,
209  ion_key_t second_key,
210  ion_key_size_t key_size
211 ) {
212  int idx;
213  char return_value = ION_RETURN_VALUE;
214 
215  /*
216  * In this case, the endianness of the process does matter as the code does
217  * a direct comparison of bytes in memory starting for MSB.
218  */
219 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
220 
221  for (idx = key_size - 1; idx >= 0; idx--) {
222 #else
223 
224  for (idx = 0; idx < key_size; idx++) {
225 #endif
226 
227  ion_byte_t firstbyte = *((ion_byte_t *) first_key + idx);
228  ion_byte_t secondbyte = *((ion_byte_t *) second_key + idx);
229 
230  if ((return_value = (firstbyte > secondbyte) - (firstbyte < secondbyte)) != ION_ZERO) {
231  return return_value;
232  }
233  }
234 
235  return return_value;
236 }
237 
238 char
240  ion_key_t first_key,
241  ion_key_t second_key,
242  ion_key_size_t key_size
243 ) {
244  int idx;
245  char return_value = ION_RETURN_VALUE;
246 
247  /*
248  * In this case, the endianness of the process does matter as the code does
249  * a direct comparison of bytes in memory starting for MSB.
250  */
251 
252 /* Start at the MSB */
253 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
254  idx = key_size - 1;
255 #else
256  idx = 0;
257 #endif
258 
259  ion_byte_t firstbyte = *((ion_byte_t *) first_key + idx);
260  ion_byte_t secondbyte = *((ion_byte_t *) second_key + idx);
261 
262  /* Do bit comparison on the sign bit to do positive/negative comparison. Lets us exit early in many cases */
263  if ((return_value = (secondbyte >> 7) - (firstbyte >> 7)) != ION_ZERO) {
264  return return_value;
265  }
266 
267 /* In this case, we are of the same sign. Do byte-for-byte comparison. */
268 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
269 
270  for (; idx >= 0; idx--) {
271 #else
272 
273  for (; idx < key_size; idx++) {
274 #endif
275  firstbyte = *((ion_byte_t *) first_key + idx);
276  secondbyte = *((ion_byte_t *) second_key + idx);
277 
278  if ((return_value = (firstbyte > secondbyte) - (firstbyte < secondbyte)) != ION_ZERO) {
279  return return_value;
280  }
281  }
282 
283  return return_value;
284 }
285 
286 ion_err_t
288  ion_dictionary_handler_t *handler,
291 ) {
293 
294  ion_err_t error = handler->open_dictionary(handler, dictionary, config, compare);
295 
296  if (err_not_implemented == error) {
298  ion_dict_cursor_t *cursor = NULL;
299  ion_record_t record;
300  ion_dictionary_handler_t fallback_handler;
301  ion_dictionary_t fallback_dict;
302  ion_err_t err;
303 
304  ffdict_init(&fallback_handler);
305 
306  ion_dictionary_config_info_t fallback_config = {
307  config->id, 0, config->type, config->key_size, config->value_size, 1
308  };
309 
310  err = dictionary_open(&fallback_handler, &fallback_dict, &fallback_config);
311 
312  if (err_ok != err) {
313  return err;
314  }
315 
317  err = dictionary_find(&fallback_dict, &predicate, &cursor);
318 
319  if (err_ok != err) {
320  return err;
321  }
322 
323  record.key = alloca(config->key_size);
324  record.value = alloca(config->value_size);
325 
326  err = dictionary_create(handler, dictionary, config->id, config->type, config->key_size, config->value_size, config->dictionary_size);
327 
328  if (err_ok != err) {
329  return err;
330  }
331 
332  ion_cursor_status_t cursor_status;
333 
334  while (cs_cursor_active == (cursor_status = cursor->next(cursor, &record)) || cs_cursor_initialized == cursor_status) {
335  ion_status_t status = dictionary_insert(dictionary, record.key, record.value);
336 
337  if (err_ok != status.error) {
338  cursor->destroy(&cursor);
339  dictionary_close(&fallback_dict);
340  dictionary_delete_dictionary(dictionary);
341  return status.error;
342  }
343  }
344 
345  if (cursor_status != cs_end_of_results) {
346  return err_uninitialized;
347  }
348 
349  cursor->destroy(&cursor);
350 
351  err = dictionary_delete_dictionary(&fallback_dict);
352 
353  if (err_ok != err) {
354  return err;
355  }
356 
357  error = err_ok;
358  }
359 
360  if (err_ok == error) {
361  dictionary->status = ion_dictionary_status_ok;
362  dictionary->instance->id = config->id;
363  }
364  else {
365  dictionary->status = ion_dictionary_status_error;
366  }
367 
368  return error;
369 }
370 
371 ion_err_t
374 ) {
375  if (ion_dictionary_status_closed == dictionary->status) {
376  return err_ok;
377  }
378 
379  ion_err_t error = dictionary->handler->close_dictionary(dictionary);
380 
381  if (err_not_implemented == error) {
383  ion_dict_cursor_t *cursor = NULL;
384  ion_record_t record;
385  ion_err_t err;
386 
388  err = dictionary_find(dictionary, &predicate, &cursor);
389 
390  if (err_ok != err) {
391  return err;
392  }
393 
394  int key_size = dictionary->instance->record.key_size;
395  int value_size = dictionary->instance->record.value_size;
396  ion_key_type_t key_type = dictionary->instance->key_type;
397 
398  record.key = alloca(key_size);
399  record.value = alloca(value_size);
400 
401  ion_dictionary_handler_t fallback_handler;
402  ion_dictionary_t fallback_dict;
403 
404  ffdict_init(&fallback_handler);
405 
406  err = dictionary_create(&fallback_handler, &fallback_dict, dictionary->instance->id, key_type, key_size, value_size, 1);
407 
408  if (err_ok != err) {
409  return err;
410  }
411 
412  ion_cursor_status_t cursor_status;
413 
414  while (cs_cursor_active == (cursor_status = cursor->next(cursor, &record)) || cs_cursor_initialized == cursor_status) {
415  ion_status_t status = dictionary_insert(&fallback_dict, record.key, record.value);
416 
417  if (err_ok != status.error) {
418  cursor->destroy(&cursor);
419  dictionary_delete_dictionary(&fallback_dict);
420  return status.error;
421  }
422  }
423 
424  /* Cursor has either reached the end of the result set or there was no
425  result set to traverse, and the cursor remains uninitialized. */
426  if ((cs_end_of_results != cursor_status) && (cs_cursor_uninitialized != cursor_status)) {
427  return err_uninitialized;
428  }
429 
430  cursor->destroy(&cursor);
431 
432  err = dictionary_close(&fallback_dict);
433 
434  if (err_ok != err) {
435  return err;
436  }
437 
438  err = dictionary_delete_dictionary(dictionary);
439 
440  if (err_ok != err) {
441  return err;
442  }
443 
444  error = err_ok;
445  }
446 
447  if (err_ok == error) {
448  dictionary->status = ion_dictionary_status_closed;
449  }
450 
451  return error;
452 }
453 
462 void
465 ) {
466  if (*predicate != NULL) {
467  free((*predicate)->statement.equality.equality_value);
468  free(*predicate);
469  *predicate = NULL;
470  }
471 }
472 
481 void
484 ) {
485  if (*predicate != NULL) {
486  free((*predicate)->statement.range.upper_bound);
487  free((*predicate)->statement.range.lower_bound);
488  free(*predicate);
489  *predicate = NULL;
490  }
491 }
492 
501 void
504 ) {
505  if (*predicate != NULL) {
506  free(*predicate);
507  *predicate = NULL;
508  }
509 }
510 
511 ion_err_t
515  ...
516 ) {
517  va_list arg_list;
518 
519  va_start(arg_list, type);
520 
521  predicate->type = type;
522 
523  switch (type) {
524  case predicate_equality: {
525  ion_key_t key = va_arg(arg_list, ion_key_t);
526 
527  predicate->statement.equality.equality_value = key;
529  break;
530  }
531 
532  case predicate_range: {
533  ion_key_t lower_bound = va_arg(arg_list, ion_key_t);
534  ion_key_t upper_bound = va_arg(arg_list, ion_key_t);
535 
536  predicate->statement.range.lower_bound = lower_bound;
537  predicate->statement.range.upper_bound = upper_bound;
539  break;
540  }
541 
542  case predicate_all_records: {
544  break;
545  }
546 
547  case predicate_predicate: {
548  return err_invalid_predicate;
549  }
550 
551  default: {
552  return err_invalid_predicate;
553  break;
554  }
555  }
556 
557  va_end(arg_list);
558  return err_ok;
559 }
560 
561 ion_err_t
565  ion_dict_cursor_t **cursor
566 ) {
567  return dictionary->handler->find(dictionary, predicate, cursor);
568 }
569 
572  ion_dict_cursor_t *cursor,
573  ion_key_t key
574 ) {
575  ion_dictionary_parent_t *parent = cursor->dictionary->instance;
576  ion_key_size_t key_size = cursor->dictionary->instance->record.key_size;
577  ion_boolean_t result = boolean_false;
578 
579  switch (cursor->predicate->type) {
580  case predicate_equality: {
581  if (parent->compare(key, cursor->predicate->statement.equality.equality_value, cursor->dictionary->instance->record.key_size) == 0) {
582  result = boolean_true;
583  }
584 
585  break;
586  }
587 
588  case predicate_range: {
589  ion_key_t lower_b = cursor->predicate->statement.range.lower_bound;
590  ion_key_t upper_b = cursor->predicate->statement.range.upper_bound;
591 
592  /* Check if key >= lower bound */
593  ion_boolean_t comp_lower = parent->compare(key, lower_b, key_size) >= 0;
594 
595  /* Check if key <= upper bound */
596  ion_boolean_t comp_upper = parent->compare(key, upper_b, key_size) <= 0;
597 
598  result = comp_lower && comp_upper;
599  break;
600  }
601 
602  case predicate_all_records: {
603  result = boolean_true;
604  break;
605  }
606  }
607 
608  return result;
609 }
#define ION_RETURN_VALUE
Definition: kv_system.h:68
unsigned char ion_byte_t
A byte type.
Definition: kv_system.h:232
ion_status_t(* insert)(ion_dictionary_t *, ion_key_t, ion_value_t)
char ion_predicate_type_t
A type for storing predicate type data.
void dictionary_destroy_predicate_all_records(ion_predicate_t **predicate)
Destroys an all records predicate.
Definition: dictionary.c:502
enum ION_KEY_TYPE ion_key_type_t
This is the available key types for ION_DB. All types will be based on system defines.
ion_cursor_status_t(* next)(ion_dict_cursor_t *, ion_record_t *record)
ion_record_info_t record
void dictionary_destroy_predicate_range(ion_predicate_t **predicate)
Destroys a range predicate.
Definition: dictionary.c:482
char dictionary_compare_signed_value(ion_key_t first_key, ion_key_t second_key, ion_key_size_t key_size)
Compares two signed integer numeric keys.
Definition: dictionary.c:239
ion_predicate_t * predicate
ion_err_t ffdict_destroy_dictionary(ion_dictionary_id_t id)
Cleans up all files created by the dictionary, and frees any allocated memory, for an already closed ...
int ion_value_size_t
The size (length) of a dictionary value in bytes.
Definition: kv_system.h:256
char dictionary_compare_char_array(ion_key_t first_key, ion_key_t second_key, ion_key_size_t key_size)
Compare any two character (byte) arrays. These are not assumed to be null-terminated.
Definition: dictionary.c:61
ion_predicate_statement_t statement
ion_dictionary_handler_t * handler
ion_dictionary_parent_t * instance
Function declarations at the dictionary interface level for the flat file store.
ion_value_t value
Definition: kv_system.h:318
ion_status_t(* remove)(ion_dictionary_t *, ion_key_t)
ion_dictionary_t * dictionary
void(* destroy)(ion_dict_cursor_t **)
ion_err_t(* destroy_dictionary)(ion_dictionary_id_t id)
Struct used to maintain key and value.
Definition: kv_system.h:315
unsigned int ion_dictionary_id_t
A type used to identify dictionaries, specifically in the master table.
unsigned int ion_dictionary_size_t
The implementation specific size of the dictionary.
Definition: kv_system.h:264
Struct containing details for opening a dictionary previously created.
char dictionary_compare_null_terminated_string(ion_key_t first_key, ion_key_t second_key, ion_key_size_t key_size)
Compare any two null-terminated strings.
Definition: dictionary.c:80
#define key(k)
Definition: bpp_tree.c:75
ion_status_t dictionary_update(ion_dictionary_t *dictionary, ion_key_t key, ion_value_t value)
Update all records with a given key.
Definition: dictionary.c:169
void dictionary_destroy_predicate_equality(ion_predicate_t **predicate)
Destroys an equality predicate.
Definition: dictionary.c:463
char dictionary_compare_unsigned_value(ion_key_t first_key, ion_key_t second_key, ion_key_size_t key_size)
Compares two unsigned integer numeric keys.
Definition: dictionary.c:207
ion_err_t error
Definition: kv_system.h:291
ion_status_t dictionary_delete(ion_dictionary_t *dictionary, ion_key_t key)
Delete a value given a key.
Definition: dictionary.c:199
ion_boolean_t test_predicate(ion_dict_cursor_t *cursor, ion_key_t key)
Tests the supplied key against the predicate registered in the cursor. If the supplied cursor if of t...
Definition: dictionary.c:571
This is the super type for all dictionaries.
ion_status_t dictionary_insert(ion_dictionary_t *dictionary, ion_key_t key, ion_value_t value)
Insert a value into a dictionary.
Definition: dictionary.c:151
ion_key_t key
Definition: kv_system.h:316
char(* ion_dictionary_compare_t)(ion_key_t, ion_key_t, ion_key_size_t)
Function pointer type for dictionary comparison methods.
char ion_err_t
The error type used to store error codes.
Definition: kv_system.h:226
int dictionary_get_filename(ion_dictionary_id_t id, char *ext, char *filename)
Given the ID, implementation specific extension, and a buffer to write to, writes back the formatted ...
Definition: dictionary.c:41
ion_err_t dictionary_create(ion_dictionary_handler_t *handler, ion_dictionary_t *dictionary, ion_dictionary_id_t id, ion_key_type_t key_type, ion_key_size_t key_size, ion_value_size_t value_size, ion_dictionary_size_t dictionary_size)
Creates as instance of a specific type of dictionary.
Definition: dictionary.c:125
void * ion_key_t
A dictionary key.
Definition: kv_system.h:241
void(* destroy)(ion_predicate_t **)
ion_status_t(* update)(ion_dictionary_t *, ion_key_t, ion_value_t)
ion_equality_statement_t equality
void * ion_value_t
A dictionary value.
Definition: kv_system.h:246
A dictionary contains information regarding an instance of the storage element and the associated han...
ion_status_t dictionary_get(ion_dictionary_t *dictionary, ion_key_t key, ion_value_t value)
Retrieve a value given a key.
Definition: dictionary.c:160
#define ION_ZERO
Definition: kv_system.h:67
ion_predicate_type_t type
ion_dictionary_id_t id
A supertype for dictionary cursor objects.
ion_err_t(* close_dictionary)(ion_dictionary_t *)
#define ION_MAX_FILENAME_LENGTH
Since the arduino conforms to 8.3 syntax, that&#39;s 8 + 3 = 11 + 1 (null terminator) characters...
Definition: kv_system.h:73
ion_err_t(* open_dictionary)(ion_dictionary_handler_t *, ion_dictionary_t *, ion_dictionary_config_info_t *, ion_dictionary_compare_t)
ion_err_t(* create_dictionary)(ion_dictionary_id_t, ion_key_type_t, ion_key_size_t, ion_value_size_t, ion_dictionary_size_t, ion_dictionary_compare_t, ion_dictionary_handler_t *, ion_dictionary_t *)
void ffdict_init(ion_dictionary_handler_t *handler)
Given the handler instance, bind the appropriate flat file functions.
ion_err_t dictionary_destroy_dictionary(ion_dictionary_handler_t *handler, ion_dictionary_id_t id)
Destroys dictionary.
Definition: dictionary.c:185
ion_err_t(* delete_dictionary)(ion_dictionary_t *)
ion_key_size_t key_size
Definition: kv_system.h:307
A supertype for cursor predicate objects.
ion_err_t dictionary_delete_dictionary(ion_dictionary_t *dictionary)
Destroys dictionary.
Definition: dictionary.c:178
ion_err_t(* find)(ion_dictionary_t *, ion_predicate_t *, ion_dict_cursor_t **)
ion_err_t dictionary_close(ion_dictionary_t *dictionary)
Closes a dictionary.
Definition: dictionary.c:372
#define error(rc)
Definition: bpp_tree.c:151
ion_key_type_t key_type
ion_dictionary_compare_t compare
ion_err_t dictionary_open(ion_dictionary_handler_t *handler, ion_dictionary_t *dictionary, ion_dictionary_config_info_t *config)
Opens a dictionary, given the desired config.
Definition: dictionary.c:287
ion_dictionary_size_t dictionary_size
ion_err_t dictionary_find(ion_dictionary_t *dictionary, ion_predicate_t *predicate, ion_dict_cursor_t **cursor)
Uses the given predicate and cursor to search the dictionary.
Definition: dictionary.c:562
int ion_key_size_t
The size (length) of a dictionary key in bytes.
Definition: kv_system.h:251
char ion_boolean_t
A boolean type.
Definition: kv_system.h:269
ion_dictionary_compare_t dictionary_switch_compare(ion_key_type_t key_type)
Definition: dictionary.c:89
ion_range_statement_t range
ion_dictionary_status_t status
ion_value_size_t value_size
Definition: kv_system.h:309
ion_err_t dictionary_build_predicate(ion_predicate_t *predicate, ion_predicate_type_t type,...)
Builds a predicate based on the type given.
Definition: dictionary.c:512
ion_status_t(* get)(ion_dictionary_t *, ion_key_t, ion_value_t)
A dictionary_handler is responsible for dealing with the specific interface for an underlying diction...
char ion_cursor_status_t
A type for the status of a cursor.
A status object that describes the result of a dictionary operation.
Definition: kv_system.h:290