tagged release 0.6.4
[parrot.git] / src / utils.c
bloba2bda498f4227fd4b56832793e9c45458bdec652
1 /*
2 Copyright (C) 2001-2008, The Perl Foundation.
3 $Id$
5 =head1 NAME
7 src/utils.c - Some utility functions
9 =head1 DESCRIPTION
11 Prototypes are in F<src/misc.h>.
13 Opcode helper functions that don't really fit elsewhere.
15 =head2 Functions
17 =over 4
19 =cut
23 #include "parrot/parrot.h"
25 typedef unsigned short _rand_buf[3];
27 /* Parrot_register_move companion functions i and data */
28 typedef struct parrot_prm_context {
29 unsigned char *dest_regs;
30 unsigned char *src_regs;
31 unsigned char temp_reg;
32 int* nb_succ;
33 int* backup;
34 int* reg_to_index;
35 Interp *interp;
36 reg_move_func mov;
37 reg_move_func mov_alt;
38 void *info;
39 } parrot_prm_context;
41 /* HEADERIZER HFILE: include/parrot/misc.h */
42 /* HEADERIZER BEGIN: static */
43 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
45 static FLOATVAL _drand48(void);
46 static FLOATVAL _erand48(_rand_buf buf);
47 static long _jrand48(_rand_buf buf);
48 static long _lrand48(void);
49 static long _mrand48(void);
50 static long _nrand48(_rand_buf buf);
51 static void _srand48(long seed);
52 static INTVAL COMPARE(PARROT_INTERP, void *a, void *b, PMC *cmp)
53 __attribute__nonnull__(1);
55 static void next_rand(_rand_buf X);
56 static void process_cycle_without_exit(
57 int node_index,
58 ARGIN(parrot_prm_context* c))
59 __attribute__nonnull__(2);
61 static void rec_climb_back_and_mark(
62 int node_index,
63 ARGIN(parrot_prm_context* c))
64 __attribute__nonnull__(2);
66 static void swap(void **x, void **y);
67 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
68 /* HEADERIZER END: static */
70 #define move_reg(from, dest, c) (c)->mov((c)->interp, (unsigned char)(dest), \
71 (unsigned char)(from), (c)->info)
75 =item C<INTVAL intval_mod>
77 NOTE: This "corrected mod" algorithm is based on the C code on page 70
78 of [1]. Assuming correct behavior of the built-in mod operator (%) with
79 positive arguments, this algorithm implements a mathematically
80 convenient version of mod, defined thus:
82 x mod y = x - y * floor(x / y)
84 For more information on this definition of mod, see section 3.4 of [2],
85 pages 81-85.
87 References:
89 [1] Donald E. Knuth, *MMIXware: A RISC Computer for the Third
90 Millennium* Springer, 1999.
92 [2] Ronald L. Graham, Donald E. Knuth and Oren Patashnik, *Concrete
93 Mathematics*, Second Edition. Addison-Wesley, 1994.
95 =cut
99 PARROT_CONST_FUNCTION
100 INTVAL
101 intval_mod(INTVAL i2, INTVAL i3)
103 INTVAL z = i3;
105 if (z == 0)
106 return i2;
107 else {
108 INTVAL r;
109 INTVAL y;
110 int s = 0;
112 y = i2;
114 if (y < 0) { s += 2; y = -y; }
115 if (z < 0) { s += 1; z = -z; }
117 r = y % z;
119 if (r) { /* # 36003 */
120 switch (s) {
121 case 0: break;
122 case 1: r = r - z; break;
123 case 2: r = z - r; break;
124 case 3: r = -r; break;
125 default: break;
129 return r;
135 =item C<FLOATVAL floatval_mod>
137 Returns C<n2 mod n3>.
139 Includes a workaround for buggy code generation in the C<lcc> compiler.
141 =cut
145 PARROT_CONST_FUNCTION
146 FLOATVAL
147 floatval_mod(FLOATVAL n2, FLOATVAL n3)
149 #ifdef __LCC__
151 /* Another workaround for buggy code generation in the lcc compiler-
152 * adding a temporary variable makes it pass the test.
154 const FLOATVAL temp = n3 * floor(n2 / n3);
156 return !FLOAT_IS_ZERO(n3)
157 ? (n2 - temp)
158 : n2;
159 #else
160 return !FLOAT_IS_ZERO(n3)
161 ? (n2 - n3 * floor(n2 / n3))
162 : n2;
163 #endif
169 =back
171 =head2 Random Number Generator
173 Based on the C<rand48()> family of functions.
175 =over 4
177 =cut
182 * currently undefined
184 #ifndef PARROT_HAS_DRAND48
187 * s. man drand48, SuS V2
189 * X(n+1) = ( aX(n) + c ) mod 2^48
192 # define A_lo 0xE66D
193 # define A_mid 0xDEEC
194 # define A_hi 0x5
195 # define C 0xB
196 # define SEED_LO 0x330E
198 static _rand_buf a = { A_lo, A_mid, A_hi };
199 static _rand_buf last_rand;
200 static unsigned short c = C;
204 =item C<static void next_rand>
206 Returns the next random number in C<X>.
208 =cut
212 static void
213 next_rand(_rand_buf X)
215 unsigned short lo, mid, hi;
216 unsigned int t;
218 /* 48 bit mul, one short at a time */
219 t = X[0] * a[0] + c;
220 lo = t & 0xffff;
221 mid = (t >> 16) & 0xffff;
223 t = X[1] * a[0] + X[0] * a[1] + mid;
224 mid = t & 0xffff;
225 hi = (t >> 16) & 0xffff;
227 t = X[2] * a[0] + X[1] * a[1] + X[0] * a[2] + hi;
229 X[0] = lo;
230 X[1] = mid;
231 X[2] = t & 0xffff;
236 =item C<static FLOATVAL _erand48>
238 Returns a C<double> in the interval C<[0.0, 1.0)>.
240 =cut
244 static FLOATVAL
245 _erand48(_rand_buf buf)
247 FLOATVAL r;
248 next_rand(buf);
249 r = ((buf[0] / 65536.0 + buf[1]) / 65536.0 + buf[2]) / 65536.0;
250 return r;
255 =item C<static FLOATVAL _drand48>
257 Returns a C<double> in the interval C<[0.0, 1.0)>.
259 =cut
263 static FLOATVAL
264 _drand48(void)
266 return _erand48(last_rand);
271 =item C<static long _jrand48>
273 Returns a C<long> in the interval C<[-2^31, 2^31)>.
275 =cut
279 static long
280 _jrand48(_rand_buf buf)
282 long ret;
283 next_rand(buf);
284 ret = buf[2] << 16 | buf[1];
285 return ret;
290 =item C<static long _nrand48>
292 Returns a C<long> in the interval C<[0, 2^31)>.
294 =cut
298 static long
299 _nrand48(_rand_buf buf)
301 return _jrand48(buf) & 0x7fffffff;
306 =item C<static long _lrand48>
308 Returns a C<long> in the interval C<[0, 2^31)>.
310 =cut
314 static long
315 _lrand48(void)
317 return _nrand48(last_rand);
322 =item C<static long _mrand48>
324 Returns a C<long> in the interval C<[-2^31, 2^31)>.
326 =cut
330 static long
331 _mrand48(void)
333 return _jrand48(last_rand);
338 =item C<static void _srand48>
340 Sets the high order 32 bits to the argument C<seed>. The low order 16
341 bits are set to the arbitrary value 0x330e.
343 =cut
347 static void
348 _srand48(long seed)
350 last_rand[0] = SEED_LO;
351 last_rand[1] = (unsigned short)seed & 0xffff;
352 last_rand[2] = (unsigned short)(seed >> 16) & 0xffff;
354 * reinit a, c if changed by lcong48()
358 # undef A_lo
359 # undef A_mid
360 # undef A_hi
361 # undef C
363 #else
365 # define _drand48 drand48
366 # define _erand48(b) erand48(b)
368 # define _lrand48 lrand48
369 # define _nrand48(b) nrand48(b)
371 # define _mrand48 mrand48
372 # define _jrand48(b) jrand48(b)
374 # define _srand48 srand48
376 #endif
380 =item C<FLOATVAL Parrot_float_rand>
382 Returns a C<FLOATVAL> in the interval C<[0.0, 1.0)>.
384 C<how_random> is ignored.
386 =cut
390 PARROT_API
391 FLOATVAL
392 Parrot_float_rand(INTVAL how_random)
394 UNUSED(how_random);
396 return _drand48(); /* [0.0..1.0] */
401 =item C<INTVAL Parrot_uint_rand>
403 Returns an C<INTVAL> in the interval C<[0, 2^31)>.
405 C<how_random> is ignored.
407 =cut
411 PARROT_API
412 INTVAL
413 Parrot_uint_rand(INTVAL how_random)
415 UNUSED(how_random);
417 return _lrand48(); /* [0..2^31] */
422 =item C<INTVAL Parrot_int_rand>
424 Returns an C<INTVAL> in the interval C<[-2^31, 2^31)>.
426 C<how_random> is ignored.
428 =cut
432 PARROT_API
433 INTVAL
434 Parrot_int_rand(INTVAL how_random)
436 UNUSED(how_random);
438 return _mrand48(); /* [-2^31..2^31] */
443 =item C<INTVAL Parrot_range_rand>
445 Returns an C<INTVAL> in the range C<[from, to]>.
447 C<how_random> is ignored.
449 =cut
453 PARROT_API
454 INTVAL
455 Parrot_range_rand(INTVAL from, INTVAL to, INTVAL how_random)
457 return (INTVAL)(from + ((double)(to - from))
458 * Parrot_float_rand(how_random));
463 =item C<void Parrot_srand>
465 Seeds the random number generator with C<seed>.
467 =cut
471 PARROT_API
472 void
473 Parrot_srand(INTVAL seed)
475 _srand48(seed);
479 /* &gen_from_enum(tm.pasm) */
480 typedef enum {
481 TM_SEC,
482 TM_MIN,
483 TM_HOUR,
484 TM_MDAY,
485 TM_MON,
486 TM_YEAR,
487 TM_WDAY,
488 TM_YDAY,
489 TM_ISDST
490 } tm_struct_enum;
491 /* &end_gen */
495 =item C<PMC* tm_to_array>
497 Helper to convert a B<struct tm *> to an Array
499 =cut
503 PARROT_WARN_UNUSED_RESULT
504 PARROT_CANNOT_RETURN_NULL
505 PMC*
506 tm_to_array(PARROT_INTERP, ARGIN(const struct tm *tm))
508 PMC * const Array = pmc_new(interp, enum_class_Array);
510 PARROT_ASSERT(tm);
512 VTABLE_set_integer_native(interp, Array, 9);
513 VTABLE_set_integer_keyed_int(interp, Array, 0, tm->tm_sec);
514 VTABLE_set_integer_keyed_int(interp, Array, 1, tm->tm_min);
515 VTABLE_set_integer_keyed_int(interp, Array, 2, tm->tm_hour);
516 VTABLE_set_integer_keyed_int(interp, Array, 3, tm->tm_mday);
517 VTABLE_set_integer_keyed_int(interp, Array, 4, tm->tm_mon + 1);
518 VTABLE_set_integer_keyed_int(interp, Array, 5, tm->tm_year + 1900);
519 VTABLE_set_integer_keyed_int(interp, Array, 6, tm->tm_wday);
520 VTABLE_set_integer_keyed_int(interp, Array, 7, tm->tm_yday);
521 VTABLE_set_integer_keyed_int(interp, Array, 8, tm->tm_isdst);
523 return Array;
528 =item C<INTVAL Parrot_byte_index>
530 Looks for the location of a substring within a longer string. Takes
531 pointers to the strings and the offset within the string at which
532 to start searching as arguments.
534 Returns an offset value if it is found, or -1 if no match.
536 =cut
540 PARROT_API
541 INTVAL
542 Parrot_byte_index(SHIM_INTERP, ARGIN(const STRING *base),
543 ARGIN(const STRING *search), UINTVAL start_offset)
545 const char * const str_start = base->strstart;
546 const INTVAL str_len = base->strlen;
547 const char * const search_str = search->strstart;
548 const INTVAL search_len = search->strlen;
549 const char *str_pos = str_start + start_offset;
550 INTVAL len_remain = str_len - start_offset;
551 const char *search_pos;
553 /* find the next position of the first character in the search string
554 * Parrot strings can have NULLs, so strchr() won't work here */
555 while ((search_pos = (const char *)memchr(str_pos, *search_str, len_remain))) {
556 const INTVAL offset = search_pos - str_start;
558 /* now look for the entire string */
559 if (memcmp(search_pos, search_str, search_len) == 0)
560 return offset;
562 /* otherwise loop and memchr() with the rest of the string */
563 len_remain = str_len - offset;
564 str_pos = search_pos + 1;
566 if (len_remain < search_len)
567 return -1;
570 return -1;
575 =item C<INTVAL Parrot_byte_rindex>
577 Substring search (like Parrot_byte_index), but works backwards,
578 from the rightmost end of the string.
580 Returns offset value or -1 (if no match).
582 =cut
586 PARROT_API
587 PARROT_WARN_UNUSED_RESULT
588 INTVAL
589 Parrot_byte_rindex(SHIM_INTERP, ARGIN(const STRING *base),
590 ARGIN(const STRING *search), UINTVAL start_offset)
592 const INTVAL searchlen = search->strlen;
593 const char * const search_start = search->strstart;
594 UINTVAL max_possible_offset = (base->strlen - search->strlen);
595 INTVAL current_offset;
597 if (start_offset && start_offset < max_possible_offset)
598 max_possible_offset = start_offset;
600 for (current_offset = max_possible_offset; current_offset >= 0;
601 current_offset--) {
602 const char * const base_start = (char *)base->strstart + current_offset;
603 if (memcmp(base_start, search_start, searchlen) == 0) {
604 return current_offset;
608 return -1;
613 =item C<static void rec_climb_back_and_mark>
615 Recursive function, used by Parrot_register_move to
616 climb back the graph of register moves operations.
618 The node must have a predecessor: it is implicit because if a node has
619 a node_index, it must have a predecessor because the node_index are the
620 index of registers in dest_regs[] array, so by definition they have
621 a corrsponding src_regs register.
623 Then it emits the move operation with its predecessor, or its backup
624 if already used/visited.
626 Then continues the climbing if the predecessor was not modified, anf in that
627 case marks it, and set node_index as its backup.
629 node_index ... the index of a destination (i.e. with a pred.) register
630 c ... the graph and all the needed params : the context
632 =cut
636 static void
637 rec_climb_back_and_mark(int node_index, ARGIN(parrot_prm_context* c))
639 const int node = c->dest_regs[node_index];
640 const int pred = c->src_regs[node_index];
641 const int pred_index = c->reg_to_index[pred];
643 if (pred_index < 0) { /* pred has no predecessor */
644 move_reg(pred, node, c);
646 else { /* pred has a predecessor, so may be processed */
647 const int src = c->backup[pred_index];
648 if (src < 0) { /* not visited */
649 move_reg(pred, node, c);
650 c->backup[pred_index] = node; /* marks pred*/
651 rec_climb_back_and_mark(pred_index, c);
653 else { /* already visited, use backup instead */
654 move_reg(src, node, c);
662 =item C<static void process_cycle_without_exit>
664 Recursive function, used by Parrot_register_move to handle the case
665 of cycles without exits, that are cycles of move ops between registers
666 where each register has exactly one predecessor and one successor
668 For instance: 1-->2, 2-->3, 3-->1
670 node_index ... the index of a destination (i.e. with a pred.) register
671 c ... the graph and all the needed params : the context
673 =cut
677 static void
678 process_cycle_without_exit(int node_index, ARGIN(parrot_prm_context* c))
680 const int pred = c->src_regs[node_index];
682 /* let's try the alternate move function*/
683 const int alt =
684 c->mov_alt
685 ? c->mov_alt(c->interp, c->dest_regs[node_index], pred, c->info)
686 : 0;
688 if (0 == alt) { /* use temp reg */
689 move_reg(c->dest_regs[node_index], c->temp_reg, c);
690 c->backup[node_index] = c->temp_reg;
692 else
693 c->backup[node_index] = c->dest_regs[node_index];
695 rec_climb_back_and_mark(node_index, c);
700 =item C<void Parrot_register_move>
702 Move C<n_regs> from the given register list C<src_regs> to C<dest_regs>.
704 n_regs ... amount of registers to move
705 dest_regs ... list of register numbers 0..255
706 src_regs ... list of register numbers 0..255
707 temp_reg ... a register number not in one of these lists
708 mov ... a register move function to be called to move one register
709 mov_alt ... a register move function to be called to move one register
710 which triese fetching from an alternate src (or NULLfunc):
712 (void) (mov)(interp, dest, src, info);
713 moved = (mov_alt)(interp, dest, src, info);
715 Some C<dest_regs> might be the same as C<src_regs>, which makes this a bit
716 non-trivial, because if the destination is already clobbered, using it
717 later as source doesn"t work. E.g.
719 0 <- 1
720 1 <- 0 # register 0 already clobbered
724 2 <- 0
725 0 <- 1
726 3 <- 2 # register 2 already clobbered - reorder moves
728 To handle such cases, we do:
730 a) rearrange the order of moves (not possible in the first case)
731 and/or if that failed:
732 b) if an alternate move function is available, it may fetch the
733 source from a different (non-clobbered) location - call it.
734 if the function returns 0 also use c)
735 c) if no alternate move function is available, use the temp reg
737 The amount of register moves should of course be minimal.
739 TODO The current implementation will not work for following cases
741 Talked to Leo and he said those cases are not likely (Vishal Soni).
742 1. I0->I1 I1->I0 I0->I3
743 2. I1->I2 I3->I2
745 TODO: Add tests for the above conditions.
747 =cut
751 PARROT_API
752 void
753 Parrot_register_move(PARROT_INTERP,
754 int n_regs,
755 ARGOUT(unsigned char *dest_regs),
756 ARGIN(unsigned char *src_regs),
757 unsigned char temp_reg,
758 reg_move_func mov,
759 reg_move_func mov_alt,
760 ARGIN(void *info))
762 int i;
763 int max_reg = 0;
764 int* nb_succ = NULL;
765 int* backup = NULL;
766 int* reg_to_index = NULL;
767 parrot_prm_context c;
769 if (n_regs == 0)
770 return;
772 if (n_regs == 1) {
773 if (src_regs[0] != dest_regs[0])
774 mov(interp, dest_regs[0], src_regs[0], info);
775 return;
778 c.interp = interp;
779 c.info = info;
780 c.mov = mov;
781 c.mov_alt = mov_alt;
782 c.src_regs = src_regs;
783 c.dest_regs = dest_regs;
784 c.temp_reg = temp_reg;
786 /* compute max_reg, the max reg number + 1 */
787 for (i = 0; i < n_regs; i++) {
788 if (src_regs[i] > max_reg)
789 max_reg = src_regs[i];
790 if (dest_regs[i] > max_reg)
791 max_reg = dest_regs[i];
793 ++max_reg;
796 /* allocate space for data structures */
797 /* NOTA: data structures could be kept allocated somewhere waiting to get reused...*/
798 c.nb_succ = nb_succ = mem_allocate_n_zeroed_typed(n_regs, int);
799 c.backup = backup = mem_allocate_n_zeroed_typed(n_regs, int);
800 c.reg_to_index = reg_to_index = mem_allocate_n_zeroed_typed(max_reg, int);
802 /* init backup array */
803 for (i = 0; i < n_regs; i++)
804 backup[i] = -1;
806 /* fill in the conversion array between a register number and its index */
807 for (i = 0; i < max_reg; i++)
808 reg_to_index[i] = -1;
809 for (i = 0; i < n_regs; i++) {
810 const int index = dest_regs[i];
811 if (index != src_regs[i]) /* get rid of self-assignment */
812 reg_to_index[index] = i;
815 /* count the nb of successors for each reg index */
816 for (i = 0; i < n_regs; i++) {
817 const int index = reg_to_index[ src_regs[i] ];
818 if (index >= 0) /* not interested in the wells that have no preds */
819 nb_succ[ index ]++;
821 /* process each well if any */
822 for (i = 0; i < n_regs; i++) {
823 if (0 == nb_succ[i]) { /* a well */
824 rec_climb_back_and_mark(i, &c);
828 /* process remaining dest registers not processed */
829 /* remaining nodes are members of cycles without exits */
830 for (i = 0; i < n_regs; i++) {
831 if (0 < nb_succ[i] && 0 > backup[i]) { /* not a well nor visited*/
832 process_cycle_without_exit(i, &c);
836 mem_sys_free(nb_succ);
837 mem_sys_free(reg_to_index);
838 mem_sys_free(backup);
841 /* TODO: Macroize swap and COMPARE */
842 static void
843 swap(void **x, void **y)
845 void *t = *x;
846 *x = *y;
847 *y = t;
850 typedef INTVAL (*sort_func_t)(PARROT_INTERP, void*, void*);
852 static INTVAL
853 COMPARE(PARROT_INTERP, void *a, void *b, PMC *cmp)
855 if (PMC_IS_NULL(cmp))
856 return mmd_dispatch_i_pp(interp, (PMC *)a, (PMC *)b, MMD_CMP);
858 if (cmp->vtable->base_type == enum_class_NCI) {
859 const sort_func_t f = (sort_func_t)D2FPTR(PMC_struct_val(cmp));
860 return f(interp, a, b);
863 return Parrot_runops_fromc_args_reti(interp, cmp, "IPP", a, b);
867 void
868 Parrot_quicksort(PARROT_INTERP, void **data, UINTVAL n, PMC *cmp)
870 while (n > 1) {
871 UINTVAL i, j, ln, rn;
873 swap(&data[0], &data[n/2]);
875 for (i = 0, j = n; ;) {
877 --j;
879 while (j > 0 && COMPARE(interp, data[j], data[0], cmp) > 0);
882 ++i;
883 while (i < j && COMPARE(interp, data[i], data[0], cmp) < 0);
885 if (i >= j)
886 break;
888 swap(&data[i], &data[j]);
891 swap(&data[j], &data[0]);
893 ln = j;
894 rn = n - ++j;
896 if (ln < rn) {
897 Parrot_quicksort(interp, data, ln, cmp);
898 data += j;
899 n = rn;
901 else {
902 Parrot_quicksort(interp, data + j, rn, cmp);
903 n = ln;
910 =back
912 =head1 HISTORY
914 Initial version by leo 2003.09.09.
916 =cut
922 * Local variables:
923 * c-file-style: "parrot"
924 * End:
925 * vim: expandtab shiftwidth=4: