Code archives/Algorithms/Container: vector

This code has been declared by its author to be Public Domain code.

Download source code

Container: vector by octothorpe2005
Vector containers have nothing to do with spatial vectors!

This library makes it painless to add many independant vector containers for many different types of objects. This is done by storing Handle()s to your objects. Each container should hold objects of only one type. For more information on containers, an example of how to use them, and a tutorial, click here.

A vector is essentially the same as an array, but it can also work like a FIFO stack.

But Blitz already has arrays! Sure, it has two kinds of arrays: basic arrays (Dim a(10)) and type arrays (Field x[10]). The first kind is global and cannot be passed to functions, the second is limited to a static number of elements. Vectors implemented with this library suffer neither of these limitations.

Additionally, you can use your vector as a stack if you use the optional push() and pop() functions.

For an example of how to use this library, scroll down to the test() function at the very bottom. This code will run standalone if you uncomment the line at the top which runs the test code.


Please post bugs or feature requests in comments.


Fundamentals

vector_new.vectorC(elements% = 0)
- create a new vector
vector_destroy(our_vector.vectorC)
- delete a vector and all of its elements

Standard Operations

vector_set(our_vector.vectorC, index%, value)
- set value at specified index
vector_get(our_vector.vectorC, index%)
- get value at specified index
vector_resize(our_vector.vectorC, elements%)
- set the size of the vector
vector_count(our_vector.vectorC)
- return the number of elements in the vector

Stack Operations

vector_push(our_vector.vectorC, value)
- add a new element to the end of the vector
vector_pop(our_vector.vectorC)
- remove an element from the end of the vector, returning its value
vector_alloc(our_vector.vectorC, elements%)
- preallocate a bunch of space for push() operations

Slow Operations

vector_remove_element(our_vector.vectorC, index%)
- remove an element from anywhere in a vector, returning its value
vector_insert_before(our_vector.vectorC, index%, value)
- add a new element before an existing one
vector_insert_after(our_vector.vectorC, index%, value)
- add a new element after an existing one
vector_shift(our_vector.vectorC)
- remove an element from the front of the vector, returning its value
vector_unshift(our_vector.vectorC, value)
- add a new element to the front of the vector

Iterators

	; for item.type = each our_vector
	it.vectorC_iter = vector_iterator_begin(our_vector)
	while vector_iterator_next(it)
		item.type = object.type(vector_iterator_get(it))
		; do stuff with item
	wend


vector_iterator_begin_reverse.vectorC_iter(our_vector.vectorC)
- create a new iterator for traversing the list backwards

---

The Code
;vector_test()

; ------------------------------------------------------------------------------
;= TO DO
; ------------------------------------------------------------------------------
; iterator sanity checking (try to catch problems which might be caused by deleting elements while iterating)

; ------------------------------------------------------------------------------
;= CHANGE LOG
; ------------------------------------------------------------------------------
; 12/11/2005 - iterator sample usage for quick copying and pasting
; 12/11/2005 - negative index values now represent elements in reverse order,
;              added remove_element(), insert_element_*(), shift(), unshift(),
;              and iterators
; 12/11/2005 - calling new() is now required
; 06/11/2005 - new() for forwards compatibility
; 03/11/2005 - renamed class from vectorType

; ------------------------------------------------------------------------------
;= CONSTANTS
; ------------------------------------------------------------------------------
const VECTORS_EXPAND_BY = 20
	; instead of resizing our bank every push() operation, grab some extra space

; ------------------------------------------------------------------------------
;= TYPES
; ------------------------------------------------------------------------------
type vectorC
	field last_element%                   ; size of the container - 1
	field elements_allocated%             ; size of the bank (not in bytes)
	field bank
end type

type vectorC_iter
	field vector.vectorC
	field forwards                        ; bool to keep track of which direction we're going
	field current_index%
end type

; ------------------------------------------------------------------------------
;= FUNDAMENTAL
; ------------------------------------------------------------------------------

; ------------------------------------------------------------------------------
function vector_new.vectorC(elements% = 0)
; create a new vector

	our_vector.vectorC = new vectorC
	our_vector\bank = createbank(0)
	vector_resize(our_vector, elements)   ; also sets \last_element to elements-1
	return our_vector
end function

; ------------------------------------------------------------------------------
function vector_destroy(our_vector.vectorC)
; delete a vector and all of its elements

	freebank(our_vector\bank)
	delete our_vector
end function

; ------------------------------------------------------------------------------
function vector_set(our_vector.vectorC, index%, value)
; set value at specified index

	if our_vector = null then runtimeerror("not a valid vectorC: null")
	if (index < 0) then index = our_vector\last_element+1 + index                   ; negative indexes reference elements in reverse order
	if (index < 0 or index > our_vector\last_element) then runtimeerror("element out of range: "+index)
	pokeint(our_vector\bank, 4 * index, value)
end function

; ------------------------------------------------------------------------------
function vector_get(our_vector.vectorC, index%)
; get value at specified index

	if our_vector = null then runtimeerror("not a valid vectorC: null")
	if (index < 0) then index = our_vector\last_element+1 + index                   ; negative indexes reference elements in reverse order
	if (index < 0 or index > our_vector\last_element) then runtimeerror("element out of range: "+index)
	return peekint(our_vector\bank, 4 * index)
end function

; ------------------------------------------------------------------------------
function vector_resize(our_vector.vectorC, elements%)
; set the size of the vector

	if our_vector = null then runtimeerror("not a valid vectorC: null")
	resizebank(our_vector\bank, 4 * elements)
	our_vector\elements_allocated = elements
	our_vector\last_element = elements - 1
end function

; ------------------------------------------------------------------------------
function vector_count(our_vector.vectorC)
; return the number of elements in the vector

	if our_vector = null then runtimeerror("not a valid vectorC: null")
	return our_vector\last_element + 1
end function

; ------------------------------------------------------------------------------
;= STACK OPERATIONS
; ------------------------------------------------------------------------------
function vector_push(our_vector.vectorC, value)
; add a new element to the end of the vector

	if our_vector = null then runtimeerror("not a valid vectorC: null")
	; allocate more space if required
	if our_vector\elements_allocated-1 = our_vector\last_element then
		our_vector\elements_allocated = our_vector\elements_allocated + VECTORS_EXPAND_BY
		resizebank(our_vector\bank, 4 * our_vector\elements_allocated)
	endif
	; store the new value
	our_vector\last_element = our_vector\last_element + 1
	pokeint(our_vector\bank, 4 * our_vector\last_element, value)
end function

; ------------------------------------------------------------------------------
function vector_pop(our_vector.vectorC)
; remove an element from the end of the vector

	if our_vector = null then runtimeerror("not a valid vectorC: null")
	if our_vector\last_element = -1 then return 0
	our_vector\last_element = our_vector\last_element - 1
	return peekint(our_vector\bank, 4 * (our_vector\last_element + 1))
end function

; ------------------------------------------------------------------------------
function vector_alloc(our_vector.vectorC, elements%)
; preallocate a bunch of space for push() operations

	if our_vector = null then runtimeerror("not a valid vectorC: null")
	if elements < our_vector\last_element + 1 then runtimeerror("cannot alloc less space than is currently being used")
	our_vector\elements_allocated = elements
	resizebank(our_vector\bank, 4 * our_vector\elements_allocated)
end function

; ------------------------------------------------------------------------------
;= SLOW OPERATIONS
; ------------------------------------------------------------------------------
function vector_remove_element(our_vector.vectorC, index%)
; remove an element from anywhere in a vector

	if our_vector = null then runtimeerror("not a valid vectorC: null")
	if (index < 0) then index = our_vector\last_element+1 + index                   ; negative indexes reference elements in reverse order
	if (index < 0 or index > our_vector\last_element) then runtimeerror("element out of range: "+index)
	value = peekint(our_vector\bank, 4 * index)
	our_vector\last_element = our_vector\last_element - 1
	; move elements backward to cover our hole
	copybank(our_vector\bank, 4*(index+1), our_vector\bank, 4*index, 4*(our_vector\last_element+1 - index))
	return value
end function

; ------------------------------------------------------------------------------
function vector_insert_before(our_vector.vectorC, index%, value)
; add a new element before an existing one
; note that we allow a reference index of our_vector\last_element+1 (which is dispatched to vector_push() anyways)


	if our_vector = null then runtimeerror("not a valid vectorC: null")
	if (index < 0) then index = our_vector\last_element+1 + index                   ; negative indexes reference elements in reverse order
	if index = our_vector\last_element+1 then return vector_push(our_vector, value) ; much faster alternative!
	if (index < 0 or index > our_vector\last_element) then runtimeerror("element out of range: "+index)
	; allocate more space if required
	if our_vector\elements_allocated-1 = our_vector\last_element then
		our_vector\elements_allocated = our_vector\elements_allocated + VECTORS_EXPAND_BY
		resizebank(our_vector\bank, 4 * our_vector\elements_allocated)
	endif
	; move elements forward
	copybank(our_vector\bank, 4*(index), our_vector\bank, 4*(index+1), 4*(our_vector\last_element+1 - index))
	our_vector\last_element = our_vector\last_element + 1
	; set our new value
	pokeint(our_vector\bank, 4 * index, value)
end function

; ------------------------------------------------------------------------------
function vector_insert_after(our_vector.vectorC, index%, value)
; add a new element after an existing one
	if (index < 0) then index = our_vector\last_element+1 + index                   ; negative indexes reference elements in reverse order
	return vector_insert_before(our_vector, index+1, value)
end function

; ------------------------------------------------------------------------------
function vector_shift(our_vector.vectorC)
; add a new element after an existing one
	return vector_remove_element(our_vector, 0)
end function

; ------------------------------------------------------------------------------
function vector_unshift(our_vector.vectorC, value)
; add a new element to the front of the vector
	vector_insert_before(our_vector, 0, value)
end function

; ------------------------------------------------------------------------------
;= ITERATORS
; ------------------------------------------------------------------------------

; sample usage

; ; for item.type = each vector
;	it.vectorC_iter = vector_iterator_begin(vector)
;	while vector_iterator_next(it)
;		item.type = object.type(vector_iterator_get(it))
;	wend


; ------------------------------------------------------------------------------
function vector_iterator_begin.vectorC_iter(our_vector.vectorC)
; create a new iterator for traversing the vector forwards

	it.vectorC_iter = new vectorC_iter
	if our_vector <> null then
		it\vector = our_vector
		it\forwards = true
		it\current_index = 0-1
	endif
	return it
end function

; ------------------------------------------------------------------------------
function vector_iterator_begin_reverse.vectorC_iter(our_vector.vectorC)
; create a new iterator for traversing the vector backwards

	it.vectorC_iter = new vectorC_iter
	if our_vector <> null then
		it\vector = our_vector
		it\forwards = false
		it\current_index = our_vector\last_element+1
	endif
	return it
end function

; ------------------------------------------------------------------------------
function vector_iterator_next(it.vectorC_iter)
; advance the iterator to the next element in the vector

	; drop out immediately if this iterator is void
	if it\vector = null then return false
	
	if it\forwards = true then
		it\current_index = it\current_index + 1
		if it\current_index > it\vector\last_element then delete it : return false
	else
		it\current_index = it\current_index - 1
		if it\current_index < 0 then delete it : return false
	endif
	return true
end function

; ------------------------------------------------------------------------------
function vector_iterator_get(it.vectorC_iter)
; return the value of the element the iterator is currently on

	return peekint(it\vector\bank, 4 * it\current_index)
end function

; ------------------------------------------------------------------------------
;= TESTING
; ------------------------------------------------------------------------------
function vector_test()
	print "vector_test()"

	sample_vector.vectorC = vector_new(2)

	vector_set(sample_vector, 0, 123)
	vector_set(sample_vector, 1, 456)
	vector_push(sample_vector, 789)
	vector_unshift(sample_vector, 321)
	vector_insert_after(sample_vector, -1, -100)

	it.vectorC_iter = vector_iterator_begin(sample_vector)
	while vector_iterator_next(it)
		value = vector_iterator_get(it)
		print value
	wend
	

	print "press any key to exit..."
	waitkey
	end

end function

Comments

None.

Code Archives Forum