Release 2.5.0
[parrot.git] / src / utils.c
blob6030fa5757b467f5aa31625e39cdec288cce9c84
1 /*
2 Copyright (C) 2001-2010, Parrot 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"
24 #include "pmc/pmc_nci.h"
26 typedef unsigned short _rand_buf[3];
28 /* Parrot_register_move companion functions i and data */
29 typedef struct parrot_prm_context {
30 unsigned char *dest_regs;
31 unsigned char *src_regs;
32 unsigned char temp_reg;
33 int* nb_succ;
34 int* backup;
35 int* reg_to_index;
36 Interp *interp;
37 reg_move_func mov;
38 reg_move_func mov_alt;
39 void *info;
40 } parrot_prm_context;
42 /* HEADERIZER HFILE: include/parrot/misc.h */
43 /* HEADERIZER BEGIN: static */
44 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
46 static FLOATVAL _drand48(void);
47 static FLOATVAL _erand48(_rand_buf buf);
48 static long _jrand48(_rand_buf buf);
49 static long _lrand48(void);
50 static long _mrand48(void);
51 static long _nrand48(_rand_buf buf);
52 static void _srand48(long seed);
53 static INTVAL COMPARE(PARROT_INTERP,
54 ARGIN(void *a),
55 ARGIN(void *b),
56 ARGIN(PMC *cmp))
57 __attribute__nonnull__(1)
58 __attribute__nonnull__(2)
59 __attribute__nonnull__(3)
60 __attribute__nonnull__(4);
62 static void next_rand(_rand_buf X);
63 static void process_cycle_without_exit(
64 int node_index,
65 ARGIN(const parrot_prm_context *c))
66 __attribute__nonnull__(2);
68 static void rec_climb_back_and_mark(
69 int node_index,
70 ARGIN(const parrot_prm_context *c))
71 __attribute__nonnull__(2);
73 #define ASSERT_ARGS__drand48 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
74 #define ASSERT_ARGS__erand48 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
75 #define ASSERT_ARGS__jrand48 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
76 #define ASSERT_ARGS__lrand48 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
77 #define ASSERT_ARGS__mrand48 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
78 #define ASSERT_ARGS__nrand48 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
79 #define ASSERT_ARGS__srand48 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
80 #define ASSERT_ARGS_COMPARE __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
81 PARROT_ASSERT_ARG(interp) \
82 , PARROT_ASSERT_ARG(a) \
83 , PARROT_ASSERT_ARG(b) \
84 , PARROT_ASSERT_ARG(cmp))
85 #define ASSERT_ARGS_next_rand __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
86 #define ASSERT_ARGS_process_cycle_without_exit __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
87 PARROT_ASSERT_ARG(c))
88 #define ASSERT_ARGS_rec_climb_back_and_mark __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
89 PARROT_ASSERT_ARG(c))
90 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
91 /* HEADERIZER END: static */
93 #define move_reg(from, dest, c) (c)->mov((c)->interp, (unsigned char)(dest), \
94 (unsigned char)(from), (c)->info)
98 =item C<INTVAL intval_mod(INTVAL i2, INTVAL i3)>
100 NOTE: This "corrected mod" algorithm is based on the C code on page 70
101 of [1]. Assuming correct behavior of the built-in mod operator (%) with
102 positive arguments, this algorithm implements a mathematically
103 convenient version of mod, defined thus:
105 x mod y = x - y * floor(x / y)
107 For more information on this definition of mod, see section 3.4 of [2],
108 pages 81-85.
110 References:
112 [1] Donald E. Knuth, *MMIXware: A RISC Computer for the Third
113 Millennium* Springer, 1999.
115 [2] Ronald L. Graham, Donald E. Knuth and Oren Patashnik, *Concrete
116 Mathematics*, Second Edition. Addison-Wesley, 1994.
118 =cut
122 PARROT_CONST_FUNCTION
123 PARROT_WARN_UNUSED_RESULT
124 INTVAL
125 intval_mod(INTVAL i2, INTVAL i3)
127 ASSERT_ARGS(intval_mod)
128 INTVAL z = i3;
130 if (z == 0)
131 return i2;
132 else {
133 INTVAL r;
134 INTVAL y;
135 int s = 0;
137 y = i2;
139 if (y < 0) { s += 2; y = -y; }
140 if (z < 0) { s += 1; z = -z; }
142 r = y % z;
144 if (r) { /* # 36003 */
145 switch (s) {
146 case 0: break;
147 case 1: r = r - z; break;
148 case 2: r = z - r; break;
149 case 3: r = -r; break;
150 default: break;
154 return r;
160 =item C<FLOATVAL floatval_mod(FLOATVAL n2, FLOATVAL n3)>
162 Returns C<n2 mod n3>.
164 Includes a workaround for buggy code generation in the C<lcc> compiler.
166 =cut
170 PARROT_CONST_FUNCTION
171 PARROT_WARN_UNUSED_RESULT
172 FLOATVAL
173 floatval_mod(FLOATVAL n2, FLOATVAL n3)
175 ASSERT_ARGS(floatval_mod)
176 #ifdef __LCC__
178 /* Another workaround for buggy code generation in the lcc compiler-
179 * adding a temporary variable makes it pass the test.
181 const FLOATVAL temp = n3 * floor(n2 / n3);
183 return !FLOAT_IS_ZERO(n3)
184 ? (n2 - temp)
185 : n2;
186 #else
187 return !FLOAT_IS_ZERO(n3)
188 ? (n2 - n3 * floor(n2 / n3))
189 : n2;
190 #endif
196 =back
198 =head2 Random Number Generator
200 Based on the C<rand48()> family of functions.
202 =over 4
204 =cut
209 * currently undefined
211 #ifndef PARROT_HAS_DRAND48
214 * s. man drand48, SuS V2
216 * X(n+1) = ( aX(n) + c ) mod 2^48
219 # define A_lo 0xE66D
220 # define A_mid 0xDEEC
221 # define A_hi 0x5
222 # define C 0xB
223 # define SEED_LO 0x330E
225 static _rand_buf a = { A_lo, A_mid, A_hi };
226 static _rand_buf last_rand;
227 static unsigned short c = C;
231 =item C<static void next_rand(_rand_buf X)>
233 Returns the next random number in C<X>.
235 =cut
239 static void
240 next_rand(_rand_buf X)
242 ASSERT_ARGS(next_rand)
243 unsigned short lo, mid, hi;
244 unsigned int t;
246 /* 48 bit mul, one short at a time */
247 t = X[0] * a[0] + c;
248 lo = t & 0xffff;
249 mid = (t >> 16) & 0xffff;
251 t = X[1] * a[0] + X[0] * a[1] + mid;
252 mid = t & 0xffff;
253 hi = (t >> 16) & 0xffff;
255 t = X[2] * a[0] + X[1] * a[1] + X[0] * a[2] + hi;
257 X[0] = lo;
258 X[1] = mid;
259 X[2] = t & 0xffff;
264 =item C<static FLOATVAL _erand48(_rand_buf buf)>
266 Returns a C<double> in the interval C<[0.0, 1.0)>.
268 =cut
272 static FLOATVAL
273 _erand48(_rand_buf buf)
275 ASSERT_ARGS(_erand48)
276 FLOATVAL r;
277 next_rand(buf);
278 r = ((buf[0] / 65536.0 + buf[1]) / 65536.0 + buf[2]) / 65536.0;
279 return r;
284 =item C<static FLOATVAL _drand48(void)>
286 Returns a C<double> in the interval C<[0.0, 1.0)>.
288 =cut
292 static FLOATVAL
293 _drand48(void)
295 ASSERT_ARGS(_drand48)
296 return _erand48(last_rand);
301 =item C<static long _jrand48(_rand_buf buf)>
303 Returns a C<long> in the interval C<[-2^31, 2^31)>.
305 =cut
309 static long
310 _jrand48(_rand_buf buf)
312 ASSERT_ARGS(_jrand48)
313 long ret;
314 next_rand(buf);
315 ret = buf[2] << 16 | buf[1];
316 return ret;
321 =item C<static long _nrand48(_rand_buf buf)>
323 Returns a C<long> in the interval C<[0, 2^31)>.
325 =cut
329 static long
330 _nrand48(_rand_buf buf)
332 ASSERT_ARGS(_nrand48)
333 return _jrand48(buf) & 0x7fffffff;
338 =item C<static long _lrand48(void)>
340 Returns a C<long> in the interval C<[0, 2^31)>.
342 =cut
346 static long
347 _lrand48(void)
349 ASSERT_ARGS(_lrand48)
350 return _nrand48(last_rand);
355 =item C<static long _mrand48(void)>
357 Returns a C<long> in the interval C<[-2^31, 2^31)>.
359 =cut
363 static long
364 _mrand48(void)
366 ASSERT_ARGS(_mrand48)
367 return _jrand48(last_rand);
372 =item C<static void _srand48(long seed)>
374 Sets the high order 32 bits to the argument C<seed>. The low order 16
375 bits are set to the arbitrary value 0x330e.
377 =cut
381 static void
382 _srand48(long seed)
384 ASSERT_ARGS(_srand48)
385 last_rand[0] = SEED_LO;
386 last_rand[1] = (unsigned short)(seed & 0xffff);
387 last_rand[2] = (unsigned short)((seed >> 16) & 0xffff);
389 * reinit a, c if changed by lcong48()
393 # undef A_lo
394 # undef A_mid
395 # undef A_hi
396 # undef C
398 #else
400 # define _drand48 drand48
401 # define _erand48(b) erand48(b)
403 # define _lrand48 lrand48
404 # define _nrand48(b) nrand48(b)
406 # define _mrand48 mrand48
407 # define _jrand48(b) jrand48(b)
409 # define _srand48 srand48
411 #endif
415 =item C<FLOATVAL Parrot_float_rand(INTVAL how_random)>
417 Returns a C<FLOATVAL> uniformly distributed in the in the interval
418 C<[0.0, 1.0]>.
420 C<how_random> is currently ignored.
422 =cut
426 PARROT_EXPORT
427 PARROT_WARN_UNUSED_RESULT
428 FLOATVAL
429 Parrot_float_rand(INTVAL how_random)
431 ASSERT_ARGS(Parrot_float_rand)
432 UNUSED(how_random);
434 return _drand48(); /* [0.0..1.0] */
439 =item C<INTVAL Parrot_uint_rand(INTVAL how_random)>
441 Returns an C<INTVAL> uniformly distributed in the interval C<[0, 2^31)>.
443 C<how_random> is ignored.
445 =cut
449 PARROT_EXPORT
450 PARROT_WARN_UNUSED_RESULT
451 INTVAL
452 Parrot_uint_rand(INTVAL how_random)
454 ASSERT_ARGS(Parrot_uint_rand)
455 UNUSED(how_random);
457 return _lrand48(); /* [0..2^31] */
462 =item C<INTVAL Parrot_int_rand(INTVAL how_random)>
464 Returns an C<INTVAL> in the interval C<[-2^31, 2^31)>.
466 C<how_random> is ignored.
468 =cut
472 PARROT_EXPORT
473 PARROT_WARN_UNUSED_RESULT
474 INTVAL
475 Parrot_int_rand(INTVAL how_random)
477 ASSERT_ARGS(Parrot_int_rand)
478 UNUSED(how_random);
480 return _mrand48(); /* [-2^31..2^31] */
485 =item C<INTVAL Parrot_range_rand(INTVAL from, INTVAL to, INTVAL how_random)>
487 Returns an C<INTVAL> in the range C<[from, to]>.
489 C<how_random> is ignored.
491 =cut
495 PARROT_EXPORT
496 PARROT_WARN_UNUSED_RESULT
497 INTVAL
498 Parrot_range_rand(INTVAL from, INTVAL to, INTVAL how_random)
500 ASSERT_ARGS(Parrot_range_rand)
501 const double spread = (double)(to - from + 1);
502 const double randpart = Parrot_float_rand(how_random);
503 const INTVAL raw = from + (INTVAL)(spread * randpart);
505 return raw;
510 =item C<void Parrot_srand(INTVAL seed)>
512 Seeds the random number generator with C<seed>.
514 =cut
518 PARROT_EXPORT
519 void
520 Parrot_srand(INTVAL seed)
522 ASSERT_ARGS(Parrot_srand)
523 _srand48(seed);
527 /* &gen_from_enum(tm.pasm) */
528 typedef enum {
529 TM_SEC,
530 TM_MIN,
531 TM_HOUR,
532 TM_MDAY,
533 TM_MON,
534 TM_YEAR,
535 TM_WDAY,
536 TM_YDAY,
537 TM_ISDST
538 } tm_struct_enum;
539 /* &end_gen */
543 =item C<PMC* Parrot_tm_to_array(PARROT_INTERP, const struct tm *tm)>
545 Helper to convert a B<struct tm *> to an Array
547 =cut
551 PARROT_EXPORT
552 PARROT_WARN_UNUSED_RESULT
553 PARROT_CANNOT_RETURN_NULL
554 PMC*
555 Parrot_tm_to_array(PARROT_INTERP, ARGIN(const struct tm *tm))
557 ASSERT_ARGS(Parrot_tm_to_array)
559 PMC * const Array = Parrot_pmc_new(interp,
560 Parrot_get_ctx_HLL_type(interp, enum_class_FixedIntegerArray));
561 VTABLE_set_integer_native(interp, Array, 9);
563 VTABLE_set_integer_keyed_int(interp, Array, 0, tm->tm_sec);
564 VTABLE_set_integer_keyed_int(interp, Array, 1, tm->tm_min);
565 VTABLE_set_integer_keyed_int(interp, Array, 2, tm->tm_hour);
566 VTABLE_set_integer_keyed_int(interp, Array, 3, tm->tm_mday);
567 VTABLE_set_integer_keyed_int(interp, Array, 4, tm->tm_mon + 1);
568 VTABLE_set_integer_keyed_int(interp, Array, 5, tm->tm_year + 1900);
569 VTABLE_set_integer_keyed_int(interp, Array, 6, tm->tm_wday);
570 VTABLE_set_integer_keyed_int(interp, Array, 7, tm->tm_yday);
571 VTABLE_set_integer_keyed_int(interp, Array, 8, tm->tm_isdst);
573 return Array;
578 =item C<INTVAL Parrot_byte_index(PARROT_INTERP, const STRING *base, const STRING
579 *search, UINTVAL start_offset)>
581 Looks for the location of a substring within a longer string. Takes
582 pointers to the strings and the offset within the string at which
583 to start searching as arguments.
585 Returns an offset value if it is found, or -1 if no match.
587 =cut
591 PARROT_EXPORT
592 PARROT_WARN_UNUSED_RESULT
593 INTVAL
594 Parrot_byte_index(SHIM_INTERP, ARGIN(const STRING *base),
595 ARGIN(const STRING *search), UINTVAL start_offset)
597 ASSERT_ARGS(Parrot_byte_index)
598 const char * const str_start = base->strstart;
599 const INTVAL str_len = base->strlen;
600 const char * const search_str = search->strstart;
601 const INTVAL search_len = search->strlen;
602 const char *str_pos = str_start + start_offset;
603 INTVAL len_remain = str_len - start_offset;
604 const char *search_pos;
606 /* find the next position of the first character in the search string
607 * Parrot strings can have NULLs, so strchr() won't work here */
608 while ((search_pos = (const char *)memchr(str_pos, *search_str, len_remain))) {
609 const INTVAL offset = search_pos - str_start;
611 /* now look for the entire string */
612 if (memcmp(search_pos, search_str, search_len) == 0)
613 return offset;
615 /* otherwise loop and memchr() with the rest of the string */
616 len_remain = str_len - offset;
617 str_pos = search_pos + 1;
619 if (len_remain < search_len)
620 return -1;
623 return -1;
628 =item C<INTVAL Parrot_byte_rindex(PARROT_INTERP, const STRING *base, const
629 STRING *search, UINTVAL start_offset)>
631 Substring search (like Parrot_byte_index), but works backwards,
632 from the rightmost end of the string.
634 Returns offset value or -1 (if no match).
636 =cut
640 PARROT_EXPORT
641 PARROT_WARN_UNUSED_RESULT
642 INTVAL
643 Parrot_byte_rindex(SHIM_INTERP, ARGIN(const STRING *base),
644 ARGIN(const STRING *search), UINTVAL start_offset)
646 ASSERT_ARGS(Parrot_byte_rindex)
647 const INTVAL searchlen = search->strlen;
648 const char * const search_start = (const char *)(search->strstart);
649 UINTVAL max_possible_offset = (base->strlen - search->strlen);
650 INTVAL current_offset;
652 if (start_offset && start_offset < max_possible_offset)
653 max_possible_offset = start_offset;
655 for (current_offset = max_possible_offset; current_offset >= 0;
656 current_offset--) {
657 const char * const base_start = (char *)(base->strstart) + current_offset;
658 if (memcmp(base_start, search_start, searchlen) == 0) {
659 return current_offset;
663 return -1;
668 =item C<static void rec_climb_back_and_mark(int node_index, const
669 parrot_prm_context *c)>
671 Recursive function, used by Parrot_register_move to
672 climb back the graph of register moves operations.
674 The node must have a predecessor: it is implicit because if a node has
675 a node_index, it must have a predecessor because the node_index are the
676 index of registers in dest_regs[] array, so by definition they have
677 a corrsponding src_regs register.
679 Then it emits the move operation with its predecessor, or its backup
680 if already used/visited.
682 Then continues the climbing if the predecessor was not modified, anf in that
683 case marks it, and set node_index as its backup.
685 node_index ... the index of a destination (i.e. with a pred.) register
686 c ... the graph and all the needed params : the context
688 =cut
692 static void
693 rec_climb_back_and_mark(int node_index, ARGIN(const parrot_prm_context *c))
695 ASSERT_ARGS(rec_climb_back_and_mark)
696 const int node = c->dest_regs[node_index];
697 const int pred = c->src_regs[node_index];
698 const int pred_index = c->reg_to_index[pred];
700 if (pred_index < 0) { /* pred has no predecessor */
701 move_reg(pred, node, c);
703 else { /* pred has a predecessor, so may be processed */
704 const int src = c->backup[pred_index];
705 if (src < 0) { /* not visited */
706 move_reg(pred, node, c);
707 c->backup[pred_index] = node; /* marks pred*/
708 rec_climb_back_and_mark(pred_index, c);
710 else { /* already visited, use backup instead */
711 move_reg(src, node, c);
719 =item C<static void process_cycle_without_exit(int node_index, const
720 parrot_prm_context *c)>
722 Recursive function, used by Parrot_register_move to handle the case
723 of cycles without exits, that are cycles of move ops between registers
724 where each register has exactly one predecessor and one successor
726 For instance: 1-->2, 2-->3, 3-->1
728 node_index ... the index of a destination (i.e. with a pred.) register
729 c ... the graph and all the needed params : the context
731 =cut
735 static void
736 process_cycle_without_exit(int node_index, ARGIN(const parrot_prm_context *c))
738 ASSERT_ARGS(process_cycle_without_exit)
739 const int pred = c->src_regs[node_index];
741 /* let's try the alternate move function*/
742 const int alt =
743 c->mov_alt
744 ? c->mov_alt(c->interp, c->dest_regs[node_index], pred, c->info)
745 : 0;
747 if (0 == alt) { /* use temp reg */
748 move_reg(c->dest_regs[node_index], c->temp_reg, c);
749 c->backup[node_index] = c->temp_reg;
751 else
752 c->backup[node_index] = c->dest_regs[node_index];
754 rec_climb_back_and_mark(node_index, c);
759 =item C<void Parrot_register_move(PARROT_INTERP, int n_regs, unsigned char
760 *dest_regs, unsigned char *src_regs, unsigned char temp_reg, reg_move_func mov,
761 reg_move_func mov_alt, void *info)>
763 Move C<n_regs> from the given register list C<src_regs> to C<dest_regs>.
765 n_regs ... amount of registers to move
766 dest_regs ... list of register numbers 0..255
767 src_regs ... list of register numbers 0..255
768 temp_reg ... a register number not in one of these lists
769 mov ... a register move function to be called to move one register
770 mov_alt ... a register move function to be called to move one register
771 which triese fetching from an alternate src (or NULLfunc):
773 (void) (mov)(interp, dest, src, info);
774 moved = (mov_alt)(interp, dest, src, info);
776 Some C<dest_regs> might be the same as C<src_regs>, which makes this a bit
777 non-trivial, because if the destination is already clobbered, using it
778 later as source doesn"t work. E.g.
780 0 <- 1
781 1 <- 0 # register 0 already clobbered
785 2 <- 0
786 0 <- 1
787 3 <- 2 # register 2 already clobbered - reorder moves
789 To handle such cases, we do:
791 a) rearrange the order of moves (not possible in the first case)
792 and/or if that failed:
793 b) if an alternate move function is available, it may fetch the
794 source from a different (non-clobbered) location - call it.
795 if the function returns 0 also use c)
796 c) if no alternate move function is available, use the temp reg
798 The amount of register moves should of course be minimal.
800 TODO The current implementation will not work for following cases
802 Talked to Leo and he said those cases are not likely (Vishal Soni).
803 1. I0->I1 I1->I0 I0->I3
804 2. I1->I2 I3->I2
806 TODO: Add tests for the above conditions.
808 =cut
812 PARROT_EXPORT
813 void
814 Parrot_register_move(PARROT_INTERP,
815 int n_regs,
816 ARGOUT(unsigned char *dest_regs),
817 ARGIN(unsigned char *src_regs),
818 unsigned char temp_reg,
819 reg_move_func mov,
820 reg_move_func mov_alt,
821 ARGIN(void *info))
823 ASSERT_ARGS(Parrot_register_move)
824 int i;
825 int max_reg = 0;
826 int* nb_succ = NULL;
827 int* backup = NULL;
828 int* reg_to_index = NULL;
829 parrot_prm_context c;
831 if (n_regs == 0)
832 return;
834 if (n_regs == 1) {
835 if (src_regs[0] != dest_regs[0])
836 mov(interp, dest_regs[0], src_regs[0], info);
837 return;
840 c.interp = interp;
841 c.info = info;
842 c.mov = mov;
843 c.mov_alt = mov_alt;
844 c.src_regs = src_regs;
845 c.dest_regs = dest_regs;
846 c.temp_reg = temp_reg;
848 /* compute max_reg, the max reg number + 1 */
849 for (i = 0; i < n_regs; ++i) {
850 if (src_regs[i] > max_reg)
851 max_reg = src_regs[i];
852 if (dest_regs[i] > max_reg)
853 max_reg = dest_regs[i];
855 ++max_reg;
858 /* allocate space for data structures */
859 /* NOTA: data structures could be kept allocated somewhere waiting to get reused...*/
860 c.nb_succ = nb_succ = mem_gc_allocate_n_zeroed_typed(interp, n_regs, int);
861 c.backup = backup = mem_gc_allocate_n_zeroed_typed(interp, n_regs, int);
862 c.reg_to_index = reg_to_index = mem_gc_allocate_n_zeroed_typed(interp, max_reg, int);
864 /* init backup array */
865 for (i = 0; i < n_regs; ++i)
866 backup[i] = -1;
868 /* fill in the conversion array between a register number and its index */
869 for (i = 0; i < max_reg; ++i)
870 reg_to_index[i] = -1;
871 for (i = 0; i < n_regs; ++i) {
872 const int index = dest_regs[i];
873 if (index != src_regs[i]) /* get rid of self-assignment */
874 reg_to_index[index] = i;
877 /* count the nb of successors for each reg index */
878 for (i = 0; i < n_regs; ++i) {
879 const int index = reg_to_index[ src_regs[i] ];
880 if (index >= 0) /* not interested in the wells that have no preds */
881 ++nb_succ[index];
883 /* process each well if any */
884 for (i = 0; i < n_regs; ++i) {
885 if (0 == nb_succ[i]) { /* a well */
886 rec_climb_back_and_mark(i, &c);
890 /* process remaining dest registers not processed */
891 /* remaining nodes are members of cycles without exits */
892 for (i = 0; i < n_regs; ++i) {
893 if (0 < nb_succ[i] && 0 > backup[i]) { /* not a well nor visited*/
894 process_cycle_without_exit(i, &c);
898 mem_gc_free(interp, nb_succ);
899 mem_gc_free(interp, reg_to_index);
900 mem_gc_free(interp, backup);
903 typedef INTVAL (*sort_func_t)(PARROT_INTERP, void *, void *);
907 =item C<static INTVAL COMPARE(PARROT_INTERP, void *a, void *b, PMC *cmp)>
909 General PMC comparison function. Takes two PMCs. Returns 0 if they are equal,
910 returns 1 if C<a> is bigger, and returns -1 if C<b> is bigger.
912 =cut
916 /* TODO: Macroize COMPARE */
917 /* This is an awfully expensive function to call, what with all the */
918 /* comparisons that never change. We ought to precompute everything. */
919 /* XXX We should be able to guarantee that *a and *b never change via const parameters. */
920 static INTVAL
921 COMPARE(PARROT_INTERP, ARGIN(void *a), ARGIN(void *b), ARGIN(PMC *cmp))
923 ASSERT_ARGS(COMPARE)
924 INTVAL result = 0;
925 if (PMC_IS_NULL(cmp))
926 return VTABLE_cmp(interp, (PMC *)a, (PMC *)b);
928 if (cmp->vtable->base_type == enum_class_NCI) {
929 const sort_func_t f = (sort_func_t)D2FPTR(PARROT_NCI(cmp)->func);
930 return f(interp, a, b);
933 Parrot_pcc_invoke_sub_from_c_args(interp, cmp, "PP->I", a, b, &result);
934 return result;
939 =item C<void Parrot_quicksort(PARROT_INTERP, void **data, UINTVAL n, PMC *cmp)>
941 Perform a quicksort on a PMC array.
943 =cut
947 void
948 Parrot_quicksort(PARROT_INTERP, ARGMOD(void **data), UINTVAL n, ARGIN(PMC *cmp))
950 ASSERT_ARGS(Parrot_quicksort)
951 while (n > 1) {
952 UINTVAL i, j, ln, rn;
953 void *temp;
955 /* Swap */
956 temp = data[0];
957 data[0] = data[n/2];
958 data[n/2] = temp;
960 for (i = 0, j = n; ;) {
962 --j;
963 while (j > 0 && COMPARE(interp, data[j], data[0], cmp) > 0);
966 ++i;
967 while (i < j && COMPARE(interp, data[i], data[0], cmp) < 0);
969 if (i >= j)
970 break;
972 /* Swap */
973 temp = data[i];
974 data[i] = data[j];
975 data[j] = temp;
978 /* Swap */
979 temp = data[j];
980 data[j] = data[0];
981 data[0] = temp;
983 ln = j;
984 rn = n - ++j;
986 if (ln < rn) {
987 Parrot_quicksort(interp, data, ln, cmp);
988 data += j;
989 n = rn;
991 else {
992 Parrot_quicksort(interp, data + j, rn, cmp);
993 n = ln;
1000 =back
1006 * Local variables:
1007 * c-file-style: "parrot"
1008 * End:
1009 * vim: expandtab shiftwidth=4: