[t][TT #1119] Convert t/op/bitwise.t to PIR
[parrot.git] / src / utils.c
blob1a2358d2eb814203bd90abee6abbccca32a5bc67
1 /*
2 Copyright (C) 2001-2009, 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(parrot_prm_context* c))
66 __attribute__nonnull__(2);
68 static void rec_climb_back_and_mark(
69 int node_index,
70 ARGIN(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 INTVAL
124 intval_mod(INTVAL i2, INTVAL i3)
126 ASSERT_ARGS(intval_mod)
127 INTVAL z = i3;
129 if (z == 0)
130 return i2;
131 else {
132 INTVAL r;
133 INTVAL y;
134 int s = 0;
136 y = i2;
138 if (y < 0) { s += 2; y = -y; }
139 if (z < 0) { s += 1; z = -z; }
141 r = y % z;
143 if (r) { /* # 36003 */
144 switch (s) {
145 case 0: break;
146 case 1: r = r - z; break;
147 case 2: r = z - r; break;
148 case 3: r = -r; break;
149 default: break;
153 return r;
159 =item C<FLOATVAL floatval_mod(FLOATVAL n2, FLOATVAL n3)>
161 Returns C<n2 mod n3>.
163 Includes a workaround for buggy code generation in the C<lcc> compiler.
165 =cut
169 PARROT_CONST_FUNCTION
170 FLOATVAL
171 floatval_mod(FLOATVAL n2, FLOATVAL n3)
173 ASSERT_ARGS(floatval_mod)
174 #ifdef __LCC__
176 /* Another workaround for buggy code generation in the lcc compiler-
177 * adding a temporary variable makes it pass the test.
179 const FLOATVAL temp = n3 * floor(n2 / n3);
181 return !FLOAT_IS_ZERO(n3)
182 ? (n2 - temp)
183 : n2;
184 #else
185 return !FLOAT_IS_ZERO(n3)
186 ? (n2 - n3 * floor(n2 / n3))
187 : n2;
188 #endif
194 =back
196 =head2 Random Number Generator
198 Based on the C<rand48()> family of functions.
200 =over 4
202 =cut
207 * currently undefined
209 #ifndef PARROT_HAS_DRAND48
212 * s. man drand48, SuS V2
214 * X(n+1) = ( aX(n) + c ) mod 2^48
217 # define A_lo 0xE66D
218 # define A_mid 0xDEEC
219 # define A_hi 0x5
220 # define C 0xB
221 # define SEED_LO 0x330E
223 static _rand_buf a = { A_lo, A_mid, A_hi };
224 static _rand_buf last_rand;
225 static unsigned short c = C;
229 =item C<static void next_rand(_rand_buf X)>
231 Returns the next random number in C<X>.
233 =cut
237 static void
238 next_rand(_rand_buf X)
240 ASSERT_ARGS(next_rand)
241 unsigned short lo, mid, hi;
242 unsigned int t;
244 /* 48 bit mul, one short at a time */
245 t = X[0] * a[0] + c;
246 lo = t & 0xffff;
247 mid = (t >> 16) & 0xffff;
249 t = X[1] * a[0] + X[0] * a[1] + mid;
250 mid = t & 0xffff;
251 hi = (t >> 16) & 0xffff;
253 t = X[2] * a[0] + X[1] * a[1] + X[0] * a[2] + hi;
255 X[0] = lo;
256 X[1] = mid;
257 X[2] = t & 0xffff;
262 =item C<static FLOATVAL _erand48(_rand_buf buf)>
264 Returns a C<double> in the interval C<[0.0, 1.0)>.
266 =cut
270 static FLOATVAL
271 _erand48(_rand_buf buf)
273 ASSERT_ARGS(_erand48)
274 FLOATVAL r;
275 next_rand(buf);
276 r = ((buf[0] / 65536.0 + buf[1]) / 65536.0 + buf[2]) / 65536.0;
277 return r;
282 =item C<static FLOATVAL _drand48(void)>
284 Returns a C<double> in the interval C<[0.0, 1.0)>.
286 =cut
290 static FLOATVAL
291 _drand48(void)
293 ASSERT_ARGS(_drand48)
294 return _erand48(last_rand);
299 =item C<static long _jrand48(_rand_buf buf)>
301 Returns a C<long> in the interval C<[-2^31, 2^31)>.
303 =cut
307 static long
308 _jrand48(_rand_buf buf)
310 ASSERT_ARGS(_jrand48)
311 long ret;
312 next_rand(buf);
313 ret = buf[2] << 16 | buf[1];
314 return ret;
319 =item C<static long _nrand48(_rand_buf buf)>
321 Returns a C<long> in the interval C<[0, 2^31)>.
323 =cut
327 static long
328 _nrand48(_rand_buf buf)
330 ASSERT_ARGS(_nrand48)
331 return _jrand48(buf) & 0x7fffffff;
336 =item C<static long _lrand48(void)>
338 Returns a C<long> in the interval C<[0, 2^31)>.
340 =cut
344 static long
345 _lrand48(void)
347 ASSERT_ARGS(_lrand48)
348 return _nrand48(last_rand);
353 =item C<static long _mrand48(void)>
355 Returns a C<long> in the interval C<[-2^31, 2^31)>.
357 =cut
361 static long
362 _mrand48(void)
364 ASSERT_ARGS(_mrand48)
365 return _jrand48(last_rand);
370 =item C<static void _srand48(long seed)>
372 Sets the high order 32 bits to the argument C<seed>. The low order 16
373 bits are set to the arbitrary value 0x330e.
375 =cut
379 static void
380 _srand48(long seed)
382 ASSERT_ARGS(_srand48)
383 last_rand[0] = SEED_LO;
384 last_rand[1] = (unsigned short)(seed & 0xffff);
385 last_rand[2] = (unsigned short)((seed >> 16) & 0xffff);
387 * reinit a, c if changed by lcong48()
391 # undef A_lo
392 # undef A_mid
393 # undef A_hi
394 # undef C
396 #else
398 # define _drand48 drand48
399 # define _erand48(b) erand48(b)
401 # define _lrand48 lrand48
402 # define _nrand48(b) nrand48(b)
404 # define _mrand48 mrand48
405 # define _jrand48(b) jrand48(b)
407 # define _srand48 srand48
409 #endif
413 =item C<FLOATVAL Parrot_float_rand(INTVAL how_random)>
415 Returns a C<FLOATVAL> in the interval C<[0.0, 1.0)>.
417 C<how_random> is ignored.
419 =cut
423 PARROT_EXPORT
424 FLOATVAL
425 Parrot_float_rand(INTVAL how_random)
427 ASSERT_ARGS(Parrot_float_rand)
428 UNUSED(how_random);
430 return _drand48(); /* [0.0..1.0] */
435 =item C<INTVAL Parrot_uint_rand(INTVAL how_random)>
437 Returns an C<INTVAL> in the interval C<[0, 2^31)>.
439 C<how_random> is ignored.
441 =cut
445 PARROT_EXPORT
446 INTVAL
447 Parrot_uint_rand(INTVAL how_random)
449 ASSERT_ARGS(Parrot_uint_rand)
450 UNUSED(how_random);
452 return _lrand48(); /* [0..2^31] */
457 =item C<INTVAL Parrot_int_rand(INTVAL how_random)>
459 Returns an C<INTVAL> in the interval C<[-2^31, 2^31)>.
461 C<how_random> is ignored.
463 =cut
467 PARROT_EXPORT
468 INTVAL
469 Parrot_int_rand(INTVAL how_random)
471 ASSERT_ARGS(Parrot_int_rand)
472 UNUSED(how_random);
474 return _mrand48(); /* [-2^31..2^31] */
479 =item C<INTVAL Parrot_range_rand(INTVAL from, INTVAL to, INTVAL how_random)>
481 Returns an C<INTVAL> in the range C<[from, to]>.
483 C<how_random> is ignored.
485 =cut
489 PARROT_EXPORT
490 INTVAL
491 Parrot_range_rand(INTVAL from, INTVAL to, INTVAL how_random)
493 ASSERT_ARGS(Parrot_range_rand)
494 return (INTVAL)(from + ((double)(to - from))
495 * Parrot_float_rand(how_random));
500 =item C<void Parrot_srand(INTVAL seed)>
502 Seeds the random number generator with C<seed>.
504 =cut
508 PARROT_EXPORT
509 void
510 Parrot_srand(INTVAL seed)
512 ASSERT_ARGS(Parrot_srand)
513 _srand48(seed);
517 /* &gen_from_enum(tm.pasm) */
518 typedef enum {
519 TM_SEC,
520 TM_MIN,
521 TM_HOUR,
522 TM_MDAY,
523 TM_MON,
524 TM_YEAR,
525 TM_WDAY,
526 TM_YDAY,
527 TM_ISDST
528 } tm_struct_enum;
529 /* &end_gen */
533 =item C<PMC* tm_to_array(PARROT_INTERP, const struct tm *tm)>
535 Helper to convert a B<struct tm *> to an Array
537 =cut
541 PARROT_WARN_UNUSED_RESULT
542 PARROT_CANNOT_RETURN_NULL
543 PMC*
544 tm_to_array(PARROT_INTERP, ARGIN(const struct tm *tm))
546 ASSERT_ARGS(tm_to_array)
547 PMC * const Array = pmc_new(interp, enum_class_Array);
549 VTABLE_set_integer_native(interp, Array, 9);
550 VTABLE_set_integer_keyed_int(interp, Array, 0, tm->tm_sec);
551 VTABLE_set_integer_keyed_int(interp, Array, 1, tm->tm_min);
552 VTABLE_set_integer_keyed_int(interp, Array, 2, tm->tm_hour);
553 VTABLE_set_integer_keyed_int(interp, Array, 3, tm->tm_mday);
554 VTABLE_set_integer_keyed_int(interp, Array, 4, tm->tm_mon + 1);
555 VTABLE_set_integer_keyed_int(interp, Array, 5, tm->tm_year + 1900);
556 VTABLE_set_integer_keyed_int(interp, Array, 6, tm->tm_wday);
557 VTABLE_set_integer_keyed_int(interp, Array, 7, tm->tm_yday);
558 VTABLE_set_integer_keyed_int(interp, Array, 8, tm->tm_isdst);
560 return Array;
565 =item C<INTVAL Parrot_byte_index(PARROT_INTERP, const STRING *base, const STRING
566 *search, UINTVAL start_offset)>
568 Looks for the location of a substring within a longer string. Takes
569 pointers to the strings and the offset within the string at which
570 to start searching as arguments.
572 Returns an offset value if it is found, or -1 if no match.
574 =cut
578 PARROT_EXPORT
579 INTVAL
580 Parrot_byte_index(SHIM_INTERP, ARGIN(const STRING *base),
581 ARGIN(const STRING *search), UINTVAL start_offset)
583 ASSERT_ARGS(Parrot_byte_index)
584 const char * const str_start = base->strstart;
585 const INTVAL str_len = base->strlen;
586 const char * const search_str = search->strstart;
587 const INTVAL search_len = search->strlen;
588 const char *str_pos = str_start + start_offset;
589 INTVAL len_remain = str_len - start_offset;
590 const char *search_pos;
592 /* find the next position of the first character in the search string
593 * Parrot strings can have NULLs, so strchr() won't work here */
594 while ((search_pos = (const char *)memchr(str_pos, *search_str, len_remain))) {
595 const INTVAL offset = search_pos - str_start;
597 /* now look for the entire string */
598 if (memcmp(search_pos, search_str, search_len) == 0)
599 return offset;
601 /* otherwise loop and memchr() with the rest of the string */
602 len_remain = str_len - offset;
603 str_pos = search_pos + 1;
605 if (len_remain < search_len)
606 return -1;
609 return -1;
614 =item C<INTVAL Parrot_byte_rindex(PARROT_INTERP, const STRING *base, const
615 STRING *search, UINTVAL start_offset)>
617 Substring search (like Parrot_byte_index), but works backwards,
618 from the rightmost end of the string.
620 Returns offset value or -1 (if no match).
622 =cut
626 PARROT_EXPORT
627 PARROT_WARN_UNUSED_RESULT
628 INTVAL
629 Parrot_byte_rindex(SHIM_INTERP, ARGIN(const STRING *base),
630 ARGIN(const STRING *search), UINTVAL start_offset)
632 ASSERT_ARGS(Parrot_byte_rindex)
633 const INTVAL searchlen = search->strlen;
634 const char * const search_start = search->strstart;
635 UINTVAL max_possible_offset = (base->strlen - search->strlen);
636 INTVAL current_offset;
638 if (start_offset && start_offset < max_possible_offset)
639 max_possible_offset = start_offset;
641 for (current_offset = max_possible_offset; current_offset >= 0;
642 current_offset--) {
643 const char * const base_start = (char *)base->strstart + current_offset;
644 if (memcmp(base_start, search_start, searchlen) == 0) {
645 return current_offset;
649 return -1;
654 =item C<static void rec_climb_back_and_mark(int node_index, parrot_prm_context*
657 Recursive function, used by Parrot_register_move to
658 climb back the graph of register moves operations.
660 The node must have a predecessor: it is implicit because if a node has
661 a node_index, it must have a predecessor because the node_index are the
662 index of registers in dest_regs[] array, so by definition they have
663 a corrsponding src_regs register.
665 Then it emits the move operation with its predecessor, or its backup
666 if already used/visited.
668 Then continues the climbing if the predecessor was not modified, anf in that
669 case marks it, and set node_index as its backup.
671 node_index ... the index of a destination (i.e. with a pred.) register
672 c ... the graph and all the needed params : the context
674 =cut
678 static void
679 rec_climb_back_and_mark(int node_index, ARGIN(parrot_prm_context* c))
681 ASSERT_ARGS(rec_climb_back_and_mark)
682 const int node = c->dest_regs[node_index];
683 const int pred = c->src_regs[node_index];
684 const int pred_index = c->reg_to_index[pred];
686 if (pred_index < 0) { /* pred has no predecessor */
687 move_reg(pred, node, c);
689 else { /* pred has a predecessor, so may be processed */
690 const int src = c->backup[pred_index];
691 if (src < 0) { /* not visited */
692 move_reg(pred, node, c);
693 c->backup[pred_index] = node; /* marks pred*/
694 rec_climb_back_and_mark(pred_index, c);
696 else { /* already visited, use backup instead */
697 move_reg(src, node, c);
705 =item C<static void process_cycle_without_exit(int node_index,
706 parrot_prm_context* c)>
708 Recursive function, used by Parrot_register_move to handle the case
709 of cycles without exits, that are cycles of move ops between registers
710 where each register has exactly one predecessor and one successor
712 For instance: 1-->2, 2-->3, 3-->1
714 node_index ... the index of a destination (i.e. with a pred.) register
715 c ... the graph and all the needed params : the context
717 =cut
721 static void
722 process_cycle_without_exit(int node_index, ARGIN(parrot_prm_context* c))
724 ASSERT_ARGS(process_cycle_without_exit)
725 const int pred = c->src_regs[node_index];
727 /* let's try the alternate move function*/
728 const int alt =
729 c->mov_alt
730 ? c->mov_alt(c->interp, c->dest_regs[node_index], pred, c->info)
731 : 0;
733 if (0 == alt) { /* use temp reg */
734 move_reg(c->dest_regs[node_index], c->temp_reg, c);
735 c->backup[node_index] = c->temp_reg;
737 else
738 c->backup[node_index] = c->dest_regs[node_index];
740 rec_climb_back_and_mark(node_index, c);
745 =item C<void Parrot_register_move(PARROT_INTERP, int n_regs, unsigned char
746 *dest_regs, unsigned char *src_regs, unsigned char temp_reg, reg_move_func mov,
747 reg_move_func mov_alt, void *info)>
749 Move C<n_regs> from the given register list C<src_regs> to C<dest_regs>.
751 n_regs ... amount of registers to move
752 dest_regs ... list of register numbers 0..255
753 src_regs ... list of register numbers 0..255
754 temp_reg ... a register number not in one of these lists
755 mov ... a register move function to be called to move one register
756 mov_alt ... a register move function to be called to move one register
757 which triese fetching from an alternate src (or NULLfunc):
759 (void) (mov)(interp, dest, src, info);
760 moved = (mov_alt)(interp, dest, src, info);
762 Some C<dest_regs> might be the same as C<src_regs>, which makes this a bit
763 non-trivial, because if the destination is already clobbered, using it
764 later as source doesn"t work. E.g.
766 0 <- 1
767 1 <- 0 # register 0 already clobbered
771 2 <- 0
772 0 <- 1
773 3 <- 2 # register 2 already clobbered - reorder moves
775 To handle such cases, we do:
777 a) rearrange the order of moves (not possible in the first case)
778 and/or if that failed:
779 b) if an alternate move function is available, it may fetch the
780 source from a different (non-clobbered) location - call it.
781 if the function returns 0 also use c)
782 c) if no alternate move function is available, use the temp reg
784 The amount of register moves should of course be minimal.
786 TODO The current implementation will not work for following cases
788 Talked to Leo and he said those cases are not likely (Vishal Soni).
789 1. I0->I1 I1->I0 I0->I3
790 2. I1->I2 I3->I2
792 TODO: Add tests for the above conditions.
794 =cut
798 PARROT_EXPORT
799 void
800 Parrot_register_move(PARROT_INTERP,
801 int n_regs,
802 ARGOUT(unsigned char *dest_regs),
803 ARGIN(unsigned char *src_regs),
804 unsigned char temp_reg,
805 reg_move_func mov,
806 reg_move_func mov_alt,
807 ARGIN(void *info))
809 ASSERT_ARGS(Parrot_register_move)
810 int i;
811 int max_reg = 0;
812 int* nb_succ = NULL;
813 int* backup = NULL;
814 int* reg_to_index = NULL;
815 parrot_prm_context c;
817 if (n_regs == 0)
818 return;
820 if (n_regs == 1) {
821 if (src_regs[0] != dest_regs[0])
822 mov(interp, dest_regs[0], src_regs[0], info);
823 return;
826 c.interp = interp;
827 c.info = info;
828 c.mov = mov;
829 c.mov_alt = mov_alt;
830 c.src_regs = src_regs;
831 c.dest_regs = dest_regs;
832 c.temp_reg = temp_reg;
834 /* compute max_reg, the max reg number + 1 */
835 for (i = 0; i < n_regs; i++) {
836 if (src_regs[i] > max_reg)
837 max_reg = src_regs[i];
838 if (dest_regs[i] > max_reg)
839 max_reg = dest_regs[i];
841 ++max_reg;
844 /* allocate space for data structures */
845 /* NOTA: data structures could be kept allocated somewhere waiting to get reused...*/
846 c.nb_succ = nb_succ = mem_allocate_n_zeroed_typed(n_regs, int);
847 c.backup = backup = mem_allocate_n_zeroed_typed(n_regs, int);
848 c.reg_to_index = reg_to_index = mem_allocate_n_zeroed_typed(max_reg, int);
850 /* init backup array */
851 for (i = 0; i < n_regs; i++)
852 backup[i] = -1;
854 /* fill in the conversion array between a register number and its index */
855 for (i = 0; i < max_reg; i++)
856 reg_to_index[i] = -1;
857 for (i = 0; i < n_regs; i++) {
858 const int index = dest_regs[i];
859 if (index != src_regs[i]) /* get rid of self-assignment */
860 reg_to_index[index] = i;
863 /* count the nb of successors for each reg index */
864 for (i = 0; i < n_regs; i++) {
865 const int index = reg_to_index[ src_regs[i] ];
866 if (index >= 0) /* not interested in the wells that have no preds */
867 nb_succ[ index ]++;
869 /* process each well if any */
870 for (i = 0; i < n_regs; i++) {
871 if (0 == nb_succ[i]) { /* a well */
872 rec_climb_back_and_mark(i, &c);
876 /* process remaining dest registers not processed */
877 /* remaining nodes are members of cycles without exits */
878 for (i = 0; i < n_regs; i++) {
879 if (0 < nb_succ[i] && 0 > backup[i]) { /* not a well nor visited*/
880 process_cycle_without_exit(i, &c);
884 mem_sys_free(nb_succ);
885 mem_sys_free(reg_to_index);
886 mem_sys_free(backup);
889 typedef INTVAL (*sort_func_t)(PARROT_INTERP, void *, void *);
893 =item C<static INTVAL COMPARE(PARROT_INTERP, void *a, void *b, PMC *cmp)>
895 General PMC comparison function. Takes two PMCs. Returns 0 if they are equal,
896 returns 1 if C<a> is bigger, and returns -1 if C<b> is bigger.
898 =cut
902 /* TODO: Macroize COMPARE */
903 /* This is an awfully expensive function to call, what with all the */
904 /* comparisons that never change. We ought to precompute everything. */
905 static INTVAL
906 COMPARE(PARROT_INTERP, ARGIN(void *a), ARGIN(void *b), ARGIN(PMC *cmp))
908 ASSERT_ARGS(COMPARE)
909 INTVAL result = 0;
910 if (PMC_IS_NULL(cmp))
911 return VTABLE_cmp(interp, (PMC *)a, (PMC *)b);
913 if (cmp->vtable->base_type == enum_class_NCI) {
914 const sort_func_t f = (sort_func_t)D2FPTR(PARROT_NCI(cmp)->func);
915 return f(interp, a, b);
918 Parrot_pcc_invoke_sub_from_c_args(interp, cmp, "PP->I", a, b, &result);
919 return result;
924 =item C<void Parrot_quicksort(PARROT_INTERP, void **data, UINTVAL n, PMC *cmp)>
926 Perform a quicksort on a PMC array.
928 =cut
932 void
933 Parrot_quicksort(PARROT_INTERP, ARGMOD(void **data), UINTVAL n, ARGIN(PMC *cmp))
935 ASSERT_ARGS(Parrot_quicksort)
936 while (n > 1) {
937 UINTVAL i, j, ln, rn;
938 void *temp;
940 /* Swap */
941 temp = data[0];
942 data[0] = data[n/2];
943 data[n/2] = temp;
945 for (i = 0, j = n; ;) {
947 --j;
948 while (j > 0 && COMPARE(interp, data[j], data[0], cmp) > 0);
951 ++i;
952 while (i < j && COMPARE(interp, data[i], data[0], cmp) < 0);
954 if (i >= j)
955 break;
957 /* Swap */
958 temp = data[i];
959 data[i] = data[j];
960 data[j] = temp;
963 /* Swap */
964 temp = data[j];
965 data[j] = data[0];
966 data[0] = temp;
968 ln = j;
969 rn = n - ++j;
971 if (ln < rn) {
972 Parrot_quicksort(interp, data, ln, cmp);
973 data += j;
974 n = rn;
976 else {
977 Parrot_quicksort(interp, data + j, rn, cmp);
978 n = ln;
985 =back
987 =head1 HISTORY
989 Initial version by leo 2003.09.09.
991 =cut
997 * Local variables:
998 * c-file-style: "parrot"
999 * End:
1000 * vim: expandtab shiftwidth=4: