Added a queue empty test in del_queue_thread().
[mpdm.git] / mpdm_v.c
blob1ff5d8224083cbb2f05a8134ec517844c3784ecd
1 /*
3 MPDM - Minimum Profit Data Manager
4 Copyright (C) 2003/2011 Angel Ortega <angel@triptico.com>
6 mpdm_v.c - Basic value management
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 http://www.triptico.com
26 #include "config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <locale.h>
33 #include "mpdm.h"
36 /** data **/
38 /* control structure */
40 struct mpdm_control *mpdm = NULL;
43 /** code **/
45 static void cleanup_value(mpdm_t v)
46 /* cleans a value */
48 /* collapse multiple values */
49 if (v->flags & MPDM_MULTIPLE)
50 mpdm_collapse(v, 0, v->size);
52 /* free data if needed */
53 if (v->data != NULL && v->flags & MPDM_FREE) {
54 free((void *) v->data);
55 v->data = NULL;
58 mpdm->count--;
60 free(v);
64 static void destroy_value(mpdm_t v)
65 /* destroys a value */
67 if (mpdm->threaded_delete) {
68 /* atomically enqueue this value */
69 mpdm_mutex_lock(mpdm->del_queue_mutex);
71 v->next = mpdm->del;
72 mpdm->del = v;
74 mpdm_mutex_unlock(mpdm->del_queue_mutex);
76 /* notify the del queue thread */
77 mpdm_semaphore_post(mpdm->del_queue_sem);
79 else
80 cleanup_value(v);
84 static mpdm_t del_queue_thread(mpdm_t args, mpdm_t ctxt)
85 /* delete queue processing thread */
87 for (;;) {
88 mpdm_t v;
90 /* wait for next value */
91 mpdm_semaphore_wait(mpdm->del_queue_sem);
93 /* do nothing if the queue is empty (should't happen) */
94 if (mpdm->del == NULL)
95 continue;
97 /* atomically dequeue */
98 mpdm_mutex_lock(mpdm->del_queue_mutex);
100 v = mpdm->del;
101 mpdm->del = v->next;
103 mpdm_mutex_unlock(mpdm->del_queue_mutex);
105 cleanup_value(v);
111 * mpdm_new - Creates a new value.
112 * @flags: flags
113 * @data: pointer to real data
114 * @size: size of data
116 * Creates a new value. @flags is an or-ed set of flags, @data is a
117 * pointer to the data the value will store and @size the size of these
118 * data (if value is to be a multiple one, @size is a number of elements,
119 * or a number of bytes otherwise).
121 * This function is normally not directly used; use any of the type
122 * creation macros instead.
123 * [Value Creation]
125 mpdm_t mpdm_new(int flags, const void *data, int size)
127 mpdm_t v = NULL;
129 /* alloc */
130 if ((v = malloc(sizeof(struct mpdm_val))) != NULL) {
131 /* account one value more */
132 mpdm->count++;
134 v->flags = flags;
135 v->ref = 0;
136 v->data = data;
137 v->size = size;
138 v->next = NULL;
141 return v;
146 * mpdm_ref - Increments the reference count of a value.
147 * @v: the value
149 * Increments the reference count of a value.
150 * [Value Management]
152 mpdm_t mpdm_ref(mpdm_t v)
154 if (v != NULL)
155 v->ref++;
157 return v;
162 * mpdm_unref - Decrements the reference count of a value.
163 * @v: the value
165 * Decrements the reference count of a value. If the reference
166 * count of the value reaches 0, it's destroyed.
167 * [Value Management]
169 mpdm_t mpdm_unref(mpdm_t v)
171 if (v != NULL) {
172 v->ref--;
174 if (v->ref <= 0) {
175 destroy_value(v);
176 v = NULL;
180 return v;
185 * mpdm_unrefnd - Decrements the reference count of a value, without destroy.
186 * @v: the value
188 * Decrements the reference count of a value, without destroying
189 * the value if it's unreferenced.
190 * [Value Management]
192 mpdm_t mpdm_unrefnd(mpdm_t v)
194 if (v != NULL)
195 v->ref--;
197 return v;
202 * mpdm_size - Returns the size of an element.
203 * @v: the element
205 * Returns the size of an element. It does not change the
206 * reference count of the value.
207 * [Value Management]
209 int mpdm_size(const mpdm_t v)
211 int r = 0;
213 /* NULL values have no size */
214 if (v != NULL)
215 r = v->size;
217 return r;
222 * mpdm_clone - Creates a clone of a value.
223 * @v: the value
225 * Creates a clone of a value. If the value is multiple, a new value will
226 * be created containing clones of all its elements; otherwise,
227 * the same unchanged value is returned.
228 * [Value Management]
230 mpdm_t mpdm_clone(const mpdm_t v)
232 mpdm_t r;
234 mpdm_ref(v);
236 if (MPDM_IS_ARRAY(v))
237 r = mpdm_aclone(v);
238 else
239 r = v;
241 mpdm_unref(v);
243 return r;
248 * mpdm_root - Returns the root hash.
250 * Returns the root hash. This hash is stored internally and can be used
251 * as a kind of global symbol table.
252 * [Value Management]
254 mpdm_t mpdm_root(void)
256 if (mpdm->root == NULL)
257 mpdm->root = mpdm_ref(MPDM_H(0));
259 return mpdm->root;
264 * mpdm_set_ival - Sets the integer value.
265 * @v: the value
266 * @ival: the integer
268 * Sets the integer value for @v. It does not change
269 * the reference count of @v.
271 mpdm_t mpdm_set_ival(mpdm_t v, int ival)
272 /* sets an integer value to a value */
274 v->flags |= MPDM_IVAL;
275 v->ival = ival;
277 return v;
282 * mpdm_set_rval - Sets the real value.
283 * @v: the value
284 * @rval: the real
286 * Sets the real value for @v. It does not change
287 * the reference count of @v.
289 mpdm_t mpdm_set_rval(mpdm_t v, double rval)
290 /* sets a real value to a value */
292 v->flags |= MPDM_RVAL;
293 v->rval = rval;
295 return v;
300 * mpdm_void - Refs then unrefs a value.
301 * @v: the value
303 * References and unreferences a value. To be used to receive
304 * the output of mpdm_exec() in case of it being void (i.e.
305 * its return value ignored).
307 void mpdm_void(mpdm_t v)
309 mpdm_ref(v);
310 mpdm_unref(v);
315 * mpdm_is_null - Returns 1 if a value is NULL.
316 * @v: the value
318 * Returns 1 if a value is NULL. The reference count is touched.
320 int mpdm_is_null(mpdm_t v)
322 int r;
324 mpdm_ref(v);
325 r = v == NULL ? 1 : 0;
326 mpdm_unref(v);
328 return r;
333 * mpdm_exec - Executes an executable value.
334 * @c: the code value
335 * @args: the arguments
336 * @ctxt: the context
338 * Executes an executable value. If @c is a scalar value, its data
339 * should be a pointer to a directly executable C function with a
340 * prototype of mpdm_t func(mpdm_t args, mpdm_t ctxt); if it's a multiple
341 * one, the first value's data should be a pointer to a directly executable
342 * C function with a prototype of
343 * mpdm_t func(mpdm_t b, mpdm_t args, mpdm_t ctxt) and
344 * the second value will be passed as the @b argument. This value is used
345 * to store bytecode or so when implementing virtual machines or compilers.
346 * The @ctxt is meant to be used as a special context to implement local
347 * symbol tables and such. Its meaning is free and can be NULL.
349 * Returns the return value of the code. If @c is NULL or not executable,
350 * returns NULL.
351 * [Value Management]
353 mpdm_t mpdm_exec(mpdm_t c, mpdm_t args, mpdm_t ctxt)
355 mpdm_t r = NULL;
357 mpdm_ref(c);
358 mpdm_ref(args);
359 mpdm_ref(ctxt);
361 if (c != NULL && (c->flags & MPDM_EXEC)) {
363 if (c->flags & MPDM_MULTIPLE) {
364 mpdm_t x;
365 mpdm_t(*func) (mpdm_t, mpdm_t, mpdm_t);
367 /* value is multiple; first element is the
368 3 argument version of the executable function,
369 next its optional additional information,
370 the arguments and the context */
371 x = mpdm_aget(c, 0);
373 if ((func =
374 (mpdm_t(*)(mpdm_t, mpdm_t, mpdm_t)) (x->data)) != NULL)
375 r = func(mpdm_aget(c, 1), args, ctxt);
377 else {
378 mpdm_t(*func) (mpdm_t, mpdm_t);
380 /* value is scalar; c is the 2 argument
381 version of the executable function */
382 if ((func = (mpdm_t(*)(mpdm_t, mpdm_t)) (c->data)) != NULL)
383 r = func(args, ctxt);
387 mpdm_unref(ctxt);
388 mpdm_unref(args);
389 mpdm_unref(c);
391 return r;
395 mpdm_t mpdm_exec_1(mpdm_t c, mpdm_t a1, mpdm_t ctxt)
397 mpdm_t r;
398 mpdm_t a = MPDM_A(1);
400 mpdm_ref(a);
401 mpdm_aset(a, a1, 0);
403 r = mpdm_exec(c, a, ctxt);
405 mpdm_unref(a);
407 return r;
411 mpdm_t mpdm_exec_2(mpdm_t c, mpdm_t a1, mpdm_t a2, mpdm_t ctxt)
413 mpdm_t r;
414 mpdm_t a = MPDM_A(2);
416 mpdm_ref(a);
417 mpdm_aset(a, a1, 0);
418 mpdm_aset(a, a2, 1);
420 r = mpdm_exec(c, a, ctxt);
422 mpdm_unref(a);
424 return r;
428 mpdm_t mpdm_exec_3(mpdm_t c, mpdm_t a1, mpdm_t a2, mpdm_t a3, mpdm_t ctxt)
430 mpdm_t r;
431 mpdm_t a = MPDM_A(3);
433 mpdm_ref(a);
434 mpdm_aset(a, a1, 0);
435 mpdm_aset(a, a2, 1);
436 mpdm_aset(a, a3, 2);
438 r = mpdm_exec(c, a, ctxt);
440 mpdm_unref(a);
442 return r;
446 mpdm_t mpdm_xnew(mpdm_t(*a1) (mpdm_t, mpdm_t, mpdm_t), mpdm_t a2)
448 mpdm_t x;
450 x = MPDM_A(2);
451 x->flags |= MPDM_EXEC;
453 mpdm_ref(x);
455 mpdm_aset(x, MPDM_X(a1), 0);
456 mpdm_aset(x, a2, 1);
458 mpdm_unrefnd(x);
460 return x;
464 mpdm_t mpdm_new_copy(int flags, void *ptr, int size)
466 mpdm_t r = NULL;
468 if (ptr != NULL) {
469 char *ptr2 = malloc(size);
470 memcpy(ptr2, ptr, size);
472 r = mpdm_new(MPDM_FREE | flags, ptr2, size);
475 return r;
479 static mpdm_t MPDM(const mpdm_t args, mpdm_t ctxt)
480 /* accesor / mutator for MPDM internal data */
482 mpdm_t v;
484 mpdm_ref(args);
486 v = mpdm_aget(args, 0);
488 if (v != NULL) {
489 mpdm_t w;
491 /* do changes */
492 if ((w = mpdm_hget_s(v, L"hash_buckets")) != NULL)
493 mpdm->hash_buckets = mpdm_ival(w);
494 else
495 if ((w = mpdm_hget_s(v, L"threaded_delete")) != NULL)
496 mpdm->threaded_delete = mpdm_ival(w);
499 /* now collect all information */
500 v = MPDM_H(0);
502 mpdm_ref(v);
504 mpdm_hset_s(v, L"version", MPDM_MBS(VERSION));
505 mpdm_hset_s(v, L"count", MPDM_I(mpdm->count));
506 mpdm_hset_s(v, L"hash_buckets", MPDM_I(mpdm->hash_buckets));
507 mpdm_hset_s(v, L"threaded_delete", MPDM_I(mpdm->threaded_delete));
509 mpdm_unref(args);
511 mpdm_unrefnd(v);
513 return v;
516 extern char **environ;
518 static mpdm_t build_env(void)
519 /* builds a hash with the environment */
521 char **ptr;
522 mpdm_t e = MPDM_H(0);
524 mpdm_ref(e);
526 for (ptr = environ; *ptr != NULL; ptr++) {
527 char *eq = strchr(*ptr, '=');
529 if (eq != NULL) {
530 mpdm_t k, v;
532 k = MPDM_NMBS((*ptr), eq - (*ptr));
533 v = MPDM_MBS(eq + 1);
535 mpdm_hset(e, k, v);
539 mpdm_unrefnd(e);
541 return e;
546 * mpdm_startup - Initializes MPDM.
548 * Initializes the Minimum Profit Data Manager. Returns 0 if
549 * everything went OK.
551 int mpdm_startup(void)
553 /* do the startup only unless done beforehand */
554 if (mpdm == NULL) {
555 /* alloc space */
556 if ((mpdm = malloc(sizeof(struct mpdm_control))) == NULL)
557 return -1;
559 /* cleans it */
560 memset(mpdm, '\0', sizeof(struct mpdm_control));
562 /* sets the defaults */
563 mpdm->hash_buckets = 31;
565 /* sets the threaded delete control */
566 mpdm->threaded_delete = 0;
568 /* create the threaded delete thread and control */
569 mpdm->del_queue_mutex = mpdm_new_mutex();
570 mpdm->del_queue_sem = mpdm_new_semaphore(0);
571 mpdm_exec_thread(MPDM_X(del_queue_thread), NULL, NULL);
573 /* sets the locale */
574 if (setlocale(LC_ALL, "") == NULL)
575 setlocale(LC_ALL, "C");
577 mpdm_encoding(NULL);
579 /* store the MPDM() function */
580 mpdm_hset_s(mpdm_root(), L"MPDM", MPDM_X(MPDM));
582 /* store the ENV hash */
583 mpdm_hset_s(mpdm_root(), L"ENV", build_env());
586 /* everything went OK */
587 return 0;
592 * mpdm_shutdown - Shuts down MPDM.
594 * Shuts down MPDM. No MPDM functions should be used from now on.
596 void mpdm_shutdown(void)
598 /* dummy, by now */
602 * MPDM_A - Creates an array value.
603 * @n: Number of elements
605 * Creates a new array value with @n elements.
606 * [Value Creation]
608 /** mpdm_t MPDM_A(int n); */
609 /* ; */
612 * MPDM_H - Creates a hash value.
613 * @n: Number of buckets in the hash (0: use default)
615 * Creates a new hash value with @n buckets. The number
616 * of buckets must be a prime number. If @n is 0, an
617 * optimal number of buckets will be used.
618 * [Value Creation]
620 /** mpdm_t MPDM_H(int n); */
621 /* ; */
624 * MPDM_LS - Creates a string value from a literal string.
625 * @wcs: the wide character string
627 * Creates a new string value from a literal, wide character string.
628 * A pointer to the string will be stored in the value (not a copy).
629 * [Value Creation]
631 /** mpdm_t MPDM_LS(wchar_t * wcs); */
632 /* ; */
635 * MPDM_S - Creates a string value from a string.
636 * @wcs: the wide character string
638 * Creates a new string value from a wide character string. The value
639 * will store a copy of the string that will be freed on destruction.
640 * [Value Creation]
642 /** mpdm_t MPDM_S(wchar_t * wcs); */
643 /* ; */
646 * MPDM_NS - Creates a string value from a string, with size.
647 * @wcs: the wide character string
648 * @s: the size in chars the string will hold
650 * Creates a new string value with a copy of the first @s characters
651 * from the @wcs string.
652 * [Value Creation]
654 /** mpdm_t MPDM_NS(wchar_t * wcs, int s); */
655 /* ; */
658 * MPDM_ENS - Creates a string value from an external string, with size.
659 * @wcs: the external wide character string
660 * @s: the size in chars the string will hold
662 * Creates a new string value with size @s. The @wcs string must be
663 * a dynamic value (i.e. allocated by malloc()) that will be freed on
664 * destruction.
665 * [Value Creation]
667 /** mpdm_t MPDM_ENS(wchar_t * wcs, int s); */
668 /* ; */
671 * MPDM_I - Creates an integer value.
672 * @i: the integer
674 * Creates a new integer value. MPDM integers are strings.
675 * [Value Creation]
677 /** mpdm_t MPDM_I(int i); */
678 /* ; */
681 * MPDM_R - Creates a real value.
682 * @r: the real number
684 * Creates a new real value. MPDM integers are strings.
685 * [Value Creation]
687 /** mpdm_t MPDM_R(double r); */
688 /* ; */
691 * MPDM_F - Creates a file value.
692 * @f: the file descriptor
694 * Creates a new file value.
695 * [Value Creation]
697 /** mpdm_t MPDM_F(FILE * f); */
698 /* ; */
701 * MPDM_MBS - Creates a string value from a multibyte string.
702 * @mbs: the multibyte string
704 * Creates a new string value from a multibyte string, that will be
705 * converted to wcs by mpdm_mbstowcs().
706 * [Value Creation]
708 /** mpdm_t MPDM_MBS(char * mbs); */
709 /* ; */
712 * MPDM_NMBS - Creates a string value from a multibyte string, with size.
713 * @mbs: the multibyte string
714 * @s: the size
716 * Creates a new string value with the first @s characters from the @mbs
717 * multibyte string, that will be converted to wcs by mpdm_mbstowcs().
718 * [Value Creation]
720 /** mpdm_t MPDM_NMBS(char * mbs, int s); */
721 /* ; */
724 * MPDM_2MBS - Creates a multibyte string value from a wide char string.
725 * @wcs: the wide char string
727 * Creates a multibyte string value from the @wcs wide char string,
728 * converting it by mpdm_wcstombs(). Take note that multibyte string values
729 * are not properly strings, so they cannot be used for string comparison
730 * and such.
731 * [Value Creation]
733 /** mpdm_t MPDM_2MBS(wchar_t * wcs); */
734 /* ; */
737 * MPDM_X - Creates a new executable value.
738 * @func: the C code function
740 * Creates a new executable value given a pointer to the @func C code function.
741 * The function must receive an mpdm_t array value (that will hold their
742 * arguments) and return another one.
743 * [Value Creation]
745 /** mpdm_t MPDM_X(mpdm_t (* func)(mpdm_t args)); */
746 /* ; */
749 * MPDM_C - Creates a new value with a copy of a buffer.
750 * @flags: additional flags
751 * @ptr: pointer to data
752 * @size: data size
754 * Create a new value with a copy of a buffer. The value will store a copy
755 * of @ptr and have the additional @flags.
756 * [Value Creation]
758 /** mpdm_t MPDM_C(int flags, void *ptr, int size); */
759 /* ; */
762 * MPDM_IS_ARRAY - Tests if a value is an array.
763 * @v: the value
765 * Returns non-zero if @v is an array.
767 /** int MPDM_IS_ARRAY(mpdm_t v); */
768 /* ; */
771 * MPDM_IS_HASH - Tests if a value is a hash.
772 * @v: the value
774 * Returns non-zero if @v is a hash.
776 /** int MPDM_IS_HASH(mpdm_t v); */
777 /* ; */
780 * MPDM_IS_EXEC - Tests if a value is executable.
781 * @v: the value
783 * Returns non-zero if @v is executable.
785 /** int MPDM_IS_EXEC(mpdm_t v); */
786 /* ; */
789 * MPDM_IS_STRING - Tests if a value is a string.
790 * @v: the value
792 * Returns non-zero if @v is a string.
794 /** int MPDM_IS_STRING(mpdm_t v); */
795 /* ; */