3 MPDM - Minimum Profit Data Manager
4 Copyright (C) 2003/2010 Angel Ortega <angel@triptico.com>
6 mpdm_t.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
38 /* control structure */
40 struct mpdm_control
*mpdm
= NULL
;
45 static void cleanup_value(mpdm_t v
)
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 mpdm
->memory_usage
-= v
->size
;
55 free((void *)v
->data
);
61 int mpdm_destroy(mpdm_t v
)
62 /* destroys a value */
67 if (v
->ref
== 0 && !(v
->flags
& MPDM_DELETED
)) {
71 v
->flags
|= MPDM_DELETED
;
76 /* try to dequeue next one */
79 if (w
&& w
->flags
& MPDM_DELETED
) {
83 /* if it's the current one, move to next */
87 /* account one value less */
90 /* add to the deleted values queue */
100 * mpdm_new - Creates a new value.
102 * @data: pointer to real data
103 * @size: size of data
105 * Creates a new value. @flags is an or-ed set of flags, @data is a
106 * pointer to the data the value will store and @size the size of these
107 * data (if value is to be a multiple one, @size is a number of elements,
108 * or a number of bytes otherwise).
110 * This function is normally not directly used; use any of the type
111 * creation macros instead.
114 mpdm_t
mpdm_new(int flags
, const void *data
, int size
)
119 if ((v
= mpdm
->del
) != NULL
)
122 if ((v
= malloc(sizeof(struct mpdm_val
))) == NULL
)
125 /* add to the circular list */
126 if (mpdm
->cur
== NULL
)
129 v
->next
= mpdm
->cur
->next
;
135 /* account one value more */
138 /* count memory if data is dynamic */
139 if (flags
& MPDM_FREE
)
140 mpdm
->memory_usage
+= size
;
152 * mpdm_ref - Increments the reference count of a value.
155 * Increments the reference count of a value.
158 mpdm_t
mpdm_ref(mpdm_t v
)
167 * mpdm_unref - Decrements the reference count of a value.
170 * Decrements the reference count of a value.
173 mpdm_t
mpdm_unref(mpdm_t v
)
178 #ifdef DESTROY_ON_UNREF
191 * mpdm_unrefnd - Decrements the reference count of a value, without destroy.
194 * Decrements the reference count of a value, without destroying
195 * the value if it's unreferenced.
198 mpdm_t
mpdm_unrefnd(mpdm_t v
)
207 * mpdm_sweep - Sweeps unreferenced values.
208 * @count: number of values to be swept
210 * Destroys values with a reference count of 0. @count is the
211 * number of values to be checked for deletion; special values of
212 * @count are -1, that forces a check of all currently known values
213 * (can be time-consuming) and 0, which tells mpdm_sweep() to check a
214 * small group of them on each call.
217 void mpdm_sweep(int count
)
219 /* if count is zero, sweep 'some' values */
221 if (mpdm
->default_sweep
< 0)
222 count
= mpdm
->count
/ -mpdm
->default_sweep
;
224 count
= mpdm
->default_sweep
;
227 /* if count is -1, sweep all */
231 for (; count
> 0 && mpdm
->count
> mpdm
->low_threshold
; count
--) {
232 mpdm_destroy(mpdm
->cur
);
233 mpdm
->cur
= mpdm
->cur
->next
;
239 * mpdm_size - Returns the size of an element.
242 * Returns the size of an element.
245 int mpdm_size(const mpdm_t v
)
247 /* NULL values have no size */
256 * mpdm_clone - Creates a clone of a value.
259 * Creates a clone of a value. If the value is multiple, a new value will
260 * be created containing clones of all its elements; otherwise,
261 * the same unchanged value is returned.
264 mpdm_t
mpdm_clone(const mpdm_t v
)
270 if (MPDM_IS_ARRAY(v
))
282 * mpdm_root - Returns the root hash.
284 * Returns the root hash. This hash is stored internally and can be used
285 * as a kind of global symbol table.
288 mpdm_t
mpdm_root(void)
290 if (mpdm
->root
== NULL
)
291 mpdm
->root
= mpdm_ref(MPDM_H(0));
297 mpdm_t
mpdm_set_ival(mpdm_t v
, int ival
)
298 /* sets an integer value to a value */
300 v
->flags
|= MPDM_IVAL
;
307 mpdm_t
mpdm_set_rval(mpdm_t v
, double rval
)
308 /* sets a real value to a value */
310 v
->flags
|= MPDM_RVAL
;
318 * mpdm_exec - Executes an executable value.
320 * @args: the arguments
322 * Executes an executable value. If @c is a scalar value, its data
323 * should be a pointer to a directly executable C function with a
324 * prototype of mpdm_t func(mpdm_t args); if it's a multiple one,
325 * the first value's data should be a pointer to a directly executable C
326 * function with a prototype of mpdm_t func(mpdm_t b, mpdm_t args) and
327 * the second value will be passed as the @b argument. This value is used
328 * to store bytecode or so when implementing virtual machines or compilers.
330 * Returns the return value of the code. If @c is NULL or not executable,
334 mpdm_t
mpdm_exec(mpdm_t c
, mpdm_t args
)
338 if (c
!= NULL
&& (c
->flags
& MPDM_EXEC
)) {
342 if (c
->flags
& MPDM_MULTIPLE
) {
344 mpdm_t(*func
) (mpdm_t
, mpdm_t
);
346 /* value is multiple; first element is the
347 2 argument version of the executable function,
348 next its optional additional information and
349 finally the arguments */
352 if ((func
= (mpdm_t(*)(mpdm_t
, mpdm_t
)) (x
->data
)) != NULL
)
353 r
= func(mpdm_aget(c
, 1), args
);
356 mpdm_t(*func
) (mpdm_t
);
358 /* value is scalar; c is the 1 argument
359 version of the executable function */
360 if ((func
= (mpdm_t(*)(mpdm_t
)) (c
->data
)) != NULL
)
372 mpdm_t
mpdm_exec_1(mpdm_t c
, mpdm_t a1
)
374 mpdm_t a
= MPDM_A(1);
377 return mpdm_exec(c
, a
);
381 mpdm_t
mpdm_exec_2(mpdm_t c
, mpdm_t a1
, mpdm_t a2
)
383 mpdm_t a
= MPDM_A(2);
387 return mpdm_exec(c
, a
);
391 mpdm_t
mpdm_exec_3(mpdm_t c
, mpdm_t a1
, mpdm_t a2
, mpdm_t a3
)
393 mpdm_t a
= MPDM_A(3);
398 return mpdm_exec(c
, a
);
402 mpdm_t
mpdm_xnew(mpdm_t(*a1
) (mpdm_t
, mpdm_t
), mpdm_t a2
)
407 x
->flags
|= MPDM_EXEC
;
409 mpdm_aset(x
, MPDM_X(a1
), 0);
416 static mpdm_t
MPDM(const mpdm_t args
)
417 /* accesor / mutator for MPDM internal data */
424 v
= mpdm_aget(args
, 0);
430 if ((w
= mpdm_hget_s(v
, L
"low_threshold")) != NULL
&& mpdm_ival(w
) > 0)
431 mpdm
->low_threshold
= mpdm_ival(w
);
433 if ((w
= mpdm_hget_s(v
, L
"default_sweep")) != NULL
)
434 mpdm
->default_sweep
= mpdm_ival(w
);
436 if ((w
= mpdm_hget_s(v
, L
"hash_buckets")) != NULL
)
437 mpdm
->hash_buckets
= mpdm_ival(w
);
440 /* loop all values counting the unreferenced and deleted ones */
441 for (n
= mpdm
->count
, v
= mpdm
->cur
; n
> 0; n
--, v
= v
->next
) {
445 if (v
->flags
& MPDM_DELETED
)
451 /* now collect all information */
454 mpdm_hset_s(v
, L
"version", MPDM_MBS(VERSION
));
455 mpdm_hset_s(v
, L
"count", MPDM_I(mpdm
->count
));
456 mpdm_hset_s(v
, L
"low_threshold", MPDM_I(mpdm
->low_threshold
));
457 mpdm_hset_s(v
, L
"default_sweep", MPDM_I(mpdm
->default_sweep
));
458 mpdm_hset_s(v
, L
"memory_usage", MPDM_I(mpdm
->memory_usage
));
459 mpdm_hset_s(v
, L
"hash_buckets", MPDM_I(mpdm
->hash_buckets
));
460 mpdm_hset_s(v
, L
"unreferenced", MPDM_I(c
));
461 mpdm_hset_s(v
, L
"deleted", MPDM_I(d
));
463 #ifdef DESTROY_ON_UNREF
464 mpdm_hset_s(v
, L
"destroy_on_unref",MPDM_I(1));
472 extern char **environ
;
474 static mpdm_t
build_env(void)
475 /* builds a hash with the environment */
478 mpdm_t e
= MPDM_H(0);
482 for (ptr
= environ
; *ptr
!= NULL
; ptr
++) {
483 char *eq
= strchr(*ptr
, '=');
488 k
= MPDM_NMBS((*ptr
), eq
- (*ptr
));
489 v
= MPDM_MBS(eq
+ 1);
502 * mpdm_startup - Initializes MPDM.
504 * Initializes the Minimum Profit Data Manager. Returns 0 if
505 * everything went OK.
507 int mpdm_startup(void)
509 /* do the startup only unless done beforehand */
512 if ((mpdm
= malloc(sizeof(struct mpdm_control
))) == NULL
)
516 memset(mpdm
, '\0', sizeof(struct mpdm_control
));
518 /* sets the defaults */
519 mpdm
->low_threshold
= 16;
520 mpdm
->default_sweep
= -50000;
521 mpdm
->hash_buckets
= 31;
523 /* sets the locale */
524 if (setlocale(LC_ALL
, "") == NULL
)
525 setlocale(LC_ALL
, "C");
529 /* store the MPDM() function */
530 mpdm_hset_s(mpdm_root(), L
"MPDM", MPDM_X(MPDM
));
532 /* store the ENV hash */
533 mpdm_hset_s(mpdm_root(), L
"ENV", build_env());
536 /* everything went OK */
542 * mpdm_shutdown - Shuts down MPDM.
544 * Shuts down MPDM. No MPDM functions should be used from now on.
546 void mpdm_shutdown(void)
552 * MPDM_A - Creates an array value.
553 * @n: Number of elements
555 * Creates a new array value with @n elements.
558 /** mpdm_t MPDM_A(int n); */
562 * MPDM_H - Creates a hash value.
563 * @n: Number of buckets in the hash (0: use default)
565 * Creates a new hash value with @n buckets. The number
566 * of buckets must be a prime number. If @n is 0, an
567 * optimal number of buckets will be used.
570 /** mpdm_t MPDM_H(int n); */
574 * MPDM_LS - Creates a string value from a literal string.
575 * @wcs: the wide character string
577 * Creates a new string value from a literal, wide character string.
578 * A pointer to the string will be stored in the value (not a copy).
581 /** mpdm_t MPDM_LS(wchar_t * wcs); */
585 * MPDM_S - Creates a string value from a string.
586 * @wcs: the wide character string
588 * Creates a new string value from a wide character string. The value
589 * will store a copy of the string that will be freed on destruction.
592 /** mpdm_t MPDM_S(wchar_t * wcs); */
596 * MPDM_NS - Creates a string value from a string, with size.
597 * @wcs: the wide character string
598 * @s: the size in chars the string will hold
600 * Creates a new string value with a copy of the first @s characters
601 * from the @wcs string.
604 /** mpdm_t MPDM_NS(wchar_t * wcs, int s); */
608 * MPDM_ENS - Creates a string value from an external string, with size.
609 * @wcs: the external wide character string
610 * @s: the size in chars the string will hold
612 * Creates a new string value with size @s. The @wcs string must be
613 * a dynamic value (i.e. allocated by malloc()) that will be freed on
617 /** mpdm_t MPDM_ENS(wchar_t * wcs, int s); */
621 * MPDM_I - Creates an integer value.
624 * Creates a new integer value. MPDM integers are strings.
627 /** mpdm_t MPDM_I(int i); */
631 * MPDM_R - Creates a real value.
632 * @r: the real number
634 * Creates a new real value. MPDM integers are strings.
637 /** mpdm_t MPDM_R(double r); */
641 * MPDM_F - Creates a file value.
642 * @f: the file descriptor
644 * Creates a new file value.
647 /** mpdm_t MPDM_F(FILE * f); */
651 * MPDM_MBS - Creates a string value from a multibyte string.
652 * @mbs: the multibyte string
654 * Creates a new string value from a multibyte string, that will be
655 * converted to wcs by mpdm_mbstowcs().
658 /** mpdm_t MPDM_MBS(char * mbs); */
662 * MPDM_NMBS - Creates a string value from a multibyte string, with size.
663 * @mbs: the multibyte string
666 * Creates a new string value with the first @s characters from the @mbs
667 * multibyte string, that will be converted to wcs by mpdm_mbstowcs().
670 /** mpdm_t MPDM_NMBS(char * mbs, int s); */
674 * MPDM_2MBS - Creates a multibyte string value from a wide char string.
675 * @wcs: the wide char string
677 * Creates a multibyte string value from the @wcs wide char string,
678 * converting it by mpdm_wcstombs(). Take note that multibyte string values
679 * are not properly strings, so they cannot be used for string comparison
683 /** mpdm_t MPDM_2MBS(wchar_t * wcs); */
687 * MPDM_X - Creates a new executable value.
688 * @func: the C code function
690 * Creates a new executable value given a pointer to the @func C code function.
691 * The function must receive an mpdm_t array value (that will hold their
692 * arguments) and return another one.
695 /** mpdm_t MPDM_X(mpdm_t (* func)(mpdm_t args)); */
699 * MPDM_IS_ARRAY - Tests if a value is an array.
702 * Returns non-zero if @v is an array.
704 /** int MPDM_IS_ARRAY(mpdm_t v); */
708 * MPDM_IS_HASH - Tests if a value is a hash.
711 * Returns non-zero if @v is a hash.
713 /** int MPDM_IS_HASH(mpdm_t v); */
717 * MPDM_IS_EXEC - Tests if a value is executable.
720 * Returns non-zero if @v is executable.
722 /** int MPDM_IS_EXEC(mpdm_t v); */
726 * MPDM_IS_STRING - Tests if a value is a string.
729 * Returns non-zero if @v is a string.
731 /** int MPDM_IS_STRING(mpdm_t v); */