3 # This file is part of Language::Befunge::Vector::XS.
4 # Copyright (c) 2008 Jerome Quelin, all rights reserved.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the same terms as Perl itself.
17 #define NEED_newRV_noinc
21 /* used for constructor new() */
23 void* intArrayPtr(int num) {
25 mortal = sv_2mortal( NEWSV(0, num * sizeof(intArray)) );
29 AV *_rasterize(AV *vec_array, AV *min_array, AV *max_array) {
30 IV i, inc = 1, nd = av_len(vec_array);
32 for (i = 0; i <= av_len(vec_array); i++) {
33 IV thisval, minval, maxval;
34 thisval = SvIV(*av_fetch(vec_array, i, 0));
35 minval = SvIV(*av_fetch(min_array, i, 0));
36 maxval = SvIV(*av_fetch(max_array, i, 0));
38 if(thisval < maxval) {
49 av_push(rv, newSViv(thisval));
55 MODULE = Language::Befunge::Vector::XS PACKAGE = Language::Befunge::Vector::XS
61 # my $vec = LB::Vector->new( $x [, $y, ...] );
63 # Create a new vector. The arguments are the actual vector data; one
64 # integer per dimension.
67 new( class, array, ... )
79 croak("Usage: %s->new($x,...)", class);
81 /* create the object and populate it */
83 for ( i=0; i<ix_array; i++ ) {
84 val = newSViv( array[i] );
85 av_push(my_array, val);
88 /* Return a blessed reference to the AV */
89 self = newRV_noinc( (SV*)my_array );
90 stash = gv_stashpv( class, TRUE );
91 sv_bless( (SV*)self, stash );
98 # my $vec = Language::Befunge::Vector::XS->new_zeroes( $dims );
100 # Create a new vector of dimension $dims, set to the origin (all
101 # zeroes). LBVXS->new_zeroes(2) is exactly equivalent to LBVXS->new(0, 0).
104 new_zeroes( class, dim )
116 croak("Usage: %s->new_zeroes($dims)", class);
118 /* create the object and populate it */
120 for ( i=0; i<dim; i++ ) {
122 av_push(my_array, zero);
125 /* return a blessed reference to the AV */
126 self = newRV_noinc( (SV*)my_array );
127 stash = gv_stashpv( class, TRUE );
128 sv_bless( (SV*)self, stash );
135 # my $vec = $v->copy;
137 # Return a new LBVXS object, which has the same dimensions and
151 /* fetch the underlying array of the object */
152 vec_array = (AV*)SvRV(vec);
154 /* create the object and populate it */
156 for ( i=0; i<=av_len(vec_array); i++ ) {
157 val = newSViv( SvIV(*av_fetch(vec_array, i, 0)) );
158 av_push(my_array, val);
161 /* return a blessed reference to the AV */
162 self = newRV_noinc( (SV*)my_array );
163 stash = SvSTASH( (SV*)vec_array );
164 sv_bless( (SV*)self, stash );
175 # my $dims = $vec->get_dims;
177 # Return the number of dimensions, an integer.
185 /* fetch the underlying array of the object */
186 my_array = (AV*)SvRV(self);
188 RETVAL = av_len(my_array) + 1;
194 # my $val = $vec->get_component($dim);
196 # Return the value for dimension $dim.
199 get_component( self, dim )
205 /* fetch the underlying array of the object */
206 my_array = (AV*)SvRV(self);
209 if ( dim < 0 || dim > av_len(my_array) )
210 croak( "No such dimension!" );
212 RETVAL = SvIV( *av_fetch(my_array, dim, 0) );
218 # my @vals = $vec->get_all_components;
220 # Get the values for all dimensions, in order from 0..N.
223 get_all_components( self )
229 /* fetch the underlying array of the object */
230 my_array = (AV*)SvRV(self);
231 dim = av_len(my_array);
233 /* extend the return stack and populate it */
235 for ( i=0; i<=dim; i++ ) {
236 val = SvIV( *av_fetch(my_array, i, 0) );
237 PUSHs( sv_2mortal( newSViv(val) ) );
246 # Set the vector back to the origin, all 0's.
256 /* fetch the underlying array of the object */
257 my_array = (AV*)SvRV(self);
258 dim = av_len(my_array);
260 /* clear each slot */
261 for ( i=0; i<=dim; i++ ) {
263 av_store(my_array, i, zero);
268 # my $val = $vec->set_component( $dim, $value );
270 # Set the value for dimension $dim to $value.
273 set_component( self, dim, value )
280 /* fetch the underlying array of the object */
281 my_array = (AV*)SvRV(self);
284 if ( dim < 0 || dim > av_len(my_array) )
285 croak( "No such dimension!" );
287 /* storing new value */
288 av_store(my_array, dim, newSViv(value));
294 # my $is_within = $vec->bounds_check($begin, $end);
296 # Check whether $vec is within the box defined by $begin and $end.
297 # Return 1 if vector is contained within the box, and 0 otherwise.
300 bounds_check( self, v1, v2 )
305 IV i, mydim, dimv1, dimv2, myval, val1, val2;
310 /* fetch the underlying array of the object */
311 my_array = (AV*)SvRV(self);
312 v1_array = (AV*)SvRV(v1);
313 v2_array = (AV*)SvRV(v2);
314 mydim = av_len(my_array);
315 dimv1 = av_len(v1_array);
316 dimv2 = av_len(v2_array);
319 if ( mydim != dimv1 || mydim != dimv2 )
320 croak("uneven dimensions in bounds check!");
322 /* compare the arrays */
324 for ( i=0 ; i<=dimv1; i++ ) {
325 myval = SvIV( *av_fetch(my_array, i, 0) );
326 val1 = SvIV( *av_fetch(v1_array, i, 0) );
327 val2 = SvIV( *av_fetch(v2_array, i, 0) );
328 if ( myval < val1 || myval > val2 ) {
338 # for(my $v = $min->copy; defined $v; $v = $v->rasterize($min, $max))
340 # Return the next vector in raster order, or undef if the hypercube space
341 # has been fully covered. To enumerate the entire storage area, the caller
342 # should call rasterize on the storage area's "min" value the first time,
343 # and keep looping while the return value is defined. To enumerate a
344 # smaller rectangle, the caller should pass in the min and max vectors
345 # describing the rectangle, and keep looping while the return value is
349 rasterize( self, minv, maxv )
356 AV* vec_array, *min_array, *max_array;
359 /* fetch the underlying array of the object */
360 vec_array = (AV*)SvRV(self);
361 min_array = (AV*)SvRV(minv);
362 max_array = (AV*)SvRV(maxv);
364 /* create the object and populate it */
365 my_array = _rasterize(vec_array, min_array, max_array);
370 /* return a blessed reference to the AV */
371 RETVAL = newRV_noinc( (SV*)my_array );
372 stash = SvSTASH( (SV*)vec_array );
373 sv_bless( (SV*)RETVAL, stash );
384 # my $vec = $v1->_add($v2);
385 # my $vec = $v1 + $v2;
387 # Return a new LBVXS object, which is the result of $v1 plus $v2.
390 _add( v1, v2, variant )
395 IV dimv1, dimv2, i, val1, val2;
402 /* fetch the underlying array of the object */
403 v1_array = (AV*)SvRV(v1);
404 v2_array = (AV*)SvRV(v2);
405 dimv1 = av_len(v1_array);
406 dimv2 = av_len(v2_array);
409 if ( dimv1 != dimv2 )
410 croak("uneven dimensions in vector addition!");
412 /* create the new array and populate it */
414 for ( i=0 ; i<=dimv1; i++ ) {
415 val1 = SvIV( *av_fetch(v1_array, i, 0) );
416 val2 = SvIV( *av_fetch(v2_array, i, 0) );
417 av_push( my_array, newSViv(val1+val2) );
420 /* return a blessed reference to the AV */
421 self = newRV_noinc( (SV*)my_array );
422 stash = SvSTASH( (SV*)v1_array );
423 sv_bless( (SV*)self, stash );
430 # my $vec = $v1->_substract($v2);
431 # my $vec = $v1 - $v2;
433 # Return a new LBVXS object, which is the result of $v1 minus $v2.
436 _substract( v1, v2, variant )
441 IV dimv1, dimv2, i, val1, val2;
448 /* fetch the underlying array of the object */
449 v1_array = (AV*)SvRV(v1);
450 v2_array = (AV*)SvRV(v2);
451 dimv1 = av_len(v1_array);
452 dimv2 = av_len(v2_array);
455 if ( dimv1 != dimv2 )
456 croak("uneven dimensions in vector addition!");
458 /* create the new array and populate it */
460 for ( i=0 ; i<=dimv1; i++ ) {
461 val1 = SvIV( *av_fetch(v1_array, i, 0) );
462 val2 = SvIV( *av_fetch(v2_array, i, 0) );
463 av_push( my_array, newSViv(val1-val2) );
466 /* return a blessed reference to the AV */
467 self = newRV_noinc( (SV*)my_array );
468 stash = SvSTASH( (SV*)v1_array );
469 sv_bless( (SV*)self, stash );
476 # my $vec = $v1->_invert;
479 # Subtract $v1 from the origin. Effectively, gives the inverse of the
480 # original vector. The new vector is the same distance from the origin,
481 # in the opposite direction.
484 _invert( v1, v2, variant )
495 /* fetch the underlying array of the object */
496 v1_array = (AV*)SvRV(v1);
497 dim = av_len(v1_array);
499 /* create the new array and populate it */
501 for ( i=0 ; i<=dim; i++ ) {
502 val = SvIV( *av_fetch(v1_array, i, 0) );
503 av_push( my_array, newSViv(-val) );
506 /* return a blessed reference to the AV */
507 self = newRV_noinc( (SV*)my_array );
508 stash = SvSTASH( (SV*)v1_array );
509 sv_bless( (SV*)self, stash );
519 # $v1->_add_inplace($v2);
522 # Adds $v2 to $v1, and stores the result back into $v1.
525 _add_inplace( v1, v2, variant )
530 IV dimv1, dimv2, i, val1, val2;
534 /* fetch the underlying array of the object */
535 v1_array = (AV*)SvRV(v1);
536 v2_array = (AV*)SvRV(v2);
537 dimv1 = av_len(v1_array);
538 dimv2 = av_len(v2_array);
541 if ( dimv1 != dimv2 )
542 croak("uneven dimensions in vector addition!");
544 /* update the array slots */
545 for ( i=0 ; i<=dimv1; i++ ) {
546 val1 = SvIV( *av_fetch(v1_array, i, 0) );
547 val2 = SvIV( *av_fetch(v2_array, i, 0) );
548 av_store( v1_array, i, newSViv(val1+val2) );
555 # $v1->_substract_inplace($v2);
558 # Substract $v2 to $v1, and stores the result back into $v1.
561 _substract_inplace( v1, v2, variant )
566 IV dimv1, dimv2, i, val1, val2;
570 /* fetch the underlying array of the object */
571 v1_array = (AV*)SvRV(v1);
572 v2_array = (AV*)SvRV(v2);
573 dimv1 = av_len(v1_array);
574 dimv2 = av_len(v2_array);
577 if ( dimv1 != dimv2 )
578 croak("uneven dimensions in vector addition!");
580 /* update the array slots */
581 for ( i=0 ; i<=dimv1; i++ ) {
582 val1 = SvIV( *av_fetch(v1_array, i, 0) );
583 val2 = SvIV( *av_fetch(v2_array, i, 0) );
584 av_store( v1_array, i, newSViv(val1-val2) );
593 # my $bool = $v1->_compare($v2);
594 # my $bool = $v1 <=> $v2;
596 # Check whether the vectors both point at the same spot. Return 0 if they
597 # do, 1 if they don't.
600 _compare( v1, v2, variant )
606 IV dimv1, dimv2, i, val1, val2;
610 /* fetch the underlying array of the object */
611 v1_array = (AV*)SvRV(v1);
612 v2_array = (AV*)SvRV(v2);
613 dimv1 = av_len(v1_array);
614 dimv2 = av_len(v2_array);
617 if ( dimv1 != dimv2 )
618 croak("uneven dimensions in bounds check!");
620 /* compare the arrays */
622 for ( i=0 ; i<=dimv1; i++ ) {
623 val1 = SvIV( *av_fetch(v1_array, i, 0) );
624 val2 = SvIV( *av_fetch(v2_array, i, 0) );
625 if ( val1 != val2 ) {
636 # my $ptr = $LBV->_xs_rasterize_ptr();
638 # Get a pointer to the C "rasterize" function, so that other XS modules can
639 # call it directly for speed.
644 void *ptr = _rasterize;
647 rv = newSVpvn((const char *)(&ptr), sizeof(ptr));