; an "identifier list" is a list of identifiers and 64-bit values associated with them.
; they are stored as
;   null-terminated string
;   64-bit value (unaligned)
;   ...
;   null-terminated string
;   64-bit value (unaligned)
;   0 byte

function ident_list_create
	argument nbytes
	local list
	list = malloc(nbytes)
	return list

function ident_list_clear
	argument list
	*1list = 0
	return

function ident_list_free
	argument list
	free(list)
	return

function ident_list_len
	argument list
	local len
	len = 0
	:ilist_len_loop
		if *1list == 0 goto ilist_len_ret
		list = memchr(list, 0)
		list += 9 ; skip null byte and value
		len += 1
		goto ilist_len_loop
	:ilist_len_ret
	return len

; idxth value stored in ident list, or 0 if idx >= length
function ident_list_value_at_index
	argument list
	argument idx
	:ilist_vai_loop
		if *1list == 0 goto return_0
		list = memchr(list, 0)
		list += 1
		if idx <= 0 goto ilist_vai_ret
		list += 8
		idx -= 1
		goto ilist_vai_loop
	:ilist_vai_ret
	return *8list
	

function ident_list_add
	argument list
	argument ident
	argument value
	
	:ilist_add_go_to_end_loop
		if *1list == 0 goto ilist_add_found_end
		list = memchr(list, 0)
		list += 9 ; skip null byte and value
		goto ilist_add_go_to_end_loop
	:ilist_add_found_end
	list = strcpy(list, ident)
	list += 1
	*8list = value ; UNALIGNED
	list += 8
	*1list = 0
	
	return

; return the value associated with this identifier, or 0 if none is
function ident_list_lookup
	argument list
	argument ident
	local b
	:ilist_lookup_loop
		if *1list == 0 goto return_0
		b = str_equals(list, ident)
		list = memchr(list, 0)
		list += 9 ; skip null byte and value
		if b == 0 goto ilist_lookup_loop
	list -= 8 ; backtrack to value
	return *8list ; UNALIGNED

; return a pointer to the value associated with ident, or 0 if none is
function ident_list_lookup_pointer
	argument list
	argument ident
	local b
	:ilist_lookup_pointer_loop
		if *1list == 0 goto return_0
		b = str_equals(list, ident)
		list = memchr(list, 0)
		list += 9 ; skip null byte and value
		if b == 0 goto ilist_lookup_pointer_loop
	list -= 8 ; backtrack to value
	return list

; if list contains ident, change its value to `value`. otherwise, add ident with the given value.
function ident_list_set
	argument list
	argument ident
	argument value
	local p
	p = ident_list_lookup_pointer(list, ident)
	if p == 0 goto ident_list_set_add
	*8p = value
	return
	:ident_list_set_add
	ident_list_add(list, ident, value)
	return

; if identifier in list, sets *pvalue to its value (if pvalue is not null) and returns 1
; otherwise, returns 0
function ident_list_lookup_check
	argument list
	argument ident
	argument pvalue
	local b
	:ilist_lookcheck_loop
		if *1list == 0 goto return_0
		b = str_equals(list, ident)
		list = memchr(list, 0)
		list += 9 ; skip null byte and value
		if b == 0 goto ilist_lookcheck_loop
	if pvalue == 0 goto return_1
	list -= 8 ; backtrack to value
	*8pvalue = *8list
	return 1
	
function ident_list_print
	argument list
	:ilist_print_loop
		if *1list == 0 goto ilist_print_loop_end
		puts(list)
		putc(':)
		putc(32)
		list = memchr(list, 0)
		list += 1
		putnln(*8list)
		list += 8
		goto ilist_print_loop
	:ilist_print_loop_end
	return
	
function ident_list_printx64
	argument list
	:ilist_printx64_loop
		if *1list == 0 goto ilist_printx64_loop_end
		puts(list)
		putc(':)
		putc(32)
		list = memchr(list, 0)
		list += 1
		putx64ln(*8list)
		list += 8
		goto ilist_printx64_loop
	:ilist_printx64_loop_end
	return

function ident_list_printx32
	argument list
	:ilist_printx32_loop
		if *1list == 0 goto ilist_printx32_loop_end
		puts(list)
		putc(':)
		putc(32)
		list = memchr(list, 0)
		list += 1
		putx32ln(*8list)
		list += 8
		goto ilist_printx32_loop
	:ilist_printx32_loop_end
	return

