3 MPDM - Minimum Profit Data Manager
4 Copyright (C) 2003/2007 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
39 /* control structure */
41 struct mpdm_control
* mpdm
= NULL
;
47 int mpdm_destroy(mpdm_t v
)
48 /* destroys a value */
50 /* if still referenced, don't do it */
54 /* collapse multiple values */
55 if(v
->flags
& MPDM_MULTIPLE
)
56 mpdm_collapse(v
, 0, v
->size
);
58 /* free data if needed */
59 if(v
->data
!= NULL
&& v
->flags
& MPDM_FREE
)
61 mpdm
->memory_usage
-= v
->size
;
66 v
->next
->prev
= v
->prev
;
67 v
->prev
->next
= v
->next
;
69 /* if it's the current one, move to next */
73 /* account one value less */
85 * mpdm_new - Creates a new value.
87 * @data: pointer to real data
90 * Creates a new value. @flags is an or-ed set of flags, @data is a
91 * pointer to the data the value will store and @size the size of these
92 * data (if value is to be a multiple one, @size is a number of elements,
93 * or a number of bytes otherwise).
95 * This function is normally not directly used; use any of the type
96 * creation macros instead.
99 mpdm_t
mpdm_new(int flags
, void * data
, int size
)
104 if((v
= mpdm
->del
) != NULL
)
107 if((v
= malloc(sizeof(struct mpdm_val
))) == NULL
)
110 /* add to the circular list */
111 if(mpdm
->cur
== NULL
)
112 v
->next
= v
->prev
= v
;
116 v
->next
= mpdm
->cur
->next
;
118 v
->prev
->next
= v
->next
->prev
= v
;
123 /* account one value more */
126 /* count memory if data is dynamic */
127 if(flags
& MPDM_FREE
)
128 mpdm
->memory_usage
+= size
;
140 * mpdm_ref - Increments the reference count of a value.
143 * Increments the reference count of a value.
146 mpdm_t
mpdm_ref(mpdm_t v
)
148 if(v
!= NULL
) v
->ref
++;
154 * mpdm_unref - Decrements the reference count of a value.
157 * Decrements the reference count of a value.
160 mpdm_t
mpdm_unref(mpdm_t v
)
162 if(v
!= NULL
) v
->ref
--;
168 * mpdm_sweep - Sweeps unreferenced values.
169 * @count: number of values to be swept
171 * Destroys values with a reference count of 0. @count is the
172 * number of values to be checked for deletion; special values of
173 * @count are -1, that forces a check of all currently known values
174 * (can be time-consuming) and 0, which tells mpdm_sweep() to check a
175 * small group of them on each call.
178 void mpdm_sweep(int count
)
180 /* if count is zero, sweep 'some' values */
181 if(count
== 0) count
= mpdm
->default_sweep
;
183 /* if count is -1, sweep all */
184 if(count
== -1) count
= mpdm
->count
;
186 for(;count
> 0 && mpdm
->count
> mpdm
->low_threshold
;count
--)
188 /* destroy it or skip it */
189 if(!mpdm_destroy(mpdm
->cur
))
190 mpdm
->cur
= mpdm
->cur
->next
;
196 * mpdm_size - Returns the size of an element.
199 * Returns the size of an element.
202 int mpdm_size(mpdm_t v
)
204 /* NULL values have no size */
205 if(v
== NULL
) return(0);
212 * mpdm_clone - Creates a clone of a value.
215 * Creates a clone of a value. If the value is multiple, a new value will
216 * be created containing clones of all its elements; otherwise,
217 * the same unchanged value is returned.
220 mpdm_t
mpdm_clone(mpdm_t v
)
230 * mpdm_root - Returns the root hash.
232 * Returns the root hash. This hash is stored internally and can be used
233 * as a kind of global symbol table.
236 mpdm_t
mpdm_root(void)
238 if(mpdm
->root
== NULL
)
239 mpdm
->root
= mpdm_ref(MPDM_H(0));
246 * mpdm_exec - Executes an executable value.
248 * @args: the arguments
250 * Executes an executable value. If @c is a scalar value, its data
251 * should be a pointer to a directly executable C function with a
252 * prototype of mpdm_t func(mpdm_t args); if it's a multiple one,
253 * the first value's data should be a pointer to a directly executable C
254 * function with a prototype of mpdm_t func(mpdm_t b, mpdm_t args) and
255 * the second value will be passed as the @b argument. This value is used
256 * to store bytecode or so when implementing virtual machines or compilers.
258 * Returns the return value of the code. If @c is NULL or not executable,
262 mpdm_t
mpdm_exec(mpdm_t c
, mpdm_t args
)
266 if(c
!= NULL
&& (c
->flags
& MPDM_EXEC
))
271 if(c
->flags
& MPDM_MULTIPLE
)
274 mpdm_t (* func
)(mpdm_t
, mpdm_t
);
276 /* value is multiple; first element is the
277 2 argument version of the executable function,
278 next its optional additional information and
279 finally the arguments */
282 if((func
= (mpdm_t (*)(mpdm_t
, mpdm_t
))(x
->data
)) != NULL
)
283 r
= func(mpdm_aget(c
, 1), args
);
287 mpdm_t (* func
)(mpdm_t
);
289 /* value is scalar; c is the 1 argument
290 version of the executable function */
291 if((func
= (mpdm_t (*)(mpdm_t
))(c
->data
)) != NULL
)
303 mpdm_t
mpdm_exec_1(mpdm_t c
, mpdm_t a1
)
306 mpdm_t a
= MPDM_A(1);
315 mpdm_t
mpdm_exec_2(mpdm_t c
, mpdm_t a1
, mpdm_t a2
)
318 mpdm_t a
= MPDM_A(2);
328 mpdm_t
mpdm_exec_3(mpdm_t c
, mpdm_t a1
, mpdm_t a2
, mpdm_t a3
)
331 mpdm_t a
= MPDM_A(3);
342 mpdm_t
mpdm_xnew(mpdm_t (* a1
)(mpdm_t
, mpdm_t
), mpdm_t a2
)
347 x
->flags
|= MPDM_EXEC
;
349 mpdm_aset(x
, MPDM_X(a1
), 0);
356 static mpdm_t
MPDM(mpdm_t args
)
357 /* accesor / mutator for MPDM internal data */
359 mpdm_t v
= mpdm_aget(args
, 0);
367 if((w
= mpdm_hget_s(v
, L
"low_threshold")) != NULL
&&
369 mpdm
->low_threshold
= mpdm_ival(w
);
371 if((w
= mpdm_hget_s(v
, L
"default_sweep")) != NULL
)
372 mpdm
->default_sweep
= mpdm_ival(w
);
374 if((w
= mpdm_hget_s(v
, L
"hash_buckets")) != NULL
)
375 mpdm
->hash_buckets
= mpdm_ival(w
);
378 /* loop all values counting the references ones */
379 for(n
= mpdm
->count
, v
= mpdm
->cur
;n
> 0;n
--, v
= v
->next
)
382 /* now collect all information */
385 mpdm_hset_s(v
, L
"version", MPDM_MBS(VERSION
));
386 mpdm_hset_s(v
, L
"count", MPDM_I(mpdm
->count
));
387 mpdm_hset_s(v
, L
"low_threshold", MPDM_I(mpdm
->low_threshold
));
388 mpdm_hset_s(v
, L
"default_sweep", MPDM_I(mpdm
->default_sweep
));
389 mpdm_hset_s(v
, L
"memory_usage", MPDM_I(mpdm
->memory_usage
));
390 mpdm_hset_s(v
, L
"hash_buckets", MPDM_I(mpdm
->hash_buckets
));
391 mpdm_hset_s(v
, L
"unreferenced", MPDM_I(c
));
398 * mpdm_startup - Initializes MPDM.
400 * Initializes the Minimum Profit Data Manager. Returns 0 if
401 * everything went OK.
403 int mpdm_startup(void)
405 /* do the startup only unless done beforehand */
409 if((mpdm
= malloc(sizeof(struct mpdm_control
))) == NULL
)
413 memset(mpdm
, '\0', sizeof(struct mpdm_control
));
415 /* sets the defaults */
416 mpdm
->low_threshold
= 16;
417 mpdm
->default_sweep
= 16;
418 mpdm
->hash_buckets
= 31;
420 /* sets the locale */
421 if(setlocale(LC_ALL
, "") == NULL
)
422 setlocale(LC_ALL
, "C");
424 /* store the MPDM() function */
425 mpdm_hset_s(mpdm_root(), L
"MPDM", MPDM_X(MPDM
));
428 /* everything went OK */
434 * mpdm_shutdown - Shuts down MPDM.
436 * Shuts down MPDM. No MPDM functions should be used from now on.
438 void mpdm_shutdown(void)
444 * MPDM_A - Creates an array value.
445 * @n: Number of elements
447 * Creates a new array value with @n elements.
450 /** mpdm_t MPDM_A(int n); */
454 * MPDM_H - Creates a hash value.
455 * @n: Number of buckets in the hash (0: use default)
457 * Creates a new hash value with @n buckets. The number
458 * of buckets must be a prime number. If @n is 0, an
459 * optimal number of buckets will be used.
462 /** mpdm_t MPDM_H(int n); */
466 * MPDM_LS - Creates a string value from a literal string.
467 * @wcs: the wide character string
469 * Creates a new string value from a literal, wide character string.
470 * A pointer to the string will be stored in the value (not a copy).
473 /** mpdm_t MPDM_LS(wchar_t * wcs); */
477 * MPDM_S - Creates a string value from a string.
478 * @wcs: the wide character string
480 * Creates a new string value from a wide character string. The value
481 * will store a copy of the string that will be freed on destruction.
484 /** mpdm_t MPDM_S(wchar_t * wcs); */
488 * MPDM_NS - Creates a string value from a string, with size.
489 * @wcs: the wide character string
490 * @s: the size in chars the string will hold
492 * Creates a new string value with a copy of the first @s characters
493 * from the @wcs string.
496 /** mpdm_t MPDM_NS(wchar_t * wcs, int s); */
500 * MPDM_ENS - Creates a string value from an external string, with size.
501 * @wcs: the external wide character string
502 * @s: the size in chars the string will hold
504 * Creates a new string value with size @s. The @wcs string must be
505 * a dynamic value (i.e. allocated by malloc()) that will be freed on
509 /** mpdm_t MPDM_ENS(wchar_t * wcs, int s); */
513 * MPDM_I - Creates an integer value.
516 * Creates a new integer value. MPDM integers are strings.
519 /** mpdm_t MPDM_I(int i); */
523 * MPDM_R - Creates a real value.
524 * @r: the real number
526 * Creates a new real value. MPDM integers are strings.
529 /** mpdm_t MPDM_R(double r); */
533 * MPDM_F - Creates a file value.
534 * @f: the file descriptor
536 * Creates a new file value.
539 /** mpdm_t MPDM_F(FILE * f); */
543 * MPDM_MBS - Creates a string value from a multibyte string.
544 * @mbs: the multibyte string
546 * Creates a new string value from a multibyte string, that will be
547 * converted to wcs by mpdm_mbstowcs().
550 /** mpdm_t MPDM_MBS(char * mbs); */
554 * MPDM_NMBS - Creates a string value from a multibyte string, with size.
555 * @mbs: the multibyte string
558 * Creates a new string value with the first @s characters from the @mbs
559 * multibyte string, that will be converted to wcs by mpdm_mbstowcs().
562 /** mpdm_t MPDM_NMBS(char * mbs, int s); */
566 * MPDM_2MBS - Creates a multibyte string value from a wide char string.
567 * @wcs: the wide char string
569 * Creates a multibyte string value from the @wcs wide char string,
570 * converting it by mpdm_wcstombs(). Take note that multibyte string values
571 * are not properly strings, so they cannot be used for string comparison
575 /** mpdm_t MPDM_2MBS(wchar_t * wcs); */
579 * MPDM_X - Creates a new executable value.
580 * @func: the C code function
582 * Creates a new executable value given a pointer to the @func C code function.
583 * The function must receive an mpdm_t array value (that will hold their
584 * arguments) and return another one.
587 /** mpdm_t MPDM_X(mpdm_t (* func)(mpdm_t args)); */
591 * MPDM_IS_ARRAY - Tests if a value is an array.
594 * Returns non-zero if @v is an array.
596 /** int MPDM_IS_ARRAY(mpdm_t v); */
600 * MPDM_IS_HASH - Tests if a value is a hash.
603 * Returns non-zero if @v is a hash.
605 /** int MPDM_IS_HASH(mpdm_t v); */
609 * MPDM_IS_EXEC - Tests if a value is executable.
612 * Returns non-zero if @v is executable.
614 /** int MPDM_IS_EXEC(mpdm_t v); */
618 * MPDM_IS_STRING - Tests if a value is a string.
621 * Returns non-zero if @v is a string.
623 /** int MPDM_IS_STRING(mpdm_t v); */