7d70e42003-02-12Andreas Pettersson /* -*- c -*- || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */ #include "global.h"
e176472003-02-14Henrik Grubbström (Grubba) 
7d70e42003-02-12Andreas Pettersson #include "object.h" #include "svalue.h" #include "array.h" #include "pike_error.h" #include "interpret.h" #include "stralloc.h" #include "program.h"
44eaa62008-08-28Henrik Grubbström (Grubba) #include "operators.h"
68ec3f2014-08-18Martin Nilsson #include "pike_types.h"
7d70e42003-02-12Andreas Pettersson  #include "program_id.h" #include "module_support.h"
e541d22003-03-18Andreas Pettersson #include "sequence.h"
7d70e42003-02-12Andreas Pettersson  /*! @module ADT */ DECLARATIONS
be4f732003-03-18Andreas Pettersson /*! @class Sequence
13670c2015-05-25Martin Nilsson  *! The sequence work similar to an array but has the possibilities to
b38b122003-05-23Andreas Pettersson  *! insert and remove elements. It also has a more powerful iterator.
7d70e42003-02-12Andreas Pettersson  */
be4f732003-03-18Andreas Pettersson PIKECLASS Sequence
7d70e42003-02-12Andreas Pettersson { CVAR int pos; CVAR struct array *a;
13670c2015-05-25Martin Nilsson 
6398fe2003-04-03Henrik Grubbström (Grubba)  //if there is more than one reference to this array copy it.
c9eefb2014-08-21Martin Nilsson  static inline void should_copy(void)
6398fe2003-04-03Henrik Grubbström (Grubba)  { if (THIS->a->refs > 1) {
4be0a02006-03-16Henrik Grubbström (Grubba)  struct array *b = copy_array(THIS->a);
6398fe2003-04-03Henrik Grubbström (Grubba)  free_array(THIS->a);
c500902006-03-16Henrik Grubbström (Grubba)  THIS->a = b;
6398fe2003-04-03Henrik Grubbström (Grubba)  }
13670c2015-05-25Martin Nilsson  }
6398fe2003-04-03Henrik Grubbström (Grubba) 
7d70e42003-02-12Andreas Pettersson /*! @decl mixed `[](int index)
b38b122003-05-23Andreas Pettersson  *! Index operator.
13670c2015-05-25Martin Nilsson  *!
7d70e42003-02-12Andreas Pettersson  *! @param index *! The index to get the value for, could be negative to index from the end. *! *! @returns
b38b122003-05-23Andreas Pettersson  *! The value at the index @[index].
7d70e42003-02-12Andreas Pettersson  *!
13670c2015-05-25Martin Nilsson  *! @throws
7d70e42003-02-12Andreas Pettersson  *! An error if the index is out of range. */ PIKEFUN mixed `[](mixed index) {
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  simple_array_index_no_free(Pike_sp, THIS->a, index); Pike_sp++; }
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson 
b38b122003-05-23Andreas Pettersson /*! @decl mixed `[]=(int index, mixed value) *! Index assign operator. *! Set the value at the index @[index] to be @[value].
13670c2015-05-25Martin Nilsson  *! *! @param index
b38b122003-05-23Andreas Pettersson  *! The index to set.
7d70e42003-02-12Andreas Pettersson  *! *! @param value
b38b122003-05-23Andreas Pettersson  *! The new value.
7d70e42003-02-12Andreas Pettersson  *! *! @returns
b38b122003-05-23Andreas Pettersson  *! The new value at the index @[index].
7d70e42003-02-12Andreas Pettersson  *! */
13670c2015-05-25Martin Nilsson 
b38b122003-05-23Andreas Pettersson  PIKEFUN mixed `[]=(mixed index, mixed value) {
13670c2015-05-25Martin Nilsson  should_copy();
7d70e42003-02-12Andreas Pettersson  simple_set_index(THIS->a, index, value);
13670c2015-05-25Martin Nilsson  }
7d70e42003-02-12Andreas Pettersson 
44eaa62008-08-28Henrik Grubbström (Grubba) /*! @decl Sequence `+(Sequence ... coll)
7d70e42003-02-12Andreas Pettersson  *! Addition operator
44eaa62008-08-28Henrik Grubbström (Grubba)  *!
13670c2015-05-25Martin Nilsson  *! Append the content of @@@[coll] to this sequence and return the results
be4f732003-03-18Andreas Pettersson  *! as a new @[Sequence].
13670c2015-05-25Martin Nilsson  *! *! @param coll
44eaa62008-08-28Henrik Grubbström (Grubba)  *! The sequences to append to this sequence.
7d70e42003-02-12Andreas Pettersson  *! *! @returns
13670c2015-05-25Martin Nilsson  *! The result of the append as a new @[Sequence].
7d70e42003-02-12Andreas Pettersson  */
44eaa62008-08-28Henrik Grubbström (Grubba)  PIKEFUN object `+(object ... coll)
7d70e42003-02-12Andreas Pettersson  {
44eaa62008-08-28Henrik Grubbström (Grubba)  int i; ref_push_array(THIS->a); for(i=0; i < args; i++) { //FIXME: Ought to work on collection classes too if (coll[i].u.object->prog == Sequence_program) { ref_push_array(OBJ2_SEQUENCE(coll[i].u.object)->a); } else {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("`+",i+1,"ADT.Sequence");
44eaa62008-08-28Henrik Grubbström (Grubba)  }
7d70e42003-02-12Andreas Pettersson  }
44eaa62008-08-28Henrik Grubbström (Grubba)  f_add(args+1); push_object(clone_object(Sequence_program, 1)); stack_pop_n_elems_keep_top(args);
7d70e42003-02-12Andreas Pettersson  }
13670c2015-05-25Martin Nilsson 
44eaa62008-08-28Henrik Grubbström (Grubba) /*! @decl Sequence `-(Sequence ... coll)
7d70e42003-02-12Andreas Pettersson  *! Subtraction operator
44eaa62008-08-28Henrik Grubbström (Grubba)  *!
13670c2015-05-25Martin Nilsson  *! Removes those values in this sequence that also are present in @@@[coll]
be4f732003-03-18Andreas Pettersson  *! and return the results as a new @[Sequence].
13670c2015-05-25Martin Nilsson  *! *! @param coll
b38b122003-05-23Andreas Pettersson  *! The sequence to subtract from this sequence.
7d70e42003-02-12Andreas Pettersson  *! *! @returns
13670c2015-05-25Martin Nilsson  *! The result of the subtraction as a new @[Sequence].
7d70e42003-02-12Andreas Pettersson  */
44eaa62008-08-28Henrik Grubbström (Grubba)  PIKEFUN object `-(object ... coll)
7d70e42003-02-12Andreas Pettersson  {
44eaa62008-08-28Henrik Grubbström (Grubba)  int i; ref_push_array(THIS->a); for (i = 0; i < args; i++) { //FIXME: Ought to work on collection classes too if (coll[i].u.object->prog == Sequence_program) { ref_push_array(OBJ2_SEQUENCE(coll[i].u.object)->a); } else {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("`-",i+1,"ADT.Sequence");
44eaa62008-08-28Henrik Grubbström (Grubba)  }
7d70e42003-02-12Andreas Pettersson  }
44eaa62008-08-28Henrik Grubbström (Grubba)  f_minus(args+1); push_object(clone_object(Sequence_program, 1)); stack_pop_n_elems_keep_top(args);
7d70e42003-02-12Andreas Pettersson  }
13670c2015-05-25Martin Nilsson 
be4f732003-03-18Andreas Pettersson /*! @decl Sequence `&(Sequence coll)
7d70e42003-02-12Andreas Pettersson  *! And operator
13670c2015-05-25Martin Nilsson  *! Perform an and on this sequence and the @[coll] sequence by only returning
b38b122003-05-23Andreas Pettersson  *! those values that is present in both sequences as a new @[Sequence]. *! The remaining values is in the same order as they are in this sequence and
a983bb2003-02-14Henrik Grubbström (Grubba)  *! the values are compared using `==.
7d70e42003-02-12Andreas Pettersson  *!
13670c2015-05-25Martin Nilsson  *! @param coll
b38b122003-05-23Andreas Pettersson  *! The sequence to and to this sequence.
7d70e42003-02-12Andreas Pettersson  *! *! @returns
13670c2015-05-25Martin Nilsson  *! The result of the and as a new @[Sequence].
7d70e42003-02-12Andreas Pettersson  */ PIKEFUN object `&(object coll) { //Should work on collection classes too
be4f732003-03-18Andreas Pettersson  if (coll->prog == Sequence_program)
7d70e42003-02-12Andreas Pettersson  {
80fc6c2003-02-21Martin Stjernholm  push_array(and_arrays(THIS->a,
be4f732003-03-18Andreas Pettersson  OBJ2_SEQUENCE(coll)->a));
13670c2015-05-25Martin Nilsson 
be4f732003-03-18Andreas Pettersson  push_object(clone_object(Sequence_program, 1));
7d70e42003-02-12Andreas Pettersson  } else {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("`&",1,"ADT.Sequence");
7d70e42003-02-12Andreas Pettersson  } }
13670c2015-05-25Martin Nilsson 
be4f732003-03-18Andreas Pettersson /*! @decl Sequence `|(Sequence coll)
7d70e42003-02-12Andreas Pettersson  *! Or operator
13670c2015-05-25Martin Nilsson  *! Perform an or on this sequence and the @[coll] sequence by returning
b38b122003-05-23Andreas Pettersson  *! those values that is present in both sequences as a new @[Sequence].
a983bb2003-02-14Henrik Grubbström (Grubba)  *! The values are compared using `==.
7d70e42003-02-12Andreas Pettersson  *!
13670c2015-05-25Martin Nilsson  *! @param coll
b38b122003-05-23Andreas Pettersson  *! The sequence to or with this sequence.
7d70e42003-02-12Andreas Pettersson  *! *! @returns
13670c2015-05-25Martin Nilsson  *! The result of the or as a new @[Sequence].
7d70e42003-02-12Andreas Pettersson  */ PIKEFUN object `|(object coll) { //Should work on collection classes too
be4f732003-03-18Andreas Pettersson  if (coll->prog == Sequence_program)
7d70e42003-02-12Andreas Pettersson  {
13670c2015-05-25Martin Nilsson  push_array(merge_array_with_order(THIS->a,
be4f732003-03-18Andreas Pettersson  OBJ2_SEQUENCE(coll)->a,
80fc6c2003-02-21Martin Stjernholm  PIKE_ARRAY_OP_OR));
13670c2015-05-25Martin Nilsson 
be4f732003-03-18Andreas Pettersson  push_object(clone_object(Sequence_program, 1));
7d70e42003-02-12Andreas Pettersson  } else {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("`|",1,"ADT.Sequence");
7d70e42003-02-12Andreas Pettersson  } }
be4f732003-03-18Andreas Pettersson /*! @decl Sequence `^(Sequence coll)
7d70e42003-02-12Andreas Pettersson  *! Xor operator
13670c2015-05-25Martin Nilsson  *! Perform a xor on this sequence and the @[coll] sequence by returning *! those values that is present in one of the sequences but not in both
be4f732003-03-18Andreas Pettersson  *! adapters as a new @[Sequence].
a983bb2003-02-14Henrik Grubbström (Grubba)  *! The values are compared using `==.
7d70e42003-02-12Andreas Pettersson  *!
13670c2015-05-25Martin Nilsson  *! @param coll
b38b122003-05-23Andreas Pettersson  *! The sequence to xor with this sequence.
7d70e42003-02-12Andreas Pettersson  *! *! @returns
13670c2015-05-25Martin Nilsson  *! The result of the xor as a new @[Sequence].
7d70e42003-02-12Andreas Pettersson  */ PIKEFUN object `^(object coll) { //Should work on collection classes too
be4f732003-03-18Andreas Pettersson  if (coll->prog == Sequence_program)
7d70e42003-02-12Andreas Pettersson  {
13670c2015-05-25Martin Nilsson  push_array(merge_array_with_order(THIS->a,
be4f732003-03-18Andreas Pettersson  OBJ2_SEQUENCE(coll)->a,
80fc6c2003-02-21Martin Stjernholm  PIKE_ARRAY_OP_XOR));
13670c2015-05-25Martin Nilsson 
be4f732003-03-18Andreas Pettersson  push_object(clone_object(Sequence_program, 1));
7d70e42003-02-12Andreas Pettersson  } else {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("`^",1,"ADT.Sequence");
7d70e42003-02-12Andreas Pettersson  } }
b38b122003-05-23Andreas Pettersson  /*! @decl int(0..1) _equal(mixed coll)
7d70e42003-02-12Andreas Pettersson  *! *! @returns
b38b122003-05-23Andreas Pettersson  *! Returns @tt{true@} if the object @[coll] is a @[Sequence]
7d70e42003-02-12Andreas Pettersson  *! and contains the same values in the same order. */
b38b122003-05-23Andreas Pettersson  PIKEFUN int(0..1) _equal(mixed coll)
7d70e42003-02-12Andreas Pettersson  {
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(*coll) == T_OBJECT &&
be4f732003-03-18Andreas Pettersson  coll->u.object->prog == Sequence_program)
7d70e42003-02-12Andreas Pettersson  {
be4f732003-03-18Andreas Pettersson  struct Sequence_struct *adapter = OBJ2_SEQUENCE(coll->u.object);
7d70e42003-02-12Andreas Pettersson  RETURN (array_equal_p(THIS->a, adapter->a, 0)); } RETURN 0; } /*! @decl array _indices() *! *! @returns *! The indices in this adapter as an array. */ PIKEFUN array _indices() { ptrdiff_t size = THIS->a->size; struct array *a;
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  a=allocate_array_no_init(size,0); while(--size>=0) {
77af4f2015-10-14Martin Nilsson  ITEM(a)[size].u.integer = (INT_TYPE)size;
7d70e42003-02-12Andreas Pettersson  }
2523ce2003-04-28Martin Stjernholm  a->type_field = BIT_INT;
7d70e42003-02-12Andreas Pettersson  RETURN a; } /*! @decl void _insert_element(int index, mixed value)
b38b122003-05-23Andreas Pettersson  *! Insert an element in the sequence at the position @[index], the value
13670c2015-05-25Martin Nilsson  *! at the position @[index] and all above will have their index increased
7f06c92006-08-06Martin Stjernholm  *! by one.
13670c2015-05-25Martin Nilsson  *! *! @param index
b38b122003-05-23Andreas Pettersson  *! The index to insert the value at.
7d70e42003-02-12Andreas Pettersson  *! *! @param value
b38b122003-05-23Andreas Pettersson  *! The new value.
7d70e42003-02-12Andreas Pettersson  *! */ PIKEFUN void _insert_element(int index, mixed value) {
3e710a2003-09-10Martin Stjernholm  FIX_AND_CHECK_INDEX(index, THIS->a->size, 1);
7d70e42003-02-12Andreas Pettersson  should_copy(); THIS->a = array_insert(THIS->a, value, index);
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  }
b38b122003-05-23Andreas Pettersson /*! @decl mixed _remove_element(int index)
be4f732003-03-18Andreas Pettersson  *! Remove the values at index @[index] from the sequence.
13670c2015-05-25Martin Nilsson  *! *! @param index
b38b122003-05-23Andreas Pettersson  *! The index to remove.
7d70e42003-02-12Andreas Pettersson  *! *! @returns *! The removed value. */ PIKEFUN mixed _remove_element(int index) { struct svalue s;
3e710a2003-09-10Martin Stjernholm  FIX_AND_CHECK_INDEX(index, THIS->a->size, 0);
7d70e42003-02-12Andreas Pettersson 
13670c2015-05-25Martin Nilsson  s = *(THIS->a->item + index);
7d70e42003-02-12Andreas Pettersson  should_copy(); THIS->a = array_remove(THIS->a, index); push_svalue(&s); }
b38b122003-05-23Andreas Pettersson /*! @decl int _search(mixed value, void|int start)
13670c2015-05-25Martin Nilsson  *! Search the sequence for a specific value. Return the index of the first *! value that is equal to @[value]. If no value was found @expr{UNDEFINED@}
b38b122003-05-23Andreas Pettersson  *! is returned instead.
13670c2015-05-25Martin Nilsson  *!
7d70e42003-02-12Andreas Pettersson  *! @param value
b38b122003-05-23Andreas Pettersson  *! The value to find.
7d70e42003-02-12Andreas Pettersson  *!
89a7e62003-03-13Martin Nilsson  *! @param start
13670c2015-05-25Martin Nilsson  *! If a start value is supplied it will start searching at the index
7d70e42003-02-12Andreas Pettersson  *! @[start]. *! *! @returns
cbe8c92003-04-07Martin Nilsson  *! Returns the index of the found value or @expr{UNDEFINED@}.
7d70e42003-02-12Andreas Pettersson  */ PIKEFUN int _search(mixed value, void|int start) {
e257f02013-01-29Henrik Grubbström (Grubba)  if(start)
13670c2015-05-25Martin Nilsson  {
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(*start) != PIKE_T_INT)
13670c2015-05-25Martin Nilsson  {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("_search",2,"int");
7d70e42003-02-12Andreas Pettersson  } RETURN array_search(THIS->a, value, start->u.integer); }
13670c2015-05-25Martin Nilsson  else
7d70e42003-02-12Andreas Pettersson  { RETURN array_search(THIS->a,value,0); } }
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson /*! @decl int _sizeof() *! *! @returns *! The number of elements in this adapter. */ PIKEFUN int _sizeof() { RETURN THIS->a->size; } /*! @decl array _values() *! *! @returns *! The values in this adapter as an array. */
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  PIKEFUN array _values() { struct array *a; a=copy_array(THIS->a); RETURN a; }
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson /*! @decl void add(mixed value)
b38b122003-05-23Andreas Pettersson  *! Add a value at the end of the sequence.
7d70e42003-02-12Andreas Pettersson  *! *! @param value
b38b122003-05-23Andreas Pettersson  *! The value to add.
7d70e42003-02-12Andreas Pettersson  */ PIKEFUN void add(mixed value) { should_copy(); THIS->a=append_array(THIS->a, value); }
7a74cc2014-08-26Per Hedbor /*! @decl array cast(string type)
a983bb2003-02-14Henrik Grubbström (Grubba)  *! Cast operator. *! *! @param type *! Casts to this type. *! *! Casts to the following types are supported: *! @string *! @value "array"
be4f732003-03-18Andreas Pettersson  *! Cast the content of this sequence to an array.
a983bb2003-02-14Henrik Grubbström (Grubba)  *! @endstring
7d70e42003-02-12Andreas Pettersson  *! *! @returns
be4f732003-03-18Andreas Pettersson  *! An array with the contents of this sequence.
7d70e42003-02-12Andreas Pettersson  */
7a74cc2014-08-26Per Hedbor  PIKEFUN array cast(string type)
68ec3f2014-08-18Martin Nilsson  flags ID_PROTECTED;
7d70e42003-02-12Andreas Pettersson  {
68ec3f2014-08-18Martin Nilsson  pop_n_elems(args); /* type as at least one more reference. */ if (type == literal_array_string) push_array(copy_array(THIS->a));
7d70e42003-02-12Andreas Pettersson  else
68ec3f2014-08-18Martin Nilsson  push_undefined();
7d70e42003-02-12Andreas Pettersson  } /*! @decl void clear()
be4f732003-03-18Andreas Pettersson  *! Clear the contents of the sequence.
7d70e42003-02-12Andreas Pettersson  *! */ PIKEFUN void clear() { should_copy(); THIS->a=resize_array(THIS->a, 0);
13670c2015-05-25Martin Nilsson  }
7d70e42003-02-12Andreas Pettersson  /*! @decl int delete_value(mixed value)
be4f732003-03-18Andreas Pettersson  *! Remove the first occurrence of the value @[value] from the sequence.
7d70e42003-02-12Andreas Pettersson  *! *! @param value
be4f732003-03-18Andreas Pettersson  *! The value to remove from the sequence.
7d70e42003-02-12Andreas Pettersson  *! *! @returns
13670c2015-05-25Martin Nilsson  *! The index of the removed element or -1 if there was no value to
b38b122003-05-23Andreas Pettersson  *! remove.
7d70e42003-02-12Andreas Pettersson  */
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  PIKEFUN int delete_value(mixed value) { INT32 index = array_search(THIS->a, value, 0); if (index > -1) { should_copy(); THIS->a = array_remove(THIS->a, index); } RETURN index; } /*! @decl int(0..1) is_empty() *! *! @returns
13670c2015-05-25Martin Nilsson  *! Returns @expr{1@} if the sequence is empty otherwise @expr{0@}.
7d70e42003-02-12Andreas Pettersson  */
b38b122003-05-23Andreas Pettersson  PIKEFUN int(0..1) is_empty()
7d70e42003-02-12Andreas Pettersson  { RETURN !(THIS->a->size); } /*! @decl int max_size() *! *! @returns *! Returns -1. */ PIKEFUN int max_size() { RETURN -1; }
13670c2015-05-25Martin Nilsson 
c11fb02003-05-27Andreas Pettersson  /*! @decl void create(array|int arg) *! Creates a new @[Sequence] around the array arg or a new
7a52702003-05-28Johan Sundström  *! @[Sequence] with the size of arg.
7d70e42003-02-12Andreas Pettersson  */
13670c2015-05-25Martin Nilsson  PIKEFUN void create(array|int arg)
c11fb02003-05-27Andreas Pettersson  {
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(*arg) == T_INT)
c11fb02003-05-27Andreas Pettersson  {
c500902006-03-16Henrik Grubbström (Grubba)  struct array *b = allocate_array_no_init(arg->u.integer, 0); free_array(THIS->a); THIS->a = b;
c11fb02003-05-27Andreas Pettersson  THIS->a->type_field = BIT_INT; }
017b572011-10-28Henrik Grubbström (Grubba)  else if (TYPEOF(*arg) == T_ARRAY)
c11fb02003-05-27Andreas Pettersson  {
c500902006-03-16Henrik Grubbström (Grubba)  free_array(THIS->a);
c11fb02003-05-27Andreas Pettersson  add_ref(THIS->a=arg->u.array);
13670c2015-05-25Martin Nilsson  }
65810c2017-12-28Martin Nilsson  pop_stack();
7d70e42003-02-12Andreas Pettersson  }
13670c2015-05-25Martin Nilsson 
be4f732003-03-18Andreas Pettersson  /*! @decl SequenceIterator _get_iterator(void|int ind) *! Create and initiate a new SequenceIterator that could be used *! to iterate over this sequence.
7d70e42003-02-12Andreas Pettersson  *! *! @param ind *! If an @[ind] value is supplied the iterator will be positioned at *! that index. *! *! @returns *! An iterator. */
13670c2015-05-25Martin Nilsson 
be4f732003-03-18Andreas Pettersson  /*! @decl SequenceIterator first() *! Create and initiate a new SequenceIterator that could be used *! to iterate over this sequence.
7d70e42003-02-12Andreas Pettersson  *! *! @returns
be4f732003-03-18Andreas Pettersson  *! An iterator positioned at the first element in the sequence.
7d70e42003-02-12Andreas Pettersson  */
13670c2015-05-25Martin Nilsson 
be4f732003-03-18Andreas Pettersson  /*! @decl SequenceIterator last() *! Create and initiate a new SequenceIterator that could be used *! to iterate over this sequence.
7d70e42003-02-12Andreas Pettersson  *! *! @returns
be4f732003-03-18Andreas Pettersson  *! An iterator positioned after the last element in the sequence.
7d70e42003-02-12Andreas Pettersson  */
13670c2015-05-25Martin Nilsson  INIT
7d70e42003-02-12Andreas Pettersson  {
f0cd2f2006-03-16Henrik Grubbström (Grubba)  add_ref(THIS->a = &empty_array);
7d70e42003-02-12Andreas Pettersson  } EXIT
9655462008-05-31Martin Nilsson  gc_trivial;
7d70e42003-02-12Andreas Pettersson  { free_array(THIS->a); }
be4f732003-03-18Andreas Pettersson  /*! @class SequenceIterator
13670c2015-05-25Martin Nilsson  *! This is the iterator for the Sequence. It implements the
b38b122003-05-23Andreas Pettersson  *! IndexIterator and the OutputIterator
13670c2015-05-25Martin Nilsson  */
be4f732003-03-18Andreas Pettersson  PIKECLASS SequenceIterator
7d70e42003-02-12Andreas Pettersson  { CVAR int pos;
be4f732003-03-18Andreas Pettersson  CVAR struct Sequence_struct *sequence;
13670c2015-05-25Martin Nilsson  CVAR struct object *obj;
7d70e42003-02-12Andreas Pettersson 
be4f732003-03-18Andreas Pettersson  /*! @decl void create(object sequence, void|int start) *! Creates a new iterator for the sequence @[sequence]. If start is
b38b122003-05-23Andreas Pettersson  *! supplied it will try to position the iterator at @[start].
13670c2015-05-25Martin Nilsson  *!
7d70e42003-02-12Andreas Pettersson  */
13670c2015-05-25Martin Nilsson  PIKEFUN void create(object sequence, void|int start)
7d70e42003-02-12Andreas Pettersson  {
13670c2015-05-25Martin Nilsson 
be4f732003-03-18Andreas Pettersson  if (sequence->prog != Sequence_program)
7d70e42003-02-12Andreas Pettersson  {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("create",1,"ADT.Sequence");
7d70e42003-02-12Andreas Pettersson  } else {
be4f732003-03-18Andreas Pettersson  THIS->sequence = OBJ2_SEQUENCE(sequence); add_ref(THIS->obj = sequence);
e257f02013-01-29Henrik Grubbström (Grubba)  if (start) // if there was an start index supplied
7d70e42003-02-12Andreas Pettersson  { THIS->pos=start->u.integer;
13670c2015-05-25Martin Nilsson  if (THIS->sequence->a && ((THIS->pos > THIS->sequence->a->size)
7d70e42003-02-12Andreas Pettersson  || (THIS->pos < 0))) {
13670c2015-05-25Martin Nilsson  Pike_error("Index %d is out of array range 0 - %d.\n", THIS->pos,
be4f732003-03-18Andreas Pettersson  THIS->sequence->a->size);
65810c2017-12-28Martin Nilsson  } pop_n_elems(2);
7d70e42003-02-12Andreas Pettersson  } else {
65810c2017-12-28Martin Nilsson  THIS->pos = 0; pop_stack();
7d70e42003-02-12Andreas Pettersson  } }
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  }
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  /*! @decl int index()
13670c2015-05-25Martin Nilsson  *!
7d70e42003-02-12Andreas Pettersson  *! @returns *! The index at the current position. */ PIKEFUN int index() {
13670c2015-05-25Martin Nilsson  if(!THIS->sequence || !THIS->sequence->a || THIS->pos >= THIS->sequence->a->size)
7d70e42003-02-12Andreas Pettersson  {
074dd12011-10-22Henrik Grubbström (Grubba)  push_undefined();
7d70e42003-02-12Andreas Pettersson  } else { RETURN THIS->pos; } }
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  /*! @decl mixed value()
13670c2015-05-25Martin Nilsson  *!
7d70e42003-02-12Andreas Pettersson  *! @returns *! The value at the current position. */ PIKEFUN mixed value() {
13670c2015-05-25Martin Nilsson  if(!THIS->sequence || !THIS->sequence->a || THIS->pos >= THIS->sequence->a->size)
7d70e42003-02-12Andreas Pettersson  {
074dd12011-10-22Henrik Grubbström (Grubba)  push_undefined();
7d70e42003-02-12Andreas Pettersson  } else {
be4f732003-03-18Andreas Pettersson  push_svalue(THIS->sequence->a->item + THIS->pos);
7d70e42003-02-12Andreas Pettersson  } }
be4f732003-03-18Andreas Pettersson  /*! @decl SequenceIterator `+(int steps)
7d70e42003-02-12Andreas Pettersson  *! Move the iterator @[steps] steps forward (negative value on @[steps] *! will cause the iterator to move backwards) and return the result *! as a new iterator. *! @returns *! A new iterator positioned @[steps] steps forward.
13670c2015-05-25Martin Nilsson  */
7d70e42003-02-12Andreas Pettersson  PIKEFUN object `+(int steps) {
7f8f512017-06-18Martin Nilsson  struct object *o=fast_clone_object(Sequence_SequenceIterator_program);
b7a55a2003-11-29Henrik Grubbström (Grubba)  struct Sequence_SequenceIterator_struct *new; new = OBJ2_SEQUENCE_SEQUENCEITERATOR(o);
7d70e42003-02-12Andreas Pettersson  new[0]=*THIS; add_ref(THIS->obj); new->pos+=steps;
13670c2015-05-25Martin Nilsson  if (new->pos < 0) {
7d70e42003-02-12Andreas Pettersson  new->pos = 0; }
13670c2015-05-25Martin Nilsson  else if (new->pos > new->sequence->a->size) { new->pos = new->sequence->a->size;
7d70e42003-02-12Andreas Pettersson  } RETURN o;
13670c2015-05-25Martin Nilsson  }
7d70e42003-02-12Andreas Pettersson 
be4f732003-03-18Andreas Pettersson  /*! @decl SequenceIterator `+=(int steps)
7d70e42003-02-12Andreas Pettersson  *! Move this iterator @[steps] steps forward (negative value on @[steps] *! will cause the iterator to move backwards) and return the result. *! *! @returns *! This iterator positioned @[steps] steps forward.
13670c2015-05-25Martin Nilsson  */
7d70e42003-02-12Andreas Pettersson  PIKEFUN object `+=(int steps) { THIS->pos+=steps;
13670c2015-05-25Martin Nilsson  if (THIS->pos < 0) {
7d70e42003-02-12Andreas Pettersson  THIS->pos = 0; }
13670c2015-05-25Martin Nilsson  else if (THIS->pos > THIS->sequence->a->size) { THIS->pos = THIS->sequence->a->size;
7d70e42003-02-12Andreas Pettersson  }
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  REF_RETURN Pike_fp->current_object; }
be4f732003-03-18Andreas Pettersson  /*! @decl SequenceIterator `-(int steps)
13670c2015-05-25Martin Nilsson  *! Move the iterator @[steps] steps backwards (negative value on *! @[steps] will cause the iterator to move forwards) and return
7d70e42003-02-12Andreas Pettersson  *! the result as a new iterator. *! @returns *! A new iterator positioned @[steps] steps backwards.
13670c2015-05-25Martin Nilsson  */
7d70e42003-02-12Andreas Pettersson  PIKEFUN object `-(int steps) {
7f8f512017-06-18Martin Nilsson  struct object *o=fast_clone_object(Sequence_SequenceIterator_program);
b7a55a2003-11-29Henrik Grubbström (Grubba)  struct Sequence_SequenceIterator_struct *new; new = OBJ2_SEQUENCE_SEQUENCEITERATOR(o);
7d70e42003-02-12Andreas Pettersson  new[0]=*THIS; add_ref(THIS->obj); new->pos-=steps;
13670c2015-05-25Martin Nilsson  if (new->pos < 0) {
7d70e42003-02-12Andreas Pettersson  new->pos = 0; }
13670c2015-05-25Martin Nilsson  else if (new->pos > new->sequence->a->size) { new->pos = new->sequence->a->size;
7d70e42003-02-12Andreas Pettersson  } RETURN o; }
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  /*! @decl int(0..1) has_next(void|int steps) *! @returns *! Returns @tt{true@} if it is possible to move @[steps] steps
b38b122003-05-23Andreas Pettersson  *! forwards, if @[steps] weren't supplied it check if it is
7d70e42003-02-12Andreas Pettersson  *! possible to move one step forward.
13670c2015-05-25Martin Nilsson  */
7d70e42003-02-12Andreas Pettersson 
34221b2003-03-08Martin Nilsson  PIKEFUN int(0..1) has_next(void|int steps)
7d70e42003-02-12Andreas Pettersson  {
e257f02013-01-29Henrik Grubbström (Grubba)  if (!steps)
7d70e42003-02-12Andreas Pettersson  {
13670c2015-05-25Martin Nilsson  RETURN (THIS->sequence && THIS->sequence->a &&
be4f732003-03-18Andreas Pettersson  (THIS->pos + 1) <= THIS->sequence->a->size);
7d70e42003-02-12Andreas Pettersson  } else
13670c2015-05-25Martin Nilsson  { RETURN (THIS->sequence && THIS->sequence->a &&
7d70e42003-02-12Andreas Pettersson  (THIS->pos + steps->u.integer) >= 0 &&
be4f732003-03-18Andreas Pettersson  (THIS->pos + steps->u.integer) <= THIS->sequence->a->size);
7d70e42003-02-12Andreas Pettersson  } }
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  /*! @decl int(0..1) has_previous(void|int steps) *! @returns *! Returns @tt{true@} if it is possible to move @[steps] steps
b38b122003-05-23Andreas Pettersson  *! backwards, if @[steps] weren't supplied it check if it is
7d70e42003-02-12Andreas Pettersson  *! possible to move one step backward.
13670c2015-05-25Martin Nilsson  */
7d70e42003-02-12Andreas Pettersson 
34221b2003-03-08Martin Nilsson  PIKEFUN int(0..1) has_previous(void|int steps)
7d70e42003-02-12Andreas Pettersson  {
e257f02013-01-29Henrik Grubbström (Grubba)  if (!steps)
7d70e42003-02-12Andreas Pettersson  {
be4f732003-03-18Andreas Pettersson  RETURN (THIS->sequence && THIS->sequence->a &&
7d70e42003-02-12Andreas Pettersson  (THIS->pos) > 0); } else {
be4f732003-03-18Andreas Pettersson  RETURN (THIS->sequence && THIS->sequence->a &&
7d70e42003-02-12Andreas Pettersson  (THIS->pos - steps->u.integer) >= 0 &&
be4f732003-03-18Andreas Pettersson  (THIS->pos - steps->u.integer) <= THIS->sequence->a->size);
7d70e42003-02-12Andreas Pettersson  } }
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  /*! @decl int(0..1) `!() *! @returns *! Returns @tt{false@} if the iterator has reached the end.
13670c2015-05-25Martin Nilsson  */
7d70e42003-02-12Andreas Pettersson 
34221b2003-03-08Martin Nilsson  PIKEFUN int(0..1) `!()
7d70e42003-02-12Andreas Pettersson  {
be4f732003-03-18Andreas Pettersson  RETURN (THIS->sequence && THIS->sequence->a && THIS->pos == THIS->sequence->a->size);
7d70e42003-02-12Andreas Pettersson  }
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  /*! @decl int(0..1) _equal(mixed iter) *! Compare this iterator with another iterator.
13670c2015-05-25Martin Nilsson  *!
7d70e42003-02-12Andreas Pettersson  *! @param iter
b38b122003-05-23Andreas Pettersson  *! The iterator to compare with.
7d70e42003-02-12Andreas Pettersson  *! @returns *! Returns @tt{true@} if both iterators iterates over the same *! objects and are positioned at the same spot.
13670c2015-05-25Martin Nilsson  */
7d70e42003-02-12Andreas Pettersson 
34221b2003-03-08Martin Nilsson  PIKEFUN int(0..1) _equal(mixed iter)
7d70e42003-02-12Andreas Pettersson  {
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(*iter) == T_OBJECT &&
b7a55a2003-11-29Henrik Grubbström (Grubba)  iter->u.object->prog == Sequence_SequenceIterator_program)
7d70e42003-02-12Andreas Pettersson  {
be4f732003-03-18Andreas Pettersson  //to do: Check so that it is an SequenceIterator
13670c2015-05-25Martin Nilsson  struct Sequence_SequenceIterator_struct *i =
b7a55a2003-11-29Henrik Grubbström (Grubba)  OBJ2_SEQUENCE_SEQUENCEITERATOR(iter->u.object);
be4f732003-03-18Andreas Pettersson  RETURN (THIS->sequence == i->sequence && THIS->pos == i->pos);
7d70e42003-02-12Andreas Pettersson  } else { RETURN 0; } }
13670c2015-05-25Martin Nilsson 
89a7e62003-03-13Martin Nilsson  /*! @decl int(0..1) `<(mixed iter)
b38b122003-05-23Andreas Pettersson  *! Less then operator.
7d70e42003-02-12Andreas Pettersson  *! *! @returns *! Returns @tt{true@} if this iterator has a lower index *! then @[iter].
13670c2015-05-25Martin Nilsson  */
7d70e42003-02-12Andreas Pettersson 
34221b2003-03-08Martin Nilsson  PIKEFUN int(0..1) `<(mixed iter)
7d70e42003-02-12Andreas Pettersson  {
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(*iter) == T_OBJECT &&
b7a55a2003-11-29Henrik Grubbström (Grubba)  iter->u.object->prog == Sequence_SequenceIterator_program)
7d70e42003-02-12Andreas Pettersson  {
be4f732003-03-18Andreas Pettersson  //to do: Check so that it is an SequenceIterator
13670c2015-05-25Martin Nilsson  struct Sequence_SequenceIterator_struct *i =
b7a55a2003-11-29Henrik Grubbström (Grubba)  OBJ2_SEQUENCE_SEQUENCEITERATOR(iter->u.object);
7d70e42003-02-12Andreas Pettersson  RETURN (THIS->pos < i->pos); } else {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("`<",1,"ADT.Sequence.SequenceIterator");
7d70e42003-02-12Andreas Pettersson  } }
fb1ba62003-04-08Johan Sundström  /*! @decl int(0..1) `>(mixed iter)
b38b122003-05-23Andreas Pettersson  *! Greater then operator.
7d70e42003-02-12Andreas Pettersson  *! *! @returns *! Returns @tt{true@} if this iterator has a higher index *! then @[iter].
fb1ba62003-04-08Johan Sundström  */
7d70e42003-02-12Andreas Pettersson 
34221b2003-03-08Martin Nilsson  PIKEFUN int(0..1) `>(mixed iter)
7d70e42003-02-12Andreas Pettersson  {
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(*iter) == T_OBJECT &&
b7a55a2003-11-29Henrik Grubbström (Grubba)  iter->u.object->prog == Sequence_SequenceIterator_program)
7d70e42003-02-12Andreas Pettersson  {
be4f732003-03-18Andreas Pettersson  //to do: Check so that it is an SequenceIterator
13670c2015-05-25Martin Nilsson  struct Sequence_SequenceIterator_struct *i =
b7a55a2003-11-29Henrik Grubbström (Grubba)  OBJ2_SEQUENCE_SEQUENCEITERATOR(iter->u.object);
7d70e42003-02-12Andreas Pettersson  RETURN (THIS->pos > i->pos); } else {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("`>",1,"ADT.Sequence.SequenceIterator");
7d70e42003-02-12Andreas Pettersson  } }
13670c2015-05-25Martin Nilsson 
c11fb02003-05-27Andreas Pettersson  /*! @decl int distance(object iter) *! *! @param iter *! The iterator to measure the distance to. *! @returns *! Returns distance between this iterator and @[iter]. *! @throws *! An error if the two iterator could not be compared.
13670c2015-05-25Martin Nilsson  */
c11fb02003-05-27Andreas Pettersson  PIKEFUN int distance(object iter) {
b7a55a2003-11-29Henrik Grubbström (Grubba)  if (iter->prog == Sequence_SequenceIterator_program)
c11fb02003-05-27Andreas Pettersson  {
13670c2015-05-25Martin Nilsson  struct Sequence_SequenceIterator_struct *i =
b7a55a2003-11-29Henrik Grubbström (Grubba)  OBJ2_SEQUENCE_SEQUENCEITERATOR(iter);
c11fb02003-05-27Andreas Pettersson  RETURN (i->pos - THIS->pos); } else {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("distance",1,"ADT.Sequence.SequenceIterator");
c11fb02003-05-27Andreas Pettersson  } }
13670c2015-05-25Martin Nilsson 
be4f732003-03-18Andreas Pettersson  /*! @decl Sequence get_collection()
7d70e42003-02-12Andreas Pettersson  *! *! @returns
be4f732003-03-18Andreas Pettersson  *! Returns the Sequence this iterator currently iterates over.
13670c2015-05-25Martin Nilsson  */
7d70e42003-02-12Andreas Pettersson  PIKEFUN object get_collection() { REF_RETURN THIS->obj; }
13670c2015-05-25Martin Nilsson 
b38b122003-05-23Andreas Pettersson  /*! @decl mixed set_value(mixed val)
7d70e42003-02-12Andreas Pettersson  *! Set the value at the current position. *! *! @param val
b38b122003-05-23Andreas Pettersson  *! The new value.
7d70e42003-02-12Andreas Pettersson  *! @returns
b38b122003-05-23Andreas Pettersson  *! Returns the old value.
13670c2015-05-25Martin Nilsson  */
7d70e42003-02-12Andreas Pettersson  PIKEFUN mixed set_value(mixed val) {
be4f732003-03-18Andreas Pettersson  if (THIS->sequence && THIS->sequence->a && THIS->pos < THIS->sequence->a->size)
7d70e42003-02-12Andreas Pettersson  { struct svalue ind; struct svalue retval; //if there is someone else using the array but the adapter
be4f732003-03-18Andreas Pettersson  if (THIS->sequence->a->refs > 1)
7d70e42003-02-12Andreas Pettersson  { //copy it
be4f732003-03-18Andreas Pettersson  free_array(THIS->sequence->a); THIS->sequence->a = copy_array(THIS->sequence->a);
7d70e42003-02-12Andreas Pettersson  }
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(ind, T_INT, NUMBER_NUMBER, integer, THIS->pos);
be4f732003-03-18Andreas Pettersson  simple_array_index_no_free(&retval, THIS->sequence->a, &ind); simple_set_index(THIS->sequence->a, &ind, val);
7d70e42003-02-12Andreas Pettersson  push_svalue(&retval); } else {
074dd12011-10-22Henrik Grubbström (Grubba)  push_undefined();
7d70e42003-02-12Andreas Pettersson  } }
13670c2015-05-25Martin Nilsson 
b467522017-06-25Martin Nilsson #ifdef PIKE_NULL_IS_SPECIAL
13670c2015-05-25Martin Nilsson  INIT
7d70e42003-02-12Andreas Pettersson  {
be4f732003-03-18Andreas Pettersson  THIS->sequence=0;
7d70e42003-02-12Andreas Pettersson  THIS->pos=0;
9655462008-05-31Martin Nilsson  THIS->obj = NULL;
7d70e42003-02-12Andreas Pettersson  }
b467522017-06-25Martin Nilsson #endif
7d70e42003-02-12Andreas Pettersson  EXIT
9655462008-05-31Martin Nilsson  gc_trivial;
7d70e42003-02-12Andreas Pettersson  {
9655462008-05-31Martin Nilsson  if( THIS->obj ) free_object(THIS->obj);
7d70e42003-02-12Andreas Pettersson  }
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  }
be4f732003-03-18Andreas Pettersson  //End SequenceIterator
7d70e42003-02-12Andreas Pettersson  /*! @endclass */
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  PIKEFUN object _get_iterator(void|int ind) { ref_push_object(Pike_fp->current_object);
e257f02013-01-29Henrik Grubbström (Grubba)  if (ind)
7d70e42003-02-12Andreas Pettersson  { push_svalue(ind); }
b7a55a2003-11-29Henrik Grubbström (Grubba)  push_object(clone_object(Sequence_SequenceIterator_program, args+1));
7d70e42003-02-12Andreas Pettersson  }
13670c2015-05-25Martin Nilsson 
7d70e42003-02-12Andreas Pettersson  PIKEFUN object first() { ref_push_object(Pike_fp->current_object);
b7a55a2003-11-29Henrik Grubbström (Grubba)  push_object(clone_object(Sequence_SequenceIterator_program, 1));
7d70e42003-02-12Andreas Pettersson  } PIKEFUN object last() { struct svalue ind;
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(ind, T_INT, NUMBER_NUMBER, integer, THIS_SEQUENCE->a->size);
7d70e42003-02-12Andreas Pettersson  ref_push_object(Pike_fp->current_object); push_svalue(&ind);
b7a55a2003-11-29Henrik Grubbström (Grubba)  push_object(clone_object(Sequence_SequenceIterator_program, 2));
7d70e42003-02-12Andreas Pettersson  }
13670c2015-05-25Martin Nilsson  }
7d70e42003-02-12Andreas Pettersson 
be4f732003-03-18Andreas Pettersson //End of Sequence
13670c2015-05-25Martin Nilsson /*! @endclass
7d70e42003-02-12Andreas Pettersson  */ /*! @endmodule */
be4f732003-03-18Andreas Pettersson void pike_init_Sequence_module(void)
7d70e42003-02-12Andreas Pettersson { INIT; }
be4f732003-03-18Andreas Pettersson void pike_exit_Sequence_module(void)
7d70e42003-02-12Andreas Pettersson { EXIT
13670c2015-05-25Martin Nilsson }
7d70e42003-02-12Andreas Pettersson