diff options
Diffstat (limited to 'v_windows/v/old/vlib/builtin')
66 files changed, 15205 insertions, 0 deletions
| diff --git a/v_windows/v/old/vlib/builtin/array.v b/v_windows/v/old/vlib/builtin/array.v new file mode 100644 index 0000000..99055f3 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/array.v @@ -0,0 +1,664 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module builtin + +import strings + +// array is a struct used for denoting array types in V +pub struct array { +pub: +	element_size int // size in bytes of one element in the array. +pub mut: +	data   voidptr +	offset int // in bytes (should be `size_t`) +	len    int // length of the array. +	cap    int // capacity of the array. +} + +// array.data uses a void pointer, which allows implementing arrays without generics and without generating +// extra code for every type. +// Internal function, used by V (`nums := []int`) +fn __new_array(mylen int, cap int, elm_size int) array { +	cap_ := if cap < mylen { mylen } else { cap } +	arr := array{ +		element_size: elm_size +		data: vcalloc(cap_ * elm_size) +		len: mylen +		cap: cap_ +	} +	return arr +} + +fn __new_array_with_default(mylen int, cap int, elm_size int, val voidptr) array { +	cap_ := if cap < mylen { mylen } else { cap } +	mut arr := array{ +		element_size: elm_size +		data: vcalloc(cap_ * elm_size) +		len: mylen +		cap: cap_ +	} +	if val != 0 { +		for i in 0 .. arr.len { +			unsafe { arr.set_unsafe(i, val) } +		} +	} +	return arr +} + +fn __new_array_with_array_default(mylen int, cap int, elm_size int, val array) array { +	cap_ := if cap < mylen { mylen } else { cap } +	mut arr := array{ +		element_size: elm_size +		data: vcalloc(cap_ * elm_size) +		len: mylen +		cap: cap_ +	} +	for i in 0 .. arr.len { +		val_clone := unsafe { val.clone_to_depth(1) } +		unsafe { arr.set_unsafe(i, &val_clone) } +	} +	return arr +} + +// Private function, used by V (`nums := [1, 2, 3]`) +fn new_array_from_c_array(len int, cap int, elm_size int, c_array voidptr) array { +	cap_ := if cap < len { len } else { cap } +	arr := array{ +		element_size: elm_size +		data: vcalloc(cap_ * elm_size) +		len: len +		cap: cap_ +	} +	// TODO Write all memory functions (like memcpy) in V +	unsafe { C.memcpy(arr.data, c_array, len * elm_size) } +	return arr +} + +// Private function, used by V (`nums := [1, 2, 3] !`) +fn new_array_from_c_array_no_alloc(len int, cap int, elm_size int, c_array voidptr) array { +	arr := array{ +		element_size: elm_size +		data: c_array +		len: len +		cap: cap +	} +	return arr +} + +// Private function. Doubles array capacity if needed. +fn (mut a array) ensure_cap(required int) { +	if required <= a.cap { +		return +	} +	mut cap := if a.cap > 0 { a.cap } else { 2 } +	for required > cap { +		cap *= 2 +	} +	new_size := cap * a.element_size +	new_data := vcalloc(new_size) +	if a.data != voidptr(0) { +		unsafe { C.memcpy(new_data, a.data, a.len * a.element_size) } +		// TODO: the old data may be leaked when no GC is used (ref-counting?) +	} +	a.data = new_data +	a.offset = 0 +	a.cap = cap +} + +// repeat returns a new array with the given array elements repeated given times. +// `cgen` will replace this with an apropriate call to `repeat_to_depth()` + +// This is a dummy placeholder that will be overridden by `cgen` with an appropriate +// call to `repeat_to_depth()`. However the `checker` needs it here. +pub fn (a array) repeat(count int) array { +	return unsafe { a.repeat_to_depth(count, 0) } +} + +// version of `repeat()` that handles multi dimensional arrays +// `unsafe` to call directly because `depth` is not checked +[unsafe] +pub fn (a array) repeat_to_depth(count int, depth int) array { +	if count < 0 { +		panic('array.repeat: count is negative: $count') +	} +	mut size := count * a.len * a.element_size +	if size == 0 { +		size = a.element_size +	} +	arr := array{ +		element_size: a.element_size +		data: vcalloc(size) +		len: count * a.len +		cap: count * a.len +	} +	if a.len > 0 { +		for i in 0 .. count { +			if depth > 0 { +				ary_clone := unsafe { a.clone_to_depth(depth) } +				unsafe { C.memcpy(arr.get_unsafe(i * a.len), &byte(ary_clone.data), a.len * a.element_size) } +			} else { +				unsafe { C.memcpy(arr.get_unsafe(i * a.len), &byte(a.data), a.len * a.element_size) } +			} +		} +	} +	return arr +} + +// sort_with_compare sorts array in-place using given `compare` function as comparator. +pub fn (mut a array) sort_with_compare(compare voidptr) { +	$if freestanding { +		panic('sort does not work with -freestanding') +	} $else { +		C.qsort(mut a.data, a.len, a.element_size, compare) +	} +} + +// insert inserts a value in the array at index `i` +pub fn (mut a array) insert(i int, val voidptr) { +	$if !no_bounds_checking ? { +		if i < 0 || i > a.len { +			panic('array.insert: index out of range (i == $i, a.len == $a.len)') +		} +	} +	a.ensure_cap(a.len + 1) +	unsafe { +		C.memmove(a.get_unsafe(i + 1), a.get_unsafe(i), (a.len - i) * a.element_size) +		a.set_unsafe(i, val) +	} +	a.len++ +} + +// insert_many inserts many values into the array from index `i`. +[unsafe] +pub fn (mut a array) insert_many(i int, val voidptr, size int) { +	$if !no_bounds_checking ? { +		if i < 0 || i > a.len { +			panic('array.insert_many: index out of range (i == $i, a.len == $a.len)') +		} +	} +	a.ensure_cap(a.len + size) +	elem_size := a.element_size +	unsafe { +		iptr := a.get_unsafe(i) +		C.memmove(a.get_unsafe(i + size), iptr, (a.len - i) * elem_size) +		C.memcpy(iptr, val, size * elem_size) +	} +	a.len += size +} + +// prepend prepends one value to the array. +pub fn (mut a array) prepend(val voidptr) { +	a.insert(0, val) +} + +// prepend_many prepends another array to this array. +[unsafe] +pub fn (mut a array) prepend_many(val voidptr, size int) { +	unsafe { a.insert_many(0, val, size) } +} + +// delete deletes array element at index `i`. +pub fn (mut a array) delete(i int) { +	a.delete_many(i, 1) +} + +// delete_many deletes `size` elements beginning with index `i` +pub fn (mut a array) delete_many(i int, size int) { +	$if !no_bounds_checking ? { +		if i < 0 || i + size > a.len { +			endidx := if size > 1 { '..${i + size}' } else { '' } +			panic('array.delete: index out of range (i == $i$endidx, a.len == $a.len)') +		} +	} +	// NB: if a is [12,34], a.len = 2, a.delete(0) +	// should move (2-0-1) elements = 1 element (the 34) forward +	old_data := a.data +	new_size := a.len - size +	new_cap := if new_size == 0 { 1 } else { new_size } +	a.data = vcalloc(new_cap * a.element_size) +	unsafe { C.memcpy(a.data, old_data, i * a.element_size) } +	unsafe { +		C.memcpy(&byte(a.data) + i * a.element_size, &byte(old_data) + (i + size) * a.element_size, +			(a.len - i - size) * a.element_size) +	} +	a.len = new_size +	a.cap = new_cap +} + +// clear clears the array without deallocating the allocated data. +pub fn (mut a array) clear() { +	a.len = 0 +} + +// trim trims the array length to "index" without modifying the allocated data. If "index" is greater +// than len nothing will be changed. +pub fn (mut a array) trim(index int) { +	if index < a.len { +		a.len = index +	} +} + +// we manually inline this for single operations for performance without -prod +[inline; unsafe] +fn (a array) get_unsafe(i int) voidptr { +	unsafe { +		return &byte(a.data) + i * a.element_size +	} +} + +// Private function. Used to implement array[] operator. +fn (a array) get(i int) voidptr { +	$if !no_bounds_checking ? { +		if i < 0 || i >= a.len { +			panic('array.get: index out of range (i == $i, a.len == $a.len)') +		} +	} +	unsafe { +		return &byte(a.data) + i * a.element_size +	} +} + +// Private function. Used to implement x = a[i] or { ... } +fn (a array) get_with_check(i int) voidptr { +	if i < 0 || i >= a.len { +		return 0 +	} +	unsafe { +		return &byte(a.data) + i * a.element_size +	} +} + +// first returns the first element of the array. +pub fn (a array) first() voidptr { +	$if !no_bounds_checking ? { +		if a.len == 0 { +			panic('array.first: array is empty') +		} +	} +	return a.data +} + +// last returns the last element of the array. +pub fn (a array) last() voidptr { +	$if !no_bounds_checking ? { +		if a.len == 0 { +			panic('array.last: array is empty') +		} +	} +	unsafe { +		return &byte(a.data) + (a.len - 1) * a.element_size +	} +} + +// pop returns the last element of the array, and removes it. +pub fn (mut a array) pop() voidptr { +	// in a sense, this is the opposite of `a << x` +	$if !no_bounds_checking ? { +		if a.len == 0 { +			panic('array.pop: array is empty') +		} +	} +	new_len := a.len - 1 +	last_elem := unsafe { &byte(a.data) + new_len * a.element_size } +	a.len = new_len +	// NB: a.cap is not changed here *on purpose*, so that +	// further << ops on that array will be more efficient. +	return unsafe { memdup(last_elem, a.element_size) } +} + +// delete_last efficiently deletes the last element of the array. +pub fn (mut a array) delete_last() { +	// copy pasting code for performance +	$if !no_bounds_checking ? { +		if a.len == 0 { +			panic('array.pop: array is empty') +		} +	} +	a.len-- +} + +// slice returns an array using the same buffer as original array +// but starting from the `start` element and ending with the element before +// the `end` element of the original array with the length and capacity +// set to the number of the elements in the slice. +fn (a array) slice(start int, _end int) array { +	mut end := _end +	$if !no_bounds_checking ? { +		if start > end { +			panic('array.slice: invalid slice index ($start > $end)') +		} +		if end > a.len { +			panic('array.slice: slice bounds out of range ($end >= $a.len)') +		} +		if start < 0 { +			panic('array.slice: slice bounds out of range ($start < 0)') +		} +	} +	offset := start * a.element_size +	data := unsafe { &byte(a.data) + offset } +	l := end - start +	res := array{ +		element_size: a.element_size +		data: data +		offset: a.offset + offset +		len: l +		cap: l +	} +	return res +} + +// used internally for [2..4] +fn (a array) slice2(start int, _end int, end_max bool) array { +	end := if end_max { a.len } else { _end } +	return a.slice(start, end) +} + +// `clone_static_to_depth()` returns an independent copy of a given array. +// Unlike `clone_to_depth()` it has a value receiver and is used internally +// for slice-clone expressions like `a[2..4].clone()` and in -autofree generated code. +fn (a array) clone_static_to_depth(depth int) array { +	return unsafe { a.clone_to_depth(depth) } +} + +// clone returns an independent copy of a given array. +// this will be overwritten by `cgen` with an apropriate call to `.clone_to_depth()` +// However the `checker` needs it here. +pub fn (a &array) clone() array { +	return unsafe { a.clone_to_depth(0) } +} + +// recursively clone given array - `unsafe` when called directly because depth is not checked +[unsafe] +pub fn (a &array) clone_to_depth(depth int) array { +	mut size := a.cap * a.element_size +	if size == 0 { +		size++ +	} +	mut arr := array{ +		element_size: a.element_size +		data: vcalloc(size) +		len: a.len +		cap: a.cap +	} +	// Recursively clone-generated elements if array element is array type +	if depth > 0 && a.element_size == sizeof(array) && a.len >= 0 && a.cap >= a.len { +		for i in 0 .. a.len { +			ar := array{} +			unsafe { C.memcpy(&ar, a.get_unsafe(i), int(sizeof(array))) } +			ar_clone := unsafe { ar.clone_to_depth(depth - 1) } +			unsafe { arr.set_unsafe(i, &ar_clone) } +		} +		return arr +	} else { +		if !isnil(a.data) { +			unsafe { C.memcpy(&byte(arr.data), a.data, a.cap * a.element_size) } +		} +		return arr +	} +} + +// we manually inline this for single operations for performance without -prod +[inline; unsafe] +fn (mut a array) set_unsafe(i int, val voidptr) { +	unsafe { C.memcpy(&byte(a.data) + a.element_size * i, val, a.element_size) } +} + +// Private function. Used to implement assigment to the array element. +fn (mut a array) set(i int, val voidptr) { +	$if !no_bounds_checking ? { +		if i < 0 || i >= a.len { +			panic('array.set: index out of range (i == $i, a.len == $a.len)') +		} +	} +	unsafe { C.memcpy(&byte(a.data) + a.element_size * i, val, a.element_size) } +} + +fn (mut a array) push(val voidptr) { +	a.ensure_cap(a.len + 1) +	unsafe { C.memmove(&byte(a.data) + a.element_size * a.len, val, a.element_size) } +	a.len++ +} + +// push_many implements the functionality for pushing another array. +// `val` is array.data and user facing usage is `a << [1,2,3]` +[unsafe] +pub fn (mut a3 array) push_many(val voidptr, size int) { +	if a3.data == val && !isnil(a3.data) { +		// handle `arr << arr` +		copy := a3.clone() +		a3.ensure_cap(a3.len + size) +		unsafe { +			// C.memcpy(a.data, copy.data, copy.element_size * copy.len) +			C.memcpy(a3.get_unsafe(a3.len), copy.data, a3.element_size * size) +		} +	} else { +		a3.ensure_cap(a3.len + size) +		if !isnil(a3.data) && !isnil(val) { +			unsafe { C.memcpy(a3.get_unsafe(a3.len), val, a3.element_size * size) } +		} +	} +	a3.len += size +} + +// reverse_in_place reverses existing array data, modifying original array. +pub fn (mut a array) reverse_in_place() { +	if a.len < 2 { +		return +	} +	unsafe { +		mut tmp_value := malloc(a.element_size) +		for i in 0 .. a.len / 2 { +			C.memcpy(tmp_value, &byte(a.data) + i * a.element_size, a.element_size) +			C.memcpy(&byte(a.data) + i * a.element_size, &byte(a.data) + +				(a.len - 1 - i) * a.element_size, a.element_size) +			C.memcpy(&byte(a.data) + (a.len - 1 - i) * a.element_size, tmp_value, a.element_size) +		} +		free(tmp_value) +	} +} + +// reverse returns a new array with the elements of the original array in reverse order. +pub fn (a array) reverse() array { +	if a.len < 2 { +		return a +	} +	mut arr := array{ +		element_size: a.element_size +		data: vcalloc(a.cap * a.element_size) +		len: a.len +		cap: a.cap +	} +	for i in 0 .. a.len { +		unsafe { arr.set_unsafe(i, a.get_unsafe(a.len - 1 - i)) } +	} +	return arr +} + +// pub fn (a []int) free() { +// free frees all memory occupied by the array. +[unsafe] +pub fn (a &array) free() { +	$if prealloc { +		return +	} +	// if a.is_slice { +	// return +	// } +	unsafe { free(&byte(a.data) - a.offset) } +} + +[unsafe] +pub fn (mut a []string) free() { +	$if prealloc { +		return +	} +	for s in a { +		unsafe { s.free() } +	} +	unsafe { free(a.data) } +} + +// str returns a string representation of the array of strings +// => '["a", "b", "c"]'. +[manualfree] +pub fn (a []string) str() string { +	mut sb := strings.new_builder(a.len * 3) +	sb.write_string('[') +	for i in 0 .. a.len { +		val := a[i] +		sb.write_string("'") +		sb.write_string(val) +		sb.write_string("'") +		if i < a.len - 1 { +			sb.write_string(', ') +		} +	} +	sb.write_string(']') +	res := sb.str() +	unsafe { sb.free() } +	return res +} + +// hex returns a string with the hexadecimal representation +// of the byte elements of the array. +pub fn (b []byte) hex() string { +	mut hex := unsafe { malloc(b.len * 2 + 1) } +	mut dst_i := 0 +	for i in b { +		n0 := i >> 4 +		unsafe { +			hex[dst_i] = if n0 < 10 { n0 + `0` } else { n0 + byte(87) } +			dst_i++ +		} +		n1 := i & 0xF +		unsafe { +			hex[dst_i] = if n1 < 10 { n1 + `0` } else { n1 + byte(87) } +			dst_i++ +		} +	} +	unsafe { +		hex[dst_i] = 0 +		return tos(hex, dst_i) +	} +} + +// copy copies the `src` byte array elements to the `dst` byte array. +// The number of the elements copied is the minimum of the length of both arrays. +// Returns the number of elements copied. +// TODO: implement for all types +pub fn copy(dst []byte, src []byte) int { +	min := if dst.len < src.len { dst.len } else { src.len } +	if min > 0 { +		unsafe { C.memcpy(&byte(dst.data), src.data, min) } +	} +	return min +} + +// Private function. Comparator for int type. +fn compare_ints(a &int, b &int) int { +	if *a < *b { +		return -1 +	} +	if *a > *b { +		return 1 +	} +	return 0 +} + +fn compare_ints_reverse(a &int, b &int) int { +	if *a > *b { +		return -1 +	} +	if *a < *b { +		return 1 +	} +	return 0 +} + +// sort sorts an array of int in place in ascending order. +pub fn (mut a []int) sort() { +	a.sort_with_compare(compare_ints) +} + +// index returns the first index at which a given element can be found in the array +// or -1 if the value is not found. +[direct_array_access] +pub fn (a []string) index(v string) int { +	for i in 0 .. a.len { +		if a[i] == v { +			return i +		} +	} +	return -1 +} + +// reduce executes a given reducer function on each element of the array, +// resulting in a single output value. +pub fn (a []int) reduce(iter fn (int, int) int, accum_start int) int { +	mut accum_ := accum_start +	for i in a { +		accum_ = iter(accum_, i) +	} +	return accum_ +} + +// grow_cap grows the array's capacity by `amount` elements. +pub fn (mut a array) grow_cap(amount int) { +	a.ensure_cap(a.cap + amount) +} + +// grow_len ensures that an array has a.len + amount of length +[unsafe] +pub fn (mut a array) grow_len(amount int) { +	a.ensure_cap(a.len + amount) +	a.len += amount +} + +// eq checks if the arrays have the same elements or not. +// TODO: make it work with all types. +pub fn (a1 []string) eq(a2 []string) bool { +	// return array_eq(a, a2) +	if a1.len != a2.len { +		return false +	} +	size_of_string := int(sizeof(string)) +	for i in 0 .. a1.len { +		offset := i * size_of_string +		s1 := unsafe { &string(&byte(a1.data) + offset) } +		s2 := unsafe { &string(&byte(a2.data) + offset) } +		if *s1 != *s2 { +			return false +		} +	} +	return true +} + +// pointers returns a new array, where each element +// is the address of the corresponding element in the array. +[unsafe] +pub fn (a array) pointers() []voidptr { +	mut res := []voidptr{} +	for i in 0 .. a.len { +		unsafe { res << a.get_unsafe(i) } +	} +	return res +} + +// voidptr.vbytes() - makes a V []byte structure from a C style memory buffer. NB: the data is reused, NOT copied! +[unsafe] +pub fn (data voidptr) vbytes(len int) []byte { +	res := array{ +		element_size: 1 +		data: data +		len: len +		cap: len +	} +	return res +} + +// byteptr.vbytes() - makes a V []byte structure from a C style memory buffer. NB: the data is reused, NOT copied! +[unsafe] +pub fn (data &byte) vbytes(len int) []byte { +	return unsafe { voidptr(data).vbytes(len) } +} diff --git a/v_windows/v/old/vlib/builtin/array_d_gcboehm_opt.v b/v_windows/v/old/vlib/builtin/array_d_gcboehm_opt.v new file mode 100644 index 0000000..330977d --- /dev/null +++ b/v_windows/v/old/vlib/builtin/array_d_gcboehm_opt.v @@ -0,0 +1,268 @@ +// non-pub versions of array functions +// that allocale new memory using `GC_MALLOC_ATOMIC()` +// when `-gc boehm_*_opt` is used. These memory areas are not +// scanned for pointers. + +module builtin + +fn __new_array_noscan(mylen int, cap int, elm_size int) array { +	cap_ := if cap < mylen { mylen } else { cap } +	arr := array{ +		element_size: elm_size +		data: vcalloc_noscan(cap_ * elm_size) +		len: mylen +		cap: cap_ +	} +	return arr +} + +fn __new_array_with_default_noscan(mylen int, cap int, elm_size int, val voidptr) array { +	cap_ := if cap < mylen { mylen } else { cap } +	mut arr := array{ +		element_size: elm_size +		data: vcalloc_noscan(cap_ * elm_size) +		len: mylen +		cap: cap_ +	} +	if val != 0 { +		for i in 0 .. arr.len { +			unsafe { arr.set_unsafe(i, val) } +		} +	} +	return arr +} + +fn __new_array_with_array_default_noscan(mylen int, cap int, elm_size int, val array) array { +	cap_ := if cap < mylen { mylen } else { cap } +	mut arr := array{ +		element_size: elm_size +		data: vcalloc_noscan(cap_ * elm_size) +		len: mylen +		cap: cap_ +	} +	for i in 0 .. arr.len { +		val_clone := val.clone() +		unsafe { arr.set_unsafe(i, &val_clone) } +	} +	return arr +} + +// Private function, used by V (`nums := [1, 2, 3]`) +fn new_array_from_c_array_noscan(len int, cap int, elm_size int, c_array voidptr) array { +	cap_ := if cap < len { len } else { cap } +	arr := array{ +		element_size: elm_size +		data: vcalloc_noscan(cap_ * elm_size) +		len: len +		cap: cap_ +	} +	// TODO Write all memory functions (like memcpy) in V +	unsafe { C.memcpy(arr.data, c_array, len * elm_size) } +	return arr +} + +// Private function. Doubles array capacity if needed. +fn (mut a array) ensure_cap_noscan(required int) { +	if required <= a.cap { +		return +	} +	mut cap := if a.cap > 0 { a.cap } else { 2 } +	for required > cap { +		cap *= 2 +	} +	new_size := cap * a.element_size +	new_data := vcalloc_noscan(new_size) +	if a.data != voidptr(0) { +		unsafe { C.memcpy(new_data, a.data, a.len * a.element_size) } +		// TODO: the old data may be leaked when no GC is used (ref-counting?) +	} +	a.data = new_data +	a.offset = 0 +	a.cap = cap +} + +// repeat returns a new array with the given array elements repeated given times. +// `cgen` will replace this with an apropriate call to `repeat_to_depth()` + +// version of `repeat()` that handles multi dimensional arrays +// `unsafe` to call directly because `depth` is not checked +[unsafe] +fn (a array) repeat_to_depth_noscan(count int, depth int) array { +	if count < 0 { +		panic('array.repeat: count is negative: $count') +	} +	mut size := count * a.len * a.element_size +	if size == 0 { +		size = a.element_size +	} +	arr := array{ +		element_size: a.element_size +		data: if depth > 0 { vcalloc(size) } else { vcalloc_noscan(size) } +		len: count * a.len +		cap: count * a.len +	} +	if a.len > 0 { +		for i in 0 .. count { +			if depth > 0 { +				ary_clone := unsafe { a.clone_to_depth_noscan(depth) } +				unsafe { C.memcpy(arr.get_unsafe(i * a.len), &byte(ary_clone.data), a.len * a.element_size) } +			} else { +				unsafe { C.memcpy(arr.get_unsafe(i * a.len), &byte(a.data), a.len * a.element_size) } +			} +		} +	} +	return arr +} + +// insert inserts a value in the array at index `i` +fn (mut a array) insert_noscan(i int, val voidptr) { +	$if !no_bounds_checking ? { +		if i < 0 || i > a.len { +			panic('array.insert: index out of range (i == $i, a.len == $a.len)') +		} +	} +	a.ensure_cap_noscan(a.len + 1) +	unsafe { +		C.memmove(a.get_unsafe(i + 1), a.get_unsafe(i), (a.len - i) * a.element_size) +		a.set_unsafe(i, val) +	} +	a.len++ +} + +// insert_many inserts many values into the array from index `i`. +[unsafe] +fn (mut a array) insert_many_noscan(i int, val voidptr, size int) { +	$if !no_bounds_checking ? { +		if i < 0 || i > a.len { +			panic('array.insert_many: index out of range (i == $i, a.len == $a.len)') +		} +	} +	a.ensure_cap_noscan(a.len + size) +	elem_size := a.element_size +	unsafe { +		iptr := a.get_unsafe(i) +		C.memmove(a.get_unsafe(i + size), iptr, (a.len - i) * elem_size) +		C.memcpy(iptr, val, size * elem_size) +	} +	a.len += size +} + +// prepend prepends one value to the array. +fn (mut a array) prepend_noscan(val voidptr) { +	a.insert_noscan(0, val) +} + +// prepend_many prepends another array to this array. +[unsafe] +fn (mut a array) prepend_many_noscan(val voidptr, size int) { +	unsafe { a.insert_many_noscan(0, val, size) } +} + +// pop returns the last element of the array, and removes it. +fn (mut a array) pop_noscan() voidptr { +	// in a sense, this is the opposite of `a << x` +	$if !no_bounds_checking ? { +		if a.len == 0 { +			panic('array.pop: array is empty') +		} +	} +	new_len := a.len - 1 +	last_elem := unsafe { &byte(a.data) + new_len * a.element_size } +	a.len = new_len +	// NB: a.cap is not changed here *on purpose*, so that +	// further << ops on that array will be more efficient. +	return unsafe { memdup_noscan(last_elem, a.element_size) } +} + +// `clone_static_to_depth_noscan()` returns an independent copy of a given array. +// Unlike `clone_to_depth_noscan()` it has a value receiver and is used internally +// for slice-clone expressions like `a[2..4].clone()` and in -autofree generated code. +fn (a array) clone_static_to_depth_noscan(depth int) array { +	return unsafe { a.clone_to_depth_noscan(depth) } +} + +// recursively clone given array - `unsafe` when called directly because depth is not checked +[unsafe] +fn (a &array) clone_to_depth_noscan(depth int) array { +	mut size := a.cap * a.element_size +	if size == 0 { +		size++ +	} +	mut arr := array{ +		element_size: a.element_size +		data: if depth == 0 { vcalloc_noscan(size) } else { vcalloc(size) } +		len: a.len +		cap: a.cap +	} +	// Recursively clone-generated elements if array element is array type +	if depth > 0 { +		for i in 0 .. a.len { +			ar := array{} +			unsafe { C.memcpy(&ar, a.get_unsafe(i), int(sizeof(array))) } +			ar_clone := unsafe { ar.clone_to_depth_noscan(depth - 1) } +			unsafe { arr.set_unsafe(i, &ar_clone) } +		} +		return arr +	} else { +		if !isnil(a.data) { +			unsafe { C.memcpy(&byte(arr.data), a.data, a.cap * a.element_size) } +		} +		return arr +	} +} + +fn (mut a array) push_noscan(val voidptr) { +	a.ensure_cap_noscan(a.len + 1) +	unsafe { C.memmove(&byte(a.data) + a.element_size * a.len, val, a.element_size) } +	a.len++ +} + +// push_many implements the functionality for pushing another array. +// `val` is array.data and user facing usage is `a << [1,2,3]` +[unsafe] +fn (mut a3 array) push_many_noscan(val voidptr, size int) { +	if a3.data == val && !isnil(a3.data) { +		// handle `arr << arr` +		copy := a3.clone() +		a3.ensure_cap_noscan(a3.len + size) +		unsafe { +			// C.memcpy(a.data, copy.data, copy.element_size * copy.len) +			C.memcpy(a3.get_unsafe(a3.len), copy.data, a3.element_size * size) +		} +	} else { +		a3.ensure_cap_noscan(a3.len + size) +		if !isnil(a3.data) && !isnil(val) { +			unsafe { C.memcpy(a3.get_unsafe(a3.len), val, a3.element_size * size) } +		} +	} +	a3.len += size +} + +// reverse returns a new array with the elements of the original array in reverse order. +fn (a array) reverse_noscan() array { +	if a.len < 2 { +		return a +	} +	mut arr := array{ +		element_size: a.element_size +		data: vcalloc_noscan(a.cap * a.element_size) +		len: a.len +		cap: a.cap +	} +	for i in 0 .. a.len { +		unsafe { arr.set_unsafe(i, a.get_unsafe(a.len - 1 - i)) } +	} +	return arr +} + +// grow_cap grows the array's capacity by `amount` elements. +fn (mut a array) grow_cap_noscan(amount int) { +	a.ensure_cap_noscan(a.cap + amount) +} + +// grow_len ensures that an array has a.len + amount of length +[unsafe] +fn (mut a array) grow_len_noscan(amount int) { +	a.ensure_cap_noscan(a.len + amount) +	a.len += amount +} diff --git a/v_windows/v/old/vlib/builtin/array_notd_gcboehm_opt.v b/v_windows/v/old/vlib/builtin/array_notd_gcboehm_opt.v new file mode 100644 index 0000000..1703167 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/array_notd_gcboehm_opt.v @@ -0,0 +1,10 @@ +// dummy placeholder for functions from `array_d_gcboehm_opt.v` +// that might be needed for compile time +// `$if gcboehm_opt ? { ... } $else { ... }` + +module builtin + +// this is needed in `string.v` +fn __new_array_noscan(mylen int, cap int, elm_size int) array { +	return array{} +} diff --git a/v_windows/v/old/vlib/builtin/array_test.v b/v_windows/v/old/vlib/builtin/array_test.v new file mode 100644 index 0000000..d7699ca --- /dev/null +++ b/v_windows/v/old/vlib/builtin/array_test.v @@ -0,0 +1,1469 @@ +fn test_pointer() { +	mut arr := []&int{} +	a := 1 +	b := 2 +	c := 3 +	arr << &a +	arr << &b +	arr << &c +	assert *arr[0] == 1 +	arr[1] = &c +	assert *arr[1] == 3 +	mut d_arr := [arr] // [][]&int +	d_arr << arr +	assert *d_arr[0][1] == 3 +	println(*d_arr[0][1]) +	assert *d_arr[1][0] == 1 +} + +fn test_assign() { +	mut arr := [2, 4, 8, 16, 32, 64, 128] +	arr[0] = 2 +	arr[1] &= 255 +	arr[2] |= 255 +	arr[3] <<= 4 +	arr[4] >>= 4 +	arr[5] %= 5 +	arr[6] ^= 3 +	assert arr[0] == 2 +	assert arr[1] == 4 & 255 +	assert arr[2] == 8 | 255 +	assert arr[3] == 16 << 4 +	assert arr[4] == 32 >> 4 +	assert arr[5] == 64 % 5 +	assert arr[6] == 128 ^ 3 +} + +fn test_ints() { +	mut a := [1, 5, 2, 3] +	assert a.len == 4 +	assert a[0] == 1 +	assert a[2] == 2 +	assert a.last() == 3 +	a << 4 +	assert a.len == 5 +	assert a[4] == 4 +	assert a.last() == 4 +	s := a.str() +	assert s == '[1, 5, 2, 3, 4]' +	assert a[1] == 5 +	assert a.last() == 4 +} + +fn test_deleting() { +	mut a := [1, 5, 2, 3, 4] +	assert a.len == 5 +	assert a.str() == '[1, 5, 2, 3, 4]' +	a.delete(0) +	assert a.str() == '[5, 2, 3, 4]' +	assert a.len == 4 +	a.delete(1) +	assert a.str() == '[5, 3, 4]' +	assert a.len == 3 +	a.delete(a.len - 1) +	assert a.str() == '[5, 3]' +	assert a.len == 2 +} + +fn test_slice_delete() { +	mut a := [1.5, 2.5, 3.25, 4.5, 5.75] +	b := a[2..4] +	a.delete(0) +	assert a == [2.5, 3.25, 4.5, 5.75] +	assert b == [3.25, 4.5] +	a = [3.75, 4.25, -1.5, 2.25, 6.0] +	c := a[..3] +	a.delete(2) +	assert a == [3.75, 4.25, 2.25, 6.0] +	assert c == [3.75, 4.25, -1.5] +} + +fn test_delete_many() { +	mut a := [1, 2, 3, 4, 5, 6, 7, 8, 9] +	b := a[2..6] +	a.delete_many(4, 3) +	assert a == [1, 2, 3, 4, 8, 9] +	assert b == [3, 4, 5, 6] +	c := a[..a.len] +	a.delete_many(2, 0) // this should just clone +	a[1] = 17 +	assert a == [1, 17, 3, 4, 8, 9] +	assert c == [1, 2, 3, 4, 8, 9] +	a.delete_many(0, a.len) +	assert a == []int{} +} + +fn test_short() { +	a := [1, 2, 3] +	assert a.len == 3 +	assert a.cap == 3 +	assert a[0] == 1 +	assert a[1] == 2 +	assert a[2] == 3 +} + +fn test_large() { +	mut a := [0].repeat(0) +	for i in 0 .. 10000 { +		a << i +	} +	assert a.len == 10000 +	assert a[234] == 234 +} + +struct Chunk { +	val string +} + +struct Kkk { +	q []Chunk +} + +fn test_empty() { +	mut chunks := []Chunk{} +	a := Chunk{} +	assert chunks.len == 0 +	chunks << a +	assert chunks.len == 1 +	chunks = [] +	assert chunks.len == 0 +	chunks << a +	assert chunks.len == 1 +} + +fn test_push() { +	mut a := []int{} +	a << 1 +	a << 3 +	assert a[1] == 3 +	assert a.str() == '[1, 3]' +} + +fn test_insert() { +	mut a := [1, 2] +	a.insert(0, 3) +	assert a[0] == 3 +	assert a[2] == 2 +	assert a.len == 3 +	a.insert(1, 4) +	assert a[1] == 4 +	assert a[2] == 1 +	assert a.len == 4 +	a.insert(4, 5) +	assert a[4] == 5 +	assert a[3] == 2 +	assert a.len == 5 +	mut b := []f64{} +	assert b.len == 0 +	b.insert(0, f64(1.1)) +	assert b.len == 1 +	assert b[0] == f64(1.1) +} + +fn test_insert_many() { +	mut a := [3, 4] +	a.insert(0, [1, 2]) +	assert a == [1, 2, 3, 4] +	b := [5, 6] +	a.insert(1, b) +	assert a == [1, 5, 6, 2, 3, 4] +} + +fn test_prepend() { +	mut a := []int{} +	assert a.len == 0 +	a.prepend(1) +	assert a.len == 1 +	assert a[0] == 1 +	mut b := []f64{} +	assert b.len == 0 +	b.prepend(f64(1.1)) +	assert b.len == 1 +	assert b[0] == f64(1.1) +} + +fn test_prepend_many() { +	mut a := [3, 4] +	a.prepend([1, 2]) +	assert a == [1, 2, 3, 4] +	b := [5, 6] +	a.prepend(b) +	assert a == [5, 6, 1, 2, 3, 4] +} + +fn test_strings() { +	a := ['a', 'b', 'c'] +	assert a.str() == "['a', 'b', 'c']" +} + +/* +fn test_compare_ints() { +    assert compare_ints(1, 2) == -1 +    assert compare_ints(2, 1) == 1 +    assert compare_ints(0, 0) == 0 + +    a := 1 +    b := 2 +    assert compare_ints(a, b) == -1 +    assert compare_ints(b, a) == 1 +    assert compare_ints(a, a) == 0 +} +*/ +fn test_repeat() { +	{ +		a := [0].repeat(5) +		assert a.len == 5 +		assert a[0] == 0 && a[1] == 0 && a[2] == 0 && a[3] == 0 && a[4] == 0 +	} +	{ +		a := [1.1].repeat(10) +		assert a[0] == 1.1 +		assert a[5] == 1.1 +		assert a[9] == 1.1 +	} +	{ +		a := [i64(-123)].repeat(10) +		assert a[0] == -123 +		assert a[5] == -123 +		assert a[9] == -123 +	} +	{ +		a := [u64(123)].repeat(10) +		assert a[0] == 123 +		assert a[5] == 123 +		assert a[9] == 123 +	} +	{ +		a := [1.1].repeat(10) +		assert a[0] == 1.1 +		assert a[5] == 1.1 +		assert a[9] == 1.1 +	} +	{ +		a := [1, 2].repeat(2) +		assert a[0] == 1 +		assert a[1] == 2 +		assert a[2] == 1 +		assert a[3] == 2 +	} +	{ +		a := ['1', 'abc'].repeat(2) +		assert a[0] == '1' +		assert a[1] == 'abc' +		assert a[2] == '1' +		assert a[3] == 'abc' +	} +	{ +		mut a := ['1', 'abc'].repeat(0) +		assert a.len == 0 +		a << 'abc' +		assert a[0] == 'abc' +	} +} + +fn test_deep_repeat() { +	mut a3 := [[[1, 1], [2, 2], [3, 3]], [[4, 4], [5, 5], [6, 6]]] +	r := a3.repeat(3) +	a3[1][1][0] = 17 +	assert r == [ +		[[1, 1], [2, 2], [3, 3]], +		[[4, 4], [5, 5], [6, 6]], +		[[1, 1], [2, 2], [3, 3]], +		[[4, 4], [5, 5], [6, 6]], +		[[1, 1], [2, 2], [3, 3]], +		[[4, 4], [5, 5], [6, 6]], +	] +	assert a3 == [[[1, 1], [2, 2], [3, 3]], [[4, 4], [17, 5], [6, 6]]] +} + +fn test_right() { +	a := [1, 2, 3, 4] +	c := a[1..a.len] +	d := a[1..] +	assert c[0] == 2 +	assert c[1] == 3 +	assert d[0] == 2 +	assert d[1] == 3 +} + +fn test_left() { +	a := [1, 2, 3] +	c := a[0..2] +	d := a[..2] +	assert c[0] == 1 +	assert c[1] == 2 +	assert d[0] == 1 +	assert d[1] == 2 +} + +fn test_slice() { +	a := [1, 2, 3, 4] +	b := a[2..4] +	assert b.len == 2 +	assert a[1..2].len == 1 +	assert a.len == 4 +} + +fn test_push_many() { +	mut a := [1, 2, 3] +	b := [4, 5, 6] +	a << b +	assert a.len == 6 +	assert a[0] == 1 +	assert a[3] == 4 +	assert a[5] == 6 +} + +fn test_reverse() { +	a := [1, 2, 3, 4] +	b := ['test', 'array', 'reverse'] +	c := a.reverse() +	println(c) +	d := b.reverse() +	for i, _ in c { +		assert c[i] == a[a.len - i - 1] +	} +	for i, _ in d { +		assert d[i] == b[b.len - i - 1] +	} +	e := []int{} +	f := e.reverse() +	assert f.len == 0 +} + +const ( +	c_n = 5 +) + +struct Foooj { +	a [5]int // c_n +} + +fn test_fixed() { +	mut nums := [4]int{} +	// x := nums[1..3] +	// assert x.len == 2 +	assert nums[0] == 0 +	assert nums[1] == 0 +	assert nums[2] == 0 +	assert nums[3] == 0 +	nums[1] = 7 +	assert nums[1] == 7 +	nums2 := [5]int{} // c_n +	assert nums2[c_n - 1] == 0 +} + +fn modify(mut numbers []int) { +	numbers[0] = 777 +} + +fn test_mut_slice() { +	mut n := [1, 2, 3] +	// modify(mut n) +	modify(mut n[..2]) +	assert n[0] == 777 +	modify(mut n[2..]) +	assert n[2] == 777 +	println(n) +} + +fn double_up(mut a []int) { +	for i := 0; i < a.len; i++ { +		a[i] = a[i] * 2 +	} +} + +fn double_up_v2(mut a []int) { +	for i, _ in a { +		a[i] = a[i] * 2 // or val*2, doesn't matter +	} +} + +fn test_mut_arg() { +	mut arr := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +	double_up(mut arr) +	assert arr.str() == '[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]' +	arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +	double_up_v2(mut arr) +	assert arr.str() == '[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]' +} + +fn test_clone() { +	nums := [1, 2, 3, 4, 100] +	_ = nums +	nums2 := nums.clone() +	assert nums2.len == 5 +	assert nums.str() == '[1, 2, 3, 4, 100]' +	assert nums2.str() == '[1, 2, 3, 4, 100]' +	assert nums[1..3].str() == '[2, 3]' +} + +/* +fn test_copy() { +	a := [1, 2, 3] +	b := a +	assert b[0] == 1 +	assert b[1] == 2 +	assert b[2] == 3 +} +*/ +fn test_multi_array_clone() { +	// 2d array_int +	mut a2_1 := [[1, 2, 3], [4, 5, 6]] +	mut a2_2 := a2_1.clone() +	a2_1[0][1] = 0 +	a2_2[1][0] = 0 +	assert a2_1 == [[1, 0, 3], [4, 5, 6]] +	assert a2_2 == [[1, 2, 3], [0, 5, 6]] +	// 2d array_string +	mut b2_1 := [['1', '2', '3'], ['4', '5', '6']] +	mut b2_2 := b2_1.clone() +	b2_1[0][1] = '0' +	b2_2[1][0] = '0' +	assert b2_1 == [['1', '0', '3'], ['4', '5', '6']] +	assert b2_2 == [['1', '2', '3'], ['0', '5', '6']] +	// 3d array_int +	mut a3_1 := [[[1, 1], [2, 2], [3, 3]], [[4, 4], [5, 5], [6, 6]]] +	mut a3_2 := a3_1.clone() +	a3_1[0][0][1] = 0 +	a3_2[0][1][0] = 0 +	assert a3_1 == [[[1, 0], [2, 2], [3, 3]], [[4, 4], [5, 5], +		[6, 6], +	]] +	assert a3_2 == [[[1, 1], [0, 2], [3, 3]], [[4, 4], [5, 5], +		[6, 6], +	]] +	// 3d array_string +	mut b3_1 := [[['1', '1'], ['2', '2'], ['3', '3']], [['4', '4'], +		['5', '5'], ['6', '6']]] +	mut b3_2 := b3_1.clone() +	b3_1[0][0][1] = '0' +	b3_2[0][1][0] = '0' +	assert b3_1 == [[['1', '0'], ['2', '2'], ['3', '3']], [['4', '4'], +		['5', '5'], ['6', '6']]] +	assert b3_2 == [[['1', '1'], ['0', '2'], ['3', '3']], [['4', '4'], +		['5', '5'], ['6', '6']]] +} + +fn test_doubling() { +	mut nums := [1, 2, 3, 4, 5] +	for i in 0 .. nums.len { +		nums[i] *= 2 +	} +	println(nums.str()) +	assert nums.str() == '[2, 4, 6, 8, 10]' +} + +struct Test2 { +	one int +	two int +} + +struct Test { +	a string +mut: +	b []Test2 +} + +// TODO: default array/struct str methods +fn (ta []Test2) str() string { +	mut s := '[' +	for i, t in ta { +		s += t.str() +		if i < ta.len - 1 { +			s += ', ' +		} +	} +	s += ']' +	return s +} + +fn (t Test2) str() string { +	return '{$t.one $t.two}' +} + +fn (t Test) str() string { +	return '{$t.a $t.b}' +} + +fn test_struct_print() { +	mut a := Test{ +		a: 'Test' +		b: [] +	} +	b := Test2{ +		one: 1 +		two: 2 +	} +	a.b << b +	a.b << b +	assert a.str() == '{Test [{1 2}, {1 2}]}' +	assert b.str() == '{1 2}' +	assert a.b.str() == '[{1 2}, {1 2}]' +} + +fn test_single_element() { +	mut a := [1] +	a << 2 +	assert a.len == 2 +	assert a[0] == 1 +	assert a[1] == 2 +	println(a) +} + +fn test_find_index() { +	// string +	a := ['v', 'is', 'great'] +	assert a.index('v') == 0 +	assert a.index('is') == 1 +	assert a.index('gre') == -1 +	// int +	b := [1, 2, 3, 4] +	assert b.index(1) == 0 +	assert b.index(4) == 3 +	assert b.index(5) == -1 +	// byte +	c := [0x22, 0x33, 0x55] +	assert c.index(0x22) == 0 +	assert c.index(0x55) == 2 +	assert c.index(0x99) == -1 +	// char +	d := [`a`, `b`, `c`] +	assert d.index(`b`) == 1 +	assert d.index(`c`) == 2 +	assert d.index(`u`) == -1 +} + +fn test_multi() { +	a := [[1, 2, 3], [4, 5, 6]] +	assert a.len == 2 +	assert a[0].len == 3 +	assert a[0][0] == 1 +	assert a[0][2] == 3 +	assert a[1][2] == 6 +	// TODO +	// b :=  [ [[1,2,3],[4,5,6]], [[1,2]] ] +	// assert b[0][0][0] == 1 +} + +fn test_in() { +	a := [1, 2, 3] +	assert 1 in a +	assert 2 in a +	assert 3 in a +	assert !(4 in a) +	assert !(0 in a) +	assert 0 !in a +	assert 4 !in a +	b := [1, 4, 0] +	c := [3, 6, 2, 0] +	assert 0 in b +	assert 0 in c +} + +fn sum(prev int, curr int) int { +	return prev + curr +} + +fn sub(prev int, curr int) int { +	return prev - curr +} + +fn test_reduce() { +	a := [1, 2, 3, 4, 5] +	b := a.reduce(sum, 0) +	c := a.reduce(sum, 5) +	d := a.reduce(sum, -1) +	assert b == 15 +	assert c == 20 +	assert d == 14 +	e := [1, 2, 3] +	f := e.reduce(sub, 0) +	g := e.reduce(sub, -1) +	assert f == -6 +	assert g == -7 +} + +fn filter_test_helper_1(a int) bool { +	return a > 3 +} + +fn test_filter() { +	a := [1, 2, 3, 4, 5, 6] +	b := a.filter(it % 2 == 0) +	assert b.len == 3 +	assert b[0] == 2 +	assert b[1] == 4 +	assert b[2] == 6 +	c := ['v', 'is', 'awesome'] +	d := c.filter(it.len > 1) +	assert d[0] == 'is' +	assert d[1] == 'awesome' +	//////// +	arr := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +	println(arr.filter(it % 2 == 0 || it % 3 == 0)) +	assert true +	assert [1, 2, 3].len == 3 +	mut mut_arr := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +	mut_arr = mut_arr.filter(it < 4) +	assert mut_arr.len == 3 +	assert a.filter(filter_test_helper_1) == [4, 5, 6] +	assert [1, 5, 10].filter(filter_test_helper_1) == [5, 10] +	// TODO +	// assert arr.filter(arr % 2).len == 5 +} + +fn test_anon_fn_filter() { +	filter_num := fn (i int) bool { +		return i % 2 == 0 +	} +	assert [1, 2, 3, 4, 5].filter(filter_num) == [2, 4] +} + +fn test_anon_fn_arg_filter() { +	a := [1, 2, 3, 4].filter(fn (i int) bool { +		return i % 2 == 0 +	}) +	assert a == [2, 4] +} + +fn map_test_helper_1(i int) int { +	return i * i +} + +fn map_test_helper_2(i int, b string) int { +	return i + b.len +} + +fn map_test_helper_3(i int, b []string) int { +	return i + b.map(it.len)[i % b.len] +} + +fn test_map() { +	nums := [1, 2, 3, 4, 5, 6] +	strs := ['v', 'is', 'awesome'] +	// assert nums.map() == <error> +	// assert nums.map(it, 'excessive') == <error> +	// identity +	assert nums.map(it) == [1, 2, 3, 4, 5, 6] +	assert strs.map(it) == ['v', 'is', 'awesome'] +	assert nums.map(it - it) == [0, 0, 0, 0, 0, 0] +	assert nums.map(it - it)[0] == 0 +	// type switch +	assert nums.map(it * 10) == [10, 20, 30, 40, 50, 60] +	assert nums.map(it * it) == [1, 4, 9, 16, 25, 36] +	assert nums.map('$it') == ['1', '2', '3', '4', '5', '6'] +	assert nums.map(it % 2 == 0) == [false, true, false, true, false, true] +	assert strs.map(it.to_upper()) == ['V', 'IS', 'AWESOME'] +	assert strs.map(it == 'awesome') == [false, false, true] +	assert strs.map(it.len in nums) == [true, true, false] +	assert strs.map(int(7)) == [7, 7, 7] +	// external func +	assert nums.map(map_test_helper_1(it)) == [1, 4, 9, 16, 25, 36] +	assert nums.map(map_test_helper_2(it, 'bb')) == [3, 4, 5, 6, 7, 8] +	assert nums.map(map_test_helper_3(it, strs)) == [3, 9, 4, 6, 12, 7] +	// empty array as input +	assert []int{len: 0}.map(it * 2) == [] +	// nested maps (where it is of same type) +	assert nums.map(strs.map(int(7)) == [7, 7, 7]) == [true, true, true, true, true, true] +	assert nums.map('$it' + strs.map('a')[0]) == ['1a', '2a', '3a', '4a', '5a', '6a'] +	assert nums.map(it + strs.map(int(7))[0]) == [8, 9, 10, 11, 12, 13] +	assert nums.map(it + strs.map(it.len)[0]) == [2, 3, 4, 5, 6, 7] +	assert strs.map(it.len + strs.map(it.len)[0]) == [2, 3, 8] +	// nested (different it types) +	assert strs.map(it[nums.map(it - it)[0]]) == [byte(`v`), `i`, `a`] +	assert nums[0..3].map('$it' + strs.map(it)[it - 1]) == ['1v', '2is', '3awesome'] +	assert nums.map(map_test_helper_1) == [1, 4, 9, 16, 25, 36] +	assert [1, 5, 10].map(map_test_helper_1) == [1, 25, 100] +	assert nums == [1, 2, 3, 4, 5, 6] +	assert strs == ['v', 'is', 'awesome'] +} + +fn test_anon_fn_map() { +	add_num := fn (i int) int { +		return i + 1 +	} +	assert [1, 2, 3].map(add_num) == [2, 3, 4] +} + +fn test_multi_anon_fn_map() { +	a := [1, 2, 3].map(fn (i int) int { +		return i + 1 +	}) +	b := [1, 2, 3].map(fn (i int) int { +		return i + 2 +	}) +	assert a == [2, 3, 4] +	assert b == [3, 4, 5] +} + +fn test_anon_fn_arg_map() { +	a := [1, 2, 3].map(fn (i int) int { +		return i + 1 +	}) +	assert a == [2, 3, 4] +} + +fn test_anon_fn_arg_different_type_map() { +	i_to_str := fn (i int) string { +		return i.str() +	} +	a := [1, 2, 3].map(i_to_str) +	assert a == ['1', '2', '3'] +} + +fn test_anon_fn_inline_different_type_map() { +	a := [1, 2, 3].map(fn (i int) string { +		return i.str() +	}) +	assert a == ['1', '2', '3'] +} + +fn test_array_str() { +	numbers := [1, 2, 3] +	assert numbers == [1, 2, 3] +	numbers2 := [numbers, [4, 5, 6]] // dup str() bug +	println(numbers2) +	assert true +	assert numbers.str() == '[1, 2, 3]' +	// QTODO +	// assert numbers2.str() == '[[1, 2, 3], [4, 5, 6]]' +} + +struct User { +	age  int +	name string +} + +fn test_eq() { +	assert [5, 6, 7] != [6, 7] +	assert [`a`, `b`] == [`a`, `b`] +	assert [User{ +		age: 22 +		name: 'bob' +	}] == [User{ +		age: 22 +		name: 'bob' +	}] +	assert [map{ +		'bob': 22 +	}, map{ +		'tom': 33 +	}] == [map{ +		'bob': 22 +	}, map{ +		'tom': 33 +	}] +	assert [[1, 2, 3], [4]] == [[1, 2, 3], [4]] +} + +fn test_fixed_array_eq() { +	a1 := [1, 2, 3]! +	assert a1 == [1, 2, 3]! +	assert a1 != [2, 3, 4]! + +	a2 := [[1, 2]!, [3, 4]!]! +	assert a2 == [[1, 2]!, [3, 4]!]! +	assert a2 != [[3, 4]!, [1, 2]!]! + +	a3 := [[1, 2], [3, 4]]! +	assert a3 == [[1, 2], [3, 4]]! +	assert a3 != [[1, 1], [2, 2]]! + +	a4 := [[`a`, `b`], [`c`, `d`]]! +	assert a4 == [[`a`, `b`], [`c`, `d`]]! +	assert a4 != [[`c`, `a`], [`a`, `b`]]! + +	a5 := [['aaa', 'bbb'], ['ccc', 'ddd']]! +	assert a5 == [['aaa', 'bbb'], ['ccc', 'ddd']]! +	assert a5 != [['abc', 'def'], ['ccc', 'ddd']]! + +	a6 := [['aaa', 'bbb']!, ['ccc', 'ddd']!]! +	assert a6 == [['aaa', 'bbb']!, ['ccc', 'ddd']!]! +	assert a6 != [['aaa', 'bbb']!, ['aaa', 'ddd']!]! + +	a7 := [[1, 2]!, [3, 4]!] +	assert a7 == [[1, 2]!, [3, 4]!] +	assert a7 != [[2, 3]!, [1, 2]!] + +	a8 := [['aaa', 'bbb']!, ['ccc', 'ddd']!] +	assert a8 == [['aaa', 'bbb']!, ['ccc', 'ddd']!] +	assert a8 != [['bbb', 'aaa']!, ['cccc', 'dddd']!] +} + +fn test_fixed_array_literal_eq() { +	assert [1, 2, 3]! == [1, 2, 3]! +	assert [1, 1, 1]! != [1, 2, 3]! + +	assert [[1, 2], [3, 4]]! == [[1, 2], [3, 4]]! +	assert [[1, 1], [2, 2]]! != [[1, 2], [3, 4]]! + +	assert [[1, 1]!, [2, 2]!]! == [[1, 1]!, [2, 2]!]! +	assert [[1, 1]!, [2, 2]!]! != [[1, 2]!, [2, 3]!]! + +	assert [[1, 1]!, [2, 2]!] == [[1, 1]!, [2, 2]!] +	assert [[1, 1]!, [2, 2]!] != [[1, 2]!, [2, 3]!] +} + +fn test_sort() { +	mut a := ['hi', '1', '5', '3'] +	a.sort() +	assert a[0] == '1' +	assert a[1] == '3' +	assert a[2] == '5' +	assert a[3] == 'hi' + +	mut nums := [67, -3, 108, 42, 7] +	nums.sort() +	assert nums[0] == -3 +	assert nums[1] == 7 +	assert nums[2] == 42 +	assert nums[3] == 67 +	assert nums[4] == 108 + +	nums.sort(a < b) +	assert nums[0] == -3 +	assert nums[1] == 7 +	assert nums[2] == 42 +	assert nums[3] == 67 +	assert nums[4] == 108 + +	mut users := [User{22, 'Peter'}, User{20, 'Bob'}, User{25, 'Alice'}] +	users.sort(a.age < b.age) +	assert users[0].age == 20 +	assert users[1].age == 22 +	assert users[2].age == 25 +	assert users[0].name == 'Bob' +	assert users[1].name == 'Peter' +	assert users[2].name == 'Alice' + +	users.sort(a.age > b.age) +	assert users[0].age == 25 +	assert users[1].age == 22 +	assert users[2].age == 20 + +	users.sort(a.name < b.name) // Test sorting by string fields +	// assert users.map(it.name).join(' ') == 'Alice Bob Peter' +} + +fn test_rune_sort() { +	mut bs := [`f`, `e`, `d`, `b`, `c`, `a`] +	bs.sort() +	println(bs) +	assert '$bs' == '[`a`, `b`, `c`, `d`, `e`, `f`]' + +	bs.sort(a > b) +	println(bs) +	assert '$bs' == '[`f`, `e`, `d`, `c`, `b`, `a`]' + +	bs.sort(a < b) +	println(bs) +	assert '$bs' == '[`a`, `b`, `c`, `d`, `e`, `f`]' +} + +fn test_sort_by_different_order_of_a_b() { +	mut x := [1, 2, 3] +	x.sort(a < b) +	println(x) +	assert x == [1, 2, 3] + +	mut y := [1, 2, 3] +	y.sort(b < a) +	println(y) +	assert y == [3, 2, 1] +} + +fn test_f32_sort() { +	mut f := [f32(50.0), 15, 1, 79, 38, 0, 27] +	f.sort() +	assert f[0] == 0.0 +	assert f[1] == 1.0 +	assert f[6] == 79.0 +} + +fn test_f64_sort() { +	mut f := [50.0, 15, 1, 79, 38, 0, 27] +	f.sort() +	assert f[0] == 0.0 +	assert f[1] == 1.0 +	assert f[6] == 79.0 +} + +fn test_i64_sort() { +	mut f := [i64(50), 15, 1, 79, 38, 0, 27] +	f.sort() +	assert f[0] == 0 +	assert f[1] == 1 +	assert f[6] == 79 +} + +/* +fn test_for_last() { +	numbers := [1, 2, 3, 4] +	mut s := '[' +	for num in numbers { +		s += '$num' +		if !last { +			s += ', ' + +		} +	} +	s += ']' +	assert s == '[1, 2, 3, 4]' +} +*/ +struct Foo { +mut: +	bar []int +} + +fn test_in_struct() { +	mut baz := Foo{ +		bar: [0, 0, 0] +	} +	baz.bar[0] += 2 +	baz.bar[0]++ +	assert baz.bar[0] == 3 +} + +[direct_array_access] +fn test_direct_modification() { +	mut foo := [2, 0, 5] +	foo[1] = 3 +	foo[0] *= 7 +	foo[1]-- +	foo[2] -= 2 +	assert foo[0] == 14 +	assert foo[1] == 2 +	assert foo[2] == 3 +} + +fn test_bools() { +	println('test b') +	mut a := [true, false] +	a << true +	println(a) +} + +fn test_push_many_self() { +	mut actual_arr := [1, 2, 3, 4] +	actual_arr << actual_arr +	expected_arr := [1, 2, 3, 4, 1, 2, 3, 4] +	assert actual_arr.len == expected_arr.len +	for i in 0 .. actual_arr.len { +		assert actual_arr[i] == expected_arr[i] +	} +} + +fn test_for() { +	nums := [1, 2, 3] +	mut sum := 0 +	for num in nums { +		sum += num +	} +	assert sum == 6 +} + +fn test_clear() { +	mut arr := [1, 2, 3] +	assert arr.len == 3 +	arr.clear() +	assert arr.len == 0 +	arr << 3 +	arr << 2 +	arr << 1 +	arr << 0 +	assert arr.len == 4 +	assert arr[0] == 3 +	assert arr[1] == 2 +	assert arr[2] == 1 +	assert arr[3] == 0 +	arr.clear() +	assert arr.len == 0 +} + +fn test_trim() { +	mut arr := [1, 2, 3, 4, 5, 6, 7, 8, 9] +	assert arr.len == 9 +	arr.trim(9) +	assert arr.len == 9 +	assert arr.last() == 9 +	arr.trim(7) +	assert arr.len == 7 +	assert arr.last() == 7 +	arr.trim(2) +	assert arr.len == 2 +	assert arr.last() == 2 +} + +fn test_hex() { +	// array hex +	st := [byte(`V`), `L`, `A`, `N`, `G`] +	assert st.hex() == '564c414e47' +	assert st.hex().len == 10 +	st1 := [byte(0x41)].repeat(100) +	assert st1.hex() == '41'.repeat(100) +} + +fn test_left_shift_precendence() { +	mut arr := []int{} +	arr << 1 + 1 +	arr << 1 - 1 +	arr << 2 / 1 +	arr << 2 * 1 +	assert arr[0] == 2 +	assert arr[1] == 0 +	assert arr[2] == 2 +	assert arr[3] == 2 +} + +fn test_array_with_cap() { +	a4 := []int{len: 1, cap: 10} +	assert a4.len == 1 +	assert a4.cap == 10 +	a5 := []int{len: 1, cap: 10} +	assert a5.len == 1 +	assert a5.cap == 10 +} + +fn test_multi_array_index() { +	mut a := [][]int{len: 2, init: []int{len: 3, init: 0}} +	a[0][0] = 1 +	assert '$a' == '[[1, 0, 0], [0, 0, 0]]' +	mut b := [[0].repeat(3)].repeat(2) +	b[0][0] = 1 +	assert '$b' == '[[1, 0, 0], [0, 0, 0]]' +} + +fn test_plus_assign_string() { +	mut a := [''] +	a[0] += 'abc' +	assert a == ['abc'] +} + +fn mut_arr_with_eq_in_fn(mut a []int) { +	if a == [1, 2, 3, 4] { +		a[0] = 0 +	} +	if [0, 2, 3, 4] == a { +		a[1] = 0 +	} +	if !(a != [0, 0, 3, 4]) { +		a[2] = 0 +	} +	if !([0, 0, 0, 4] != a) { +		a[3] = 0 +	} +} + +fn test_mut_arr_with_eq_in_fn() { +	mut a := [1, 2, 3, 4] +	mut_arr_with_eq_in_fn(mut a) +	assert a == [0, 0, 0, 0] +} + +fn array_in_mut(mut a []int) { +	if 1 in a { +		a[0] = 2 +	} +} + +fn test_array_in_mut() { +	mut a := [1, 2] +	array_in_mut(mut a) +	assert a == [2, 2] +} + +// test array delete in function with mut argument +fn delete_nums(mut arr []int) { +	arr.delete(0) +} + +fn test_array_delete_in_mut() { +	mut nums := [1, 2, 3] +	delete_nums(mut nums) +	assert nums == [2, 3] +} + +// test array add in function with mut argument +fn add_nums(mut arr []int) { +	arr << 4 +} + +fn test_array_add_in_mut() { +	mut nums := [1, 2, 3] +	add_nums(mut nums) +	assert nums == [1, 2, 3, 4] +} + +fn test_reverse_in_place() { +	mut a := [1, 2, 3, 4] +	a.reverse_in_place() +	assert a == [4, 3, 2, 1] +	mut b := ['a', 'b', 'c'] +	b.reverse_in_place() +	assert b == ['c', 'b', 'a'] +	mut c := [[1, 2], [3, 4], [5, 6]] +	c.reverse_in_place() +	assert c == [[5, 6], [3, 4], [1, 2]] +} + +fn test_array_int_pop() { +	mut a := [1, 2, 3, 4, 5] +	assert a.len == 5 +	x := a.last() +	y := a.pop() +	assert x == y +	assert a.len == 4 +	z := a.pop() +	assert a.len == 3 +	assert z == 4 +	x1 := a.pop() +	x2 := a.pop() +	final := a.pop() +	assert final == 1 +} + +fn test_array_string_pop() { +	mut a := ['abc', 'def', 'xyz'] +	assert a.len == 3 +	assert a.pop() == 'xyz' +	assert a.pop() == 'def' +	assert a.pop() == 'abc' +	assert a.len == 0 +	assert a.cap == 3 +} + +fn test_array_first() { +	a := [3] +	assert a.first() == 3 +	b := [1, 2, 3, 4] +	assert b.first() == 1 +	c := ['abc', 'def'] +	assert c.first()[0] == `a` +	s := [Chunk{'a'}] +	assert s.first().val == 'a' +} + +fn test_array_last() { +	a := [3] +	assert a.last() == 3 +	b := [1, 2, 3, 4] +	assert b.last() == 4 +	c := ['abc', 'def'] +	assert c.last()[0] == `d` +	s := [Chunk{'a'}] +	assert s.last().val == 'a' +} + +[direct_array_access] +fn test_direct_array_access() { +	mut a := [11, 22, 33, 44] +	assert a[0] == 11 +	assert a[2] == 33 +	x := a[0] +	a[0] = 21 +	a[1] += 2 +	a[2] = x + 3 +	a[3] -= a[1] +	assert a == [21, 24, 14, 20] +} + +[direct_array_access] +fn test_direct_array_access_via_ptr() { +	mut b := [11, 22, 33, 44] +	unsafe { +		mut a := &b +		assert a[0] == 11 +		assert a[2] == 33 +		x := a[0] +		a[0] = 21 +		a[1] += 2 +		a[2] = x + 3 +		a[3] -= a[1] +		assert a == [21, 24, 14, 20] +	} +} + +fn test_push_arr_string_free() { +	mut lines := ['hi'] +	s := 'a' + 'b' +	lines << s +	// make sure the data in the array is valid after freeing the string +	unsafe { s.free() } +	// +	println(lines) +	assert lines.len == 2 +	assert lines[0] == 'hi' +	assert lines[1] == 'ab' +} + +const ( +	grid_size_1 = 2 +	grid_size_2 = 3 +	grid_size_3 = 4 +	cell_value  = 123 +) + +fn test_multidimensional_array_initialization_with_consts() { +	mut data := [][][]int{len: grid_size_1, init: [][]int{len: grid_size_2, init: []int{len: grid_size_3, init: cell_value}}} +	assert data.len == grid_size_1 +	assert data[0].len == grid_size_2 +	assert data[0][0].len == grid_size_3 +	assert data[0][0][0] == cell_value +	assert data[1][1][1] == cell_value +} + +fn test_byteptr_vbytes() { +	unsafe { +		bp := malloc(5) +		bp[0] = 1 +		bp[1] = 2 +		bp[2] = 3 +		bp[3] = 4 +		bp[4] = 255 +		bytes := bp.vbytes(5) +		println(bytes) +		assert bytes.len == 5 +		assert bytes[0] == 1 +		assert bytes[1] == 2 +		assert bytes[2] == 3 +		assert bytes[3] == 4 +		assert bytes[4] == 255 +	} +} + +fn test_voidptr_vbytes() { +	unsafe { +		bp := malloc(3) +		bp[0] = 4 +		bp[1] = 5 +		bp[2] = 6 +		bytes := voidptr(bp).vbytes(3) +		assert bytes.len == 3 +		assert bytes[0] == 4 +		assert bytes[1] == 5 +		assert bytes[2] == 6 +		println(bytes) +	} +} + +fn test_multi_array_prepend() { +	mut a := [][]int{} +	a.prepend([1, 2, 3]) +	assert a == [[1, 2, 3]] +	mut b := [][]int{} +	b.prepend([[1, 2, 3]]) +	assert b == [[1, 2, 3]] +} + +fn test_multi_array_insert() { +	mut a := [][]int{} +	a.insert(0, [1, 2, 3]) +	assert a == [[1, 2, 3]] +	mut b := [][]int{} +	b.insert(0, [[1, 2, 3]]) +	assert b == [[1, 2, 3]] +} + +fn test_multi_array_in() { +	a := [[1]] +	println([1] in a) +	assert [1] in a +} + +fn test_any_type_array_contains() { +	a := [true, false] +	assert a.contains(true) +	assert true in a +	assert a.contains(false) +	assert false in a +	b := [i64(2), 3, 4] +	assert b.contains(i64(3)) +	assert 5 !in b +	c := [[1], [2]] +	assert c.contains([1]) +	assert [2] in c +	assert [3] !in c +} + +struct Person { +	name string +	nums []int +	kv   map[string]string +} + +fn test_struct_array_of_multi_type_in() { +	ivan := Person{ +		name: 'ivan' +		nums: [1, 2, 3] +		kv: map{ +			'aaa': '111' +		} +	} +	people := [Person{ +		name: 'ivan' +		nums: [1, 2, 3] +		kv: map{ +			'aaa': '111' +		} +	}, Person{ +		name: 'bob' +		nums: [2] +		kv: map{ +			'bbb': '222' +		} +	}] +	println(ivan in people) +	assert ivan in people +} + +fn test_struct_array_of_multi_type_index() { +	ivan := Person{ +		name: 'ivan' +		nums: [1, 2, 3] +		kv: map{ +			'aaa': '111' +		} +	} +	people := [Person{ +		name: 'ivan' +		nums: [1, 2, 3] +		kv: map{ +			'aaa': '111' +		} +	}, Person{ +		name: 'bob' +		nums: [2] +		kv: map{ +			'bbb': '222' +		} +	}] +	println(people.index(ivan)) +	assert people.index(ivan) == 0 +} + +struct Coord { +	x int +	y int +	z int +} + +fn test_array_struct_contains() { +	mut coords := []Coord{} +	coord_1 := Coord{ +		x: 1 +		y: 2 +		z: -1 +	} +	coords << coord_1 +	exists := coord_1 in coords +	not_exists := coord_1 !in coords +	println('`exists`: $exists and `not exists`: $not_exists') +	assert exists == true +	assert not_exists == false +} + +fn test_array_struct_ref_contains() { +	mut coords := []&Coord{} +	coord_1 := &Coord{ +		x: 1 +		y: 2 +		z: -1 +	} +	coords << coord_1 +	exists := coord_1 in coords +	println(exists) +	assert exists == true +} + +fn test_array_struct_ref_index() { +	mut coords := []&Coord{} +	coord_1 := &Coord{ +		x: 1 +		y: 2 +		z: -1 +	} +	coords << coord_1 +	println(coords.index(coord_1)) +	assert coords.index(coord_1) == 0 +} + +fn test_array_of_array_append() { +	mut x := [][]int{len: 4} +	println(x) // OK +	x[2] << 123 // RTE +	println(x) +	assert '$x' == '[[], [], [123], []]' +} + +fn test_array_of_map_insert() { +	mut x := []map[string]int{len: 4} +	println(x) // OK +	x[2]['123'] = 123 // RTE +	println(x) +	assert '$x' == "[{}, {}, {'123': 123}, {}]" +} + +fn test_multi_fixed_array_init() { +	a := [3][3]int{} +	assert '$a' == '[[0, 0, 0], [0, 0, 0], [0, 0, 0]]' +} + +struct Numbers { +	odds  []int +	evens []int +} + +fn test_array_of_multi_filter() { +	arr := [1, 2, 3, 4, 5] +	nums := Numbers{ +		odds: arr.filter(it % 2 == 1) +		evens: arr.filter(it % 2 == 0) +	} +	println(nums) +	assert nums.odds == [1, 3, 5] +	assert nums.evens == [2, 4] +} + +fn test_array_of_multi_map() { +	arr := [1, 3, 5] +	nums := Numbers{ +		odds: arr.map(it + 2) +		evens: arr.map(it * 2) +	} +	println(nums) +	assert nums.odds == [3, 5, 7] +	assert nums.evens == [2, 6, 10] +} + +fn test_multi_fixed_array_with_default_init() { +	a := [3][3]int{init: [3]int{init: 10}} +	println(a) +	assert a == [[10, 10, 10]!, [10, 10, 10]!, [10, 10, 10]!]! +} + +struct Abc { +mut: +	x i64 +	y i64 +	z i64 +} + +fn test_clone_of_same_elem_size_array() { +	mut arr := []Abc{} +	arr << Abc{1, 2, 3} +	arr << Abc{2, 3, 4} +	arr2 := arr.clone() +	println(arr2) +	assert arr2 == [Abc{1, 2, 3}, Abc{2, 3, 4}] +} + +pub fn example<T>(mut arr []T) []T { +	return arr.clone() +} + +fn test_generic_mutable_arrays() { +	mut arr := [1, 2, 3] +	assert example(mut arr) == [1, 2, 3] +} diff --git a/v_windows/v/old/vlib/builtin/builtin.c.v b/v_windows/v/old/vlib/builtin/builtin.c.v new file mode 100644 index 0000000..0b0ca80 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/builtin.c.v @@ -0,0 +1,527 @@ +module builtin + +type FnExitCb = fn () + +fn C.atexit(f FnExitCb) int +fn C.strerror(int) &char + +[noreturn] +fn vhalt() { +	for {} +} + +// exit terminates execution immediately and returns exit `code` to the shell. +[noreturn] +pub fn exit(code int) { +	C.exit(code) +} + +fn vcommithash() string { +	return unsafe { tos5(&char(C.V_CURRENT_COMMIT_HASH)) } +} + +// panic_debug private function that V uses for panics, -cg/-g is passed +// recent versions of tcc print nicer backtraces automatically +// NB: the duplication here is because tcc_backtrace should be called directly +// inside the panic functions. +[noreturn] +fn panic_debug(line_no int, file string, mod string, fn_name string, s string) { +	// NB: the order here is important for a stabler test output +	// module is less likely to change than function, etc... +	// During edits, the line number will change most frequently, +	// so it is last +	$if freestanding { +		bare_panic(s) +	} $else { +		eprintln('================ V panic ================') +		eprintln('   module: $mod') +		eprintln(' function: ${fn_name}()') +		eprintln('  message: $s') +		eprintln('     file: $file:$line_no') +		eprintln('   v hash: $vcommithash()') +		eprintln('=========================================') +		$if exit_after_panic_message ? { +			C.exit(1) +		} $else $if no_backtrace ? { +			C.exit(1) +		} $else { +			$if tinyc { +				$if panics_break_into_debugger ? { +					break_if_debugger_attached() +				} $else { +					C.tcc_backtrace(c'Backtrace') +				} +				C.exit(1) +			} +			print_backtrace_skipping_top_frames(1) +			$if panics_break_into_debugger ? { +				break_if_debugger_attached() +			} +			C.exit(1) +		} +	} +	vhalt() +} + +[noreturn] +pub fn panic_optional_not_set(s string) { +	panic('optional not set ($s)') +} + +// panic prints a nice error message, then exits the process with exit code of 1. +// It also shows a backtrace on most platforms. +[noreturn] +pub fn panic(s string) { +	$if freestanding { +		bare_panic(s) +	} $else { +		eprint('V panic: ') +		eprintln(s) +		eprintln('v hash: $vcommithash()') +		$if exit_after_panic_message ? { +			C.exit(1) +		} $else $if no_backtrace ? { +			C.exit(1) +		} $else { +			$if tinyc { +				$if panics_break_into_debugger ? { +					break_if_debugger_attached() +				} $else { +					C.tcc_backtrace(c'Backtrace') +				} +				C.exit(1) +			} +			print_backtrace_skipping_top_frames(1) +			$if panics_break_into_debugger ? { +				break_if_debugger_attached() +			} +			C.exit(1) +		} +	} +	vhalt() +} + +// return a C-API error message matching to `errnum` +pub fn c_error_number_str(errnum int) string { +	mut err_msg := '' +	$if freestanding { +		err_msg = 'error $errnum' +	} $else { +		$if !vinix { +			c_msg := C.strerror(errnum) +			err_msg = string{ +				str: &byte(c_msg) +				len: unsafe { C.strlen(c_msg) } +				is_lit: 1 +			} +		} +	} +	return err_msg +} + +// panic with a C-API error message matching `errnum` +[noreturn] +pub fn panic_error_number(basestr string, errnum int) { +	panic(basestr + c_error_number_str(errnum)) +} + +// eprintln prints a message with a line end, to stderr. Both stderr and stdout are flushed. +pub fn eprintln(s string) { +	if s.str == 0 { +		eprintln('eprintln(NIL)') +		return +	} +	$if freestanding { +		// flushing is only a thing with C.FILE from stdio.h, not on the syscall level +		bare_eprint(s.str, u64(s.len)) +		bare_eprint(c'\n', 1) +	} $else $if ios { +		C.WrappedNSLog(s.str) +	} $else { +		C.fflush(C.stdout) +		C.fflush(C.stderr) +		// eprintln is used in panics, so it should not fail at all +		$if android { +			C.fprintf(C.stderr, c'%.*s\n', s.len, s.str) +		} +		_writeln_to_fd(2, s) +		C.fflush(C.stderr) +	} +} + +// eprint prints a message to stderr. Both stderr and stdout are flushed. +pub fn eprint(s string) { +	if s.str == 0 { +		eprint('eprint(NIL)') +		return +	} +	$if freestanding { +		// flushing is only a thing with C.FILE from stdio.h, not on the syscall level +		bare_eprint(s.str, u64(s.len)) +	} $else $if ios { +		// TODO: Implement a buffer as NSLog doesn't have a "print" +		C.WrappedNSLog(s.str) +	} $else { +		C.fflush(C.stdout) +		C.fflush(C.stderr) +		$if android { +			C.fprintf(C.stderr, c'%.*s', s.len, s.str) +		} +		_write_buf_to_fd(2, s.str, s.len) +		C.fflush(C.stderr) +	} +} + +// print prints a message to stdout. Unlike `println` stdout is not automatically flushed. +// A call to `flush()` will flush the output buffer to stdout. +[manualfree] +pub fn print(s string) { +	$if android { +		C.fprintf(C.stdout, c'%.*s', s.len, s.str) // logcat +	} +	// no else if for android termux support +	$if ios { +		// TODO: Implement a buffer as NSLog doesn't have a "print" +		C.WrappedNSLog(s.str) +	} $else $if freestanding { +		bare_print(s.str, u64(s.len)) +	} $else { +		_write_buf_to_fd(1, s.str, s.len) +	} +} + +// println prints a message with a line end, to stdout. stdout is flushed. +[manualfree] +pub fn println(s string) { +	if s.str == 0 { +		println('println(NIL)') +		return +	} +	$if android { +		C.fprintf(C.stdout, c'%.*s\n', s.len, s.str) // logcat +		return +	} +	// no else if for android termux support +	$if ios { +		C.WrappedNSLog(s.str) +		return +	} $else $if freestanding { +		bare_print(s.str, u64(s.len)) +		bare_print(c'\n', 1) +		return +	} $else { +		_writeln_to_fd(1, s) +	} +} + +[manualfree] +fn _writeln_to_fd(fd int, s string) { +	unsafe { +		buf_len := s.len + 1 // space for \n +		mut buf := malloc(buf_len) +		defer { +			free(buf) +		} +		C.memcpy(buf, s.str, s.len) +		buf[s.len] = `\n` +		_write_buf_to_fd(fd, buf, buf_len) +	} +} + +[manualfree] +fn _write_buf_to_fd(fd int, buf &byte, buf_len int) { +	if buf_len <= 0 { +		return +	} +	unsafe { +		mut ptr := buf +		mut remaining_bytes := buf_len +		for remaining_bytes > 0 { +			x := C.write(fd, ptr, remaining_bytes) +			ptr += x +			remaining_bytes -= x +		} +	} +} + +__global total_m = i64(0) +// malloc dynamically allocates a `n` bytes block of memory on the heap. +// malloc returns a `byteptr` pointing to the memory address of the allocated space. +// unlike the `calloc` family of functions - malloc will not zero the memory block. +[unsafe] +pub fn malloc(n int) &byte { +	if n <= 0 { +		panic('> V malloc(<=0)') +	} +	$if vplayground ? { +		if n > 10000 { +			panic('allocating more than 10 KB at once is not allowed in the V playground') +		} +		if total_m > 50 * 1024 * 1024 { +			panic('allocating more than 50 MB is not allowed in the V playground') +		} +	} +	$if trace_malloc ? { +		total_m += n +		C.fprintf(C.stderr, c'_v_malloc %6d total %10d\n', n, total_m) +		// print_backtrace() +	} +	mut res := &byte(0) +	$if prealloc { +		return unsafe { prealloc_malloc(n) } +	} $else $if gcboehm ? { +		unsafe { +			res = C.GC_MALLOC(n) +		} +	} $else $if freestanding { +		mut e := Errno{} +		res, e = mm_alloc(u64(n)) +		if e != .enoerror { +			eprint('malloc() failed: ') +			eprintln(e.str()) +			panic('malloc() failed') +		} +	} $else { +		res = unsafe { C.malloc(n) } +	} +	if res == 0 { +		panic('malloc($n) failed') +	} +	$if debug_malloc ? { +		// Fill in the memory with something != 0, so it is easier to spot +		// when the calling code wrongly relies on it being zeroed. +		unsafe { C.memset(res, 0x88, n) } +	} +	return res +} + +[unsafe] +pub fn malloc_noscan(n int) &byte { +	if n <= 0 { +		panic('> V malloc(<=0)') +	} +	$if vplayground ? { +		if n > 10000 { +			panic('allocating more than 10 KB at once is not allowed in the V playground') +		} +		if total_m > 50 * 1024 * 1024 { +			panic('allocating more than 50 MB is not allowed in the V playground') +		} +	} +	$if trace_malloc ? { +		total_m += n +		C.fprintf(C.stderr, c'_v_malloc %6d total %10d\n', n, total_m) +		// print_backtrace() +	} +	mut res := &byte(0) +	$if prealloc { +		return unsafe { prealloc_malloc(n) } +	} $else $if gcboehm ? { +		$if gcboehm_opt ? { +			unsafe { +				res = C.GC_MALLOC_ATOMIC(n) +			} +		} $else { +			unsafe { +				res = C.GC_MALLOC(n) +			} +		} +	} $else $if freestanding { +		mut e := Errno{} +		res, e = mm_alloc(u64(n)) +		if e != .enoerror { +			eprint('malloc() failed: ') +			eprintln(e.str()) +			panic('malloc() failed') +		} +	} $else { +		res = unsafe { C.malloc(n) } +	} +	if res == 0 { +		panic('malloc($n) failed') +	} +	$if debug_malloc ? { +		// Fill in the memory with something != 0, so it is easier to spot +		// when the calling code wrongly relies on it being zeroed. +		unsafe { C.memset(res, 0x88, n) } +	} +	return res +} + +// v_realloc resizes the memory block `b` with `n` bytes. +// The `b byteptr` must be a pointer to an existing memory block +// previously allocated with `malloc`, `v_calloc` or `vcalloc`. +// Please, see also realloc_data, and use it instead if possible. +[unsafe] +pub fn v_realloc(b &byte, n int) &byte { +	$if trace_realloc ? { +		C.fprintf(C.stderr, c'v_realloc %6d\n', n) +	} +	mut new_ptr := &byte(0) +	$if prealloc { +		unsafe { +			new_ptr = malloc(n) +			C.memcpy(new_ptr, b, n) +		} +		return new_ptr +	} $else $if gcboehm ? { +		new_ptr = unsafe { C.GC_REALLOC(b, n) } +	} $else { +		new_ptr = unsafe { C.realloc(b, n) } +	} +	if new_ptr == 0 { +		panic('realloc($n) failed') +	} +	return new_ptr +} + +// realloc_data resizes the memory block pointed by `old_data` to `new_size` +// bytes. `old_data` must be a pointer to an existing memory block, previously +// allocated with `malloc`, `v_calloc` or `vcalloc`, of size `old_data`. +// realloc_data returns a pointer to the new location of the block. +// NB: if you know the old data size, it is preferable to call `realloc_data`, +// instead of `v_realloc`, at least during development, because `realloc_data` +// can make debugging easier, when you compile your program with +// `-d debug_realloc`. +[unsafe] +pub fn realloc_data(old_data &byte, old_size int, new_size int) &byte { +	$if trace_realloc ? { +		C.fprintf(C.stderr, c'realloc_data old_size: %6d new_size: %6d\n', old_size, new_size) +	} +	$if prealloc { +		return unsafe { prealloc_realloc(old_data, old_size, new_size) } +	} +	$if debug_realloc ? { +		// NB: this is slower, but helps debugging memory problems. +		// The main idea is to always force reallocating: +		// 1) allocate a new memory block +		// 2) copy the old to the new +		// 3) fill the old with 0x57 (`W`) +		// 4) free the old block +		// => if there is still a pointer to the old block somewhere +		//    it will point to memory that is now filled with 0x57. +		unsafe { +			new_ptr := malloc(new_size) +			min_size := if old_size < new_size { old_size } else { new_size } +			C.memcpy(new_ptr, old_data, min_size) +			C.memset(old_data, 0x57, old_size) +			free(old_data) +			return new_ptr +		} +	} +	mut nptr := &byte(0) +	$if gcboehm ? { +		nptr = unsafe { C.GC_REALLOC(old_data, new_size) } +	} $else { +		nptr = unsafe { C.realloc(old_data, new_size) } +	} +	if nptr == 0 { +		panic('realloc_data($old_data, $old_size, $new_size) failed') +	} +	return nptr +} + +// vcalloc dynamically allocates a zeroed `n` bytes block of memory on the heap. +// vcalloc returns a `byteptr` pointing to the memory address of the allocated space. +// Unlike `v_calloc` vcalloc checks for negative values given in `n`. +pub fn vcalloc(n int) &byte { +	if n < 0 { +		panic('calloc(<0)') +	} else if n == 0 { +		return &byte(0) +	} +	$if trace_vcalloc ? { +		total_m += n +		C.fprintf(C.stderr, c'vcalloc %6d total %10d\n', n, total_m) +	} +	$if prealloc { +		return unsafe { prealloc_calloc(n) } +	} $else $if gcboehm ? { +		return unsafe { &byte(C.GC_MALLOC(n)) } +	} $else { +		return unsafe { C.calloc(1, n) } +	} +} + +// special versions of the above that allocate memory which is not scanned +// for pointers (but is collected) when the Boehm garbage collection is used +pub fn vcalloc_noscan(n int) &byte { +	$if trace_vcalloc ? { +		total_m += n +		C.fprintf(C.stderr, c'vcalloc_noscan %6d total %10d\n', n, total_m) +	} +	$if prealloc { +		return unsafe { prealloc_calloc(n) } +	} $else $if gcboehm ? { +		$if vplayground ? { +			if n > 10000 { +				panic('allocating more than 10 KB is not allowed in the playground') +			} +		} +		if n < 0 { +			panic('calloc(<0)') +		} +		return $if gcboehm_opt ? { +			unsafe { &byte(C.memset(C.GC_MALLOC_ATOMIC(n), 0, n)) } +		} $else { +			unsafe { &byte(C.GC_MALLOC(n)) } +		} +	} $else { +		return unsafe { vcalloc(n) } +	} +} + +// free allows for manually freeing memory allocated at the address `ptr`. +[unsafe] +pub fn free(ptr voidptr) { +	$if prealloc { +		return +	} $else $if gcboehm ? { +		// It is generally better to leave it to Boehm's gc to free things. +		// Calling C.GC_FREE(ptr) was tried initially, but does not work +		// well with programs that do manual management themselves. +		// +		// The exception is doing leak detection for manual memory management: +		$if gcboehm_leak ? { +			unsafe { C.GC_FREE(ptr) } +		} +	} $else { +		C.free(ptr) +	} +} + +// memdup dynamically allocates a `sz` bytes block of memory on the heap +// memdup then copies the contents of `src` into the allocated space and +// returns a pointer to the newly allocated space. +[unsafe] +pub fn memdup(src voidptr, sz int) voidptr { +	if sz == 0 { +		return vcalloc(1) +	} +	unsafe { +		mem := malloc(sz) +		return C.memcpy(mem, src, sz) +	} +} + +[unsafe] +pub fn memdup_noscan(src voidptr, sz int) voidptr { +	if sz == 0 { +		return vcalloc_noscan(1) +	} +	unsafe { +		mem := vcalloc_noscan(sz) +		return C.memcpy(mem, src, sz) +	} +} + +[inline] +fn v_fixed_index(i int, len int) int { +	$if !no_bounds_checking ? { +		if i < 0 || i >= len { +			s := 'fixed array index out of range (index: $i, len: $len)' +			panic(s) +		} +	} +	return i +} diff --git a/v_windows/v/old/vlib/builtin/builtin.v b/v_windows/v/old/vlib/builtin/builtin.v new file mode 100644 index 0000000..d3a1474 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/builtin.v @@ -0,0 +1,131 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module builtin + +// isnil returns true if an object is nil (only for C objects). +[inline] +pub fn isnil(v voidptr) bool { +	return v == 0 +} + +/* +fn on_panic(f fn(int)int) { +	// TODO +} +*/ + +// print_backtrace shows a backtrace of the current call stack on stdout +pub fn print_backtrace() { +	// At the time of backtrace_symbols_fd call, the C stack would look something like this: +	// * print_backtrace_skipping_top_frames +	// * print_backtrace itself +	// * the rest of the backtrace frames +	// => top 2 frames should be skipped, since they will not be informative to the developer +	$if !no_backtrace ? { +		$if freestanding { +			println(bare_backtrace()) +		} $else { +			$if tinyc { +				C.tcc_backtrace(c'Backtrace') +			} $else { +				print_backtrace_skipping_top_frames(2) +			} +		} +	} +} + +struct VCastTypeIndexName { +	tindex int +	tname  string +} + +// will be filled in cgen +__global as_cast_type_indexes []VCastTypeIndexName + +fn __as_cast(obj voidptr, obj_type int, expected_type int) voidptr { +	if obj_type != expected_type { +		mut obj_name := as_cast_type_indexes[0].tname.clone() +		mut expected_name := as_cast_type_indexes[0].tname.clone() +		for x in as_cast_type_indexes { +			if x.tindex == obj_type { +				obj_name = x.tname.clone() +			} +			if x.tindex == expected_type { +				expected_name = x.tname.clone() +			} +		} +		panic('as cast: cannot cast `$obj_name` to `$expected_name`') +	} +	return obj +} + +// VAssertMetaInfo is used during assertions. An instance of it +// is filled in by compile time generated code, when an assertion fails. +pub struct VAssertMetaInfo { +pub: +	fpath   string // the source file path of the assertion +	line_nr int    // the line number of the assertion +	fn_name string // the function name in which the assertion is +	src     string // the actual source line of the assertion +	op      string // the operation of the assertion, i.e. '==', '<', 'call', etc ... +	llabel  string // the left side of the infix expressions as source +	rlabel  string // the right side of the infix expressions as source +	lvalue  string // the stringified *actual value* of the left side of a failed assertion +	rvalue  string // the stringified *actual value* of the right side of a failed assertion +} + +fn __print_assert_failure(i &VAssertMetaInfo) { +	eprintln('$i.fpath:${i.line_nr + 1}: FAIL: fn $i.fn_name: assert $i.src') +	if i.op.len > 0 && i.op != 'call' { +		eprintln('   left value: $i.llabel = $i.lvalue') +		if i.rlabel == i.rvalue { +			eprintln('  right value: $i.rlabel') +		} else { +			eprintln('  right value: $i.rlabel = $i.rvalue') +		} +	} +} + +// MethodArgs holds type information for function and/or method arguments. +pub struct MethodArgs { +pub: +	typ  int +	name string +} + +// FunctionData holds information about a parsed function. +pub struct FunctionData { +pub: +	name        string +	attrs       []string +	args        []MethodArgs +	return_type int +	typ         int +} + +// FieldData holds information about a field. Fields reside on structs. +pub struct FieldData { +pub: +	name      string +	attrs     []string +	is_pub    bool +	is_mut    bool +	is_shared bool +	typ       int +} + +pub enum AttributeKind { +	plain // [name] +	string // ['name'] +	number // [123] +	comptime_define // [if name] +} + +pub struct StructAttribute { +pub: +	name    string +	has_arg bool +	arg     string +	kind    AttributeKind +} diff --git a/v_windows/v/old/vlib/builtin/builtin_d_gcboehm.v b/v_windows/v/old/vlib/builtin/builtin_d_gcboehm.v new file mode 100644 index 0000000..befec1d --- /dev/null +++ b/v_windows/v/old/vlib/builtin/builtin_d_gcboehm.v @@ -0,0 +1,91 @@ +module builtin + +#flag -DGC_THREADS=1 + +$if static_boehm ? { +	$if macos { +		#flag -I$first_existing("/opt/homebrew/include",     "/usr/local/include") +		#flag   $first_existing("/opt/homebrew/lib/libgc.a", "/usr/local/lib/libgc.a") +	} $else $if linux { +		#flag -l:libgc.a +	} $else $if openbsd { +		#flag -I/usr/local/include +		#flag /usr/local/lib/libgc.a +		#flag -lpthread +	} $else $if windows { +		#flag -DGC_NOT_DLL=1 +		$if tinyc { +			#flag -I@VEXEROOT/thirdparty/libgc/include +			#flag -L@VEXEROOT/thirdparty/libgc +			#flag -lgc +		} $else { +			#flag -DGC_BUILTIN_ATOMIC=1 +			#flag -I@VEXEROOT/thirdparty/libgc +			#flag @VEXEROOT/thirdparty/libgc/gc.o +		} +	} $else { +		#flag -lgc +	} +} $else { +	$if macos { +		#pkgconfig bdw-gc +	} $else $if openbsd || freebsd { +		#flag -I/usr/local/include +		#flag -L/usr/local/lib +	} +	$if windows { +		$if tinyc { +			#flag -I@VEXEROOT/thirdparty/libgc/include +			#flag -L@VEXEROOT/thirdparty/libgc +			#flag -lgc +		} $else { +			#flag -DGC_BUILTIN_ATOMIC=1 +			#flag -I@VEXEROOT/thirdparty/libgc +			#flag @VEXEROOT/thirdparty/libgc/gc.o +		} +	} $else { +		#flag -lgc +	} +} + +$if gcboehm_leak ? { +	#flag -DGC_DEBUG=1 +} + +#include <gc.h> + +// replacements for `malloc()/calloc()`, `realloc()` and `free()` +// for use with Boehm-GC +// Do not use them manually. They are automatically chosen when +// compiled with `-gc boehm` or `-gc boehm_leak`. +fn C.GC_MALLOC(n size_t) voidptr + +fn C.GC_MALLOC_ATOMIC(n size_t) voidptr + +fn C.GC_MALLOC_UNCOLLECTABLE(n size_t) voidptr + +fn C.GC_REALLOC(ptr voidptr, n size_t) voidptr + +fn C.GC_FREE(ptr voidptr) + +// explicitely perform garbage collection now! Garbage collections +// are done automatically when needed, so this function is hardly needed +fn C.GC_gcollect() + +// functions to temporarily suspend/resume garbage collection +fn C.GC_disable() + +fn C.GC_enable() + +// returns non-zero if GC is disabled +fn C.GC_is_disabled() int + +// protect memory block from being freed before this call +fn C.GC_reachable_here(voidptr) + +// for leak detection it is advisable to do explicit garbage collections +pub fn gc_check_leaks() { +	$if gcboehm_leak ? { +		C.GC_gcollect() +	} +} diff --git a/v_windows/v/old/vlib/builtin/builtin_ios.c.v b/v_windows/v/old/vlib/builtin/builtin_ios.c.v new file mode 100644 index 0000000..f745b4d --- /dev/null +++ b/v_windows/v/old/vlib/builtin/builtin_ios.c.v @@ -0,0 +1,6 @@ +module builtin + +// TODO: Remove this later, added to make sure v self works +$if ios { +	#include "@VEXEROOT/thirdparty/ios/ios.m" +} diff --git a/v_windows/v/old/vlib/builtin/builtin_nix.c.v b/v_windows/v/old/vlib/builtin/builtin_nix.c.v new file mode 100644 index 0000000..0d79af4 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/builtin_nix.c.v @@ -0,0 +1,144 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module builtin + +// pub fn vsyscall(id int +// + +/* +pub const ( +	sys_write = 1 +	sys_mkdir = 83 +) +const ( +	stdin_value = 0 +	stdout_value = 1 +	stderr_value  = 2 +) +*/ + +fn builtin_init() { +	// Do nothing +} + +fn print_backtrace_skipping_top_frames(xskipframes int) bool { +	$if no_backtrace ? { +		return false +	} $else { +		skipframes := xskipframes + 2 +		$if macos || freebsd || openbsd || netbsd { +			return print_backtrace_skipping_top_frames_bsd(skipframes) +		} $else $if linux { +			return print_backtrace_skipping_top_frames_linux(skipframes) +		} $else { +			println('print_backtrace_skipping_top_frames is not implemented. skipframes: $skipframes') +		} +	} +	return false +} + +// the functions below are not called outside this file, +// so there is no need to have their twins in builtin_windows.v +fn print_backtrace_skipping_top_frames_bsd(skipframes int) bool { +	$if no_backtrace ? { +		return false +	} $else { +		$if macos || freebsd || openbsd || netbsd { +			buffer := [100]voidptr{} +			nr_ptrs := C.backtrace(&buffer[0], 100) +			if nr_ptrs < 2 { +				eprintln('C.backtrace returned less than 2 frames') +				return false +			} +			C.backtrace_symbols_fd(&buffer[skipframes], nr_ptrs - skipframes, 2) +		} +		return true +	} +} + +fn C.tcc_backtrace(fmt &char) int +fn print_backtrace_skipping_top_frames_linux(skipframes int) bool { +	$if android { +		eprintln('On Android no backtrace is available.') +		return false +	} +	$if !glibc { +		eprintln('backtrace_symbols is missing => printing backtraces is not available.') +		eprintln('Some libc implementations like musl simply do not provide it.') +		return false +	} +	$if no_backtrace ? { +		return false +	} $else { +		$if linux && !freestanding { +			$if tinyc { +				C.tcc_backtrace(c'Backtrace') +				return false +			} +			buffer := [100]voidptr{} +			nr_ptrs := C.backtrace(&buffer[0], 100) +			if nr_ptrs < 2 { +				eprintln('C.backtrace returned less than 2 frames') +				return false +			} +			nr_actual_frames := nr_ptrs - skipframes +			mut sframes := []string{} +			//////csymbols := backtrace_symbols(*voidptr(&buffer[skipframes]), nr_actual_frames) +			csymbols := C.backtrace_symbols(voidptr(&buffer[skipframes]), nr_actual_frames) +			for i in 0 .. nr_actual_frames { +				sframes << unsafe { tos2(&byte(csymbols[i])) } +			} +			for sframe in sframes { +				executable := sframe.all_before('(') +				addr := sframe.all_after('[').all_before(']') +				beforeaddr := sframe.all_before('[') +				cmd := 'addr2line -e $executable $addr' +				// taken from os, to avoid depending on the os module inside builtin.v +				f := C.popen(&char(cmd.str), c'r') +				if isnil(f) { +					eprintln(sframe) +					continue +				} +				buf := [1000]byte{} +				mut output := '' +				unsafe { +					bp := &buf[0] +					for C.fgets(&char(bp), 1000, f) != 0 { +						output += tos(bp, vstrlen(bp)) +					} +				} +				output = output.trim_space() + ':' +				if C.pclose(f) != 0 { +					eprintln(sframe) +					continue +				} +				if output in ['??:0:', '??:?:'] { +					output = '' +				} +				// See http://wiki.dwarfstd.org/index.php?title=Path_Discriminators +				// NB: it is shortened here to just d. , just so that it fits, and so +				// that the common error file:lineno: line format is enforced. +				output = output.replace(' (discriminator', ': (d.') +				eprintln('${output:-55s} | ${addr:14s} | $beforeaddr') +			} +		} +	} +	return true +} + +fn break_if_debugger_attached() { +	unsafe { +		mut ptr := &voidptr(0) +		*ptr = voidptr(0) +		_ = ptr +	} +} + +// These functions are Windows specific - provide dummys for *nix +pub fn winapi_lasterr_str() string { +	return '' +} + +[noreturn] +pub fn panic_lasterr() {} diff --git a/v_windows/v/old/vlib/builtin/builtin_notd_gcboehm.v b/v_windows/v/old/vlib/builtin/builtin_notd_gcboehm.v new file mode 100644 index 0000000..4479072 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/builtin_notd_gcboehm.v @@ -0,0 +1,20 @@ +module builtin + +// Just define the C functions, so that V does not error because of the missing definitions. + +// NB: they will NOT be used, since calls to them are wrapped with `$if gcboehm ? { }` + +fn C.GC_MALLOC(n size_t) voidptr + +fn C.GC_MALLOC_ATOMIC(n size_t) voidptr + +fn C.GC_MALLOC_UNCOLLECTABLE(n size_t) voidptr + +fn C.GC_REALLOC(ptr voidptr, n size_t) voidptr + +fn C.GC_FREE(ptr voidptr) + +// provide an empty function when manual memory management is used +// to simplify leak detection +// +pub fn gc_check_leaks() {} diff --git a/v_windows/v/old/vlib/builtin/builtin_windows.c.v b/v_windows/v/old/vlib/builtin/builtin_windows.c.v new file mode 100644 index 0000000..97592cf --- /dev/null +++ b/v_windows/v/old/vlib/builtin/builtin_windows.c.v @@ -0,0 +1,304 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module builtin + +// dbghelp.h is already included in cheaders.v +#flag windows -l dbghelp +// SymbolInfo is used by print_backtrace_skipping_top_frames_msvc +pub struct SymbolInfo { +pub mut: +	f_size_of_struct u32 // must be 88 to be recognised by SymFromAddr +	f_type_index     u32 // Type Index of symbol +	f_reserved       [2]u64 +	f_index          u32 +	f_size           u32 +	f_mod_base       u64 // Base Address of module comtaining this symbol +	f_flags          u32 +	f_value          u64  // Value of symbol, ValuePresent should be 1 +	f_address        u64  // Address of symbol including base address of module +	f_register       u32  // register holding value or pointer to value +	f_scope          u32  // scope of the symbol +	f_tag            u32  // pdb classification +	f_name_len       u32  // Actual length of name +	f_max_name_len   u32  // must be manually set +	f_name           byte // must be calloc(f_max_name_len) +} + +pub struct SymbolInfoContainer { +pub mut: +	syminfo     SymbolInfo +	f_name_rest [254]char +} + +pub struct Line64 { +pub mut: +	f_size_of_struct u32 +	f_key            voidptr +	f_line_number    u32 +	f_file_name      &byte +	f_address        u64 +} + +// returns the current options mask +fn C.SymSetOptions(symoptions u32) u32 + +// returns handle +fn C.GetCurrentProcess() voidptr + +fn C.SymInitialize(h_process voidptr, p_user_search_path &byte, b_invade_process int) int + +fn C.CaptureStackBackTrace(frames_to_skip u32, frames_to_capture u32, p_backtrace voidptr, p_backtrace_hash voidptr) u16 + +fn C.SymFromAddr(h_process voidptr, address u64, p_displacement voidptr, p_symbol voidptr) int + +fn C.SymGetLineFromAddr64(h_process voidptr, address u64, p_displacement voidptr, p_line &Line64) int + +// Ref - https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-symsetoptions +const ( +	symopt_undname               = 0x00000002 +	symopt_deferred_loads        = 0x00000004 +	symopt_no_cpp                = 0x00000008 +	symopt_load_lines            = 0x00000010 +	symopt_include_32bit_modules = 0x00002000 +	symopt_allow_zero_address    = 0x01000000 +	symopt_debug                 = 0x80000000 +) + +// g_original_codepage - used to restore the original windows console code page when exiting +__global ( +	g_original_codepage = u32(0) +) + +// utf8 to stdout needs C.SetConsoleOutputCP(C.CP_UTF8) +fn C.GetConsoleOutputCP() u32 + +fn C.SetConsoleOutputCP(wCodePageID u32) bool + +fn restore_codepage() { +	C.SetConsoleOutputCP(g_original_codepage) +} + +fn is_terminal(fd int) int { +	mut mode := u32(0) +	osfh := voidptr(C._get_osfhandle(fd)) +	C.GetConsoleMode(osfh, voidptr(&mode)) +	return int(mode) +} + +fn builtin_init() { +	g_original_codepage = C.GetConsoleOutputCP() +	C.SetConsoleOutputCP(C.CP_UTF8) +	C.atexit(restore_codepage) +	if is_terminal(1) > 0 { +		C.SetConsoleMode(C.GetStdHandle(C.STD_OUTPUT_HANDLE), C.ENABLE_PROCESSED_OUTPUT | C.ENABLE_WRAP_AT_EOL_OUTPUT | 0x0004) // enable_virtual_terminal_processing +		C.SetConsoleMode(C.GetStdHandle(C.STD_ERROR_HANDLE), C.ENABLE_PROCESSED_OUTPUT | C.ENABLE_WRAP_AT_EOL_OUTPUT | 0x0004) // enable_virtual_terminal_processing +		unsafe { +			C.setbuf(C.stdout, 0) +			C.setbuf(C.stderr, 0) +		} +	} +	$if !no_backtrace ? { +		add_unhandled_exception_handler() +	} +} + +fn print_backtrace_skipping_top_frames(skipframes int) bool { +	$if msvc { +		return print_backtrace_skipping_top_frames_msvc(skipframes) +	} +	$if tinyc { +		return print_backtrace_skipping_top_frames_tcc(skipframes) +	} +	$if mingw { +		return print_backtrace_skipping_top_frames_mingw(skipframes) +	} +	eprintln('print_backtrace_skipping_top_frames is not implemented') +	return false +} + +fn print_backtrace_skipping_top_frames_msvc(skipframes int) bool { +	$if msvc { +		mut offset := u64(0) +		backtraces := [100]voidptr{} +		sic := SymbolInfoContainer{} +		mut si := &sic.syminfo +		si.f_size_of_struct = sizeof(SymbolInfo) // Note: C.SYMBOL_INFO is 88 +		si.f_max_name_len = sizeof(SymbolInfoContainer) - sizeof(SymbolInfo) - 1 +		fname := &char(&si.f_name) +		mut sline64 := Line64{ +			f_file_name: &byte(0) +		} +		sline64.f_size_of_struct = sizeof(Line64) + +		handle := C.GetCurrentProcess() +		defer { +			C.SymCleanup(handle) +		} + +		C.SymSetOptions(symopt_debug | symopt_load_lines | symopt_undname) + +		syminitok := C.SymInitialize(handle, 0, 1) +		if syminitok != 1 { +			eprintln('Failed getting process: Aborting backtrace.\n') +			return false +		} + +		frames := int(C.CaptureStackBackTrace(skipframes + 1, 100, &backtraces[0], 0)) +		if frames < 2 { +			eprintln('C.CaptureStackBackTrace returned less than 2 frames') +			return false +		} +		for i in 0 .. frames { +			frame_addr := backtraces[i] +			if C.SymFromAddr(handle, frame_addr, &offset, si) == 1 { +				nframe := frames - i - 1 +				mut lineinfo := '' +				if C.SymGetLineFromAddr64(handle, frame_addr, &offset, &sline64) == 1 { +					file_name := unsafe { tos3(sline64.f_file_name) } +					lnumber := sline64.f_line_number +					lineinfo = '$file_name:$lnumber' +				} else { +					addr: +					lineinfo = '?? : address = 0x${(&frame_addr):x}' +				} +				sfunc := unsafe { tos3(fname) } +				eprintln('${nframe:-2d}: ${sfunc:-25s}  $lineinfo') +			} else { +				// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes +				cerr := int(C.GetLastError()) +				if cerr == 87 { +					eprintln('SymFromAddr failure: $cerr = The parameter is incorrect)') +				} else if cerr == 487 { +					// probably caused because the .pdb isn't in the executable folder +					eprintln('SymFromAddr failure: $cerr = Attempt to access invalid address (Verify that you have the .pdb file in the right folder.)') +				} else { +					eprintln('SymFromAddr failure: $cerr (see https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes)') +				} +			} +		} +		return true +	} $else { +		eprintln('print_backtrace_skipping_top_frames_msvc must be called only when the compiler is msvc') +		return false +	} +} + +fn print_backtrace_skipping_top_frames_mingw(skipframes int) bool { +	eprintln('print_backtrace_skipping_top_frames_mingw is not implemented') +	return false +} + +fn C.tcc_backtrace(fmt &char) int + +fn print_backtrace_skipping_top_frames_tcc(skipframes int) bool { +	$if tinyc { +		$if no_backtrace ? { +			eprintln('backtraces are disabled') +			return false +		} $else { +			C.tcc_backtrace(c'Backtrace') +			return true +		} +	} $else { +		eprintln('print_backtrace_skipping_top_frames_tcc must be called only when the compiler is tcc') +		return false +	} +	// Not reachable, but it looks like it's not detectable by V +	return false +} + +// TODO copypaste from os +// we want to be able to use this here without having to `import os` +struct ExceptionRecord { +pub: +	// status_ constants +	code        u32 +	flags       u32 +	record      &ExceptionRecord +	address     voidptr +	param_count u32 +	// params []voidptr +} + +struct ContextRecord { +	// TODO +} + +struct ExceptionPointers { +pub: +	exception_record &ExceptionRecord +	context_record   &ContextRecord +} + +type VectoredExceptionHandler = fn (&ExceptionPointers) int + +fn C.AddVectoredExceptionHandler(int, C.PVECTORED_EXCEPTION_HANDLER) + +fn add_vectored_exception_handler(handler VectoredExceptionHandler) { +	C.AddVectoredExceptionHandler(1, C.PVECTORED_EXCEPTION_HANDLER(handler)) +} + +[windows_stdcall] +fn unhandled_exception_handler(e &ExceptionPointers) int { +	match e.exception_record.code { +		// These are 'used' by the backtrace printer +		// so we dont want to catch them... +		0x4001000A, 0x40010006 { +			return 0 +		} +		else { +			println('Unhandled Exception 0x${e.exception_record.code:X}') +			print_backtrace_skipping_top_frames(5) +		} +	} + +	return 0 +} + +fn add_unhandled_exception_handler() { +	add_vectored_exception_handler(VectoredExceptionHandler(voidptr(unhandled_exception_handler))) +} + +fn C.IsDebuggerPresent() bool + +fn C.__debugbreak() + +fn break_if_debugger_attached() { +	$if tinyc { +		unsafe { +			mut ptr := &voidptr(0) +			*ptr = voidptr(0) +			_ = ptr +		} +	} $else { +		if C.IsDebuggerPresent() { +			C.__debugbreak() +		} +	} +} + +// return an error message generated from WinAPI's `LastError` +pub fn winapi_lasterr_str() string { +	err_msg_id := C.GetLastError() +	if err_msg_id == 8 { +		// handle this case special since `FormatMessage()` might not work anymore +		return 'insufficient memory' +	} +	mut msgbuf := &u16(0) +	res := C.FormatMessage(C.FORMAT_MESSAGE_ALLOCATE_BUFFER | C.FORMAT_MESSAGE_FROM_SYSTEM | C.FORMAT_MESSAGE_IGNORE_INSERTS, +		C.NULL, err_msg_id, C.MAKELANGID(C.LANG_NEUTRAL, C.SUBLANG_DEFAULT), &msgbuf, +		0, C.NULL) +	err_msg := if res == 0 { +		'Win-API error $err_msg_id' +	} else { +		unsafe { string_from_wide(msgbuf) } +	} +	return err_msg +} + +// panic with an error message generated from WinAPI's `LastError` +[noreturn] +pub fn panic_lasterr(base string) { +	panic(base + winapi_lasterr_str()) +} diff --git a/v_windows/v/old/vlib/builtin/byte_test.v b/v_windows/v/old/vlib/builtin/byte_test.v new file mode 100644 index 0000000..8b38eb8 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/byte_test.v @@ -0,0 +1,22 @@ +fn test_clone() { +	a := [byte(0), 1, 2] +	b := a.clone() +	assert b.len == 3 +	assert b[0] == 0 +	assert b[1] == 1 +	assert b[2] == 2 +	assert b[1].str() == '1' +	xx := byte(35) +	assert xx.str() == '35' +	assert xx.ascii_str() == '#' +	println(typeof(`A`).name) +	assert typeof(`A`).name == 'rune' +	x := rune(`A`) +	assert x.str() == 'A' +	assert typeof(x).name == 'rune' +	// +	y := `Z` +	assert typeof(y).name == 'rune' +	assert y.str() == 'Z' +	// assert b[1].str() == '1' TODO +} diff --git a/v_windows/v/old/vlib/builtin/cfns.c.v b/v_windows/v/old/vlib/builtin/cfns.c.v new file mode 100644 index 0000000..b67da34 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/cfns.c.v @@ -0,0 +1,462 @@ +module builtin + +// <string.h> +fn C.memcpy(dest &byte, src &byte, n int) voidptr + +fn C.memcmp(&byte, &byte, int) int + +fn C.memmove(&byte, &byte, int) voidptr + +[trusted] +fn C.calloc(int, int) &byte + +fn C.malloc(int) &byte + +fn C.realloc(a &byte, b int) &byte + +fn C.free(ptr voidptr) + +[noreturn; trusted] +fn C.exit(code int) + +fn C.qsort(base voidptr, items size_t, item_size size_t, cb qsort_callback_func) + +fn C.sprintf(a ...voidptr) int + +fn C.strlen(s &char) int + +fn C.sscanf(&byte, &byte, ...&byte) int + +[trusted] +fn C.isdigit(c int) bool + +// stdio.h +fn C.popen(c &char, t &char) voidptr + +// <execinfo.h> +fn C.backtrace(a &voidptr, size int) int + +fn C.backtrace_symbols(a &voidptr, size int) &&char + +fn C.backtrace_symbols_fd(a &voidptr, size int, fd int) + +// <libproc.h> +pub fn proc_pidpath(int, voidptr, int) int + +fn C.realpath(&char, &char) &char + +// fn C.chmod(byteptr, mode_t) int +fn C.chmod(&char, u32) int + +fn C.printf(&char, ...voidptr) int + +fn C.puts(&char) int + +fn C.fputs(str &char, stream &C.FILE) int + +fn C.fflush(&C.FILE) int + +// TODO define args in these functions +fn C.fseek(stream &C.FILE, offset int, whence int) int + +fn C.fopen(filename &char, mode &char) &C.FILE + +fn C.fileno(&C.FILE) int + +fn C.fread(ptr voidptr, item_size size_t, items size_t, stream &C.FILE) size_t + +fn C.fwrite(ptr voidptr, item_size size_t, items size_t, stream &C.FILE) size_t + +fn C.fclose(stream &C.FILE) int + +fn C.pclose(stream &C.FILE) int + +// process execution, os.process: +[trusted] +fn C.getpid() int + +fn C.getuid() int + +fn C.geteuid() int + +fn C.system(cmd &char) int + +fn C.posix_spawn(child_pid &int, path &char, file_actions voidptr, attrp voidptr, argv &&char, envp &&char) int + +fn C.posix_spawnp(child_pid &int, exefile &char, file_actions voidptr, attrp voidptr, argv &&char, envp &&char) int + +fn C.execve(cmd_path &char, args voidptr, envs voidptr) int + +fn C.execvp(cmd_path &char, args &&char) int + +fn C._execve(cmd_path &char, args voidptr, envs voidptr) int + +fn C._execvp(cmd_path &char, args &&char) int + +[trusted] +fn C.fork() int + +fn C.wait(status &int) int + +fn C.waitpid(pid int, status &int, options int) int + +[trusted] +fn C.kill(pid int, sig int) int + +fn C.setenv(&char, &char, int) int + +fn C.unsetenv(&char) int + +fn C.access(path &char, amode int) int + +fn C.remove(filename &char) int + +fn C.rmdir(path &char) int + +fn C.chdir(path &char) int + +fn C.rewind(stream &C.FILE) int + +fn C.stat(&char, voidptr) int + +fn C.lstat(path &char, buf &C.stat) int + +fn C.rename(old_filename &char, new_filename &char) int + +fn C.fgets(str &char, n int, stream &C.FILE) int + +fn C.memset(str voidptr, c int, n size_t) int + +[trusted] +fn C.sigemptyset() int + +fn C.getcwd(buf &char, size size_t) &char + +[trusted] +fn C.mktime() int + +fn C.gettimeofday(tv &C.timeval, tz &C.timezone) int + +[trusted] +fn C.sleep(seconds u32) u32 + +// fn C.usleep(usec useconds_t) int +[trusted] +fn C.usleep(usec u32) int + +fn C.opendir(&char) voidptr + +fn C.closedir(dirp &C.DIR) int + +// fn C.mkdir(path &char, mode mode_t) int +fn C.mkdir(path &char, mode u32) int + +// C.rand returns a pseudorandom integer from 0 (inclusive) to C.RAND_MAX (exclusive) +[trusted] +fn C.rand() int + +// C.srand seeds the internal PRNG with the given value. +[trusted] +fn C.srand(seed u32) + +fn C.atof(str &char) f64 + +[trusted] +fn C.tolower(c int) int + +[trusted] +fn C.toupper(c int) int + +[trusted] +fn C.getchar() int + +[trusted] +fn C.strerror(int) &char + +fn C.snprintf(str &char, size size_t, format &char, opt ...voidptr) int + +fn C.fprintf(voidptr, &char, ...voidptr) + +[trusted] +fn C.WIFEXITED(status int) bool + +[trusted] +fn C.WEXITSTATUS(status int) int + +[trusted] +fn C.WIFSIGNALED(status int) bool + +[trusted] +fn C.WTERMSIG(status int) int + +[trusted] +fn C.isatty(fd int) int + +fn C.syscall(number int, va ...voidptr) int + +fn C.sysctl(name &int, namelen u32, oldp voidptr, oldlenp voidptr, newp voidptr, newlen size_t) int + +[trusted] +fn C._fileno(int) int + +fn C._get_osfhandle(fd int) C.intptr_t + +fn C.GetModuleFileName(hModule voidptr, lpFilename &u16, nSize u32) int + +fn C.GetModuleFileNameW(hModule voidptr, lpFilename &u16, nSize u32) u32 + +fn C.CreateFile(lpFilename &u16, dwDesiredAccess u32, dwShareMode u32, lpSecurityAttributes &u16, dwCreationDisposition u32, dwFlagsAndAttributes u32, hTemplateFile voidptr) voidptr + +fn C.CreateFileW(lpFilename &u16, dwDesiredAccess u32, dwShareMode u32, lpSecurityAttributes &u16, dwCreationDisposition u32, dwFlagsAndAttributes u32, hTemplateFile voidptr) u32 + +fn C.GetFinalPathNameByHandleW(hFile voidptr, lpFilePath &u16, nSize u32, dwFlags u32) int + +fn C.CreatePipe(hReadPipe &voidptr, hWritePipe &voidptr, lpPipeAttributes voidptr, nSize u32) bool + +fn C.SetHandleInformation(hObject voidptr, dwMask u32, dw_flags u32) bool + +fn C.ExpandEnvironmentStringsW(lpSrc &u16, lpDst &u16, nSize u32) u32 + +fn C.GetComputerNameW(&u16, &u32) bool + +fn C.GetUserNameW(&u16, &u32) bool + +[trusted] +fn C.SendMessageTimeout() u32 + +fn C.SendMessageTimeoutW(hWnd voidptr, Msg u32, wParam &u16, lParam &u32, fuFlags u32, uTimeout u32, lpdwResult &u64) u32 + +fn C.CreateProcessW(lpApplicationName &u16, lpCommandLine &u16, lpProcessAttributes voidptr, lpThreadAttributes voidptr, bInheritHandles bool, dwCreationFlags u32, lpEnvironment voidptr, lpCurrentDirectory &u16, lpStartupInfo voidptr, lpProcessInformation voidptr) bool + +fn C.ReadFile(hFile voidptr, lpBuffer voidptr, nNumberOfBytesToRead u32, lpNumberOfBytesRead C.LPDWORD, lpOverlapped voidptr) bool + +fn C.GetFileAttributesW(lpFileName &byte) u32 + +fn C.RegQueryValueEx(hKey voidptr, lpValueName &u16, lp_reserved &u32, lpType &u32, lpData &byte, lpcbData &u32) voidptr + +fn C.RegQueryValueExW(hKey voidptr, lpValueName &u16, lp_reserved &u32, lpType &u32, lpData &byte, lpcbData &u32) int + +fn C.RegOpenKeyEx(hKey voidptr, lpSubKey &u16, ulOptions u32, samDesired u32, phkResult voidptr) voidptr + +fn C.RegOpenKeyExW(hKey voidptr, lpSubKey &u16, ulOptions u32, samDesired u32, phkResult voidptr) int + +fn C.RegSetValueEx() voidptr + +fn C.RegSetValueExW(hKey voidptr, lpValueName &u16, Reserved u32, dwType u32, lpData &byte, lpcbData u32) int + +fn C.RegCloseKey(hKey voidptr) + +fn C.RemoveDirectory(lpPathName &u16) int + +// fn C.GetStdHandle() voidptr +fn C.GetStdHandle(u32) voidptr + +// fn C.SetConsoleMode() +fn C.SetConsoleMode(voidptr, u32) int + +// fn C.GetConsoleMode() int +fn C.GetConsoleMode(voidptr, &u32) int + +[trusted] +fn C.GetCurrentProcessId() int + +fn C.wprintf() + +// fn C.setbuf() +fn C.setbuf(voidptr, &char) + +fn C.SymCleanup(hProcess voidptr) + +fn C.MultiByteToWideChar(codePage u32, dwFlags u32, lpMultiMyteStr &char, cbMultiByte int, lpWideCharStr &u16, cchWideChar int) int + +fn C.wcslen(str &u16) int + +fn C.WideCharToMultiByte(codePage u32, dwFlags u32, lpWideCharStr &u16, cchWideChar int, lpMultiByteStr &char, cbMultiByte int, lpDefaultChar &char, lpUsedDefaultChar &int) int + +fn C._wstat(path &u16, buffer &C._stat) int + +fn C._wrename(oldname &u16, newname &u16) int + +fn C._wfopen(filename &u16, mode &u16) voidptr + +fn C._wpopen(command &u16, mode &u16) voidptr + +fn C._pclose(stream &C.FILE) int + +fn C._wsystem(command &u16) int + +fn C._wgetenv(varname &u16) voidptr + +fn C._putenv(envstring &char) int + +fn C._waccess(path &u16, mode int) int + +fn C._wremove(path &u16) int + +fn C.ReadConsole(in_input_handle voidptr, out_buffer voidptr, in_chars_to_read u32, out_read_chars &u32, in_input_control voidptr) bool + +fn C.WriteConsole() voidptr + +fn C.WriteFile() voidptr + +fn C._wchdir(dirname &u16) + +fn C._wgetcwd(buffer &u16, maxlen int) int + +fn C._fullpath() int + +fn C.GetFullPathName(voidptr, u32, voidptr, voidptr) u32 + +[trusted] +fn C.GetCommandLine() voidptr + +fn C.LocalFree() + +fn C.FindFirstFileW(lpFileName &u16, lpFindFileData voidptr) voidptr + +fn C.FindFirstFile(lpFileName &byte, lpFindFileData voidptr) voidptr + +fn C.FindNextFile(hFindFile voidptr, lpFindFileData voidptr) int + +fn C.FindClose(hFindFile voidptr) + +// macro +fn C.MAKELANGID(lgid voidptr, srtid voidptr) int + +fn C.FormatMessage(dwFlags u32, lpSource voidptr, dwMessageId u32, dwLanguageId u32, lpBuffer voidptr, nSize int, Arguments ...voidptr) voidptr + +fn C.CloseHandle(voidptr) int + +fn C.GetExitCodeProcess(hProcess voidptr, lpExitCode &u32) + +[trusted] +fn C.GetTickCount() i64 + +[trusted] +fn C.Sleep(dwMilliseconds u32) + +fn C.WSAStartup(u16, &voidptr) int + +fn C.WSAGetLastError() int + +fn C.closesocket(int) int + +fn C.vschannel_init(&C.TlsContext) + +fn C.request(&C.TlsContext, int, &u16, &byte, &&byte) int + +fn C.vschannel_cleanup(&C.TlsContext) + +fn C.URLDownloadToFile(int, &u16, &u16, int, int) + +fn C.GetLastError() u32 + +fn C.CreateDirectory(&byte, int) bool + +// win crypto +fn C.BCryptGenRandom(int, voidptr, int, int) int + +// win synchronization +fn C.CreateMutex(int, bool, &byte) voidptr + +fn C.WaitForSingleObject(voidptr, int) int + +fn C.ReleaseMutex(voidptr) bool + +fn C.CreateEvent(int, bool, bool, &byte) voidptr + +fn C.SetEvent(voidptr) int + +fn C.CreateSemaphore(voidptr, int, int, voidptr) voidptr + +fn C.ReleaseSemaphore(voidptr, int, voidptr) voidptr + +fn C.InitializeSRWLock(voidptr) + +fn C.AcquireSRWLockShared(voidptr) + +fn C.AcquireSRWLockExclusive(voidptr) + +fn C.ReleaseSRWLockShared(voidptr) + +fn C.ReleaseSRWLockExclusive(voidptr) + +// pthread.h +fn C.pthread_mutex_init(voidptr, voidptr) int + +fn C.pthread_mutex_lock(voidptr) int + +fn C.pthread_mutex_unlock(voidptr) int + +fn C.pthread_mutex_destroy(voidptr) int + +fn C.pthread_rwlockattr_init(voidptr) int + +fn C.pthread_rwlockattr_setkind_np(voidptr, int) int + +fn C.pthread_rwlockattr_setpshared(voidptr, int) int + +fn C.pthread_rwlock_init(voidptr, voidptr) int + +fn C.pthread_rwlock_rdlock(voidptr) int + +fn C.pthread_rwlock_wrlock(voidptr) int + +fn C.pthread_rwlock_unlock(voidptr) int + +fn C.pthread_condattr_init(voidptr) int + +fn C.pthread_condattr_setpshared(voidptr, int) int + +fn C.pthread_condattr_destroy(voidptr) int + +fn C.pthread_cond_init(voidptr, voidptr) int + +fn C.pthread_cond_signal(voidptr) int + +fn C.pthread_cond_wait(voidptr, voidptr) int + +fn C.pthread_cond_timedwait(voidptr, voidptr, voidptr) int + +fn C.pthread_cond_destroy(voidptr) int + +fn C.sem_init(voidptr, int, u32) int + +fn C.sem_post(voidptr) int + +fn C.sem_wait(voidptr) int + +fn C.sem_trywait(voidptr) int + +fn C.sem_timedwait(voidptr, voidptr) int + +fn C.sem_destroy(voidptr) int + +// MacOS semaphore functions +fn C.dispatch_semaphore_create(i64) voidptr + +fn C.dispatch_semaphore_signal(voidptr) i64 + +fn C.dispatch_semaphore_wait(voidptr, u64) i64 + +fn C.dispatch_time(u64, i64) u64 + +fn C.dispatch_release(voidptr) + +// file descriptor based reading/writing +fn C.read(fd int, buf voidptr, count size_t) int + +fn C.write(fd int, buf voidptr, count size_t) int + +fn C.close(fd int) int + +// pipes +fn C.pipe(pipefds &int) int + +fn C.dup2(oldfd int, newfd int) int + +// used by gl, stbi, freetype +fn C.glTexImage2D() + +// used by ios for println +fn C.WrappedNSLog(str &byte) diff --git a/v_windows/v/old/vlib/builtin/chan.v b/v_windows/v/old/vlib/builtin/chan.v new file mode 100644 index 0000000..1692d5f --- /dev/null +++ b/v_windows/v/old/vlib/builtin/chan.v @@ -0,0 +1,32 @@ +module builtin + +// ChanState describes the result of an attempted channel transaction. +pub enum ChanState { +	success +	not_ready // push()/pop() would have to wait, but no_block was requested +	closed +} + +/* +The following methods are only stubs. +The real implementation is in `vlib/sync/channels.v` +*/ + +// close closes the channel for further push transactions. +// closed channels cannot be pushed to, however they can be popped +// from as long as there is still objects available in the channel buffer. +pub fn (ch chan) close() {} + +// try_pop returns `ChanState.success` if an object is popped from the channel. +// try_pop effectively pops from the channel without waiting for objects to become available. +// Both the test and pop transaction is done atomically. +pub fn (ch chan) try_pop(obj voidptr) ChanState { +	return .success +} + +// try_push returns `ChanState.success` if the object is pushed to the channel. +// try_push effectively both push and test if the transaction `ch <- a` succeeded. +// Both the test and push transaction is done atomically. +pub fn (ch chan) try_push(obj voidptr) ChanState { +	return .success +} diff --git a/v_windows/v/old/vlib/builtin/float.v b/v_windows/v/old/vlib/builtin/float.v new file mode 100644 index 0000000..99fe8b8 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/float.v @@ -0,0 +1,205 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license that can be found in the LICENSE file. +module builtin + +import strconv + +#include <float.h> +/* +----------------------------------- +----- f64 to string functions ----- +*/ +// str return a `f64` as `string` in suitable notation. +[inline] +pub fn (x f64) str() string { +	unsafe { +		f := strconv.Float64u{ +			f: x +		} +		if f.u == strconv.double_minus_zero { +			return '-0' +		} +		if f.u == strconv.double_plus_zero { +			return '0' +		} +	} +	abs_x := f64_abs(x) +	if abs_x >= 0.0001 && abs_x < 1.0e6 { +		return strconv.f64_to_str_l(x) +	} else { +		return strconv.ftoa_64(x) +	} +} + +// strg return a `f64` as `string` in "g" printf format +[inline] +pub fn (x f64) strg() string { +	if x == 0 { +		return '0' +	} +	abs_x := f64_abs(x) +	if abs_x >= 0.0001 && abs_x < 1.0e6 { +		return strconv.f64_to_str_l_no_dot(x) +	} else { +		return strconv.ftoa_64(x) +	} +} + +// str returns the value of the `float_literal` as a `string`. +[inline] +pub fn (d float_literal) str() string { +	return f64(d).str() +} + +// strsci returns the `f64` as a `string` in scientific notation with `digit_num` decimals displayed, max 17 digits. +// Example: assert f64(1.234).strsci(3) == '1.234e+00' +[inline] +pub fn (x f64) strsci(digit_num int) string { +	mut n_digit := digit_num +	if n_digit < 1 { +		n_digit = 1 +	} else if n_digit > 17 { +		n_digit = 17 +	} +	return strconv.f64_to_str(x, n_digit) +} + +// strlong returns a decimal notation of the `f64` as a `string`. +// Example: assert f64(1.23456).strlong() == '1.23456' +[inline] +pub fn (x f64) strlong() string { +	return strconv.f64_to_str_l(x) +} + +/* +----------------------------------- +----- f32 to string functions ----- +*/ +// str returns a `f32` as `string` in suitable notation. +[inline] +pub fn (x f32) str() string { +	unsafe { +		f := strconv.Float32u{ +			f: x +		} +		if f.u == strconv.single_minus_zero { +			return '-0' +		} +		if f.u == strconv.single_plus_zero { +			return '0' +		} +	} +	abs_x := f32_abs(x) +	if abs_x >= 0.0001 && abs_x < 1.0e6 { +		return strconv.f32_to_str_l(x) +	} else { +		return strconv.ftoa_32(x) +	} +} + +// strg return a `f32` as `string` in "g" printf format +[inline] +pub fn (x f32) strg() string { +	if x == 0 { +		return '0' +	} +	abs_x := f32_abs(x) +	if abs_x >= 0.0001 && abs_x < 1.0e6 { +		return strconv.f32_to_str_l_no_dot(x) +	} else { +		return strconv.ftoa_32(x) +	} +} + +// strsci returns the `f32` as a `string` in scientific notation with `digit_num` deciamals displayed, max 8 digits. +// Example: assert f32(1.234).strsci(3) == '1.234e+00' +[inline] +pub fn (x f32) strsci(digit_num int) string { +	mut n_digit := digit_num +	if n_digit < 1 { +		n_digit = 1 +	} else if n_digit > 8 { +		n_digit = 8 +	} +	return strconv.f32_to_str(x, n_digit) +} + +// strlong returns a decimal notation of the `f32` as a `string`. +[inline] +pub fn (x f32) strlong() string { +	return strconv.f32_to_str_l(x) +} + +/* +----------------------- +----- C functions ----- +*/ +// f32_abs returns the absolute value of `a` as a `f32` value. +// Example: assert f32_abs(-2.0) == 2.0 +[inline] +pub fn f32_abs(a f32) f32 { +	return if a < 0 { -a } else { a } +} + +// f64_abs returns the absolute value of `a` as a `f64` value. +// Example: assert f64_abs(-2.0) == f64(2.0) +[inline] +fn f64_abs(a f64) f64 { +	return if a < 0 { -a } else { a } +} + +// f32_max returns the largest `f32` of input `a` and `b`. +// Example: assert f32_max(2.0,3.0) == 3.0 +[inline] +pub fn f32_max(a f32, b f32) f32 { +	return if a > b { a } else { b } +} + +// f32_min returns the smallest `f32` of input `a` and `b`. +// Example: assert f32_min(2.0,3.0) == 2.0 +[inline] +pub fn f32_min(a f32, b f32) f32 { +	return if a < b { a } else { b } +} + +// f64_max returns the largest `f64` of input `a` and `b`. +// Example: assert f64_max(2.0,3.0) == 3.0 +[inline] +pub fn f64_max(a f64, b f64) f64 { +	return if a > b { a } else { b } +} + +// f64_min returns the smallest `f64` of input `a` and `b`. +// Example: assert f64_min(2.0,3.0) == 2.0 +[inline] +fn f64_min(a f64, b f64) f64 { +	return if a < b { a } else { b } +} + +// eq_epsilon returns true if the `f32` is equal to input `b`. +// using an epsilon of typically 1E-5 or higher (backend/compiler dependent). +// Example: assert f32(2.0).eq_epsilon(2.0) +[inline] +pub fn (a f32) eq_epsilon(b f32) bool { +	hi := f32_max(f32_abs(a), f32_abs(b)) +	delta := f32_abs(a - b) +	if hi > f32(1.0) { +		return delta <= hi * (4 * f32(C.FLT_EPSILON)) +	} else { +		return (1 / (4 * f32(C.FLT_EPSILON))) * delta <= hi +	} +} + +// eq_epsilon returns true if the `f64` is equal to input `b`. +// using an epsilon of typically 1E-9 or higher (backend/compiler dependent). +// Example: assert f64(2.0).eq_epsilon(2.0) +[inline] +pub fn (a f64) eq_epsilon(b f64) bool { +	hi := f64_max(f64_abs(a), f64_abs(b)) +	delta := f64_abs(a - b) +	if hi > 1.0 { +		return delta <= hi * (4 * f64(C.DBL_EPSILON)) +	} else { +		return (1 / (4 * f64(C.DBL_EPSILON))) * delta <= hi +	} +} diff --git a/v_windows/v/old/vlib/builtin/float_test.v b/v_windows/v/old/vlib/builtin/float_test.v new file mode 100644 index 0000000..cad2799 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/float_test.v @@ -0,0 +1,147 @@ +fn test_float_decl() { +	// z := 1f +	// assert z > 0 +	x1 := 1e10 +	x2 := -2e16 +	x3 := 1e-15 +	x4 := -9e-4 +	assert typeof(x1).name == 'f64' +	assert typeof(x2).name == 'f64' +	assert typeof(x3).name == 'f64' +	assert typeof(x4).name == 'f64' +	x5 := 4e108 +	x6 := -7e99 +	x7 := 3e-205 +	x8 := -6e-147 +	assert typeof(x5).name == 'f64' +	assert typeof(x6).name == 'f64' +	assert typeof(x7).name == 'f64' +	assert typeof(x8).name == 'f64' +	x9 := 312874834.77 +	x10 := -22399994.06 +	x11 := 0.0000000019 +	x12 := -0.00000000008 +	assert typeof(x9).name == 'f64' +	assert typeof(x10).name == 'f64' +	assert typeof(x11).name == 'f64' +	assert typeof(x12).name == 'f64' +	x13 := 34234234809890890898903213154353453453253253243432413232228908902183918392183902432432438980380123021983901392183921389083913890389089031.0 +	x14 := -39999999999999999999222212128182813294989082302832183928343325325233253242312331324392839238239829389038097438248932789371837218372837293.8 +	x15 := 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002 +	x16 := -0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004 +	assert typeof(x13).name == 'f64' +	assert typeof(x14).name == 'f64' +	assert typeof(x15).name == 'f64' +	assert typeof(x16).name == 'f64' +} + +fn test_f32_equal_operator() { +	b := f32(1.0) +	mut a := f32(1.0) +	a += 0.0000019073486328125 +	assert a != b +	a -= 0.0000019073486328125 +	assert a == b +	assert -1 == 1 * -1 +	assert -1.0 == 1.0 * -1.0 +	a = 1 +	a += 0.0000019073486328125 +	a -= 0.0000019073486328125 +	assert a == f32(1.0) +	a += 0.000001 +	assert !(a < f32(1)) +	assert !(a <= f32(1)) +	assert a > f32(1) +	assert a >= 1 +	assert a != 1 +	f := 1.2 +	ab := int(f) +	assert ab == 1 +	e := f32(-1.602176634e-19) +	m := f32(9.1093837015e-31) +	assert e < m +	assert e <= m +	assert e != m +	assert !(e == m) +	assert m >= e +	assert m > e +} + +fn test_f64_equal_operator() { +	b := 1.0 +	mut a := 1.0 +	a += 0.0000019073486328125 +	assert a != b +	a -= 0.0000019073486328125 +	assert a == b +	e := -1.602176634e-19 +	m := 9.1093837015e-31 +	assert e < m +	assert e <= m +	assert e != m +	assert !(e == m) +	assert m >= e +	assert m > e +} + +fn test_f64_eq_epsilon() { +	a := 1.662248544459347e308 +	b := 1.662248544459348e308 +	x := 1.662248544459352e308 +	assert a != b +	assert a.eq_epsilon(b) +	assert b.eq_epsilon(a) +	assert (-a).eq_epsilon(-b) +	assert (-b).eq_epsilon(-a) +	assert !a.eq_epsilon(x) +	assert !x.eq_epsilon(a) +	assert !a.eq_epsilon(-b) +	assert !(-a).eq_epsilon(b) +	c := 1.5367748374385438503 +	d := -1.5367748374385447257 +	z := 1.5367748378943546 +	assert c != -d +	assert c.eq_epsilon(-d) +	assert d.eq_epsilon(-c) +	assert !c.eq_epsilon(z) +	assert !z.eq_epsilon(c) +	e := 2.531434251587394233e-308 +	f := 2.531434251587395675e-308 +	y := 2.531434251587398934e-308 +	assert e != f +	assert e.eq_epsilon(f) +	assert (-f).eq_epsilon(-e) +	assert !e.eq_epsilon(y) +	assert !(-y).eq_epsilon(-e) +} + +fn test_f32_eq_epsilon() { +	a := f32(3.244331e38) +	b := f32(3.244332e38) +	x := f32(3.244338e38) +	assert a != b +	assert a.eq_epsilon(b) +	assert b.eq_epsilon(a) +	assert (-a).eq_epsilon(-b) +	assert (-b).eq_epsilon(-a) +	assert !a.eq_epsilon(x) +	assert !(-x).eq_epsilon(-a) +	assert !a.eq_epsilon(-b) +	assert !(-a).eq_epsilon(b) +	c := f32(0.9546742) +	d := f32(-0.9546745) +	z := f32(0.9546754) +	assert c != -d +	assert c.eq_epsilon(-d) +	assert d.eq_epsilon(-c) +	assert !c.eq_epsilon(z) +	assert !z.eq_epsilon(c) +	e := f32(-1.5004390e-38) +	f := f32(-1.5004395e-38) +	y := f32(-1.5004409e-38) +	assert e != f +	assert e.eq_epsilon(f) +	assert (-f).eq_epsilon(-e) +	assert !e.eq_epsilon(y) +	assert !(-y).eq_epsilon(-e) +} diff --git a/v_windows/v/old/vlib/builtin/float_x64.v b/v_windows/v/old/vlib/builtin/float_x64.v new file mode 100644 index 0000000..4a491a0 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/float_x64.v @@ -0,0 +1,6 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license that can be found in the LICENSE file. +module builtin + +fn float_test() { +} diff --git a/v_windows/v/old/vlib/builtin/int.v b/v_windows/v/old/vlib/builtin/int.v new file mode 100644 index 0000000..9c769d9 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/int.v @@ -0,0 +1,479 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module builtin + +// +// ----- value to string functions ----- +// + +type u8 = byte + +// ptr_str returns the address of `ptr` as a `string`. +pub fn ptr_str(ptr voidptr) string { +	buf1 := u64(ptr).hex() +	return buf1 +} + +pub fn (x size_t) str() string { +	return u64(x).str() +} + +pub fn (cptr &char) str() string { +	return u64(cptr).hex() +} + +const ( +	// digit pairs in reverse order +	digit_pairs = '00102030405060708090011121314151617181910212223242526272829203132333435363738393041424344454647484940515253545556575859506162636465666768696071727374757677787970818283848586878889809192939495969798999' +) + +// This implementation is the quickest with gcc -O2 +// str_l returns the string representation of the integer nn with max chars. +[direct_array_access; inline] +fn (nn int) str_l(max int) string { +	unsafe { +		mut n := i64(nn) +		mut d := 0 +		if n == 0 { +			return '0' +		} + +		mut is_neg := false +		if n < 0 { +			n = -n +			is_neg = true +		} +		mut index := max +		mut buf := malloc_noscan(max + 1) +		buf[index] = 0 +		index-- + +		for n > 0 { +			n1 := int(n / 100) +			// calculate the digit_pairs start index +			d = ((int(n) - (n1 * 100)) << 1) +			n = n1 +			buf[index] = digit_pairs.str[d] +			index-- +			d++ +			buf[index] = digit_pairs.str[d] +			index-- +		} +		index++ +		// remove head zero +		if d < 20 { +			index++ +		} +		// Prepend - if it's negative +		if is_neg { +			index-- +			buf[index] = `-` +		} +		diff := max - index +		C.memmove(buf, buf + index, diff + 1) +		/* +		// === manual memory move for bare metal === +		mut c:= 0 +		for c < diff { +			buf[c] = buf[c+index] +			c++ +		} +		buf[c] = 0 +		*/ +		return tos(buf, diff) + +		// return tos(memdup(&buf[0] + index, (max - index)), (max - index)) +	} +} + +// str returns the value of the `i8` as a `string`. +// Example: assert i8(-2).str() == '-2' +pub fn (n i8) str() string { +	return int(n).str_l(5) +} + +// str returns the value of the `i16` as a `string`. +// Example: assert i16(-20).str() == '-20' +pub fn (n i16) str() string { +	return int(n).str_l(7) +} + +// str returns the value of the `u16` as a `string`. +// Example: assert u16(20).str() == '20' +pub fn (n u16) str() string { +	return int(n).str_l(7) +} + +// str returns the value of the `int` as a `string`. +// Example: assert int(-2020).str() == '-2020' +pub fn (n int) str() string { +	return n.str_l(12) +} + +// str returns the value of the `u32` as a `string`. +// Example: assert u32(20000).str() == '20000' +[direct_array_access; inline] +pub fn (nn u32) str() string { +	unsafe { +		mut n := nn +		mut d := u32(0) +		if n == 0 { +			return '0' +		} +		max := 12 +		mut buf := malloc_noscan(max + 1) +		mut index := max +		buf[index] = 0 +		index-- +		for n > 0 { +			n1 := n / u32(100) +			d = ((n - (n1 * u32(100))) << u32(1)) +			n = n1 +			buf[index] = digit_pairs[d] +			index-- +			d++ +			buf[index] = digit_pairs[d] +			index-- +		} +		index++ +		// remove head zero +		if d < u32(20) { +			index++ +		} +		diff := max - index +		C.memmove(buf, buf + index, diff + 1) +		return tos(buf, diff) + +		// return tos(memdup(&buf[0] + index, (max - index)), (max - index)) +	} +} + +// str returns the value of the `int_literal` as a `string`. +[inline] +pub fn (n int_literal) str() string { +	return i64(n).str() +} + +// str returns the value of the `i64` as a `string`. +// Example: assert i64(-200000).str() == '-200000' +[direct_array_access; inline] +pub fn (nn i64) str() string { +	unsafe { +		mut n := nn +		mut d := i64(0) +		if n == 0 { +			return '0' +		} +		max := 20 +		mut buf := malloc_noscan(max + 1) +		mut is_neg := false +		if n < 0 { +			n = -n +			is_neg = true +		} +		mut index := max +		buf[index] = 0 +		index-- +		for n > 0 { +			n1 := n / i64(100) +			d = ((n - (n1 * i64(100))) << i64(1)) +			n = n1 +			buf[index] = digit_pairs[d] +			index-- +			d++ +			buf[index] = digit_pairs[d] +			index-- +		} +		index++ +		// remove head zero +		if d < i64(20) { +			index++ +		} +		// Prepend - if it's negative +		if is_neg { +			index-- +			buf[index] = `-` +		} +		diff := max - index +		C.memmove(buf, buf + index, diff + 1) +		return tos(buf, diff) +		// return tos(memdup(&buf[0] + index, (max - index)), (max - index)) +	} +} + +// str returns the value of the `u64` as a `string`. +// Example: assert u64(2000000).str() == '2000000' +[direct_array_access; inline] +pub fn (nn u64) str() string { +	unsafe { +		mut n := nn +		mut d := u64(0) +		if n == 0 { +			return '0' +		} +		max := 20 +		mut buf := malloc_noscan(max + 1) +		mut index := max +		buf[index] = 0 +		index-- +		for n > 0 { +			n1 := n / 100 +			d = ((n - (n1 * 100)) << 1) +			n = n1 +			buf[index] = digit_pairs[d] +			index-- +			d++ +			buf[index] = digit_pairs[d] +			index-- +		} +		index++ +		// remove head zero +		if d < 20 { +			index++ +		} +		diff := max - index +		C.memmove(buf, buf + index, diff + 1) +		return tos(buf, diff) +		// return tos(memdup(&buf[0] + index, (max - index)), (max - index)) +	} +} + +// str returns the value of the `bool` as a `string`. +// Example: assert (2 > 1).str() == 'true' +pub fn (b bool) str() string { +	if b { +		return 'true' +	} +	return 'false' +} + +// +// ----- value to hex string functions ----- +// + +// u64_to_hex converts the number `nn` to a (zero padded if necessary) hexadecimal `string`. +[direct_array_access; inline] +fn u64_to_hex(nn u64, len byte) string { +	mut n := nn +	mut buf := [256]byte{} +	buf[len] = 0 +	mut i := 0 +	for i = len - 1; i >= 0; i-- { +		d := byte(n & 0xF) +		x := if d < 10 { d + `0` } else { d + 87 } +		buf[i] = x +		n = n >> 4 +	} +	return unsafe { tos(memdup(&buf[0], len + 1), len) } +} + +// u64_to_hex_no_leading_zeros converts the number `nn` to hexadecimal `string`. +[direct_array_access; inline] +fn u64_to_hex_no_leading_zeros(nn u64, len byte) string { +	mut n := nn +	mut buf := [256]byte{} +	buf[len] = 0 +	mut i := 0 +	for i = len - 1; i >= 0; i-- { +		d := byte(n & 0xF) +		x := if d < 10 { d + `0` } else { d + 87 } +		buf[i] = x +		n = n >> 4 +		if n == 0 { +			break +		} +	} +	res_len := len - i +	return unsafe { tos(memdup(&buf[i], res_len + 1), res_len) } +} + +// hex returns the value of the `byte` as a hexadecimal `string`. +// Note that the output is zero padded for values below 16. +// Example: assert byte(2).hex() == '02' +// Example: assert byte(15).hex() == '0f' +// Example: assert byte(255).hex() == 'ff' +pub fn (nn byte) hex() string { +	if nn == 0 { +		return '00' +	} +	return u64_to_hex(nn, 2) +} + +// hex returns the value of the `i8` as a hexadecimal `string`. +// Note that the output is zero padded for values below 16. +// Example: assert i8(8).hex() == '08' +// Example: assert i8(10).hex() == '0a' +// Example: assert i8(15).hex() == '0f' +pub fn (nn i8) hex() string { +	return byte(nn).hex() +} + +// hex returns the value of the `u16` as a hexadecimal `string`. +// Note that the output is ***not*** zero padded. +// Example: assert u16(2).hex() == '2' +// Example: assert u16(200).hex() == 'c8' +pub fn (nn u16) hex() string { +	if nn == 0 { +		return '0' +	} +	return u64_to_hex_no_leading_zeros(nn, 4) +} + +// hex returns the value of the `i16` as a hexadecimal `string`. +// Note that the output is ***not*** zero padded. +// Example: assert i16(2).hex() == '2' +// Example: assert i16(200).hex() == 'c8' +pub fn (nn i16) hex() string { +	return u16(nn).hex() +} + +// hex returns the value of the `u32` as a hexadecimal `string`. +// Note that the output is ***not*** zero padded. +// Example: assert u32(2).hex() == '2' +// Example: assert u32(200).hex() == 'c8' +pub fn (nn u32) hex() string { +	if nn == 0 { +		return '0' +	} +	return u64_to_hex_no_leading_zeros(nn, 8) +} + +// hex returns the value of the `int` as a hexadecimal `string`. +// Note that the output is ***not*** zero padded. +// Example: assert int(2).hex() == '2' +// Example: assert int(200).hex() == 'c8' +pub fn (nn int) hex() string { +	return u32(nn).hex() +} + +// hex2 returns the value of the `int` as a `0x`-prefixed hexadecimal `string`. +// Note that the output after `0x` is ***not*** zero padded. +// Example: assert int(8).hex2() == '0x8' +// Example: assert int(15).hex2() == '0xf' +// Example: assert int(18).hex2() == '0x12' +pub fn (n int) hex2() string { +	return '0x' + n.hex() +} + +// hex returns the value of the `u64` as a hexadecimal `string`. +// Note that the output is ***not*** zero padded. +// Example: assert u64(2).hex() == '2' +// Example: assert u64(2000).hex() == '7d0' +pub fn (nn u64) hex() string { +	if nn == 0 { +		return '0' +	} +	return u64_to_hex_no_leading_zeros(nn, 16) +} + +// hex returns the value of the `i64` as a hexadecimal `string`. +// Note that the output is ***not*** zero padded. +// Example: assert i64(2).hex() == '2' +// Example: assert i64(-200).hex() == 'ffffffffffffff38' +// Example: assert i64(2021).hex() == '7e5' +pub fn (nn i64) hex() string { +	return u64(nn).hex() +} + +// hex returns the value of the `int_literal` as a hexadecimal `string`. +// Note that the output is ***not*** zero padded. +pub fn (nn int_literal) hex() string { +	return u64(nn).hex() +} + +// hex returns the value of the `voidptr` as a hexadecimal `string`. +// Note that the output is ***not*** zero padded. +pub fn (nn voidptr) str() string { +	return u64(nn).hex() +} + +// hex returns the value of the `byteptr` as a hexadecimal `string`. +// Note that the output is ***not*** zero padded. +// pub fn (nn byteptr) str() string { +pub fn (nn byteptr) str() string { +	return u64(nn).hex() +} + +pub fn (nn byte) hex_full() string { +	return u64_to_hex(u64(nn), 2) +} + +pub fn (nn i8) hex_full() string { +	return u64_to_hex(u64(nn), 2) +} + +pub fn (nn u16) hex_full() string { +	return u64_to_hex(u64(nn), 4) +} + +pub fn (nn i16) hex_full() string { +	return u64_to_hex(u64(nn), 4) +} + +pub fn (nn u32) hex_full() string { +	return u64_to_hex(u64(nn), 8) +} + +pub fn (nn int) hex_full() string { +	return u64_to_hex(u64(nn), 8) +} + +pub fn (nn i64) hex_full() string { +	return u64_to_hex(u64(nn), 16) +} + +pub fn (nn voidptr) hex_full() string { +	return u64_to_hex(u64(nn), 16) +} + +pub fn (nn int_literal) hex_full() string { +	return u64_to_hex(u64(nn), 16) +} + +// hex_full returns the value of the `u64` as a *full* 16-digit hexadecimal `string`. +// Example: assert u64(2).hex_full() == '0000000000000002' +// Example: assert u64(255).hex_full() == '00000000000000ff' +pub fn (nn u64) hex_full() string { +	return u64_to_hex(nn, 16) +} + +// str returns the contents of `byte` as a zero terminated `string`. +// Example: assert byte(111).str() == '111' +pub fn (b byte) str() string { +	return int(b).str_l(7) +} + +// ascii_str returns the contents of `byte` as a zero terminated ASCII `string` character. +// Example: assert byte(97).ascii_str() == 'a' +pub fn (b byte) ascii_str() string { +	mut str := string{ +		str: unsafe { malloc_noscan(2) } +		len: 1 +	} +	unsafe { +		str.str[0] = b +		str.str[1] = 0 +	} +	// println(str) +	return str +} + +// str_escaped returns the contents of `byte` as an escaped `string`. +// Example: assert byte(0).str_escaped() == r'`\0`' +pub fn (b byte) str_escaped() string { +	str := match b { +		0 { r'`\0`' } +		7 { r'`\a`' } +		8 { r'`\b`' } +		9 { r'`\t`' } +		10 { r'`\n`' } +		11 { r'`\v`' } +		12 { r'`\f`' } +		13 { r'`\r`' } +		27 { r'`\e`' } +		32...126 { b.ascii_str() } +		else { '0x' + b.hex() } +	} +	return str +} diff --git a/v_windows/v/old/vlib/builtin/int_test.v b/v_windows/v/old/vlib/builtin/int_test.v new file mode 100644 index 0000000..900cf27 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/int_test.v @@ -0,0 +1,230 @@ +const ( +	a = 3 +	u = u64(1) +) + +fn test_const() { +	b := (true && true) || false +	assert b == true +	assert a == 3 +	assert u == u64(1) +	assert u == 1 // make sure this works without the cast +} + +fn test_str_methods() { +	assert i8(1).str() == '1' +	assert i8(-1).str() == '-1' +	assert i16(1).str() == '1' +	assert i16(-1).str() == '-1' +	assert int(1).str() == '1' +	assert int(-1).str() == '-1' +	assert int(2147483647).str() == '2147483647' +	assert int(2147483648).str() == '-2147483648' +	assert int(-2147483648).str() == '-2147483648' +	assert i64(1).str() == '1' +	assert i64(-1).str() == '-1' +	// assert byte(1).str() == '1' +	// assert byte(-1).str() == '255' +	assert u16(1).str() == '1' +	assert u16(-1).str() == '65535' +	assert u32(1).str() == '1' +	assert u32(-1).str() == '4294967295' +	assert u64(1).str() == '1' +	assert u64(-1).str() == '18446744073709551615' +	assert voidptr(-1).str() == 'ffffffffffffffff' +	assert voidptr(1).str() == '1' +	assert byteptr(-1).str() == 'ffffffffffffffff' +	assert byteptr(1).str() == '1' +} + +fn test_and_precendence() { +	assert (2 & 0 == 0) == ((2 & 0) == 0) +	assert (2 & 0 != 0) == ((2 & 0) != 0) +	assert (0 & 0 >= 0) == ((0 & 0) >= 0) +	assert (0 & 0 <= 0) == ((0 & 0) <= 0) +	assert (0 & 0 < 1) == ((0 & 0) < 1) +	assert (1 & 2 > 0) == ((1 & 2) > 0) +} + +fn test_or_precendence() { +	assert (1 | 0 == 0) == ((1 | 0) == 0) +	assert (1 | 0 != 1) == ((1 | 0) != 1) +	assert (1 | 0 >= 2) == ((1 | 0) >= 2) +	assert (1 | 0 <= 0) == ((1 | 0) <= 0) +	assert (1 | 0 < 0) == ((1 | 0) < 0) +	assert (1 | 0 > 1) == ((1 | 0) > 1) +} + +fn test_xor_precendence() { +	assert (1 ^ 0 == 2) == ((1 ^ 0) == 2) +	assert (1 ^ 0 != 2) == ((1 ^ 0) != 2) +	assert (1 ^ 0 >= 0) == ((1 ^ 0) >= 0) +	assert (1 ^ 0 <= 1) == ((1 ^ 0) <= 1) +	assert (1 ^ 0 < 0) == ((1 ^ 0) < 0) +	assert (1 ^ 0 > 1) == ((1 ^ 0) > 1) +} + +fn test_left_shift_precendence() { +	assert (2 << 4 | 3) == ((2 << 4) | 3) +	assert (2 << 4 | 3) != (2 << (4 | 3)) +} + +fn test_right_shift_precendence() { +	assert (256 >> 4 | 3) == ((256 >> 4) | 3) +	assert (256 >> 4 | 3) != (256 >> (4 | 3)) +} + +fn test_i8_print() { +	b := i8(0) +	println(b) +	c := i16(7) +	println(c) +	d := u16(6) +	println(d) +	assert true +} + +/* +fn test_cmp() { +	assert 1 ≠ 2 +	assert 1 ⩽ 2 +	assert 1 ⩾ 0 +} +*/ +type MyInt = int + +fn test_int_alias() { +	i := MyInt(2) +	assert i + 10 == 12 +} + +fn test_hex() { +	x := u64(10) +	assert x.hex() == 'a' +	b := 1234 +	assert b.hex() == '4d2' +	b1 := -1 +	assert b1.hex() == 'ffffffff' +} + +fn test_bin() { +	x1 := 0b10 +	assert x1 == 2 +	x2 := 0b10101010 +	assert x2 == 0xAA +	x3 := -0b0000001 +	assert x3 == -1 +	x4 := 0b11111111 +	assert x4 == 255 +	x5 := byte(0b11111111) +	assert x5 == 255 +	x6 := char(0b11111111) +	assert int(x6) == -1 +	x7 := 0b0 +	assert x7 == 0 +	x8 := -0b0 +	assert x8 == 0 +} + +fn test_oct() { +	x1 := 0o12 +	assert x1 == 10 +	x2 := 00000o350 +	assert x2 == 232 +	x3 := 000o00073 +	assert x3 == 59 +	x4 := 00000000 +	assert x4 == 0 +	x5 := 00000195 +	assert x5 == 195 +	x6 := -0o744 +	assert x6 == -484 +	x7 := -000o000042 +	assert x7 == -34 +	x8 := -0000112 +	assert x8 == -112 +	x9 := -000 +	assert x9 == 0 +} + +fn test_num_separator() { +	// int +	assert 100_000_0 == 1000000 +	assert -2_23_4_6 == -22346 + +	// bin +	assert 0b0_11 == 3 +	assert -0b0_100 == -4 + +	// oct +	assert 0o1_73 == 123 +	assert -0o17_5 == -125 +	assert -0o175 == -125 + +	// hex +	assert 0xFF == 255 +	assert 0xF_F == 255 + +	// f32 or f64 +	assert 312_2.55 == 3122.55 +	assert 312_2.55 == 3122.55 + +} + +fn test_int_decl() { +	x1 := 0 +	x2 := 1333 +	x3 := -88955 +	x4 := 2000000000 +	x5 := -1999999999 +	assert typeof(x1).name == 'int' +	assert typeof(x2).name == 'int' +	assert typeof(x3).name == 'int' +	assert typeof(x4).name == 'int' +	assert typeof(x5).name == 'int' +	x7 := u64(-321314588900011) +	assert typeof(x7).name == 'u64' +} + +fn test_int_to_hex() { +	// array hex +	st := [byte(`V`), `L`, `A`, `N`, `G`] +	assert st.hex() == '564c414e47' +	assert st.hex().len == 10 +	st1 := [byte(0x41)].repeat(100) +	assert st1.hex() == '41'.repeat(100) +	// --- int to hex tests +	c0 := 12 +	// 8Bit +	assert byte(0).hex() == '00' +	assert byte(c0).hex() == '0c' +	assert i8(c0).hex() == '0c' +	assert byte(127).hex() == '7f' +	assert i8(127).hex() == '7f' +	assert byte(255).hex() == 'ff' +	assert byte(-1).hex() == 'ff' +	// 16bit +	assert u16(0).hex() == '0' +	assert i16(c0).hex() == 'c' +	assert u16(c0).hex() == 'c' +	assert i16(32767).hex() == '7fff' +	assert u16(32767).hex() == '7fff' +	assert i16(-1).hex() == 'ffff' +	assert u16(65535).hex() == 'ffff' +	// 32bit +	assert u32(0).hex() == '0' +	assert c0.hex() == 'c' +	assert u32(c0).hex() == 'c' +	assert 2147483647.hex() == '7fffffff' +	assert u32(2147483647).hex() == '7fffffff' +	assert (-1).hex() == 'ffffffffffffffff' +	assert u32(4294967295).hex() == 'ffffffff' +	// 64 bit +	assert u64(0).hex() == '0' +	assert i64(c0).hex() == 'c' +	assert u64(c0).hex() == 'c' +	assert i64(9223372036854775807).hex() == '7fffffffffffffff' +	assert u64(9223372036854775807).hex() == '7fffffffffffffff' +	assert i64(-1).hex() == 'ffffffffffffffff' +	assert u64(18446744073709551615).hex() == 'ffffffffffffffff' +} diff --git a/v_windows/v/old/vlib/builtin/isnil_test.v b/v_windows/v/old/vlib/builtin/isnil_test.v new file mode 100644 index 0000000..15df9f0 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/isnil_test.v @@ -0,0 +1,19 @@ +fn test_isnil_byteptr() { +	pb := &byte(0) +	assert isnil(pb) +} + +fn test_isnil_voidptr() { +	pv := voidptr(0) +	assert isnil(pv) +} + +fn test_isnil_charptr() { +	pc := &char(0) +	assert isnil(pc) +} + +fn test_isnil_intptr() { +	pi := &int(0) +	assert isnil(pi) +} diff --git a/v_windows/v/old/vlib/builtin/js/array.js.v b/v_windows/v/old/vlib/builtin/js/array.js.v new file mode 100644 index 0000000..a741059 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/js/array.js.v @@ -0,0 +1,195 @@ +module builtin + +struct array { +	arr JS.Array +pub: +	len int +	cap int +} + +#function flatIntoArray(target, source, sourceLength, targetIndex, depth) { +#"use strict"; +# +#for (var sourceIndex = 0; sourceIndex < sourceLength; ++sourceIndex) { +#if (sourceIndex in source) { +#var element = source[sourceIndex]; +#if (depth > 0 && Array.isArray(element)) +#targetIndex = flatIntoArray(target, element, element.length, targetIndex, depth - 1); +#else { +#target[targetIndex] = element; +#++targetIndex; +#} +#} +#} +#return targetIndex; +#} +#function flatArray(target,depth) { +#var array = target +#var length = array.length; +#var depthNum = 1; +# +#if (depth !== undefined) +#depthNum = +depth +# +#var result = [] +# +#flatIntoArray(result, array, length, 0, depthNum); +#return result; +#} + +[unsafe] +pub fn (a array) repeat_to_depth(count int, depth int) array { +	if count < 0 { +		panic('array.repeat: count is negative: $count') +	} +	mut arr := empty_array() +	#let tmp = new Array(a.arr.length * +count); +	#tmp.fill(a.arr); +	# +	#arr.arr = flatArray(tmp,depth+1); + +	return arr +} + +// last returns the last element of the array. +pub fn (a array) last() voidptr { +	mut res := voidptr(0) +	#res = a.arr[a.len-1]; + +	return res +} + +fn (a array) get(ix int) voidptr { +	mut result := voidptr(0) +	#result = a.arr[ix] + +	return result +} + +pub fn (a array) repeat(count int) array { +	unsafe { +		return a.repeat_to_depth(count, 0) +	} +} + +fn empty_array() array { +	mut arr := array{} +	#arr = new array([]) + +	return arr +} + +fn (a &array) set_len(i int) { +	#a.arr.length=i +} + +pub fn (mut a array) sort_with_compare(compare voidptr) { +	#a.arr.sort(compare) +} + +#function $sortComparator(a, b) +#{ +#"use strict"; +#a = a.$toJS(); +#b = b.$toJS(); +# +#if (a > b) return 1; +#if (a < b) return -1; +#return 0; +# +# +#} + +pub fn (mut a array) sort() { +	#a.arr.sort($sortComparator) +} + +pub fn (a array) index(v string) int { +	for i in 0 .. a.len { +		#if (a.arr[i].toString() == v.toString()) + +		{ +			return i +		} +	} +	return -1 +} + +pub fn (a array) slice(start int, end int) array { +	mut result := a +	#result = new array(a.arr.slice(start,end)) + +	return result +} + +pub fn (mut a array) insert(i int, val voidptr) { +	#a.arr.splice(i,0,val) +} + +pub fn (mut a array) insert_many(i int, val voidptr, size int) { +	#a.arr.splice(i,0,...val.slice(0,+size)) +} + +pub fn (mut a array) join(separator string) string { +	mut res := '' +	#res = new builtin.string(a.arr.join(separator +'')); + +	return res +} + +fn (a array) push(val voidptr) { +	#a.arr.push(val) +} + +pub fn (a array) str() string { +	mut res := '' +	#res = new builtin.string(a + '') + +	return res +} + +#array.prototype[Symbol.iterator] = function () { return this.arr[Symbol.iterator](); } +#array.prototype.entries = function () { return this.arr.entries(); } +#array.prototype.map = function(callback) { return new builtin.array(this.arr.map(callback)); } +#array.prototype.filter = function(callback) { return new array(this.arr.filter( function (it) { return (+callback(it)) != 0; } )); } +#Object.defineProperty(array.prototype,'cap',{ get: function () { return this.len; } }) +// delete deletes array element at index `i`. +pub fn (mut a array) delete(i int) { +	a.delete_many(i, 1) +} + +// delete_many deletes `size` elements beginning with index `i` +pub fn (mut a array) delete_many(i int, size int) { +	#a.arr.splice(i.valueOf(),size.valueOf()) +} + +// prepend prepends one value to the array. +pub fn (mut a array) prepend(val voidptr) { +	a.insert(0, val) +} + +// prepend_many prepends another array to this array. +[unsafe] +pub fn (mut a array) prepend_many(val voidptr, size int) { +	unsafe { a.insert_many(0, val, size) } +} + +pub fn (a array) reverse() array { +	mut res := array{} +	#res.arr = Array.from(a.arr).reverse() + +	return res +} + +#array.prototype.$includes = function (elem) { return this.arr.find(function(e) { return vEq(elem,e); }) !== undefined;} + +// reduce executes a given reducer function on each element of the array, +// resulting in a single output value. +pub fn (a array) reduce(iter fn (int, int) int, accum_start int) int { +	mut accum_ := accum_start +	#for (let i of a)  { +	#accum_ = iter(accum_, a.arr[i]) +	#} + +	return accum_ +} diff --git a/v_windows/v/old/vlib/builtin/js/builtin.js.v b/v_windows/v/old/vlib/builtin/js/builtin.js.v new file mode 100644 index 0000000..d763466 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/js/builtin.js.v @@ -0,0 +1,6 @@ +module builtin + +// used to generate JS throw statements. +pub fn js_throw(s any) { +	#throw (s instanceof Error ? s : new Error(s)) +} diff --git a/v_windows/v/old/vlib/builtin/js/builtin.v b/v_windows/v/old/vlib/builtin/js/builtin.v new file mode 100644 index 0000000..86b60ad --- /dev/null +++ b/v_windows/v/old/vlib/builtin/js/builtin.v @@ -0,0 +1,96 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +module builtin + +fn (a any) toString() + +pub fn println(s any) { +	// Quickfix to properly print basic types +	// TODO: Add proper detection code for this +	JS.console.log(s.toString()) +} + +pub fn print(s any) { +	// TODO +	// $if js.node { +	JS.process.stdout.write(s.toString()) +	// } $else { +	//	panic('Cannot `print` in a browser, use `println` instead') +	// } +} + +pub fn eprintln(s any) { +	JS.console.error(s.toString()) +} + +pub fn eprint(s any) { +	// TODO +	// $if js.node { +	JS.process.stderr.write(s.toString()) +	// } $else { +	//	panic('Cannot `eprint` in a browser, use `eprintln` instead') +	// } +} + +// Exits the process in node, and halts execution in the browser +// because `process.exit` is undefined. Workaround for not having +// a 'real' way to exit in the browser. +pub fn exit(c int) { +	JS.process.exit(c) +	js_throw('exit($c)') +} + +pub fn unwrap(opt any) any { +	o := &Option(opt) +	if o.state != 0 { +		js_throw(o.err) +	} +	return opt +} + +pub fn panic(s string) { +	eprintln('V panic: $s') +	exit(1) +} + +struct Option { +	state byte +	err   Error +} + +pub struct Error { +pub: +	msg  string +	code int +} + +pub fn (o Option) str() string { +	if o.state == 0 { +		return 'Option{ ok }' +	} +	if o.state == 1 { +		return 'Option{ none }' +	} +	return 'Option{ error: "$o.err" }' +} + +pub fn error(s string) Option { +	return Option{ +		state: 2 +		err: Error{ +			msg: s +		} +	} +} + +pub fn error_with_code(s string, code int) Option { +	return Option{ +		state: 2 +		err: Error{ +			msg: s +			code: code +		} +	} +} diff --git a/v_windows/v/old/vlib/builtin/js/byte.js.v b/v_windows/v/old/vlib/builtin/js/byte.js.v new file mode 100644 index 0000000..a2508db --- /dev/null +++ b/v_windows/v/old/vlib/builtin/js/byte.js.v @@ -0,0 +1,8 @@ +module builtin + +pub fn (b byte) is_space() bool { +	mut result := false +	#result = /^\s*$/.test(String.fromCharCode(b)) + +	return result +} diff --git a/v_windows/v/old/vlib/builtin/js/int.js.v b/v_windows/v/old/vlib/builtin/js/int.js.v new file mode 100644 index 0000000..08e52a9 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/js/int.js.v @@ -0,0 +1,8 @@ +module builtin + +pub fn (i int) str() string { +	mut res := '' +	#res = new builtin.string( i ) + +	return res +} diff --git a/v_windows/v/old/vlib/builtin/js/jsfns.js.v b/v_windows/v/old/vlib/builtin/js/jsfns.js.v new file mode 100644 index 0000000..277c702 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/js/jsfns.js.v @@ -0,0 +1,125 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +// This file contains JS functions present in both node and the browser. +// They have been ported from their TypeScript definitions. + +module builtin + +pub struct JS.Number {} + +pub struct JS.String { +	length JS.Number +} + +pub struct JS.Boolean {} + +pub struct JS.Array { +	length JS.Number +} + +pub struct JS.Map {} + +// browser: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Error +// node: https://nodejs.org/api/errors.html#errors_class_error +pub struct JS.Error { +pub: +	name    string +	message string +	stack   string +} + +// Type prototype functions +fn (v JS.String) toString() JS.String +fn (v JS.Number) toString() JS.String +fn (v JS.Boolean) toString() JS.String +fn (v JS.Array) toString() JS.String +fn (v JS.Map) toString() JS.String + +// Hack for "`[]JS.String` is not a struct" when returning arr.length or arr.len +// TODO: Fix []JS.String not a struct error +fn native_str_arr_len(arr []JS.String) int { +	len := 0 +	#len = arr.length + +	return len +} + +// Top level functions +fn JS.eval(string) any +fn JS.parseInt(string, f64) JS.Number +fn JS.parseFloat(string) JS.Number +fn JS.isNaN(f64) bool +fn JS.isFinite(f64) bool +fn JS.decodeURI(string) string +fn JS.decodeURIComponent(string) string +fn JS.encodeURI(string) string + +type EncodeURIComponentArg = bool | f64 | string + +fn JS.encodeURIComponent(EncodeURIComponentArg) string +fn JS.escape(string) string +fn JS.unescape(string) string + +// console +fn JS.console.assert(bool, ...any) +fn JS.console.clear() +fn JS.console.count(string) +fn JS.console.countReset(string) +fn JS.console.debug(...any) +fn JS.console.dir(any, any) +fn JS.console.dirxml(...any) +fn JS.console.error(...any) +fn JS.console.exception(string, ...any) +fn JS.console.group(...any) +fn JS.console.groupCollapsed(...any) +fn JS.console.groupEnd() +fn JS.console.info(...any) +fn JS.console.log(...any) +fn JS.console.table(any, []string) +fn JS.console.time(string) +fn JS.console.timeEnd(string) +fn JS.console.timeLog(string, ...any) +fn JS.console.timeStamp(string) +fn JS.console.trace(...any) +fn JS.console.warn(...any) + +// Math +fn JS.Math.abs(f64) f64 +fn JS.Math.acos(f64) f64 +fn JS.Math.asin(f64) f64 +fn JS.Math.atan(f64) f64 +fn JS.Math.atan2(f64, f64) f64 +fn JS.Math.ceil(f64) f64 +fn JS.Math.cos(f64) f64 +fn JS.Math.exp(f64) f64 +fn JS.Math.floor(f64) f64 +fn JS.Math.log(f64) f64 +fn JS.Math.max(...f64) f64 +fn JS.Math.min(...f64) f64 +fn JS.Math.pow(f64, f64) f64 +fn JS.Math.random() f64 +fn JS.Math.round(f64) f64 +fn JS.Math.sin(f64) f64 +fn JS.Math.sqrt(f64) f64 +fn JS.Math.tan(f64) f64 + +// JSON +fn JS.JSON.stringify(any) string +fn JS.JSON.parse(string) any + +// String +fn (v JS.String) slice(a int, b int) JS.String +fn (v JS.String) split(dot JS.String) []JS.String +fn (s JS.String) indexOf(needle JS.String) int +fn (s JS.String) lastIndexOf(needle JS.String) int + +fn (s JS.String) charAt(i int) JS.String +fn (s JS.String) charCodeAt(i int) byte +fn (s JS.String) toUpperCase() JS.String +fn (s JS.String) toLowerCase() JS.String +fn (s JS.String) concat(a JS.String) JS.String +fn (s JS.String) includes(substr JS.String) bool +fn (s JS.String) endsWith(substr JS.String) bool +fn (s JS.String) startsWith(substr JS.String) bool diff --git a/v_windows/v/old/vlib/builtin/js/jsfns_browser.js.v b/v_windows/v/old/vlib/builtin/js/jsfns_browser.js.v new file mode 100644 index 0000000..72daec3 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/js/jsfns_browser.js.v @@ -0,0 +1,59 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +// This file contains JS functions only present in the browser. +// They have been ported from their TypeScript definitions. + +module builtin + +// Window +fn JS.atob(string) string +fn JS.btoa(string) string +fn JS.clearInterval(int) +fn JS.clearTimeout(int) + +// fn JS.createImageBitmap(ImageBitmapSource, ImageBitmapOptions) Promise<ImageBitmap> +// fn JS.createImageBitmap(ImageBitmapSource, int, int, int, int, ImageBitmapOptions) Promise<ImageBitmap> + +// TODO: js async attribute +// [js_async] +// fn JS.fetch(RequestInfo, RequestInit) Promise<Response> +fn JS.queueMicrotask(fn ()) +fn JS.setInterval(any, int, ...any) int +fn JS.setTimeout(any, int, ...any) int + +fn JS.alert(any) +fn JS.blur() +fn JS.captureEvents() +fn JS.close() +fn JS.confirm(string) bool + +// fn JS.departFocus(NavigationReason, FocusNavigationOrigin) +fn JS.focus() + +// fn JS.getComputedStyle(Element, string | null) CSSStyleDeclaration +// fn JS.getMatchedCSSRules(Element, string | null) CSSRuleList +// fn JS.getSelection() Selection | null +// fn JS.matchMedia(string) MediaQueryList +fn JS.moveBy(int, int) +fn JS.moveTo(int, int) +fn JS.msWriteProfilerMark(string) + +// fn JS.open(string, string, string, bool) ?Window +// fn JS.postMessage(any, string, []Transferable) +fn JS.print() +fn JS.prompt(string, string) ?string +fn JS.releaseEvents() +fn JS.resizeBy(int, int) +fn JS.resizeTo(int, int) + +// fn JS.scroll(ScrollToOptions) +fn JS.scroll(int, int) + +// fn JS.scrollBy(ScrollToOptions) +fn JS.scrollBy(int, int) + +// fn JS.scrollTo(ScrollToOptions) +fn JS.scrollTo(int, int) +fn JS.stop() diff --git a/v_windows/v/old/vlib/builtin/js/jsfns_node.js.v b/v_windows/v/old/vlib/builtin/js/jsfns_node.js.v new file mode 100644 index 0000000..6f65629 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/js/jsfns_node.js.v @@ -0,0 +1,31 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +// This file contains JS functions only present in node.js. +// They have been ported from their TypeScript definitions. + +module builtin + +pub struct JS.node_process { +pub: +	arch     string +	argsv    []string +	env      []string +	platform string +	version  string +	// TODO: add all properties +} + +// hack to access  process properties +pub fn js_node_process() JS.node_process { +	#return process + +	return JS.node_process{} +} + +fn JS.process.exit(int) +fn JS.process.stdout.write(string) bool +fn JS.process.stdout.writeln(string) bool +fn JS.process.stderr.write(string) bool +fn JS.process.stderr.writeln(string) bool diff --git a/v_windows/v/old/vlib/builtin/js/map.js.v b/v_windows/v/old/vlib/builtin/js/map.js.v new file mode 100644 index 0000000..894d614 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/js/map.js.v @@ -0,0 +1,16 @@ +module builtin + +struct map { +	m   JS.Map +	len int +} + +// Removes the mapping of a particular key from the map. +[unsafe] +pub fn (mut m map) delete(key voidptr) { +	#m.map.delete(key) +} + +pub fn (m &map) free() {} + +#map.prototype[Symbol.iterator] = function () { return this.map[Symbol.iterator](); } diff --git a/v_windows/v/old/vlib/builtin/js/string.js.v b/v_windows/v/old/vlib/builtin/js/string.js.v new file mode 100644 index 0000000..e7d2708 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/js/string.js.v @@ -0,0 +1,466 @@ +module builtin + +pub struct string { +pub: +	str JS.String +	len int +} + +pub fn (s string) slice(a int, b int) string { +	return string(s.str.slice(a, b)) +} + +pub fn (s string) after(dot string) string { +	return string(s.str.slice(s.str.lastIndexOf(dot.str) + 1, int(s.str.length))) +} + +pub fn (s string) after_char(dot byte) string { +	// TODO: Implement after byte +	return s +} + +pub fn (s string) all_after(dot string) string { +	return string(s.str.slice(s.str.indexOf(dot.str) + 1, int(s.str.length))) +} + +// why does this exist? +pub fn (s string) all_after_last(dot string) string { +	return s.after(dot) +} + +pub fn (s string) all_before(dot string) string { +	return string(s.str.slice(0, s.str.indexOf(dot.str))) +} + +pub fn (s string) all_before_last(dot string) string { +	return string(s.str.slice(0, s.str.lastIndexOf(dot.str))) +} + +pub fn (s string) bool() bool { +	return s == 'true' +} + +pub fn (s string) split(dot string) []string { +	mut arr := s.str.split(dot.str).map(string(it)) +	#arr = new array(arr) + +	return arr +} + +pub fn (s string) bytes() []byte { +	sep := '' +	mut arr := s.str.split(sep.str).map(it.charCodeAt(0)) +	#arr = new array(arr) + +	return arr +} + +pub fn (s string) capitalize() string { +	part := string(s.str.slice(1, int(s.str.length))) +	return string(s.str.charAt(0).toUpperCase().concat(part.str)) +} + +pub fn (s string) clone() string { +	return string(s.str) +} + +pub fn (s string) contains(substr string) bool { +	return s.str.includes(substr.str) +} + +pub fn (s string) contains_any(chars string) bool { +	sep := '' +	for x in chars.str.split(sep.str) { +		if s.str.includes(x) { +			return true +		} +	} +	return false +} + +pub fn (s string) contains_any_substr(chars []string) bool { +	for x in chars { +		if s.str.includes(x.str) { +			return true +		} +	} +	return false +} + +pub fn (s string) count(substr string) int { +	// TODO: "error: `[]JS.String` is not a struct" when returning arr.length or arr.len +	arr := s.str.split(substr.str) +	return native_str_arr_len(arr) +} + +pub fn (s string) ends_with(p string) bool { +	return s.str.endsWith(p.str) +} + +pub fn (s string) starts_with(p string) bool { +	return s.str.startsWith(p.str) +} + +pub fn (s string) fields() []string { +	mut res := []string{} +	mut word_start := 0 +	mut word_len := 0 +	mut is_in_word := false +	mut is_space := false +	for i, c in s { +		is_space = c in [32, 9, 10] +		if !is_space { +			word_len++ +		} +		if !is_in_word && !is_space { +			word_start = i +			is_in_word = true +			continue +		} +		if is_space && is_in_word { +			res << s[word_start..word_start + word_len] +			is_in_word = false +			word_len = 0 +			word_start = 0 +			continue +		} +	} +	if is_in_word && word_len > 0 { +		// collect the remainder word at the end +		res << s[word_start..s.len] +	} +	return res +} + +pub fn (s string) find_between(start string, end string) string { +	return string(s.str.slice(s.str.indexOf(start.str), s.str.indexOf(end.str) + 1)) +} + +// unnecessary in the JS backend, implemented for api parity. +pub fn (s string) free() {} + +pub fn (s string) hash() int { +	mut h := u32(0) +	if h == 0 && s.len > 0 { +		for c in s { +			h = h * 31 + u32(c) +		} +	} +	return int(h) +} + +// int returns the value of the string as an integer `'1'.int() == 1`. +pub fn (s string) int() int { +	return int(JS.parseInt(s)) +} + +// i64 returns the value of the string as i64 `'1'.i64() == i64(1)`. +pub fn (s string) i64() i64 { +	return i64(JS.parseInt(s)) +} + +// i8 returns the value of the string as i8 `'1'.i8() == i8(1)`. +pub fn (s string) i8() i8 { +	return i8(JS.parseInt(s)) +} + +// i16 returns the value of the string as i16 `'1'.i16() == i16(1)`. +pub fn (s string) i16() i16 { +	return i16(JS.parseInt(s)) +} + +// f32 returns the value of the string as f32 `'1.0'.f32() == f32(1)`. +pub fn (s string) f32() f32 { +	// return C.atof(&char(s.str)) +	return f32(JS.parseFloat(s)) +} + +// f64 returns the value of the string as f64 `'1.0'.f64() == f64(1)`. +pub fn (s string) f64() f64 { +	return f64(JS.parseFloat(s)) +} + +// u16 returns the value of the string as u16 `'1'.u16() == u16(1)`. +pub fn (s string) u16() u16 { +	return u16(JS.parseInt(s)) +} + +// u32 returns the value of the string as u32 `'1'.u32() == u32(1)`. +pub fn (s string) u32() u32 { +	return u32(JS.parseInt(s)) +} + +// u64 returns the value of the string as u64 `'1'.u64() == u64(1)`. +pub fn (s string) u64() u64 { +	return u64(JS.parseInt(s)) +} + +// trim_right strips any of the characters given in `cutset` from the right of the string. +// Example: assert ' Hello V d'.trim_right(' d') == ' Hello V' +pub fn (s string) trim_right(cutset string) string { +	if s.len < 1 || cutset.len < 1 { +		return s.clone() +	} + +	mut pos := s.len - 1 + +	for pos >= 0 { +		mut found := false +		for cs in cutset { +			if s[pos] == cs { +				found = true +			} +		} +		if !found { +			break +		} +		pos-- +	} + +	if pos < 0 { +		return '' +	} + +	return s[..pos + 1] +} + +// trim_left strips any of the characters given in `cutset` from the left of the string. +// Example: assert 'd Hello V developer'.trim_left(' d') == 'Hello V developer' +[direct_array_access] +pub fn (s string) trim_left(cutset string) string { +	if s.len < 1 || cutset.len < 1 { +		return s.clone() +	} +	mut pos := 0 +	for pos < s.len { +		mut found := false +		for cs in cutset { +			if s[pos] == cs { +				found = true +				break +			} +		} +		if !found { +			break +		} +		pos++ +	} +	return s[pos..] +} + +// trim_prefix strips `str` from the start of the string. +// Example: assert 'WorldHello V'.trim_prefix('World') == 'Hello V' +pub fn (s string) trim_prefix(str string) string { +	if s.starts_with(str) { +		return s[str.len..] +	} +	return s.clone() +} + +// trim_suffix strips `str` from the end of the string. +// Example: assert 'Hello VWorld'.trim_suffix('World') == 'Hello V' +pub fn (s string) trim_suffix(str string) string { +	if s.ends_with(str) { +		return s[..s.len - str.len] +	} +	return s.clone() +} + +// compare_strings returns `-1` if `a < b`, `1` if `a > b` else `0`. +pub fn compare_strings(a &string, b &string) int { +	if a < b { +		return -1 +	} +	if a > b { +		return 1 +	} +	return 0 +} + +// compare_strings_reverse returns `1` if `a < b`, `-1` if `a > b` else `0`. +fn compare_strings_reverse(a &string, b &string) int { +	if a < b { +		return 1 +	} +	if a > b { +		return -1 +	} +	return 0 +} + +// compare_strings_by_len returns `-1` if `a.len < b.len`, `1` if `a.len > b.len` else `0`. +fn compare_strings_by_len(a &string, b &string) int { +	if a.len < b.len { +		return -1 +	} +	if a.len > b.len { +		return 1 +	} +	return 0 +} + +// compare_lower_strings returns the same as compare_strings but converts `a` and `b` to lower case before comparing. +fn compare_lower_strings(a &string, b &string) int { +	aa := a.to_lower() +	bb := b.to_lower() +	return compare_strings(&aa, &bb) +} + +// at returns the byte at index `idx`. +// Example: assert 'ABC'.at(1) == byte(`B`) +fn (s string) at(idx int) byte { +	mut result := byte(0) +	#result = new byte(s.str.charCodeAt(result)) + +	return result +} + +pub fn (s string) to_lower() string { +	mut result := '' +	#let str = s.str.toLowerCase() +	#result = new string(str) + +	return result +} + +// TODO: check if that behaves the same as V's own string.replace(old_sub,new_sub): +pub fn (s string) replace(old_sub string, new_sub string) string { +	mut result := '' +	#result = new string( s.str.replaceAll(old_sub.str, new_sub.str) ) + +	return result +} + +pub fn (s string) to_upper() string { +	mut result := '' +	#let str = s.str.toUpperCase() +	#result = new string(str) + +	return result +} + +// sort sorts the string array. +pub fn (mut s []string) sort() { +	s.sort_with_compare(compare_strings) +} + +// sort_ignore_case sorts the string array using case insesitive comparing. +pub fn (mut s []string) sort_ignore_case() { +	s.sort_with_compare(compare_lower_strings) +} + +// sort_by_len sorts the the string array by each string's `.len` length. +pub fn (mut s []string) sort_by_len() { +	s.sort_with_compare(compare_strings_by_len) +} + +// str returns a copy of the string +pub fn (s string) str() string { +	return s.clone() +} + +pub fn (s string) repeat(count int) string { +	mut result := '' +	#result = new string(s.str.repeat(count)) + +	return result +} + +// TODO(playX): Use this iterator instead of using .split('').map(c => byte(c)) +#function string_iterator(string) { this.stringIteratorFieldIndex = 0; this.stringIteratorIteratedString = string.str; } +#string_iterator.prototype.next = function next() { +#var done = true; +#var value = undefined; +#var position = this.stringIteratorFieldIndex; +#if (position !== -1) { +#var string = this.stringIteratorIteratedString; +#var length = string.length >>> 0; +#if (position >= length) { +#this.stringIteratorFieldIndex = -1; +#} else { +#done = false; +#var first = string.charCodeAt(position); +#if (first < 0xD800 || first > 0xDBFF || position + 1 === length) +#value = new byte(string[position]); +#else { +#value = new byte(string[position]+string[position+1]) +#} +#this.stringIteratorFieldIndex = position + value.length; +#} +#} +#return { +#value, done +#} +#} +#string.prototype[Symbol.iterator] = function () { return new string_iterator(this) } + +// TODO: Make these functions actually work. +// strip_margin allows multi-line strings to be formatted in a way that removes white-space +// before a delimeter. by default `|` is used. +// Note: the delimiter has to be a byte at this time. That means surrounding +// the value in ``. +// +// Example: +// st := 'Hello there, +// |this is a string, +// |    Everything before the first | is removed'.strip_margin() +// Returns: +// Hello there, +// this is a string, +// Everything before the first | is removed +pub fn (s string) strip_margin() string { +	return s.strip_margin_custom(`|`) +} + +// strip_margin_custom does the same as `strip_margin` but will use `del` as delimiter instead of `|` +[direct_array_access] +pub fn (s string) strip_margin_custom(del byte) string { +	mut sep := del +	if sep.is_space() { +		eprintln('Warning: `strip_margin` cannot use white-space as a delimiter') +		eprintln('    Defaulting to `|`') +		sep = `|` +	} +	// don't know how much space the resulting string will be, but the max it +	// can be is this big +	mut ret := []byte{} +	#ret = new array() + +	mut count := 0 +	for i := 0; i < s.len; i++ { +		if s[i] in [10, 13] { +			unsafe { +				ret[count] = s[i] +			} +			count++ +			// CRLF +			if s[i] == 13 && i < s.len - 1 && s[i + 1] == 10 { +				unsafe { +					ret[count] = s[i + 1] +				} +				count++ +				i++ +			} +			for s[i] != sep { +				i++ +				if i >= s.len { +					break +				} +			} +		} else { +			unsafe { +				ret[count] = s[i] +			} +			count++ +		} +	} +	/* +	unsafe { +		ret[count] = 0 +		return ret.vstring_with_len(count) +	}*/ +	mut result := '' +	#for (let x of ret.arr) result.str += String.fromCharCode(x.val) + +	return result +} diff --git a/v_windows/v/old/vlib/builtin/linux_bare/libc_impl.v b/v_windows/v/old/vlib/builtin/linux_bare/libc_impl.v new file mode 100644 index 0000000..735cac6 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/libc_impl.v @@ -0,0 +1,157 @@ +module builtin + +[unsafe] +pub fn memcpy(dest &C.void, src &C.void, n size_t) &C.void { +	dest_ := unsafe { &byte(dest) } +	src_ := unsafe { &byte(src) } +	unsafe { +		for i in 0 .. int(n) { +			dest_[i] = src_[i] +		} +	} +	return unsafe { dest } +} + +[export: 'malloc'] +[unsafe] +fn __malloc(n size_t) &C.void { +	return unsafe { malloc(int(n)) } +} + +[unsafe] +fn strlen(_s &C.void) size_t { +	s := unsafe { &byte(_s) } +	mut i := 0 +	for ; unsafe { s[i] } != 0; i++ {} +	return size_t(i) +} + +[unsafe] +fn realloc(old_area &C.void, new_size size_t) &C.void { +	if old_area == 0 { +		return unsafe { malloc(int(new_size)) } +	} +	if new_size == size_t(0) { +		unsafe { free(old_area) } +		return 0 +	} +	old_size := unsafe { *(&u64(old_area - sizeof(u64))) } +	if u64(new_size) <= old_size { +		return unsafe { old_area } +	} else { +		new_area := unsafe { malloc(int(new_size)) } +		unsafe { memmove(new_area, old_area, size_t(old_size)) } +		unsafe { free(old_area) } +		return new_area +	} +} + +[unsafe] +fn memset(s &C.void, c int, n size_t) &C.void { +	mut s_ := unsafe { &char(s) } +	for i in 0 .. int(n) { +		unsafe { +			s_[i] = char(c) +		} +	} +	return unsafe { s } +} + +[unsafe] +fn memmove(dest &C.void, src &C.void, n size_t) &C.void { +	dest_ := unsafe { &byte(dest) } +	src_ := unsafe { &byte(src) } +	mut temp_buf := unsafe { malloc(int(n)) } +	for i in 0 .. int(n) { +		unsafe { +			temp_buf[i] = src_[i] +		} +	} + +	for i in 0 .. int(n) { +		unsafe { +			dest_[i] = temp_buf[i] +		} +	} +	unsafe { free(temp_buf) } +	return unsafe { dest } +} + +[export: 'calloc'] +[unsafe] +fn __calloc(nmemb size_t, size size_t) &C.void { +	new_area := unsafe { malloc(int(nmemb) * int(size)) } +	unsafe { memset(new_area, 0, nmemb * size) } +	return new_area +} + +fn getchar() int { +	x := byte(0) +	sys_read(0, &x, 1) +	return int(x) +} + +fn memcmp(a &C.void, b &C.void, n size_t) int { +	a_ := unsafe { &byte(a) } +	b_ := unsafe { &byte(b) } +	for i in 0 .. int(n) { +		if unsafe { a_[i] != b_[i] } { +			unsafe { +				return a_[i] - b_[i] +			} +		} +	} +	return 0 +} + +[export: 'free'] +[unsafe] +fn __free(ptr &C.void) { +	err := mm_free(ptr) +	if err != .enoerror { +		eprintln('free error:') +		panic(err) +	} +} + +fn vsprintf(str &char, format &char, ap &byte) int { +	panic('vsprintf(): string interpolation is not supported in `-freestanding`') +} + +fn vsnprintf(str &char, size size_t, format &char, ap &byte) int { +	panic('vsnprintf(): string interpolation is not supported in `-freestanding`') +} + +// not really needed +fn bare_read(buf &byte, count u64) (i64, Errno) { +	return sys_read(0, buf, count) +} + +fn bare_print(buf &byte, len u64) { +	sys_write(1, buf, len) +} + +fn bare_eprint(buf &byte, len u64) { +	sys_write(2, buf, len) +} + +pub fn write(fd i64, buf &byte, count u64) i64 { +	x, _ := sys_write(fd, buf, count) +	return x +} + +[noreturn] +fn bare_panic(msg string) { +	println('V panic' + msg) +	exit(1) +} + +fn bare_backtrace() string { +	return 'backtraces are not available with `-freestanding`' +} + +[export: 'exit'] +[noreturn] +fn __exit(code int) { +	sys_exit(code) +} diff --git a/v_windows/v/old/vlib/builtin/linux_bare/linux_syscalls.v b/v_windows/v/old/vlib/builtin/linux_bare/linux_syscalls.v new file mode 100644 index 0000000..b0b2c47 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/linux_syscalls.v @@ -0,0 +1,433 @@ +module builtin + +enum SigIndex { +	si_signo = 0x00 +	si_code = 0x02 +	si_pid = 0x04 +	si_uid = 0x05 +	si_status = 0x06 +	si_size = 0x80 +} + +enum Signo { +	sighup = 1 // Hangup. +	sigint = 2 // Interactive attention signal. +	sigquit = 3 // Quit. +	sigill = 4 // Illegal instruction. +	sigtrap = 5 // Trace/breakpoint trap. +	sigabrt = 6 // Abnormal termination. +	sigbus = 7 +	sigfpe = 8 // Erroneous arithmetic operation. +	sigkill = 9 // Killed. +	sigusr1 = 10 +	sigsegv = 11 // Invalid access to memory. +	sigusr2 = 12 +	sigpipe = 13 // Broken pipe. +	sigalrm = 14 // Alarm clock. +	sigterm = 15 // Termination request. +	sigstkflt = 16 +	sigchld = 17 +	sigcont = 18 +	sigstop = 19 +	sigtstp = 20 +	sigttin = 21 // Background read from control terminal. +	sigttou = 22 // Background write to control terminal. +	sigurg = 23 +	sigxcpu = 24 // CPU time limit exceeded. +	sigxfsz = 25 // File size limit exceeded. +	sigvtalrm = 26 // Virtual timer expired. +	sigprof = 27 // Profiling timer expired. +	sigwinch = 28 +	sigpoll = 29 +	sigsys = 31 +} + +// List of all the errors returned by syscalls +enum Errno { +	enoerror = 0x00000000 +	eperm = 0x00000001 +	enoent = 0x00000002 +	esrch = 0x00000003 +	eintr = 0x00000004 +	eio = 0x00000005 +	enxio = 0x00000006 +	e2big = 0x00000007 +	enoexec = 0x00000008 +	ebadf = 0x00000009 +	echild = 0x0000000a +	eagain = 0x0000000b +	enomem = 0x0000000c +	eacces = 0x0000000d +	efault = 0x0000000e +	enotblk = 0x0000000f +	ebusy = 0x00000010 +	eexist = 0x00000011 +	exdev = 0x00000012 +	enodev = 0x00000013 +	enotdir = 0x00000014 +	eisdir = 0x00000015 +	einval = 0x00000016 +	enfile = 0x00000017 +	emfile = 0x00000018 +	enotty = 0x00000019 +	etxtbsy = 0x0000001a +	efbig = 0x0000001b +	enospc = 0x0000001c +	espipe = 0x0000001d +	erofs = 0x0000001e +	emlink = 0x0000001f +	epipe = 0x00000020 +	edom = 0x00000021 +	erange = 0x00000022 +} + +enum MemProt { +	prot_read = 0x1 +	prot_write = 0x2 +	prot_exec = 0x4 +	prot_none = 0x0 +	prot_growsdown = 0x01000000 +	prot_growsup = 0x02000000 +} + +enum MapFlags { +	map_shared = 0x01 +	map_private = 0x02 +	map_shared_validate = 0x03 +	map_type = 0x0f +	map_fixed = 0x10 +	map_file = 0x00 +	map_anonymous = 0x20 +	map_huge_shift = 26 +	map_huge_mask = 0x3f +} + +//   const ( +// 	fcntlf_dupfd         = 0x00000000 +// 	fcntlf_exlck         = 0x00000004 +// 	fcntlf_getfd         = 0x00000001 +// 	fcntlf_getfl         = 0x00000003 +// 	fcntlf_getlk         = 0x00000005 +// 	fcntlf_getlk64       = 0x0000000c +// 	fcntlf_getown        = 0x00000009 +// 	fcntlf_getowner_uids = 0x00000011 +// 	fcntlf_getown_ex     = 0x00000010 +// 	fcntlf_getsig        = 0x0000000b +// 	fcntlf_ofd_getlk     = 0x00000024 +// 	fcntlf_ofd_setlk     = 0x00000025 +// 	fcntlf_ofd_setlkw    = 0x00000026 +// 	fcntlf_owner_pgrp    = 0x00000002 +// 	fcntlf_owner_pid     = 0x00000001 +// 	fcntlf_owner_tid     = 0x00000000 +// 	fcntlf_rdlck         = 0x00000000 +// 	fcntlf_setfd         = 0x00000002 +// 	fcntlf_setfl         = 0x00000004 +// 	fcntlf_setlk         = 0x00000006 +// 	fcntlf_setlk64       = 0x0000000d +// 	fcntlf_setlkw        = 0x00000007 +// 	fcntlf_setlkw64      = 0x0000000e +// 	fcntlf_setown        = 0x00000008 +// 	fcntlf_setown_ex     = 0x0000000f +// 	fcntlf_setsig        = 0x0000000a +// 	fcntlf_shlck         = 0x00000008 +// 	fcntlf_unlck         = 0x00000002 +// 	fcntlf_wrlck         = 0x00000001 +// 	fcntllock_ex         = 0x00000002 +// 	fcntllock_mand       = 0x00000020 +// 	fcntllock_nb         = 0x00000004 +// 	fcntllock_read       = 0x00000040 +// 	fcntllock_rw         = 0x000000c0 +// 	fcntllock_sh         = 0x00000001 +// 	fcntllock_un         = 0x00000008 +// 	fcntllock_write      = 0x00000080 +// 	fcntlo_accmode       = 0x00000003 +// 	fcntlo_append        = 0x00000400 +// 	fcntlo_cloexec       = 0x00080000 +// 	fcntlo_creat         = 0x00000040 +// 	fcntlo_direct        = 0x00004000 +// 	fcntlo_directory     = 0x00010000 +// 	fcntlo_dsync         = 0x00001000 +// 	fcntlo_excl          = 0x00000080 +// 	fcntlo_largefile     = 0x00008000 +// 	fcntlo_ndelay        = 0x00000800 +// 	fcntlo_noatime       = 0x00040000 +// 	fcntlo_noctty        = 0x00000100 +// 	fcntlo_nofollow      = 0x00020000 +// 	fcntlo_nonblock      = 0x00000800 +// 	fcntlo_path          = 0x00200000 +// 	fcntlo_rdonly        = 0x00000000 +// 	fcntlo_rdwr          = 0x00000002 +// 	fcntlo_trunc         = 0x00000200 +// 	fcntlo_wronly        = 0x00000001 +// ) + +/* +Paraphrased from "man 2 waitid" on Linux + +	Upon successful return, waitid() fills in the +	following fields of the siginfo_t structure +	pointed to by infop: + +	si_pid, offset 0x10, int index 0x04: +		The process ID of the child. + +	si_uid: offset 0x14, int index 0x05 +		The real user ID of the child. + +	si_signo: offset 0x00, int index 0x00 +		Always set to SIGCHLD. + +	si_status: ofset 0x18, int index 0x06 +		1 the exit status of the child, as given to _exit(2) +			(or exit(3)) (sc_sys.cld_exited) +		2 the signal that caused the child to terminate, stop, +			or continue. +		3 The si_code field can be used to determine how to +			interpret this field. + +	si_code, set to one of (enum Wi_si_code), offset 0x08, int index 0x02: +		CLD_EXITED (child called _exit(2)); +		CLD_KILLED (child killed by signal); +		CLD_DUMPED (child  killed by signal, and dumped core); +		CLD_STOPPED (child stopped by signal); +		CLD_TRAPPED (traced child has trapped); +		CLD_CONTINUED (child continued by SIGCONT). +*/ + +const ( +	wp_sys_wnohang     = u64(0x00000001) +	wp_sys_wuntraced   = u64(0x00000002) +	wp_sys_wstopped    = u64(0x00000002) +	wp_sys_wexited     = u64(0x00000004) +	wp_sys_wcontinued  = u64(0x00000008) +	wp_sys_wnowait     = u64(0x01000000) // don't reap, just poll status. +	wp_sys___wnothread = u64(0x20000000) // don't wait on children of other threads in this group +	wp_sys___wall      = u64(0x40000000) // wait on all children, regardless of type +	wp_sys___wclone    = u64(0x80000000) // wait only on non-sigchld children +) + +// First argument to waitid: +enum WiWhich { +	p_all = 0 +	p_pid = 1 +	p_pgid = 2 +} + +enum WiSiCode { +	cld_exited = 1 // child has exited +	cld_killed = 2 // child was killed +	cld_dumped = 3 // child terminated abnormally +	cld_trapped = 4 // traced child has trapped +	cld_stopped = 5 // child has stopped +	cld_continued = 6 // stopped child has continued +} + +fn split_int_errno(rc_in u64) (i64, Errno) { +	rc := i64(rc_in) +	if rc < 0 { +		return i64(-1), Errno(-rc) +	} +	return rc, Errno.enoerror +} + +// 0 sys_read +fn sys_read(fd i64, buf &byte, count u64) (i64, Errno) { +	return split_int_errno(sys_call3(0, u64(fd), u64(buf), count)) +} + +// 1 sys_write +pub fn sys_write(fd i64, buf &byte, count u64) (i64, Errno) { +	return split_int_errno(sys_call3(1, u64(fd), u64(buf), count)) +} + +// 2 sys_open +fn sys_open(filename &byte, flags i64, mode int) (i64, Errno) { +	return split_int_errno(sys_call3(2, u64(filename), u64(flags), u64(mode))) +} + +// 3 sys_close +fn sys_close(fd i64) Errno { +	return Errno(-i64(sys_call1(3, u64(fd)))) +} + +// 9 sys_mmap +fn sys_mmap(addr &byte, len u64, prot MemProt, flags MapFlags, fildes u64, off u64) (&byte, Errno) { +	rc := sys_call6(9, u64(addr), len, u64(prot), u64(flags), fildes, off) +	a, e := split_int_errno(rc) +	return &byte(a), e +} + +// 11 sys_munmap +fn sys_munmap(addr voidptr, len u64) Errno { +	return Errno(-sys_call2(11, u64(addr), len)) +} + +// 22  sys_pipe +fn sys_pipe(filedes &int) Errno { +	return Errno(sys_call1(22, u64(filedes))) +} + +// 24 sys_sched_yield +fn sys_sched_yield() Errno { +	return Errno(sys_call0(24)) +} + +// 28 sys_madvise +fn sys_madvise(addr voidptr, len u64, advice int) Errno { +	return Errno(sys_call3(28, u64(addr), len, u64(advice))) +} + +// 39 sys_getpid +fn sys_getpid() int { +	return int(sys_call0(39)) +} + +// 57 sys_fork +fn sys_fork() int { +	return int(sys_call0(57)) +} + +// 58 sys_vfork +fn sys_vfork() int { +	return int(sys_call0(58)) +} + +// 33  sys_dup2 +fn sys_dup2(oldfd int, newfd int) (i64, Errno) { +	return split_int_errno(sys_call2(33, u64(oldfd), u64(newfd))) +} + +// 59  sys_execve +fn sys_execve(filename &byte, argv []&byte, envp []&byte) int { +	return int(sys_call3(59, u64(filename), argv.data, envp.data)) +} + +// 60 sys_exit +[noreturn] +fn sys_exit(ec int) { +	sys_call1(60, u64(ec)) +	for {} +} + +// 102 sys_getuid +fn sys_getuid() int { +	return int(sys_call0(102)) +} + +// 247 sys_waitid +fn sys_waitid(which WiWhich, pid int, infop &int, options int, ru voidptr) Errno { +	return Errno(sys_call5(247, u64(which), u64(pid), u64(infop), u64(options), u64(ru))) +} + +fn sys_call0(scn u64) u64 { +	mut res := u64(0) +	asm amd64 { +		syscall +		; =a (res) +		; a (scn) +	} +	return res +} + +fn sys_call1(scn u64, arg1 u64) u64 { +	mut res := u64(0) +	asm amd64 { +		syscall +		; =a (res) +		; a (scn) +		  D (arg1) +	} +	return res +} + +fn sys_call2(scn u64, arg1 u64, arg2 u64) u64 { +	mut res := u64(0) +	asm amd64 { +		syscall +		; =a (res) +		; a (scn) +		  D (arg1) +		  S (arg2) +	} +	return res +} + +fn sys_call3(scn u64, arg1 u64, arg2 u64, arg3 u64) u64 { +	mut res := u64(0) +	asm amd64 { +		syscall +		; =a (res) +		; a (scn) +		  D (arg1) +		  S (arg2) +		  d (arg3) +	} +	return res +} + +fn sys_call4(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64) u64 { +	mut res := u64(0) +	asm amd64 { +		mov r10, arg4 +		syscall +		; =a (res) +		; a (scn) +		  D (arg1) +		  S (arg2) +		  d (arg3) +		  r (arg4) +		; r10 +	} +	return res +} + +fn sys_call5(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64, arg5 u64) u64 { +	mut res := u64(0) +	asm amd64 { +		mov r10, arg4 +		mov r8, arg5 +		syscall +		; =a (res) +		; a (scn) +		  D (arg1) +		  S (arg2) +		  d (arg3) +		  r (arg4) +		  r (arg5) +		; r10 +		  r8 +	} +	return res +} + +fn sys_call6(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64, arg5 u64, arg6 u64) u64 { +	mut res := u64(0) +	asm amd64 { +		mov r10, arg4 +		mov r8, arg5 +		mov r9, arg6 +		syscall +		; =a (res) +		; a (scn) +		  D (arg1) +		  S (arg2) +		  d (arg3) +		  r (arg4) +		  r (arg5) +		  r (arg6) +		; r10 +		  r8 +		  r9 +	} +	return res +} + +asm amd64 { +	.globl _start +	_start: +	call main +	mov rax, 60 +	xor rdi, rdi +	syscall +	ret +} diff --git a/v_windows/v/old/vlib/builtin/linux_bare/memory_managment.v b/v_windows/v/old/vlib/builtin/linux_bare/memory_managment.v new file mode 100644 index 0000000..9c23dcf --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/memory_managment.v @@ -0,0 +1,29 @@ +module builtin + +fn mm_alloc(size u64) (&byte, Errno) { +	// BEGIN CONSTS +	// the constants need to be here, since the initialization of other constants, +	// which happen before these ones would, require malloc +	mem_prot := MemProt(int(MemProt.prot_read) | int(MemProt.prot_write)) +	map_flags := MapFlags(int(MapFlags.map_private) | int(MapFlags.map_anonymous)) +	// END CONSTS + +	a, e := sys_mmap(&byte(0), size + sizeof(u64), mem_prot, map_flags, -1, 0) +	if e == .enoerror { +		unsafe { +			mut ap := &u64(a) +			*ap = size +			x2 := &byte(a + sizeof(u64)) +			return x2, e +		} +	} +	return &byte(0), e +} + +fn mm_free(addr &byte) Errno { +	unsafe { +		ap := &u64(addr - sizeof(u64)) +		size := *ap +		return sys_munmap(addr - sizeof(u64), size + sizeof(u64)) +	} +} diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/.gitignore b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/.gitignore new file mode 100644 index 0000000..4132964 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/.gitignore @@ -0,0 +1,5 @@ +checks +linuxsys/linuxsys +string/string +consts/consts +structs/structs diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/checks.v b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/checks.v new file mode 100644 index 0000000..8fd3575 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/checks.v @@ -0,0 +1,32 @@ +module main + +import os + +fn failed (msg string) { +	println ("!!! failed: $msg") +} + +fn passed (msg string) { +	println (">>> passed: $msg") +} + + +fn vcheck(vfile string) { +	run_check := "v -user_mod_path . -freestanding run " +	if 0 == os.system("$run_check $vfile/${vfile}.v") { +		passed(run_check) +	} else { +		failed(run_check) +	} +	os.system("ls -lh $vfile/$vfile") +	os.system("rm -f $vfile/$vfile") +} + +fn main() { +	vcheck("linuxsys") +	vcheck("string") +	vcheck("consts") +	vcheck("structs") +	exit(0) +} + diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/consts/consts.v b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/consts/consts.v new file mode 100644 index 0000000..eee2c61 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/consts/consts.v @@ -0,0 +1,22 @@ +module main +import forkedtest + +const ( +	integer1 = 111 +	integer2 = 222 +	integer3 = integer1+integer2 +	integer9 = integer3 * 3 +	abc = "123" +) + +fn check_const_initialization() { +	assert abc == "123" +	assert integer9 == 999 +} + +fn main(){ +	mut fails := 0 +	fails += forkedtest.normal_run(check_const_initialization, "check_const_initialization") +	assert fails == 0 +	sys_exit(0) +} diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/forkedtest/forkedtest.v b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/forkedtest/forkedtest.v new file mode 100644 index 0000000..6d9272c --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/forkedtest/forkedtest.v @@ -0,0 +1,49 @@ +module forkedtest + +pub fn run (op fn(), label string, code Wi_si_code, status int) int { +	child := sys_fork() +	if child == 0 { +		op() +		sys_exit(0) +	} + +	siginfo := []int{len:int(Sig_index.si_size)} + +	e := sys_waitid(.p_pid, child, intptr(&siginfo[0]), .wexited, 0) + +	assert e == .enoerror +	assert siginfo[int(Sig_index.si_pid)] == child +	assert siginfo[int(Sig_index.si_signo)] == int(Signo.sigchld) +	assert siginfo[int(Sig_index.si_uid)] == sys_getuid() + +	r_code := siginfo[Sig_index.si_code] +	r_status := siginfo[Sig_index.si_status] + +	print("+++ ") +	print(label) +	if (int(code) == r_code) && (status == r_status) { +		println(" PASSED") +		return 0 +	} +	println(" FAILED") + +	if int(code) != r_code { +		print(">> Expecting si_code 0x") +		println(i64_str(int(code),16)) +		print(">> Got 0x") +		println(i64_str(r_code,16)) +	} + +	if status != r_status { +		print(">> Expecting status 0x") +		println(i64_str(status,16)) +		print(">> Got 0x") +		println(i64_str(r_status,16)) +	} + +	return 1 +} + +pub fn normal_run (op fn(), label string) int { +	return run (op, label, .cld_exited, 0) +} diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/linuxsys/linuxsys.v b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/linuxsys/linuxsys.v new file mode 100644 index 0000000..cca5cb6 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/linuxsys/linuxsys.v @@ -0,0 +1,300 @@ +module main +import forkedtest + +const ( +	sample_text_file1 = "" +) + +fn check_fork_minimal () { +	child := sys_fork() +	ec := 100 +	if child == 0 { +		println("child") +		sys_exit(ec) +	} +	siginfo := [ +		0, 0, 0, 0, 0, 0, 0, 0, +		0, 0, 0, 0, 0, 0, 0, 0, +		0, 0, 0, 0, 0, 0, 0, 0, +		0, 0, 0, 0, 0, 0, 0, 0, +		0, 0, 0, 0, 0, 0, 0, 0, +		0, 0, 0, 0, 0, 0, 0, 0, +		0, 0, 0, 0, 0, 0, 0, 0, +		0, 0, 0, 0, 0, 0, 0, 0] + +	e := sys_waitid(.p_pid, child, intptr(siginfo.data) , .wexited, 0) + +	assert e == .enoerror +	//println(i64_tos(buffer0,80,siginfo[Sig_index.si_code],16)) +	assert siginfo[Sig_index.si_code] == int(Wi_si_code.cld_exited) +	assert siginfo[Sig_index.si_pid] == child +	assert siginfo[Sig_index.si_status] == ec +	assert siginfo[Sig_index.si_signo] == int(Signo.sigchld) +	assert siginfo[Sig_index.si_uid] == sys_getuid() +} + +fn check_read_write_pipe() { +	//	Checks the following system calls: +	//		sys_pipe +	//		sys_write +	//		sys_read +	//		sys_close +	// +	buffer0 := []byte{len:(128)} +	buffer := byteptr(buffer0.data) + +	fd := [-1, -1] + +	assert fd[0] == -1 +	assert fd[1] == -1 + +	a := sys_pipe(intptr(&fd[0])) + +	assert a == .enoerror + +	assert fd[0] != -1 +	assert fd[1] != -1 + +	test_data := "test_data" +	b := test_data.len + 1 +	c1, e1 := sys_write (fd[1], test_data.str, u64(b)) + +	assert e1 == .enoerror +	assert c1 == b + +	c2, e2 := sys_read(fd[0], buffer, u64(b)) + +	assert e2 == .enoerror +	assert c2 == b + +	assert buffer[b-1] == 0 + +	for i in 0..b { +		assert test_data[i] == buffer[i] +	} + +	assert sys_close(fd[0]) == .enoerror +	assert sys_close(fd[1]) == .enoerror + +	assert sys_close(-1) == .ebadf +} + +fn check_read_file() { +	/* +		Checks the following system calls: +			sys_read +			sys_write +			sys_close +			sys_open +	*/ +	buffer0 := []byte{len:(128)} +	buffer := byteptr(buffer0.data) + +	test_file := "sample_text1.txt" +	sample_text := "Do not change this text.\n" +	fd, ec := sys_open(test_file.str, .o_rdonly, 0) +	assert fd > 0 +	assert ec == .enoerror +	n := sample_text.len +	c, e := sys_read(fd, buffer, u64(n*2)) +	assert e == .enoerror +	assert c == n +	for i in 0..n { +		assert sample_text[i] == buffer[i] +	} +	assert sys_close(fd) == .enoerror +} + +fn check_open_file_fail() { +	fd1, ec1 := sys_open("./nofilehere".str, .o_rdonly, 0) +	assert fd1 == -1 +	assert ec1 == .enoent +} + +/* +fn check_print() { +	println ("checking print and println") + +	a := sys_pipe(intptr(fd)) +	assert a != -1 +	assert fd[0] != -1 +	assert fd[1] != -1 + +	//sys_dup2 +	println ("print and println passed") +} +*/ + +fn check_munmap_fail() { +	ec := sys_munmap(-16384,8192) +	assert ec == .einval +} + +fn check_mmap_one_page() { +	mp := int(Mm_prot.prot_read) | int(Mm_prot.prot_write) +	mf := int(Map_flags.map_private) | int(Map_flags.map_anonymous) +	mut a, e := sys_mmap(0, u64(Linux_mem.page_size), Mm_prot(mp), Map_flags(mf), -1, 0) + +	assert e == .enoerror +	assert a != byteptr(-1) + +	for i in 0..int(Linux_mem.page_size) { +		b := i & 0xFF +		a[i] = b +		assert a[i] == b +	} + +	ec := sys_munmap(a, u64(Linux_mem.page_size)) +	assert ec == .enoerror +} + +fn check_mm_pages() { +	for i in 0 .. int(Linux_mem.page_size)-4 { +		assert u32(1) == mm_pages(u64(i)) +	} +	for i in int(Linux_mem.page_size)-3 .. (int(Linux_mem.page_size)*2)-4 { +		assert u32(2) == mm_pages(u64(i)) +	} +	for i in (int(Linux_mem.page_size)*2)-3 .. (int(Linux_mem.page_size)*3)-4 { +		assert u32(3) == mm_pages(u64(i)) +	} +} + +//pub fn mm_alloc(size u64) (voidptr, Errno) + +fn check_mm_alloc() { +	for i in 1 .. 2000 { +		size := u64(i*1000) +		pages := mm_pages(size) +		mut a, e := mm_alloc(size) + +		assert e == .enoerror +		ap := intptr(a-4) +		assert *ap == int(pages) +		assert e == .enoerror +		assert !isnil(a) + +		if (i%111) == 0 { +			for j in 0 .. int(size) { +				b := j & 0xFF +				a[j] = b +				assert b == int(a[j]) +			} +		} + +		mfa := mm_free(a) + +		assert mfa == .enoerror +	} +} + +fn check_int_array_ro() { +	a := [100,110,120,130] +	assert a.len == 4 +	assert a[0] == 100 +	assert a[1] == 110 +	assert a[2] == 120 +	assert a[3] == 130 +} + +fn check_int_array_rw() { +	mut a := [-10,-11,-12,-13] +	assert a.len == 4 +	assert a[0] == -10 +	assert a[1] == -11 +	assert a[2] == -12 +	assert a[3] == -13 +	for i in 0..a.len { +		b := -a[i] * 10 +		a[i] = b +		assert a[i] == b +	} +	assert a[3] == 130 +} + +fn check_int64_array_ro() { +	a := [i64(1000),1100,1200,1300,1400] +	assert a.len == 5 +	assert a[0] == 1000 +	assert a[1] == 1100 +	assert a[2] == 1200 +	assert a[3] == 1300 +	assert a[4] == 1400 +} + +fn check_voidptr_array_ro() { +	a := [ +		voidptr(10000), +		voidptr(11000), +		voidptr(12000), +		voidptr(13000), +		voidptr(14000), +		voidptr(15000) +	] +	assert a.len == 6 +	assert a[0] == voidptr(10000) +	assert a[1] == voidptr(11000) +	assert a[2] == voidptr(12000) +	assert a[3] == voidptr(13000) +	assert a[4] == voidptr(14000) +	assert a[5] == voidptr(15000) +} + +fn check_voidptr_array_rw() { +	mut a := [ +		voidptr(-1), +		voidptr(-1), +		voidptr(-1), +		voidptr(-1), +		voidptr(-1), +		voidptr(-1) +	] +	assert a.len == 6 + +	assert a[0] == voidptr(-1) +	assert a[1] == voidptr(-1) +	assert a[2] == voidptr(-1) +	assert a[3] == voidptr(-1) +	assert a[4] == voidptr(-1) +	assert a[5] == voidptr(-1) + +	a[0] = voidptr(100000) +	assert a[0] == voidptr(100000) + +	a[1] = voidptr(110000) +	assert a[1] == voidptr(110000) + +	a[2] = voidptr(120000) +	assert a[2] == voidptr(120000) + +	a[3] = voidptr(130000) +	assert a[3] == voidptr(130000) + +	a[4] = voidptr(140000) +	assert a[4] == voidptr(140000) + +	a[5] = voidptr(150000) +	assert a[5] == voidptr(150000) +} + + +fn main() { +	mut fails := 0 +	fails += forkedtest.normal_run(check_fork_minimal, "check_fork_minimal") +	fails += forkedtest.normal_run(check_munmap_fail, "check_munmap_fail") +	fails += forkedtest.normal_run(check_mmap_one_page, "check_mmap_one_page") +	fails += forkedtest.normal_run(check_mm_pages, "check_mm_pages") +	fails += forkedtest.normal_run(check_mm_alloc, "check_mm_alloc") +	fails += forkedtest.normal_run(check_read_write_pipe, "check_read_write_pipe") +	fails += forkedtest.normal_run(check_read_file, "check_read_file") +	// check_print() +	fails += forkedtest.normal_run(check_open_file_fail, "check_open_file_fail") +	fails += forkedtest.normal_run(check_int_array_ro, "check_int_array_ro") +	fails += forkedtest.normal_run(check_int_array_rw, "check_int_array_rw") +	fails += forkedtest.normal_run(check_int64_array_ro, "check_int64_array_ro") +	fails += forkedtest.normal_run(check_voidptr_array_ro, "check_voidptr_array_ro") +	fails += forkedtest.normal_run(check_voidptr_array_rw, "check_voidptr_array_rw") + +	assert fails == 0 +	sys_exit(0) +} diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/readme.md b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/readme.md new file mode 100644 index 0000000..03c1b30 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/readme.md @@ -0,0 +1,5 @@ +In this directory: +``` +v run checks.v +``` + diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/sample_text1.txt b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/sample_text1.txt new file mode 100644 index 0000000..f06e75a --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/sample_text1.txt @@ -0,0 +1 @@ +Do not change this text. diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/string/string.v b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/string/string.v new file mode 100644 index 0000000..54c06e7 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/string/string.v @@ -0,0 +1,63 @@ +module main +import forkedtest + +fn check_string_eq () { +	assert "monkey" != "rat" +	some_animal := "a bird" +	assert some_animal == "a bird" +} + +fn check_i64_tos() { +	buffer0 := []byte{len:(128)} +	buffer := byteptr(buffer0.data) + +	s0 := i64_tos(buffer, 70, 140, 10) +	assert s0 == "140" + +	s1 := i64_tos(buffer, 70, -160, 10) +	assert s1 == "-160" + +	s2 := i64_tos(buffer, 70, 65537, 16) +	assert s2 == "10001" + +	s3 := i64_tos(buffer, 70, -160000, 10) +	assert s3 == "-160000" +} + +fn check_i64_str() { +	assert "141" == i64_str(141, 10) +	assert "-161" == i64_str(-161, 10) +	assert "10002" == i64_str(65538, 16) +	assert "-160001" == i64_str(-160001, 10) +} + +fn check_str_clone() { +	a := i64_str(1234,10) +	b := a.clone() +	assert a == b +	c := i64_str(-6789,10).clone() +	assert c == "-6789" +} + +fn check_string_add_works(){ +  abc := 'abc' +  combined := 'a' + 'b' + 'c' +  assert abc.len == combined.len +  assert abc[0] == combined[0] +  assert abc[1] == combined[1] +  assert abc[2] == combined[2] +  assert abc[0] == `a` +  assert abc == combined +}   + +fn main () { +	mut fails := 0 +	fails += forkedtest.normal_run(check_string_eq, "check_string_eq") +	fails += forkedtest.normal_run(check_i64_tos, "check_i64_tos") +	fails += forkedtest.normal_run(check_i64_str, "check_i64_str") +	fails += forkedtest.normal_run(check_str_clone, "check_str_clone") +	fails += forkedtest.normal_run(check_string_add_works,    "check_string_add_works") +	assert fails == 0 +	sys_exit(0) +} + diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/structs/structs.v b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/structs/structs.v new file mode 100644 index 0000000..f63285d --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/.checks/structs/structs.v @@ -0,0 +1,42 @@ +module main +import forkedtest + +struct SimpleEmptyStruct{ +} + +struct NonEmptyStruct{ +  x int +  y int +  z int +} + +fn check_simple_empty_struct(){   +  s := SimpleEmptyStruct{} +  addr_s := &s +  str_addr_s := ptr_str( addr_s ) +  assert !isnil(addr_s) +  assert str_addr_s.len > 3 +  println(str_addr_s) +} + +fn check_non_empty_struct(){   +  a := NonEmptyStruct{1,2,3} +  b := NonEmptyStruct{4,5,6} +  assert sizeof(NonEmptyStruct) > 0 +  assert sizeof(SimpleEmptyStruct) < sizeof(NonEmptyStruct) +  assert a.x == 1 +  assert a.y == 2 +  assert a.z == 3 +  assert b.x + b.y + b.z == 15 +  assert ptr_str(&a) != ptr_str(&b) +  println('sizeof SimpleEmptyStruct:' + i64_str( sizeof(SimpleEmptyStruct) , 10 )) +  println('sizeof NonEmptyStruct:' + i64_str( sizeof(NonEmptyStruct) , 10 )) +} + +fn main(){ +	mut fails := 0 +	fails += forkedtest.normal_run(check_simple_empty_struct, "check_simple_empty_struct") +	fails += forkedtest.normal_run(check_non_empty_struct,    "check_non_empty_struct") +	assert fails == 0 +	sys_exit(0) +} diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/array_bare.v b/v_windows/v/old/vlib/builtin/linux_bare/old/array_bare.v new file mode 100644 index 0000000..b92214f --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/array_bare.v @@ -0,0 +1,53 @@ +module builtin + +pub struct array { +pub: +	data         voidptr +	len          int +	cap          int +	element_size int +} + +// for now off the stack +fn new_array_from_c_array(len int, cap int, elm_size int, c_array voidptr) array { +	arr := array{ +		len: len +		cap: cap +		element_size: elm_size +		data: c_array +	} +	return arr +} + +// Private function. Used to implement array[] operator +fn (a array) get(i int) voidptr { +	if i < 0 || i >= a.len { +		panic('array.get: index out of range') // FIXME: (i == $i, a.len == $a.len)') +	} +	return a.data + i * a.element_size +} + +// Private function. Used to implement assigment to the array element. +fn (mut a array) set(i int, val voidptr) { +	if i < 0 || i >= a.len { +		panic('array.set: index out of range') // FIXME: (i == $i, a.len == $a.len)') +	} +	mem_copy(a.data + a.element_size * i, val, a.element_size) +} + +// array.repeat returns new array with the given array elements +// repeated `nr_repeat` times +pub fn (a array) repeat(nr_repeats int) array { +	assert nr_repeats >= 0 + +	arr := array{ +		len: nr_repeats * a.len +		cap: nr_repeats * a.len +		element_size: a.element_size +		data: malloc(nr_repeats * a.len * a.element_size) +	} +	for i in 0 .. nr_repeats { +		mem_copy(arr.data + i * a.len * a.element_size, a.data, a.len * a.element_size) +	} +	return arr +} diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/builtin_bare.v b/v_windows/v/old/vlib/builtin/linux_bare/old/builtin_bare.v new file mode 100644 index 0000000..a7be853 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/builtin_bare.v @@ -0,0 +1,60 @@ +module builtin + +// called by the generated main/init +fn init() { +} + +pub fn isnil(p voidptr) bool { +	return p == 0 +} + +pub fn print(s string) { +	sys_write(1, s.str, u64(s.len)) +} + +pub fn println(s string) { +	print(s) +	print('\n') +} + +pub fn panic(s string) { +	eprint('V panic: ') +	eprintln(s) +	sys_exit(1) +} + +// replaces panic when -debug arg is passed +fn panic_debug(line_no int, file string, mod string, fn_name string, s string) { +	eprintln('================ V panic ================') +	eprint('   module: ') +	eprintln('mod') +	eprint(' function: ') +	eprint(fn_name) +	eprintln('()') +	eprintln('     file: ') +	eprintln(file) +	// println('     line: ${line_no}') +	eprint('  message: ') +	eprintln(s) +	eprintln('=========================================') +	sys_exit(1) +} + +pub fn eprint(s string) { +	if isnil(s.str) { +		panic('eprint(NIL)') +	} +	sys_write(2, s.str, u64(s.len)) +} + +pub fn eprint_ln(s string) { +	eprint(s) +	eprint('\n') +} + +pub fn eprintln(s string) { +	if isnil(s.str) { +		panic('eprintln(NIL)') +	} +	eprint_ln(s) +} diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/linuxsys_bare.v b/v_windows/v/old/vlib/builtin/linux_bare/old/linuxsys_bare.v new file mode 100644 index 0000000..ddec203 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/linuxsys_bare.v @@ -0,0 +1,759 @@ +module builtin + +pub enum Linux_mem { +	page_size = 4096 +} + +pub const ( +	wp_sys_wnohang     = u64(0x00000001) +	wp_sys_wuntraced   = u64(0x00000002) +	wp_sys_wstopped    = u64(0x00000002) +	wp_sys_wexited     = u64(0x00000004) +	wp_sys_wcontinued  = u64(0x00000008) +	wp_sys_wnowait     = u64(0x01000000) // don't reap, just poll status. +	wp_sys___wnothread = u64(0x20000000) // don't wait on children of other threads in this group +	wp_sys___wall      = u64(0x40000000) // wait on all children, regardless of type +	wp_sys___wclone    = u64(0x80000000) // wait only on non-sigchld children +) + +// First argument to waitid: +pub enum Wi_which { +	p_all = 0 +	p_pid = 1 +	p_pgid = 2 +} + +pub enum Wi_si_code { +	cld_exited = 1 // child has exited +	cld_killed = 2 // child was killed +	cld_dumped = 3 // child terminated abnormally +	cld_trapped = 4 // traced child has trapped +	cld_stopped = 5 // child has stopped +	cld_continued = 6 // stopped child has continued +} + +/* +Paraphrased from "man 2 waitid" on Linux + +	Upon successful return, waitid() fills in the +	following fields of the siginfo_t structure +	pointed to by infop: + +	si_pid, offset 0x10, int index 0x04: +		The process ID of the child. + +	si_uid: offset 0x14, int index 0x05 +		The real user ID of the child. + +	si_signo: offset 0x00, int index 0x00 +		Always set to SIGCHLD. + +	si_status: ofset 0x18, int index 0x06 +		1 the exit status of the child, as given to _exit(2) +			(or exit(3)) (sc_sys.cld_exited) +		2 the signal that caused the child to terminate, stop, +			or continue. +		3 The si_code field can be used to determine how to +			interpret this field. + +	si_code, set to one of (enum Wi_si_code), offset 0x08, int index 0x02: +		CLD_EXITED (child called _exit(2)); +		CLD_KILLED (child killed by signal); +		CLD_DUMPED (child  killed by signal, and dumped core); +		CLD_STOPPED (child stopped by signal); +		CLD_TRAPPED (traced child has trapped); +		CLD_CONTINUED (child continued by SIGCONT). +*/ + +pub enum Sig_index { +	si_signo = 0x00 +	si_code = 0x02 +	si_pid = 0x04 +	si_uid = 0x05 +	si_status = 0x06 +	si_size = 0x80 +} + +pub enum Signo { +	sighup = 1 // Hangup. +	sigint = 2 // Interactive attention signal. +	sigquit = 3 // Quit. +	sigill = 4 // Illegal instruction. +	sigtrap = 5 // Trace/breakpoint trap. +	sigabrt = 6 // Abnormal termination. +	sigbus = 7 +	sigfpe = 8 // Erroneous arithmetic operation. +	sigkill = 9 // Killed. +	sigusr1 = 10 +	sigsegv = 11 // Invalid access to storage. +	sigusr2 = 12 +	sigpipe = 13 // Broken pipe. +	sigalrm = 14 // Alarm clock. +	sigterm = 15 // Termination request. +	sigstkflt = 16 +	sigchld = 17 +	sigcont = 18 +	sigstop = 19 +	sigtstp = 20 +	sigttin = 21 // Background read from control terminal. +	sigttou = 22 // Background write to control terminal. +	sigurg = 23 +	sigxcpu = 24 // CPU time limit exceeded. +	sigxfsz = 25 // File size limit exceeded. +	sigvtalrm = 26 // Virtual timer expired. +	sigprof = 27 // Profiling timer expired. +	sigwinch = 28 +	sigpoll = 29 +	sigsys = 31 +} + +pub const ( +	fcntlf_dupfd         = 0x00000000 +	fcntlf_exlck         = 0x00000004 +	fcntlf_getfd         = 0x00000001 +	fcntlf_getfl         = 0x00000003 +	fcntlf_getlk         = 0x00000005 +	fcntlf_getlk64       = 0x0000000c +	fcntlf_getown        = 0x00000009 +	fcntlf_getowner_uids = 0x00000011 +	fcntlf_getown_ex     = 0x00000010 +	fcntlf_getsig        = 0x0000000b +	fcntlf_ofd_getlk     = 0x00000024 +	fcntlf_ofd_setlk     = 0x00000025 +	fcntlf_ofd_setlkw    = 0x00000026 +	fcntlf_owner_pgrp    = 0x00000002 +	fcntlf_owner_pid     = 0x00000001 +	fcntlf_owner_tid     = 0x00000000 +	fcntlf_rdlck         = 0x00000000 +	fcntlf_setfd         = 0x00000002 +	fcntlf_setfl         = 0x00000004 +	fcntlf_setlk         = 0x00000006 +	fcntlf_setlk64       = 0x0000000d +	fcntlf_setlkw        = 0x00000007 +	fcntlf_setlkw64      = 0x0000000e +	fcntlf_setown        = 0x00000008 +	fcntlf_setown_ex     = 0x0000000f +	fcntlf_setsig        = 0x0000000a +	fcntlf_shlck         = 0x00000008 +	fcntlf_unlck         = 0x00000002 +	fcntlf_wrlck         = 0x00000001 +	fcntllock_ex         = 0x00000002 +	fcntllock_mand       = 0x00000020 +	fcntllock_nb         = 0x00000004 +	fcntllock_read       = 0x00000040 +	fcntllock_rw         = 0x000000c0 +	fcntllock_sh         = 0x00000001 +	fcntllock_un         = 0x00000008 +	fcntllock_write      = 0x00000080 +	fcntlo_accmode       = 0x00000003 +	fcntlo_append        = 0x00000400 +	fcntlo_cloexec       = 0x00080000 +	fcntlo_creat         = 0x00000040 +	fcntlo_direct        = 0x00004000 +	fcntlo_directory     = 0x00010000 +	fcntlo_dsync         = 0x00001000 +	fcntlo_excl          = 0x00000080 +	fcntlo_largefile     = 0x00008000 +	fcntlo_ndelay        = 0x00000800 +	fcntlo_noatime       = 0x00040000 +	fcntlo_noctty        = 0x00000100 +	fcntlo_nofollow      = 0x00020000 +	fcntlo_nonblock      = 0x00000800 +	fcntlo_path          = 0x00200000 +	fcntlo_rdonly        = 0x00000000 +	fcntlo_rdwr          = 0x00000002 +	fcntlo_trunc         = 0x00000200 +	fcntlo_wronly        = 0x00000001 +) + +pub enum Errno { +	enoerror = 0x00000000 +	e2big = 0x00000007 +	eacces = 0x0000000d +	eagain = 0x0000000b +	ebadf = 0x00000009 +	ebusy = 0x00000010 +	echild = 0x0000000a +	edom = 0x00000021 +	eexist = 0x00000011 +	efault = 0x0000000e +	efbig = 0x0000001b +	eintr = 0x00000004 +	einval = 0x00000016 +	eio = 0x00000005 +	eisdir = 0x00000015 +	emfile = 0x00000018 +	emlink = 0x0000001f +	enfile = 0x00000017 +	enodev = 0x00000013 +	enoent = 0x00000002 +	enoexec = 0x00000008 +	enomem = 0x0000000c +	enospc = 0x0000001c +	enotblk = 0x0000000f +	enotdir = 0x00000014 +	enotty = 0x00000019 +	enxio = 0x00000006 +	eperm = 0x00000001 +	epipe = 0x00000020 +	erange = 0x00000022 +	erofs = 0x0000001e +	espipe = 0x0000001d +	esrch = 0x00000003 +	etxtbsy = 0x0000001a +	exdev = 0x00000012 +} + +pub enum Mm_prot { +	prot_read = 0x1 +	prot_write = 0x2 +	prot_exec = 0x4 +	prot_none = 0x0 +	prot_growsdown = 0x01000000 +	prot_growsup = 0x02000000 +} + +pub enum Map_flags { +	map_shared = 0x01 +	map_private = 0x02 +	map_shared_validate = 0x03 +	map_type = 0x0f +	map_fixed = 0x10 +	map_file = 0x00 +	map_anonymous = 0x20 +	map_huge_shift = 26 +	map_huge_mask = 0x3f +} + +fn sys_call0(scn u64) u64 { +	res := u64(0) +	asm amd64 { +		syscall +		; =a (res) +		; a (scn) +	} +	return res +} + +fn sys_call1(scn u64, arg1 u64) u64 { +	res := u64(0) +	asm amd64 { +		syscall +		; =a (res) +		; a (scn) +		  D (arg1) +	} +	return res +} + +fn sys_call2(scn u64, arg1 u64, arg2 u64) u64 { +	res := u64(0) +	asm amd64 { +		syscall +		; =a (res) +		; a (scn) +		  D (arg1) +		  S (arg2) +	} +	return res +} + +fn sys_call3(scn u64, arg1 u64, arg2 u64, arg3 u64) u64 { +	res := u64(0) +	asm amd64 { +		syscall +		; =a (res) +		; a (scn) +		  D (arg1) +		  S (arg2) +		  d (arg3) +	} +	return res +} + +fn sys_call4(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64) u64 { +	res := u64(0) +	asm amd64 { +		mov r10, arg4 +		syscall +		; =a (res) +		; a (scn) +		  D (arg1) +		  S (arg2) +		  d (arg3) +		  r (arg4) +		; r10 +	} +	return res +} + +fn sys_call5(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64, arg5 u64) u64 { +	res := u64(0) +	asm amd64 { +		mov r10, arg4 +		mov r8, arg5 +		syscall +		; =a (res) +		; a (scn) +		  D (arg1) +		  S (arg2) +		  d (arg3) +		  r (arg4) +		  r (arg5) +		; r10 +		  r8 +	} +	return res +} + +fn sys_call6(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64, arg5 u64, arg6 u64) u64 { +	res := u64(0) +	asm amd64 { +		mov r10, arg4 +		mov r8, arg5 +		mov r9, arg6 +		syscall +		; =a (res) +		; a (scn) +		  D (arg1) +		  S (arg2) +		  d (arg3) +		  r (arg4) +		  r (arg5) +		  r (arg6) +		; r10 +		  r8 +		  r9 +	} +	return res +} + +fn split_int_errno(rc_in u64) (i64, Errno) { +	rc := i64(rc_in) +	if rc < 0 { +		return i64(-1), Errno(-rc) +	} +	return rc, Errno.enoerror +} + +// 0 sys_read unsigned int fd char *buf size_t count +pub fn sys_read(fd i64, buf &byte, count u64) (i64, Errno) { +	return split_int_errno(sys_call3(0, u64(fd), u64(buf), count)) +} + +// 1 sys_write unsigned int fd, const char *buf, size_t count +pub fn sys_write(fd i64, buf &byte, count u64) (i64, Errno) { +	return split_int_errno(sys_call3(1, u64(fd), u64(buf), count)) +} + +pub fn sys_open(filename &byte, flags i64, mode int) (i64, Errno) { +	// 2 sys_open  const char *filename  int flags int mode +	return split_int_errno(sys_call3(2, u64(filename), u64(flags), u64(mode))) +} + +pub fn sys_close(fd i64) Errno { +	// 3 sys_close unsigned int fd +	return Errno(-i64(sys_call1(3, u64(fd)))) +} + +// 9 sys_mmap unsigned long addr  unsigned long len unsigned long prot  unsigned long flags unsigned long fd  unsigned long off +pub fn sys_mmap(addr &byte, len u64, prot Mm_prot, flags Map_flags, fildes u64, off u64) (&byte, Errno) { +	rc := sys_call6(9, u64(addr), len, u64(prot), u64(flags), fildes, off) +	a, e := split_int_errno(rc) +	return &byte(a), e +} + +pub fn sys_munmap(addr voidptr, len u64) Errno { +	// 11 sys_munmap  unsigned long addr  size_t len +	return Errno(-sys_call2(11, u64(addr), len)) +} + +// 22  sys_pipe  int *filedes +pub fn sys_pipe(filedes &int) Errno { +	return Errno(sys_call1(22, u64(filedes))) +} + +// 24 sys_sched_yield +pub fn sys_sched_yield() Errno { +	return Errno(sys_call0(24)) +} + +pub fn sys_madvise(addr voidptr, len u64, advice int) Errno { +	// 28 sys_madvise unsigned long start size_t len_in int behavior +	return Errno(sys_call3(28, u64(addr), len, u64(advice))) +} + +// 39 sys_getpid +pub fn sys_getpid() int { +	return int(sys_call0(39)) +} + +// 57 sys_fork +pub fn sys_fork() int { +	return int(sys_call0(57)) +} + +// 58 sys_vfork +pub fn sys_vfork() int { +	return int(sys_call0(58)) +} + +// 33  sys_dup2  unsigned int oldfd  unsigned int newfd +pub fn sys_dup2(oldfd int, newfd int) (i64, Errno) { +	return split_int_errno(sys_call2(33, u64(oldfd), u64(newfd))) +} + +// 59  sys_execve  const char *filename  const char *const argv[]  const char *const envp[] +// pub fn sys_execve(filename byteptr, argv []byteptr, envp []byteptr) int { +//  return sys_call3(59, filename, argv, envp) +//} + +// 60 sys_exit  int error_code +pub fn sys_exit(ec int) { +	sys_call1(60, u64(ec)) +} + +// 102 sys_getuid +pub fn sys_getuid() int { +	return int(sys_call0(102)) +} + +// 247 sys_waitid  int which pid_t upid  struct siginfo *infop int options struct rusage *ru +pub fn sys_waitid(which Wi_which, pid int, infop &int, options int, ru voidptr) Errno { +	return Errno(sys_call5(247, u64(which), u64(pid), u64(infop), u64(options), u64(ru))) +} + +/* +A few years old, but still relevant +https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/ + +>0 sys_read unsigned int fd char *buf size_t count +>1 sys_write unsigned int fd const char *buf size_t count +>2 sys_open  const char *filename  int flags int mode +>3 sys_close unsigned int fd +4 sys_stat  const char *filename  struct stat *statbuf +5 sys_fstat unsigned int fd struct stat *statbuf +6 sys_lstat fconst char *filename struct stat *statbuf +7 sys_poll  struct poll_fd *ufds  unsigned int nfds long timeout_msecs +8 sys_lseek unsigned int fd off_t offset  unsigned int origin +>9 sys_mmap unsigned long addr  unsigned long len unsigned long prot  unsigned long flags unsigned long fd  unsigned long off +10  sys_mprotect  unsigned long start size_t len  unsigned long prot +>11 sys_munmap  unsigned long addr  size_t len +12  sys_brk unsigned long brk +13  sys_rt_sigaction  int sig const struct sigaction *act struct sigaction *oact  size_t sigsetsize +14  sys_rt_sigprocmask  int how sigset_t *nset  sigset_t *oset  size_t sigsetsize +15  sys_rt_sigreturn  unsigned long __unused +16  sys_ioctl unsigned int fd unsigned int cmd  unsigned long arg +17  sys_pread64 unsigned long fd  char *buf size_t count  loff_t pos +18  sys_pwrite64  unsigned int fd const char *buf size_t count  loff_t pos +19  sys_readv unsigned long fd  const struct iovec *vec unsigned long vlen +20  sys_writev  unsigned long fd  const struct iovec *vec unsigned long vlen +21  sys_access  const char *filename  int mode +>22  sys_pipe  int *filedes +23  sys_select  int n fd_set *inp fd_set *outp  fd_set*exp  struct timeval *tvp +>24 sys_sched_yield +25  sys_mremap  unsigned long addr  unsigned long old_len unsigned long new_len unsigned long flags unsigned long new_addr +26  sys_msync unsigned long start size_t len  int flags +27  sys_mincore unsigned long start size_t len  unsigned char *vec +>28 sys_madvise unsigned long start size_t len_in int behavior +29  sys_shmget  key_t key size_t size int shmflg +30  sys_shmat int shmid char *shmaddr int shmflg +31  sys_shmctl  int shmid int cmd struct shmid_ds *buf +32  sys_dup unsigned int fildes +33  sys_dup2  unsigned int oldfd  unsigned int newfd +34  sys_pause +35  sys_nanosleep struct timespec *rqtp struct timespec *rmtp +36  sys_getitimer int which struct itimerval *value +37  sys_alarm unsigned int seconds +38  sys_setitimer int which struct itimerval *value struct itimerval *ovalue +>39 sys_getpid +40  sys_sendfile  int out_fd  int in_fd off_t *offset size_t count +41  sys_socket  int family  int type  int protocol +42  sys_connect int fd  struct sockaddr *uservaddr  int addrlen +43  sys_accept  int fd  struct sockaddr *upeer_sockaddr int *upeer_addrlen +44  sys_sendto  int fd  void *buff  size_t len  unsigned flags  struct sockaddr *addr int addr_len +45  sys_recvfrom  int fd  void *ubuf  size_t size unsigned flags  struct sockaddr *addr int *addr_len +46  sys_sendmsg int fd  struct msghdr *msg  unsigned flags +47  sys_recvmsg int fd  struct msghdr *msg  unsigned int flags +48  sys_shutdown  int fd  int how +49  sys_bind  int fd  struct sokaddr *umyaddr int addrlen +50  sys_listen  int fd  int backlog +51  sys_getsockname int fd  struct sockaddr *usockaddr  int *usockaddr_len +52  sys_getpeername int fd  struct sockaddr *usockaddr  int *usockaddr_len +53  sys_socketpair  int family  int type  int protocol  int *usockvec +54  sys_setsockopt  int fd  int level int optname char *optval  int optlen +55  sys_getsockopt  int fd  int level int optname char *optval  int *optlen +56  sys_clone unsigned long clone_flags unsigned long newsp void *parent_tid  void *child_tid +>57 sys_fork +>58 sys_vfork +>59 sys_execve  const char *filename  const char *const argv[]  const char *const envp[] +>60 sys_exit  int error_code +61  sys_wait4 pid_t upid  int *stat_addr  int options struct rusage *ru +62  sys_kill  pid_t pid int sig +63  sys_uname struct old_utsname *name +64  sys_semget  key_t key int nsems int semflg +65  sys_semop int semid struct sembuf *tsops  unsigned nsops +66  sys_semctl  int semid int semnum  int cmd union semun arg +67  sys_shmdt char *shmaddr +68  sys_msgget  key_t key int msgflg +69  sys_msgsnd  int msqid struct msgbuf *msgp size_t msgsz  int msgflg +70  sys_msgrcv  int msqid struct msgbuf *msgp size_t msgsz  long msgtyp int msgflg +71  sys_msgctl  int msqid int cmd struct msqid_ds *buf +72  sys_fcntl unsigned int fd unsigned int cmd  unsigned long arg +73  sys_flock unsigned int fd unsigned int cmd +74  sys_fsync unsigned int fd +75  sys_fdatasync unsigned int fd +76  sys_truncate  const char *path  long length +77  sys_ftruncate unsigned int fd unsigned long length +78  sys_getdents  unsigned int fd struct linux_dirent *dirent unsigned int count +79  sys_getcwd  char *buf unsigned long size +80  sys_chdir const char *filename +81  sys_fchdir  unsigned int fd +82  sys_rename  const char *oldname const char *newname +83  sys_mkdir const char *pathname  int mode +84  sys_rmdir const char *pathname +85  sys_creat const char *pathname  int mode +86  sys_link  const char *oldname const char *newname +87  sys_unlink  const char *pathname +88  sys_symlink const char *oldname const char *newname +89  sys_readlink  const char *path  char *buf int bufsiz +90  sys_chmod const char *filename  mode_t mode +91  sys_fchmod  unsigned int fd mode_t mode +92  sys_chown const char *filename  uid_t user  gid_t group +93  sys_fchown  unsigned int fd uid_t user  gid_t group +94  sys_lchown  const char *filename  uid_t user  gid_t group +95  sys_umask int mask +96  sys_gettimeofday  struct timeval *tv  struct timezone *tz +97  sys_getrlimit unsigned int resource struct rlimit *rlim +98  sys_getrusage int who struct rusage *ru +99  sys_sysinfo struct sysinfo *info +100 sys_times struct sysinfo *info +101 sys_ptrace  long request  long pid  unsigned long addr  unsigned long data +>102 sys_getuid +103 sys_syslog  int type  char *buf int len +104 sys_getgid +105 sys_setuid  uid_t uid +106 sys_setgid  gid_t gid +107 sys_geteuid +108 sys_getegid +109 sys_setpgid pid_t pid pid_t pgid +110 sys_getppid +111 sys_getpgrp +112 sys_setsid +113 sys_setreuid  uid_t ruid  uid_t euid +114 sys_setregid  gid_t rgid  gid_t egid +115 sys_getgroups int gidsetsize  gid_t *grouplist +116 sys_setgroups int gidsetsize  gid_t *grouplist +117 sys_setresuid uid_t *ruid uid_t *euid uid_t *suid +118 sys_getresuid uid_t *ruid uid_t *euid uid_t *suid +119 sys_setresgid gid_t rgid  gid_t egid  gid_t sgid +120 sys_getresgid gid_t *rgid gid_t *egid gid_t *sgid +121 sys_getpgid pid_t pid +122 sys_setfsuid  uid_t uid +123 sys_setfsgid  gid_t gid +124 sys_getsid  pid_t pid +125 sys_capget  cap_user_header_t header  cap_user_data_t dataptr +126 sys_capset  cap_user_header_t header  const cap_user_data_t data +127 sys_rt_sigpending sigset_t *set size_t sigsetsize +128 sys_rt_sigtimedwait const sigset_t *uthese  siginfo_t *uinfo  const struct timespec *uts  size_t sigsetsize +129 sys_rt_sigqueueinfo pid_t pid int sig siginfo_t *uinfo +130 sys_rt_sigsuspend sigset_t *unewset size_t sigsetsize +131 sys_sigaltstack const stack_t *uss  stack_t *uoss +132 sys_utime char *filename  struct utimbuf *times +133 sys_mknod const char *filename  umode_t mode  unsigned dev +134 sys_uselib  NOT IMPLEMENTED +135 sys_personality unsigned int personality +136 sys_ustat unsigned dev  struct ustat *ubuf +137 sys_statfs  const char *pathname  struct statfs *buf +138 sys_fstatfs unsigned int fd struct statfs *buf +139 sys_sysfs int option  unsigned long arg1  unsigned long arg2 +140 sys_getpriority int which int who +141 sys_setpriority int which int who int niceval +142 sys_sched_setparam  pid_t pid struct sched_param *param +143 sys_sched_getparam  pid_t pid struct sched_param *param +144 sys_sched_setscheduler  pid_t pid int policy  struct sched_param *param +145 sys_sched_getscheduler  pid_t pid +146 sys_sched_get_priority_max  int policy +147 sys_sched_get_priority_min  int policy +148 sys_sched_rr_get_interval pid_t pid struct timespec *interval +149 sys_mlock unsigned long start size_t len +150 sys_munlock unsigned long start size_t len +151 sys_mlockall  int flags +152 sys_munlockall +153 sys_vhangup +154 sys_modify_ldt  int func  void *ptr unsigned long bytecount +155 sys_pivot_root  const char *new_root  const char *put_old +156 sys__sysctl struct __sysctl_args *args +157 sys_prctl int option  unsigned long arg2  unsigned long arg3  unsigned long arg4    unsigned long arg5 +158 sys_arch_prctl  struct task_struct *task  int code  unsigned long *addr +159 sys_adjtimex  struct timex *txc_p +160 sys_setrlimit unsigned int resource struct rlimit *rlim +161 sys_chroot  const char *filename +162 sys_sync +163 sys_acct  const char *name +164 sys_settimeofday  struct timeval *tv  struct timezone *tz +165 sys_mount char *dev_name  char *dir_name  char *type  unsigned long flags void *data +166 sys_umount2 const char *target  int flags +167 sys_swapon  const char *specialfile int swap_flags +168 sys_swapoff const char *specialfile +169 sys_reboot  int magic1  int magic2  unsigned int cmd  void *arg +170 sys_sethostname char *name  int len +171 sys_setdomainname char *name  int len +172 sys_iopl  unsigned int level  struct pt_regs *regs +173 sys_ioperm  unsigned long from  unsigned long num int turn_on +174 sys_create_module REMOVED IN Linux 2.6 +175 sys_init_module void *umod  unsigned long len const char *uargs +176 sys_delete_module const chat *name_user unsigned int flags +177 sys_get_kernel_syms REMOVED IN Linux 2.6 +178 sys_query_module  REMOVED IN Linux 2.6 +179 sys_quotactl  unsigned int cmd  const char *special qid_t id  void *addr +180 sys_nfsservctl  NOT IMPLEMENTED +181 sys_getpmsg NOT IMPLEMENTED +182 sys_putpmsg NOT IMPLEMENTED +183 sys_afs_syscall NOT IMPLEMENTED +184 sys_tuxcall NOT IMPLEMENTED +185 sys_security  NOT IMPLEMENTED +186 sys_gettid +187 sys_readahead int fd  loff_t offset size_t count +188 sys_setxattr  const char *pathname  const char *name  const void *value size_t size int flags +189 sys_lsetxattr const char *pathname  const char *name  const void *value size_t size int flags +190 sys_fsetxattr int fd  const char *name  const void *value size_t size int flags +191 sys_getxattr  const char *pathname  const char *name  void *value size_t size +192 sys_lgetxattr const char *pathname  const char *name  void *value size_t size +193 sys_fgetxattr int fd  const har *name void *value size_t size +194 sys_listxattr const char *pathname  char *list  size_t size +195 sys_llistxattr  const char *pathname  char *list  size_t size +196 sys_flistxattr  int fd  char *list  size_t size +197 sys_removexattr const char *pathname  const char *name +198 sys_lremovexattr  const char *pathname  const char *name +199 sys_fremovexattr  int fd  const char *name +200 sys_tkill pid_t pid ing sig +201 sys_time  time_t *tloc +202 sys_futex u32 *uaddr  int op  u32 val struct timespec *utime  u32 *uaddr2 u32 val3 +203 sys_sched_setaffinity pid_t pid unsigned int len  unsigned long *user_mask_ptr +204 sys_sched_getaffinity pid_t pid unsigned int len  unsigned long *user_mask_ptr +205 sys_set_thread_area NOT IMPLEMENTED. Use arch_prctl +206 sys_io_setup  unsigned nr_events  aio_context_t *ctxp +207 sys_io_destroy  aio_context_t ctx +208 sys_io_getevents  aio_context_t ctx_id  long min_nr long nr struct io_event *events +209 sys_io_submit aio_context_t ctx_id  long nr struct iocb **iocbpp +210 sys_io_cancel aio_context_t ctx_id  struct iocb *iocb struct io_event *result +211 sys_get_thread_area NOT IMPLEMENTED. Use arch_prctl +212 sys_lookup_dcookie  u64 cookie64  long buf  long len +213 sys_epoll_create  int size +214 sys_epoll_ctl_old NOT IMPLEMENTED +215 sys_epoll_wait_old  NOT IMPLEMENTED +216 sys_remap_file_pages  unsigned long start unsigned long size  unsigned long prot  unsigned long pgoff unsigned long flags +217 sys_getdents64  unsigned int fd struct linux_dirent64 *dirent unsigned int count +218 sys_set_tid_address int *tidptr +219 sys_restart_syscall +220 sys_semtimedop  int semid struct sembuf *tsops  unsigned nsops  const struct timespec *timeout +221 sys_fadvise64 int fd  loff_t offset size_t len  int advice +222 sys_timer_create  const clockid_t which_clock struct sigevent *timer_event_spec timer_t *created_timer_id +223 sys_timer_settime timer_t timer_id  int flags const struct itimerspec *new_setting  struct itimerspec *old_setting +224 sys_timer_gettime timer_t timer_id  struct itimerspec *setting +225 sys_timer_getoverrun  timer_t timer_id +226 sys_timer_delete  timer_t timer_id +227 sys_clock_settime const clockid_t which_clock const struct timespec *tp +228 sys_clock_gettime const clockid_t which_clock struct timespec *tp +229 sys_clock_getres  const clockid_t which_clock struct timespec *tp +230 sys_clock_nanosleep const clockid_t which_clock int flags const struct timespec *rqtp struct timespec *rmtp +231 sys_exit_group  int error_code +232 sys_epoll_wait  int epfd  struct epoll_event *events  int maxevents int timeout +233 sys_epoll_ctl int epfd  int op  int fd  struct epoll_event *event +234 sys_tgkill  pid_t tgid  pid_t pid int sig +235 sys_utimes  char *filename  struct timeval *utimes +236 sys_vserver NOT IMPLEMENTED +237 sys_mbind unsigned long start unsigned long len unsigned long mode  unsigned long *nmask  unsigned long maxnode unsigned flags +238 sys_set_mempolicy int mode  unsigned long *nmask  unsigned long maxnode +239 sys_get_mempolicy int *policy unsigned long *nmask  unsigned long maxnode unsigned long addr  unsigned long flags +240 sys_mq_open const char *u_name  int oflag mode_t mode struct mq_attr *u_attr +241 sys_mq_unlink const char *u_name +242 sys_mq_timedsend  mqd_t mqdes const char *u_msg_ptr size_t msg_len  unsigned int msg_prio const stuct timespec *u_abs_timeout +243 sys_mq_timedreceive mqd_t mqdes char *u_msg_ptr size_t msg_len  unsigned int *u_msg_prio  const struct timespec *u_abs_timeout +244 sys_mq_notify mqd_t mqdes const struct sigevent *u_notification +245 sys_mq_getsetattr mqd_t mqdes const struct mq_attr *u_mqstat  struct mq_attr *u_omqstat +246 sys_kexec_load  unsigned long entry unsigned long nr_segments struct kexec_segment *segments  unsigned long flags +>247 sys_waitid  int which pid_t upid  struct siginfo *infop int options struct rusage *ru +248 sys_add_key const char *_type const char *_description  const void *_payload  size_t plen +249 sys_request_key const char *_type const char *_description  const char *_callout_info key_serial_t destringid +250 sys_keyctl  int option  unsigned long arg2  unsigned long arg3  unsigned long arg4  unsigned long arg5 +251 sys_ioprio_set  int which int who int ioprio +252 sys_ioprio_get  int which int who +253 sys_inotify_init +254 sys_inotify_add_watch int fd  const char *pathname  u32 mask +255 sys_inotify_rm_watch  int fd  __s32 wd +256 sys_migrate_pages pid_t pid unsigned long maxnode const unsigned long *old_nodes  const unsigned long *new_nodes +257 sys_openat  int dfd const char *filename  int flags int mode +258 sys_mkdirat int dfd const char *pathname  int mode +259 sys_mknodat int dfd const char *filename  int mode  unsigned dev +260 sys_fchownat  int dfd const char *filename  uid_t user  gid_t group int flag +261 sys_futimesat int dfd const char *filename  struct timeval *utimes +262 sys_newfstatat  int dfd const char *filename  struct stat *statbuf  int flag +263 sys_unlinkat  int dfd const char *pathname  int flag +264 sys_renameat  int oldfd const char *oldname int newfd const char *newname +265 sys_linkat  int oldfd const char *oldname int newfd const char *newname int flags +266 sys_symlinkat const char *oldname int newfd const char *newname +267 sys_readlinkat  int dfd const char *pathname  char *buf int bufsiz +268 sys_fchmodat  int dfd const char *filename  mode_t mode +269 sys_faccessat int dfd const char *filename  int mode +270 sys_pselect6  int n fd_set *inp fd_set *outp  fd_set *exp struct timespec *tsp  void *sig +271 sys_ppoll struct pollfd *ufds unsigned int nfds struct timespec *tsp  const sigset_t *sigmask size_t sigsetsize +272 sys_unshare unsigned long unshare_flags +273 sys_set_robust_list struct robust_list_head *head size_t len +274 sys_get_robust_list int pid struct robust_list_head **head_ptr  size_t *len_ptr +275 sys_splice  int fd_in loff_t *off_in  int fd_out  loff_t *off_out size_t len  unsigned int flags +276 sys_tee int fdin  int fdout size_t len  unsigned int flags +277 sys_sync_file_range long fd loff_t offset loff_t bytes  long flags +278 sys_vmsplice  int fd  const struct iovec *iov unsigned long nr_segs unsigned int flags +279 sys_move_pages  pid_t pid unsigned long nr_pages  const void **pages  const int *nodes  int *status int flags +280 sys_utimensat int dfd const char *filename  struct timespec *utimes int flags +281 sys_epoll_pwait int epfd  struct epoll_event *events  int maxevents int timeout const sigset_t *sigmask size_t sigsetsize +282 sys_signalfd  int ufd sigset_t *user_mask size_t sizemask +283 sys_timerfd_create  int clockid int flags +284 sys_eventfd unsigned int count +285 sys_fallocate long fd long mode loff_t offset loff_t len +286 sys_timerfd_settime int ufd int flags const struct itimerspec *utmr struct itimerspec *otmr +287 sys_timerfd_gettime int ufd struct itimerspec *otmr +288 sys_accept4 int fd  struct sockaddr *upeer_sockaddr int *upeer_addrlen  int flags +289 sys_signalfd4 int ufd sigset_t *user_mask size_t sizemask int flags +290 sys_eventfd2  unsigned int count  int flags +291 sys_epoll_create1 int flags +292 sys_dup3  unsigned int oldfd  unsigned int newfd  int flags +293 sys_pipe2 int *filedes  int flags +294 sys_inotify_init1 int flags +295 sys_preadv  unsigned long fd  const struct iovec *vec unsigned long vlen  unsigned long pos_l unsigned long pos_h +296 sys_pwritev unsigned long fd  const struct iovec *vec unsigned long vlen  unsigned long pos_l unsigned long pos_h +297 sys_rt_tgsigqueueinfo pid_t tgid  pid_t pid int sig siginfo_t *uinfo +298 sys_perf_event_open struct perf_event_attr *attr_uptr pid_t pid int cpu int group_fd  unsigned long flags +299 sys_recvmmsg  int fd  struct msghdr *mmsg unsigned int vlen unsigned int flags  struct timespec *timeout +300 sys_fanotify_init unsigned int flags  unsigned int event_f_flags +301 sys_fanotify_mark long fanotify_fd  long flags  __u64 mask  long dfd  long pathname +302 sys_prlimit64 pid_t pid unsigned int resource const struct rlimit64 *new_rlim struct rlimit64 *old_rlim +303 sys_name_to_handle_at int dfd const char *name  struct file_handle *handle  int *mnt_id int flag +304 sys_open_by_handle_at int dfd const char *name  struct file_handle *handle  int *mnt_id int flags +305 sys_clock_adjtime clockid_t which_clock struct timex *tx +306 sys_syncfs  int fd +307 sys_sendmmsg  int fd  struct mmsghdr *mmsg  unsigned int vlen unsigned int flags +308 sys_setns int fd  int nstype +309 sys_getcpu  unsigned *cpup  unsigned *nodep struct getcpu_cache *unused +310 sys_process_vm_readv  pid_t pid const struct iovec *lvec  unsigned long liovcnt const struct iovec *rvec  unsigned long riovcnt unsigned long flags +311 sys_process_vm_writev pid_t pid const struct iovec *lvec  unsigned long liovcnt const struct iovcc *rvec  unsigned long riovcnt unsigned long flags +312 sys_kcmp  pid_t pid1  pid_t pid2  int type  unsigned long idx1  unsigned long idx2 +313 sys_finit_module  int fd  const char __user *uargs  int flags +314 sys_sched_setattr pid_t pid struct sched_attr __user *attr  unsigned int flags +315 sys_sched_getattr pid_t pid struct sched_attr __user *attr  unsigned int size unsigned int flags +316 sys_renameat2 int olddfd  const char __user *oldname  int newdfd  const char __user *newname  unsigned int flags +317 sys_seccomp unsigned int op unsigned int flags  const char __user *uargs +318 sys_getrandom char __user *buf  size_t count  unsigned int flags +319 sys_memfd_create  const char __user *uname_ptr  unsigned int flags +320 sys_kexec_file_load int kernel_fd int initrd_fd unsigned long cmdline_len const char __user *cmdline_ptr  unsigned long flags +321 sys_bpf int cmd union bpf_attr *attr  unsigned int size +322 stub_execveat int dfd const char __user *filename const char __user *const __user *argv const char __user *const __user *envp int flags +323 userfaultfd int flags +324 membarrier  int cmd int flags +325 mlock2  unsigned long start size_t len  int flags +326 copy_file_range int fd_in loff_t __user *off_in int fd_out  loff_t __user * off_out size_t len  unsigned int flags +327 preadv2 unsigned long fd  const struct iovec __user *vec  unsigned long vlen  unsigned long pos_l unsigned long pos_h int flags +328 pwritev2  unsigned long fd  const struct iovec __user *vec  unsigned long vlen  unsigned long pos_l unsigned long pos_h int flags +*/ diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/mm_bare.v b/v_windows/v/old/vlib/builtin/linux_bare/old/mm_bare.v new file mode 100644 index 0000000..cee5f99 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/mm_bare.v @@ -0,0 +1,58 @@ +module builtin + +const ( +	mem_prot  = Mm_prot(int(Mm_prot.prot_read) | int(Mm_prot.prot_write)) +	mem_flags = Map_flags(int(Map_flags.map_private) | int(Map_flags.map_anonymous)) +	page_size = u64(Linux_mem.page_size) +) + +pub fn mm_pages(size u64) u32 { +	pages := (size + u64(4) + page_size) / page_size +	return u32(pages) +} + +pub fn mm_alloc(size u64) (&byte, Errno) { +	pages := mm_pages(size) +	n_bytes := u64(pages * u32(Linux_mem.page_size)) + +	a, e := sys_mmap(0, n_bytes, mem_prot, mem_flags, -1, 0) +	if e == .enoerror { +		mut ap := &int(a) +		*ap = pages +		return &byte(a + 4), e +	} +	return &byte(0), e +} + +pub fn mm_free(addr &byte) Errno { +	ap := &int(addr - 4) +	size := u64(*ap) * u64(Linux_mem.page_size) + +	return sys_munmap(ap, size) +} + +pub fn mem_copy(dest0 voidptr, src0 voidptr, n int) voidptr { +	mut dest := &byte(dest0) +	src := &byte(src0) +	for i in 0 .. n { +		dest[i] = src[i] +	} +	return dest0 +} + +[unsafe] +pub fn malloc(n int) &byte { +	if n < 0 { +		panic('malloc(<0)') +	} + +	ptr, e := mm_alloc(u64(n)) +	assert e == .enoerror +	assert !isnil(ptr) +	return ptr +} + +[unsafe] +pub fn free(ptr voidptr) { +	assert mm_free(ptr) == .enoerror +} diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/string_bare.v b/v_windows/v/old/vlib/builtin/linux_bare/old/string_bare.v new file mode 100644 index 0000000..8f7edfc --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/string_bare.v @@ -0,0 +1,150 @@ +module builtin + +pub struct string { +pub: +	str &byte +	len int +} + +pub fn strlen(s &byte) int { +	mut i := 0 +	for ; s[i] != 0; i++ {} +	return i +} + +pub fn tos(s &byte, len int) string { +	if s == 0 { +		panic('tos(): nil string') +	} +	return string{ +		str: s +		len: len +	} +} + +fn (s string) add(a string) string { +	new_len := a.len + s.len +	mut res := string{ +		len: new_len +		str: malloc(new_len + 1) +	} +	for j in 0 .. s.len { +		res[j] = s[j] +	} +	for j in 0 .. a.len { +		res[s.len + j] = a[j] +	} +	res[new_len] = 0 // V strings are not null terminated, but just in case +	return res +} + +/* +pub fn tos_clone(s byteptr) string { +	if s == 0 { +		panic('tos: nil string') +	} +	return tos2(s).clone() +} +*/ + +// Same as `tos`, but calculates the length. Called by `string(bytes)` casts. +// Used only internally. +pub fn tos2(s &byte) string { +	if s == 0 { +		panic('tos2: nil string') +	} +	return string{ +		str: s +		len: strlen(s) +	} +} + +pub fn tos3(s &char) string { +	if s == 0 { +		panic('tos3: nil string') +	} +	return string{ +		str: &byte(s) +		len: strlen(&byte(s)) +	} +} + +pub fn string_eq(s1 string, s2 string) bool { +	if s1.len != s2.len { +		return false +	} +	for i in 0 .. s1.len { +		if s1[i] != s2[i] { +			return false +		} +	} +	return true +} + +pub fn string_ne(s1 string, s2 string) bool { +	return !string_eq(s1, s2) +} + +pub fn i64_tos(buf &byte, len int, n0 i64, base int) string { +	if base < 2 { +		panic('base must be >= 2') +	} +	if base > 36 { +		panic('base must be <= 36') +	} + +	mut b := tos(buf, len) +	mut i := len - 1 + +	mut n := n0 +	neg := n < 0 +	if neg { +		n = -n +	} + +	b[i--] = 0 + +	for { +		c := (n % base) + 48 +		b[i--] = if c > 57 { c + 7 } else { c } +		if i < 0 { +			panic('buffer to small') +		} +		n /= base +		if n < 1 { +			break +		} +	} +	if neg { +		if i < 0 { +			panic('buffer to small') +		} +		b[i--] = 45 +	} +	offset := i + 1 +	b.str = b.str + offset +	b.len -= (offset + 1) +	return b +} + +pub fn i64_str(n0 i64, base int) string { +	buf := malloc(80) +	return i64_tos(buf, 79, n0, base) +} + +pub fn ptr_str(ptr voidptr) string { +	buf := [16]byte{} +	hex := i64_tos(buf, 15, i64(ptr), 16) +	res := '0x' + hex +	return res +} + +pub fn (a string) clone() string { +	mut b := string{ +		len: a.len +		str: malloc(a.len + 1) +	} +	mem_copy(b.str, a.str, a.len) +	b[a.len] = 0 +	return b +} diff --git a/v_windows/v/old/vlib/builtin/linux_bare/old/syscallwrapper_test.v b/v_windows/v/old/vlib/builtin/linux_bare/old/syscallwrapper_test.v new file mode 100644 index 0000000..cbaf355 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/linux_bare/old/syscallwrapper_test.v @@ -0,0 +1,27 @@ +import os + +fn test_syscallwrappers() { +	if true { +		return +	} +	$if linux { +		$if x64 { +			exe := os.executable() +			vdir := os.dir(exe) +			if vdir.len > 1 { +				dot_checks := vdir + '/.checks' +				assert os.is_dir(dot_checks) + +				os.chdir(dot_checks) +				checks_v := 'checks.v' +				assert os.exists(checks_v) +				rc := os.execute_or_exit('v run $checks_v') +				assert rc.exit_code == 0 +				assert !rc.output.contains('V panic: An assertion failed.') +				assert !rc.output.contains('failed') +			} else { +				panic("Can't find test directory") +			} +		} +	} +} diff --git a/v_windows/v/old/vlib/builtin/map.v b/v_windows/v/old/vlib/builtin/map.v new file mode 100644 index 0000000..37b2e49 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/map.v @@ -0,0 +1,794 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module builtin + +fn C.wyhash(&byte, u64, u64, &u64) u64 + +fn C.wyhash64(u64, u64) u64 + +/* +This is a highly optimized hashmap implementation. It has several traits that +in combination makes it very fast and memory efficient. Here is a short expl- +anation of each trait. After reading this you should have a basic understand- +ing of how it functions: + +1. Hash-function: Wyhash. Wyhash is the fastest hash-function for short keys +passing SMHasher, so it was an obvious choice. + +2. Open addressing: Robin Hood Hashing. With this method, a hash-collision is +resolved by probing. As opposed to linear probing, Robin Hood hashing has a +simple but clever twist: As new keys are inserted, old keys are shifted arou- +nd in a way such that all keys stay reasonably close to the slot they origin- +ally hash to. A new key may displace a key already inserted if its probe cou- +nt is larger than that of the key at the current position. + +3. Memory layout: key-value pairs are stored in a `DenseArray`. This is a dy- +namic array with a very low volume of unused memory, at the cost of more rea- +llocations when inserting elements. It also preserves the order of the key-v- +alues. This array is named `key_values`. Instead of probing a new key-value, +this map probes two 32-bit numbers collectively. The first number has its 8 +most significant bits reserved for the probe-count and the remaining 24 bits +are cached bits from the hash which are utilized for faster re-hashing. This +number is often referred to as `meta`. The other 32-bit number is the index +at which the key-value was pushed to in `key_values`. Both of these numbers +are stored in a sparse array `metas`. The `meta`s and `kv_index`s are stored +at even and odd indices, respectively: + +metas = [meta, kv_index, 0, 0, meta, kv_index, 0, 0, meta, kv_index, ...] +key_values = [kv, kv, kv, ...] + +4. The size of metas is a power of two. This enables the use of bitwise AND +to convert the 64-bit hash to a bucket/index that doesn't overflow metas. If +the size is power of two you can use "hash & (SIZE - 1)" instead of "hash % +SIZE". Modulo is extremely expensive so using '&' is a big performance impro- +vement. The general concern with this approach is that you only make use of +the lower bits of the hash which can cause more collisions. This is solved by +using a well-dispersed hash-function. + +5. The hashmap keeps track of the highest probe_count. The trick is to alloc- +ate `extra_metas` > max(probe_count), so you never have to do any bounds-che- +cking since the extra meta memory ensures that a meta will never go beyond +the last index. + +6. Cached rehashing. When the `load_factor` of the map exceeds the `max_load_ +factor` the size of metas is doubled and all the key-values are "rehashed" to +find the index for their meta's in the new array. Instead of rehashing compl- +etely, it simply uses the cached-hashbits stored in the meta, resulting in +much faster rehashing. +*/ +const ( +	// Number of bits from the hash stored for each entry +	hashbits            = 24 +	// Number of bits from the hash stored for rehashing +	max_cached_hashbits = 16 +	// Initial log-number of buckets in the hashtable +	init_log_capicity   = 5 +	// Initial number of buckets in the hashtable +	init_capicity       = 1 << init_log_capicity +	// Maximum load-factor (len / capacity) +	max_load_factor     = 0.8 +	// Initial highest even index in metas +	init_even_index     = init_capicity - 2 +	// Used for incrementing `extra_metas` when max +	// probe count is too high, to avoid overflow +	extra_metas_inc     = 4 +	// Bitmask to select all the hashbits +	hash_mask           = u32(0x00FFFFFF) +	// Used for incrementing the probe-count +	probe_inc           = u32(0x01000000) +) + +// fast_string_eq is intended to be fast when +// the strings are very likely to be equal +// TODO: add branch prediction hints +[inline] +fn fast_string_eq(a string, b string) bool { +	if a.len != b.len { +		return false +	} +	unsafe { +		return C.memcmp(a.str, b.str, b.len) == 0 +	} +} + +// DenseArray represents a dynamic array with very low growth factor +struct DenseArray { +	key_bytes   int +	value_bytes int +mut: +	cap     int +	len     int +	deletes u32 // count +	// array allocated (with `cap` bytes) on first deletion +	// has non-zero element when key deleted +	all_deleted &byte +	values      &byte +	keys        &byte +} + +[inline] +fn new_dense_array(key_bytes int, value_bytes int) DenseArray { +	cap := 8 +	return DenseArray{ +		key_bytes: key_bytes +		value_bytes: value_bytes +		cap: cap +		len: 0 +		deletes: 0 +		all_deleted: 0 +		keys: unsafe { malloc(cap * key_bytes) } +		values: unsafe { malloc(cap * value_bytes) } +	} +} + +[inline] +fn (d &DenseArray) key(i int) voidptr { +	return unsafe { d.keys + i * d.key_bytes } +} + +// for cgen +[inline] +fn (d &DenseArray) value(i int) voidptr { +	return unsafe { d.values + i * d.value_bytes } +} + +[inline] +fn (d &DenseArray) has_index(i int) bool { +	return d.deletes == 0 || unsafe { d.all_deleted[i] } == 0 +} + +// Make space to append an element and return index +// The growth-factor is roughly 1.125 `(x + (x >> 3))` +[inline] +fn (mut d DenseArray) expand() int { +	old_cap := d.cap +	old_value_size := d.value_bytes * old_cap +	old_key_size := d.key_bytes * old_cap +	if d.cap == d.len { +		d.cap += d.cap >> 3 +		unsafe { +			d.keys = realloc_data(d.keys, old_key_size, d.key_bytes * d.cap) +			d.values = realloc_data(d.values, old_value_size, d.value_bytes * d.cap) +			if d.deletes != 0 { +				d.all_deleted = realloc_data(d.all_deleted, old_cap, d.cap) +				C.memset(d.all_deleted + d.len, 0, d.cap - d.len) +			} +		} +	} +	push_index := d.len +	unsafe { +		if d.deletes != 0 { +			d.all_deleted[push_index] = 0 +		} +	} +	d.len++ +	return push_index +} + +// Move all zeros to the end of the array and resize array +fn (mut d DenseArray) zeros_to_end() { +	// TODO alloca? +	mut tmp_value := unsafe { malloc(d.value_bytes) } +	mut tmp_key := unsafe { malloc(d.key_bytes) } +	mut count := 0 +	for i in 0 .. d.len { +		if d.has_index(i) { +			// swap (TODO: optimize) +			unsafe { +				if count != i { +					// Swap keys +					C.memcpy(tmp_key, d.key(count), d.key_bytes) +					C.memcpy(d.key(count), d.key(i), d.key_bytes) +					C.memcpy(d.key(i), tmp_key, d.key_bytes) +					// Swap values +					C.memcpy(tmp_value, d.value(count), d.value_bytes) +					C.memcpy(d.value(count), d.value(i), d.value_bytes) +					C.memcpy(d.value(i), tmp_value, d.value_bytes) +				} +			} +			count++ +		} +	} +	unsafe { +		free(tmp_value) +		free(tmp_key) +		d.deletes = 0 +		// TODO: reallocate instead as more deletes are likely +		free(d.all_deleted) +	} +	d.len = count +	old_cap := d.cap +	d.cap = if count < 8 { 8 } else { count } +	unsafe { +		d.values = realloc_data(d.values, d.value_bytes * old_cap, d.value_bytes * d.cap) +		d.keys = realloc_data(d.keys, d.key_bytes * old_cap, d.key_bytes * d.cap) +	} +} + +type MapHashFn = fn (voidptr) u64 + +type MapEqFn = fn (voidptr, voidptr) bool + +type MapCloneFn = fn (voidptr, voidptr) + +type MapFreeFn = fn (voidptr) + +// map is the internal representation of a V `map` type. +pub struct map { +	// Number of bytes of a key +	key_bytes int +	// Number of bytes of a value +	value_bytes int +mut: +	// Highest even index in the hashtable +	even_index u32 +	// Number of cached hashbits left for rehashing +	cached_hashbits byte +	// Used for right-shifting out used hashbits +	shift byte +	// Array storing key-values (ordered) +	key_values DenseArray +	// Pointer to meta-data: +	// - Odd indices store kv_index. +	// - Even indices store probe_count and hashbits. +	metas &u32 +	// Extra metas that allows for no ranging when incrementing +	// index in the hashmap +	extra_metas     u32 +	has_string_keys bool +	hash_fn         MapHashFn +	key_eq_fn       MapEqFn +	clone_fn        MapCloneFn +	free_fn         MapFreeFn +pub mut: +	// Number of key-values currently in the hashmap +	len int +} + +fn map_hash_string(pkey voidptr) u64 { +	key := *unsafe { &string(pkey) } +	return C.wyhash(key.str, u64(key.len), 0, &u64(C._wyp)) +} + +fn map_hash_int_1(pkey voidptr) u64 { +	return C.wyhash64(*unsafe { &byte(pkey) }, 0) +} + +fn map_hash_int_2(pkey voidptr) u64 { +	return C.wyhash64(*unsafe { &u16(pkey) }, 0) +} + +fn map_hash_int_4(pkey voidptr) u64 { +	return C.wyhash64(*unsafe { &u32(pkey) }, 0) +} + +fn map_hash_int_8(pkey voidptr) u64 { +	return C.wyhash64(*unsafe { &u64(pkey) }, 0) +} + +fn map_eq_string(a voidptr, b voidptr) bool { +	return fast_string_eq(*unsafe { &string(a) }, *unsafe { &string(b) }) +} + +fn map_eq_int_1(a voidptr, b voidptr) bool { +	return unsafe { *&byte(a) == *&byte(b) } +} + +fn map_eq_int_2(a voidptr, b voidptr) bool { +	return unsafe { *&u16(a) == *&u16(b) } +} + +fn map_eq_int_4(a voidptr, b voidptr) bool { +	return unsafe { *&u32(a) == *&u32(b) } +} + +fn map_eq_int_8(a voidptr, b voidptr) bool { +	return unsafe { *&u64(a) == *&u64(b) } +} + +fn map_clone_string(dest voidptr, pkey voidptr) { +	unsafe { +		s := *&string(pkey) +		(*&string(dest)) = s.clone() +	} +} + +fn map_clone_int_1(dest voidptr, pkey voidptr) { +	unsafe { +		*&byte(dest) = *&byte(pkey) +	} +} + +fn map_clone_int_2(dest voidptr, pkey voidptr) { +	unsafe { +		*&u16(dest) = *&u16(pkey) +	} +} + +fn map_clone_int_4(dest voidptr, pkey voidptr) { +	unsafe { +		*&u32(dest) = *&u32(pkey) +	} +} + +fn map_clone_int_8(dest voidptr, pkey voidptr) { +	unsafe { +		*&u64(dest) = *&u64(pkey) +	} +} + +fn map_free_string(pkey voidptr) { +	unsafe { +		(*&string(pkey)).free() +	} +} + +fn map_free_nop(_ voidptr) { +} + +fn new_map(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn) map { +	metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc)) +	// for now assume anything bigger than a pointer is a string +	has_string_keys := key_bytes > sizeof(voidptr) +	return map{ +		key_bytes: key_bytes +		value_bytes: value_bytes +		even_index: init_even_index +		cached_hashbits: max_cached_hashbits +		shift: init_log_capicity +		key_values: new_dense_array(key_bytes, value_bytes) +		metas: unsafe { &u32(vcalloc_noscan(metasize)) } +		extra_metas: extra_metas_inc +		len: 0 +		has_string_keys: has_string_keys +		hash_fn: hash_fn +		key_eq_fn: key_eq_fn +		clone_fn: clone_fn +		free_fn: free_fn +	} +} + +fn new_map_init(hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn, n int, key_bytes int, value_bytes int, keys voidptr, values voidptr) map { +	mut out := new_map(key_bytes, value_bytes, hash_fn, key_eq_fn, clone_fn, free_fn) +	// TODO pre-allocate n slots +	mut pkey := &byte(keys) +	mut pval := &byte(values) +	for _ in 0 .. n { +		unsafe { +			out.set(pkey, pval) +			pkey = pkey + key_bytes +			pval = pval + value_bytes +		} +	} +	return out +} + +pub fn (mut m map) move() map { +	r := *m +	unsafe { +		C.memset(m, 0, sizeof(map)) +	} +	return r +} + +[inline] +fn (m &map) key_to_index(pkey voidptr) (u32, u32) { +	hash := m.hash_fn(pkey) +	index := hash & m.even_index +	meta := ((hash >> m.shift) & hash_mask) | probe_inc +	return u32(index), u32(meta) +} + +[inline] +fn (m &map) meta_less(_index u32, _metas u32) (u32, u32) { +	mut index := _index +	mut meta := _metas +	for meta < unsafe { m.metas[index] } { +		index += 2 +		meta += probe_inc +	} +	return index, meta +} + +[inline] +fn (mut m map) meta_greater(_index u32, _metas u32, kvi u32) { +	mut meta := _metas +	mut index := _index +	mut kv_index := kvi +	for unsafe { m.metas[index] } != 0 { +		if meta > unsafe { m.metas[index] } { +			unsafe { +				tmp_meta := m.metas[index] +				m.metas[index] = meta +				meta = tmp_meta +				tmp_index := m.metas[index + 1] +				m.metas[index + 1] = kv_index +				kv_index = tmp_index +			} +		} +		index += 2 +		meta += probe_inc +	} +	unsafe { +		m.metas[index] = meta +		m.metas[index + 1] = kv_index +	} +	probe_count := (meta >> hashbits) - 1 +	m.ensure_extra_metas(probe_count) +} + +[inline] +fn (mut m map) ensure_extra_metas(probe_count u32) { +	if (probe_count << 1) == m.extra_metas { +		size_of_u32 := sizeof(u32) +		old_mem_size := (m.even_index + 2 + m.extra_metas) +		m.extra_metas += extra_metas_inc +		mem_size := (m.even_index + 2 + m.extra_metas) +		unsafe { +			x := realloc_data(&byte(m.metas), int(size_of_u32 * old_mem_size), int(size_of_u32 * mem_size)) +			m.metas = &u32(x) +			C.memset(m.metas + mem_size - extra_metas_inc, 0, int(sizeof(u32) * extra_metas_inc)) +		} +		// Should almost never happen +		if probe_count == 252 { +			panic('Probe overflow') +		} +	} +} + +// Insert new element to the map. The element is inserted if its key is +// not equivalent to the key of any other element already in the container. +// If the key already exists, its value is changed to the value of the new element. +fn (mut m map) set(key voidptr, value voidptr) { +	load_factor := f32(m.len << 1) / f32(m.even_index) +	if load_factor > max_load_factor { +		m.expand() +	} +	mut index, mut meta := m.key_to_index(key) +	index, meta = m.meta_less(index, meta) +	// While we might have a match +	for meta == unsafe { m.metas[index] } { +		kv_index := int(unsafe { m.metas[index + 1] }) +		pkey := unsafe { m.key_values.key(kv_index) } +		if m.key_eq_fn(key, pkey) { +			unsafe { +				pval := m.key_values.value(kv_index) +				C.memcpy(pval, value, m.value_bytes) +			} +			return +		} +		index += 2 +		meta += probe_inc +	} +	kv_index := m.key_values.expand() +	unsafe { +		pkey := m.key_values.key(kv_index) +		pvalue := m.key_values.value(kv_index) +		m.clone_fn(pkey, key) +		C.memcpy(&byte(pvalue), value, m.value_bytes) +	} +	m.meta_greater(index, meta, u32(kv_index)) +	m.len++ +} + +// Doubles the size of the hashmap +fn (mut m map) expand() { +	old_cap := m.even_index +	m.even_index = ((m.even_index + 2) << 1) - 2 +	// Check if any hashbits are left +	if m.cached_hashbits == 0 { +		m.shift += max_cached_hashbits +		m.cached_hashbits = max_cached_hashbits +		m.rehash() +	} else { +		m.cached_rehash(old_cap) +		m.cached_hashbits-- +	} +} + +// A rehash is the reconstruction of the hash table: +// All the elements in the container are rearranged according +// to their hash value into the newly sized key-value container. +// Rehashes are performed when the load_factor is going to surpass +// the max_load_factor in an operation. +fn (mut m map) rehash() { +	meta_bytes := sizeof(u32) * (m.even_index + 2 + m.extra_metas) +	unsafe { +		// TODO: use realloc_data here too +		x := v_realloc(&byte(m.metas), int(meta_bytes)) +		m.metas = &u32(x) +		C.memset(m.metas, 0, meta_bytes) +	} +	for i := 0; i < m.key_values.len; i++ { +		if !m.key_values.has_index(i) { +			continue +		} +		pkey := unsafe { m.key_values.key(i) } +		mut index, mut meta := m.key_to_index(pkey) +		index, meta = m.meta_less(index, meta) +		m.meta_greater(index, meta, u32(i)) +	} +} + +// This method works like rehash. However, instead of rehashing the +// key completely, it uses the bits cached in `metas`. +fn (mut m map) cached_rehash(old_cap u32) { +	old_metas := m.metas +	metasize := int(sizeof(u32) * (m.even_index + 2 + m.extra_metas)) +	m.metas = unsafe { &u32(vcalloc(metasize)) } +	old_extra_metas := m.extra_metas +	for i := u32(0); i <= old_cap + old_extra_metas; i += 2 { +		if unsafe { old_metas[i] } == 0 { +			continue +		} +		old_meta := unsafe { old_metas[i] } +		old_probe_count := ((old_meta >> hashbits) - 1) << 1 +		old_index := (i - old_probe_count) & (m.even_index >> 1) +		mut index := (old_index | (old_meta << m.shift)) & m.even_index +		mut meta := (old_meta & hash_mask) | probe_inc +		index, meta = m.meta_less(index, meta) +		kv_index := unsafe { old_metas[i + 1] } +		m.meta_greater(index, meta, kv_index) +	} +	unsafe { free(old_metas) } +} + +// This method is used for assignment operators. If the argument-key +// does not exist in the map, it's added to the map along with the zero/default value. +// If the key exists, its respective value is returned. +fn (mut m map) get_and_set(key voidptr, zero voidptr) voidptr { +	for { +		mut index, mut meta := m.key_to_index(key) +		for { +			if meta == unsafe { m.metas[index] } { +				kv_index := int(unsafe { m.metas[index + 1] }) +				pkey := unsafe { m.key_values.key(kv_index) } +				if m.key_eq_fn(key, pkey) { +					pval := unsafe { m.key_values.value(kv_index) } +					return unsafe { &byte(pval) } +				} +			} +			index += 2 +			meta += probe_inc +			if meta > unsafe { m.metas[index] } { +				break +			} +		} +		// Key not found, insert key with zero-value +		m.set(key, zero) +	} +	assert false +	return voidptr(0) +} + +// If `key` matches the key of an element in the container, +// the method returns a reference to its mapped value. +// If not, a zero/default value is returned. +fn (m &map) get(key voidptr, zero voidptr) voidptr { +	mut index, mut meta := m.key_to_index(key) +	for { +		if meta == unsafe { m.metas[index] } { +			kv_index := int(unsafe { m.metas[index + 1] }) +			pkey := unsafe { m.key_values.key(kv_index) } +			if m.key_eq_fn(key, pkey) { +				pval := unsafe { m.key_values.value(kv_index) } +				return unsafe { &byte(pval) } +			} +		} +		index += 2 +		meta += probe_inc +		if meta > unsafe { m.metas[index] } { +			break +		} +	} +	return zero +} + +// If `key` matches the key of an element in the container, +// the method returns a reference to its mapped value. +// If not, a zero pointer is returned. +// This is used in `x := m['key'] or { ... }` +fn (m &map) get_check(key voidptr) voidptr { +	mut index, mut meta := m.key_to_index(key) +	for { +		if meta == unsafe { m.metas[index] } { +			kv_index := int(unsafe { m.metas[index + 1] }) +			pkey := unsafe { m.key_values.key(kv_index) } +			if m.key_eq_fn(key, pkey) { +				pval := unsafe { m.key_values.value(kv_index) } +				return unsafe { &byte(pval) } +			} +		} +		index += 2 +		meta += probe_inc +		if meta > unsafe { m.metas[index] } { +			break +		} +	} +	return 0 +} + +// Checks whether a particular key exists in the map. +fn (m &map) exists(key voidptr) bool { +	mut index, mut meta := m.key_to_index(key) +	for { +		if meta == unsafe { m.metas[index] } { +			kv_index := int(unsafe { m.metas[index + 1] }) +			pkey := unsafe { m.key_values.key(kv_index) } +			if m.key_eq_fn(key, pkey) { +				return true +			} +		} +		index += 2 +		meta += probe_inc +		if meta > unsafe { m.metas[index] } { +			break +		} +	} +	return false +} + +[inline] +fn (mut d DenseArray) delete(i int) { +	if d.deletes == 0 { +		d.all_deleted = vcalloc(d.cap) // sets to 0 +	} +	d.deletes++ +	unsafe { +		d.all_deleted[i] = 1 +	} +} + +// Removes the mapping of a particular key from the map. +[unsafe] +pub fn (mut m map) delete(key voidptr) { +	mut index, mut meta := m.key_to_index(key) +	index, meta = m.meta_less(index, meta) +	// Perform backwards shifting +	for meta == unsafe { m.metas[index] } { +		kv_index := int(unsafe { m.metas[index + 1] }) +		pkey := unsafe { m.key_values.key(kv_index) } +		if m.key_eq_fn(key, pkey) { +			for (unsafe { m.metas[index + 2] } >> hashbits) > 1 { +				unsafe { +					m.metas[index] = m.metas[index + 2] - probe_inc +					m.metas[index + 1] = m.metas[index + 3] +				} +				index += 2 +			} +			m.len-- +			m.key_values.delete(kv_index) +			unsafe { +				m.metas[index] = 0 +				m.free_fn(pkey) +				// Mark key as deleted +				C.memset(pkey, 0, m.key_bytes) +			} +			if m.key_values.len <= 32 { +				return +			} +			// Clean up key_values if too many have been deleted +			if m.key_values.deletes >= (m.key_values.len >> 1) { +				m.key_values.zeros_to_end() +				m.rehash() +			} +			return +		} +		index += 2 +		meta += probe_inc +	} +} + +// Returns all keys in the map. +fn (m &map) keys() array { +	mut keys := __new_array(m.len, 0, m.key_bytes) +	mut item := unsafe { &byte(keys.data) } +	if m.key_values.deletes == 0 { +		for i := 0; i < m.key_values.len; i++ { +			unsafe { +				pkey := m.key_values.key(i) +				m.clone_fn(item, pkey) +				item = item + m.key_bytes +			} +		} +		return keys +	} +	for i := 0; i < m.key_values.len; i++ { +		if !m.key_values.has_index(i) { +			continue +		} +		unsafe { +			pkey := m.key_values.key(i) +			m.clone_fn(item, pkey) +			item = item + m.key_bytes +		} +	} +	return keys +} + +// warning: only copies keys, does not clone +[unsafe] +fn (d &DenseArray) clone() DenseArray { +	res := DenseArray{ +		key_bytes: d.key_bytes +		value_bytes: d.value_bytes +		cap: d.cap +		len: d.len +		deletes: d.deletes +		all_deleted: 0 +		values: 0 +		keys: 0 +	} +	unsafe { +		if d.deletes != 0 { +			res.all_deleted = memdup(d.all_deleted, d.cap) +		} +		res.keys = memdup(d.keys, d.cap * d.key_bytes) +		res.values = memdup(d.values, d.cap * d.value_bytes) +	} +	return res +} + +// clone returns a clone of the `map`. +[unsafe] +pub fn (m &map) clone() map { +	metasize := int(sizeof(u32) * (m.even_index + 2 + m.extra_metas)) +	res := map{ +		key_bytes: m.key_bytes +		value_bytes: m.value_bytes +		even_index: m.even_index +		cached_hashbits: m.cached_hashbits +		shift: m.shift +		key_values: unsafe { m.key_values.clone() } +		metas: unsafe { &u32(malloc(metasize)) } +		extra_metas: m.extra_metas +		len: m.len +		has_string_keys: m.has_string_keys +		hash_fn: m.hash_fn +		key_eq_fn: m.key_eq_fn +		clone_fn: m.clone_fn +		free_fn: m.free_fn +	} +	unsafe { C.memcpy(res.metas, m.metas, metasize) } +	if !m.has_string_keys { +		return res +	} +	// clone keys +	for i in 0 .. m.key_values.len { +		if !m.key_values.has_index(i) { +			continue +		} +		m.clone_fn(res.key_values.key(i), m.key_values.key(i)) +	} +	return res +} + +// free releases all memory resources occupied by the `map`. +[unsafe] +pub fn (m &map) free() { +	unsafe { free(m.metas) } +	if m.key_values.deletes == 0 { +		for i := 0; i < m.key_values.len; i++ { +			unsafe { +				pkey := m.key_values.key(i) +				m.free_fn(pkey) +			} +		} +	} else { +		for i := 0; i < m.key_values.len; i++ { +			if !m.key_values.has_index(i) { +				continue +			} +			unsafe { +				pkey := m.key_values.key(i) +				m.free_fn(pkey) +			} +		} +		unsafe { free(m.key_values.all_deleted) } +	} +	unsafe { +		free(m.key_values.keys) +		free(m.key_values.values) +	} +} diff --git a/v_windows/v/old/vlib/builtin/map_d_gcboehm_opt.v b/v_windows/v/old/vlib/builtin/map_d_gcboehm_opt.v new file mode 100644 index 0000000..93049b7 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/map_d_gcboehm_opt.v @@ -0,0 +1,146 @@ +// "noscan" versions of `map` initialization routines +// +// They are used when the compiler can proof that either the keys or the values or both +// do not contain any pointers. Such objects can be placed in a memory area that is not +// scanned by the garbage collector + +module builtin + +[inline] +fn new_dense_array_noscan(key_bytes int, key_noscan bool, value_bytes int, value_noscan bool) DenseArray { +	cap := 8 +	keys := if key_noscan { +		unsafe { malloc_noscan(cap * key_bytes) } +	} else { +		unsafe { malloc(cap * key_bytes) } +	} +	values := if value_noscan { +		unsafe { malloc_noscan(cap * value_bytes) } +	} else { +		unsafe { malloc(cap * value_bytes) } +	} +	return DenseArray{ +		key_bytes: key_bytes +		value_bytes: value_bytes +		cap: cap +		len: 0 +		deletes: 0 +		all_deleted: 0 +		keys: keys +		values: values +	} +} + +fn new_map_noscan_key(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn) map { +	metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc)) +	// for now assume anything bigger than a pointer is a string +	has_string_keys := key_bytes > sizeof(voidptr) +	return map{ +		key_bytes: key_bytes +		value_bytes: value_bytes +		even_index: init_even_index +		cached_hashbits: max_cached_hashbits +		shift: init_log_capicity +		key_values: new_dense_array_noscan(key_bytes, true, value_bytes, false) +		metas: unsafe { &u32(vcalloc_noscan(metasize)) } +		extra_metas: extra_metas_inc +		len: 0 +		has_string_keys: has_string_keys +		hash_fn: hash_fn +		key_eq_fn: key_eq_fn +		clone_fn: clone_fn +		free_fn: free_fn +	} +} + +fn new_map_noscan_value(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn) map { +	metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc)) +	// for now assume anything bigger than a pointer is a string +	has_string_keys := key_bytes > sizeof(voidptr) +	return map{ +		key_bytes: key_bytes +		value_bytes: value_bytes +		even_index: init_even_index +		cached_hashbits: max_cached_hashbits +		shift: init_log_capicity +		key_values: new_dense_array_noscan(key_bytes, false, value_bytes, true) +		metas: unsafe { &u32(vcalloc_noscan(metasize)) } +		extra_metas: extra_metas_inc +		len: 0 +		has_string_keys: has_string_keys +		hash_fn: hash_fn +		key_eq_fn: key_eq_fn +		clone_fn: clone_fn +		free_fn: free_fn +	} +} + +fn new_map_noscan_key_value(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn) map { +	metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc)) +	// for now assume anything bigger than a pointer is a string +	has_string_keys := key_bytes > sizeof(voidptr) +	return map{ +		key_bytes: key_bytes +		value_bytes: value_bytes +		even_index: init_even_index +		cached_hashbits: max_cached_hashbits +		shift: init_log_capicity +		key_values: new_dense_array_noscan(key_bytes, true, value_bytes, true) +		metas: unsafe { &u32(vcalloc_noscan(metasize)) } +		extra_metas: extra_metas_inc +		len: 0 +		has_string_keys: has_string_keys +		hash_fn: hash_fn +		key_eq_fn: key_eq_fn +		clone_fn: clone_fn +		free_fn: free_fn +	} +} + +fn new_map_init_noscan_key(hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn, n int, key_bytes int, value_bytes int, keys voidptr, values voidptr) map { +	mut out := new_map_noscan_key(key_bytes, value_bytes, hash_fn, key_eq_fn, clone_fn, +		free_fn) +	// TODO pre-allocate n slots +	mut pkey := &byte(keys) +	mut pval := &byte(values) +	for _ in 0 .. n { +		unsafe { +			out.set(pkey, pval) +			pkey = pkey + key_bytes +			pval = pval + value_bytes +		} +	} +	return out +} + +fn new_map_init_noscan_value(hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn, n int, key_bytes int, value_bytes int, keys voidptr, values voidptr) map { +	mut out := new_map_noscan_value(key_bytes, value_bytes, hash_fn, key_eq_fn, clone_fn, +		free_fn) +	// TODO pre-allocate n slots +	mut pkey := &byte(keys) +	mut pval := &byte(values) +	for _ in 0 .. n { +		unsafe { +			out.set(pkey, pval) +			pkey = pkey + key_bytes +			pval = pval + value_bytes +		} +	} +	return out +} + +fn new_map_init_noscan_key_value(hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn, n int, key_bytes int, value_bytes int, keys voidptr, values voidptr) map { +	mut out := new_map_noscan_key_value(key_bytes, value_bytes, hash_fn, key_eq_fn, clone_fn, +		free_fn) +	// TODO pre-allocate n slots +	mut pkey := &byte(keys) +	mut pval := &byte(values) +	for _ in 0 .. n { +		unsafe { +			out.set(pkey, pval) +			pkey = pkey + key_bytes +			pval = pval + value_bytes +		} +	} +	return out +} diff --git a/v_windows/v/old/vlib/builtin/map_of_floats_test.v b/v_windows/v/old/vlib/builtin/map_of_floats_test.v new file mode 100644 index 0000000..3906cb1 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/map_of_floats_test.v @@ -0,0 +1,27 @@ +fn test_map_of_f32() { +	mut m32 := map[f32]string{} +	m32[1.0] = 'one' +	println(m32) +	assert '$m32' == r"{1.: 'one'}" +	for k, v in m32 { +		assert typeof(k).name == 'f32' +		assert typeof(v).name == 'string' +		assert k == 1.0 +		assert v == 'one' +	} +} + +fn test_map_of_f64() { +	mut m64 := map{ +		3.14: 'pi' +	} +	m64[1.0] = 'one' +	println(m64) +	assert '$m64' == r"{3.14: 'pi', 1.: 'one'}" +	for k, v in m64 { +		assert typeof(k).name == 'f64' +		assert typeof(v).name == 'string' +		assert k in [1.0, 3.14] +		assert v in ['pi', 'one'] +	} +} diff --git a/v_windows/v/old/vlib/builtin/map_test.v b/v_windows/v/old/vlib/builtin/map_test.v new file mode 100644 index 0000000..9c50ab7 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/map_test.v @@ -0,0 +1,947 @@ +import rand + +const ( +	strings = unique_strings(20000, 10) +) + +fn unique_strings(arr_len int, str_len int) []string { +	mut arr := []string{cap: arr_len} +	for arr.len < arr_len { +		str := rand.string(str_len) +		if str !in arr { +			arr << str +		} +	} +	return arr +} + +fn test_get_and_set_many() { +	mut m := map[string]int{} +	for i, s in strings { +		m[s] = i +		assert m[s] == i +		assert m.len == i + 1 +	} +	for i, s in strings { +		assert m[s] == i +	} +	assert m.len == strings.len +} + +fn test_for_in_many() { +	mut m := map[string]int{} +	for i, s in strings { +		m[s] = i +	} +	for k, v in m { +		assert m[k] == v +	} +} + +fn test_keys_many() { +	mut m := map[string]int{} +	for i, s in strings { +		m[s] = i +	} +	keys := m.keys() +	assert keys.len == strings.len +	assert keys.len == m.len +	assert keys == strings +} + +fn test_deletes_many() { +	mut m := map[string]int{} +	for i, s in strings { +		m[s] = i +	} +	for i, s in strings { +		m.delete(s) +		assert m[s] == 0 +		assert m.len == strings.len - (i + 1) +	} +	assert m.len == 0 +	assert m.keys().len == 0 +} + +struct User { +mut: +	name string +} + +struct Aaa { +mut: +	m     map[string]int +	users map[string]User +} + +fn (mut a Aaa) set(key string, val int) { +	a.m[key] = val +} + +fn test_map() { +	mut m := map[string]int{} +	assert m.len == 0 +	m['hi'] = 80 +	m['hello'] = 101 +	assert m['hi'] == 80 +	assert m['hello'] == 101 +	assert m.len == 2 +	assert 'hi' in m +	mut sum := 0 +	// Test `for in` +	for _, val in m { +		sum += val +	} +	assert sum == 80 + 101 +	// Test `.keys()` +	keys := m.keys() +	assert keys.len == 2 +	assert 'hi' in keys +	assert 'hello' in keys +	m.delete('hi') +	assert m.len == 1 +	m.delete('aloha') +	assert m.len == 1 +	assert m['hi'] == 0 +	assert m.keys().len == 1 +	assert m.keys()[0] == 'hello' +	// // +	mut users := map[string]User{} +	users['1'] = User{'Peter'} +	peter := users['1'] +	assert peter.name == 'Peter' +	mut a := Aaa{ +		m: map[string]int{} +		users: map[string]User{} +	} +	a.users['Bob'] = User{'Bob'} +	q := a.users['Bob'] +	assert q.name == 'Bob' +	// test struct field change +	a.users['Bob'].name = 'bob' +	q2 := a.users['Bob'] +	assert q2.name == 'bob' +	a.m['one'] = 1 +	a.set('two', 2) +	assert a.m['one'] == 1 +	assert a.m['two'] == 2 +} + +fn test_map_init() { +	one := 'one' +	three := 'three' +	m := map{ +		one:   1 +		'two': 2 +		three: 1 + 2 +	} +	assert m['one'] == 1 +	assert m['two'] == 2 +	assert m['three'] == 3 +	assert m['unknown'] == 0 +} + +fn test_string_map() { +	// m := map[string]Fn +} + +fn test_large_map() { +	// ticks := time.ticks() +	mut nums := map[string]int{} +	n := 30 * 1000 +	for i in 0 .. n { +		key := i.str() +		nums[key] = i +	} +	assert nums['1'] == 1 +	assert nums['999'] == 999 +	assert nums['1000000'] == 0 +	// println(time.ticks() - ticks) +} + +fn test_various_map_value() { +	mut m1 := map[string]int{} +	m1['test'] = 1 +	assert m1['test'] == 1 +	mut m2 := map[string]string{} +	m2['test'] = 'test' +	assert m2['test'] == 'test' +	mut m3 := map[string]i8{} +	m3['test'] = i8(0) +	assert m3['test'] == i8(0) +	mut m4 := map[string]i16{} +	m4['test'] = i16(0) +	assert m4['test'] == i16(0) +	mut m7 := map[string]u16{} +	m7['test'] = u16(0) +	assert m7['test'] == u16(0) +	mut m8 := map[string]u32{} +	m8['test'] = u32(0) +	assert m8['test'] == u32(0) +	mut m9 := map[string]bool{} +	m9['test'] = true +	assert m9['test'] == true +	mut m10 := map[string]byte{} +	m10['test'] = byte(0) +	assert m10['test'] == byte(0) +	mut m11 := map[string]f32{} +	m11['test'] = f32(0.0) +	assert m11['test'] == f32(0.0) +	mut m12 := map[string]f64{} +	m12['test'] = f64(0.0) +	assert m12['test'] == f64(0.0) +	// mut m13 := map[string]rune +	// m13['test'] = rune(0) +	// assert m13['test'] == rune(0) +	mut m14 := map[string]voidptr{} +	m14['test'] = voidptr(0) +	assert m14['test'] == voidptr(0) +	mut m15 := map[string]&byte{} +	m15['test'] = &byte(0) +	assert m15['test'] == &byte(0) +	mut m16 := map[string]i64{} +	m16['test'] = i64(0) +	assert m16['test'] == i64(0) +	mut m17 := map[string]u64{} +	m17['test'] = u64(0) +	assert m17['test'] == u64(0) +	mut m18 := map[string]&int{} +	m18['test'] = &int(0) +	assert m18['test'] == &int(0) +} + +fn test_string_arr() { +	mut m := map[string][]string{} +	m['a'] = ['one', 'two'] +	assert m['a'].len == 2 +	assert m['a'][0] == 'one' +	assert m['a'][1] == 'two' +} + +fn mut_map(mut m map[string]int) { +	m['a'] = 10 +} + +fn test_mut_arg() { +	mut m := map[string]int{} +	mut_map(mut m) +	a := m['a'] +	assert a == 10 +} + +fn test_delete() { +	mut m := map[string]int{} +	m['one'] = 1 +	m['two'] = 2 +	println(m['two']) // => "2" +	m.delete('two') +	println(m['two'].str()) // => 0 +	assert ('two' in m) == false +	println('two' in m) // => true, on Linux  and Windows  <-- wrong ! +} + +fn test_delete_size() { +	arr := ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] +	mut m := map[string]int{} +	for _ in 0 .. 10 { +		for i in 0 .. 10 { +			m[arr[i]] = i +		} +		assert m.len == 10 +		println(m.len) +		for i in 0 .. 10 { +			m.delete(arr[i]) +		} +	} +} + +fn test_nested_for_in() { +	mut m := map[string]int{} +	for i in 0 .. 1000 { +		m[i.str()] = i +	} +	mut i := 0 +	for key1, _ in m { +		assert key1 == i.str() +		i++ +		mut j := 0 +		for key2, _ in m { +			assert key2 == j.str() +			j++ +		} +	} +} + +fn test_delete_in_for_in() { +	mut m := map[string]string{} +	for i in 0 .. 1000 { +		m[i.str()] = i.str() +	} +	mut i := 0 +	for key, _ in m { +		assert key == i.str() +		m.delete(key) +		i++ +	} +	assert m.str() == '{}' +	assert m.len == 0 +} + +fn test_set_in_for_in() { +	mut m := map[string]string{} +	for i in 0 .. 10 { +		m[i.str()] = i.str() +	} +	mut last_key := '' +	mut i := 0 +	for key, _ in m { +		m['10'] = '10' +		assert key == i.str() +		last_key = key +		i++ +	} +	assert last_key == '10' +} + +fn test_delete_and_set_in_for_in() { +	mut m := map[string]string{} +	for i in 0 .. 1000 { +		m[i.str()] = i.str() +	} +	mut i := 0 +	for key, _ in m { +		assert key == i.str() +		m.delete(key) +		m[key] = i.str() +		if i == 999 { +			break +		} +		i++ +	} +	assert m.len == 1000 +	i = 0 +	for key, _ in m { +		assert m[key] == i.str() +		i++ +	} +	assert i == 1000 +} + +struct Mstruct1 { +pub mut: +	mymap map[string]int +} + +struct Mstruct2 { +pub mut: +	mymap map[string]f64 +} + +struct Mstruct3 { +pub mut: +	mymap map[string]u16 +} + +fn test_map_assign() { +	mut a := map[string]f64{} +	mut b := map[string]int{} +	mut c := map[string]u16{} +	a = map{ +		'x': 12.4 +		'y': 3 +	} +	b = map{ +		'u': -13 +		'v': 12 +	} +	c = map{ +		's': u16(5) +		't': 3 +	} +	_ := Mstruct1{map{ +		'p': 12 +	}} +	_ := Mstruct2{map{ +		'q': 1.7 +	}} +	_ := Mstruct3{map{ +		'r': u16(6) +		's': 5 +	}} +} + +fn test_postfix_op_directly() { +	mut a := map[string]int{} +	a['aaa']++ +	assert a['aaa'] == 1 +	a['aaa']++ +	assert a['aaa'] == 2 +	a['bbb']-- +	assert a['bbb'] == -1 +	a['bbb']-- +	assert a['bbb'] == -2 +} + +fn test_map_push_directly() { +	mut a := map[string][]string{} +	a['aaa'] << ['a', 'b', 'c'] +	assert a['aaa'].len == 3 +	assert a['aaa'] == ['a', 'b', 'c'] +} + +fn test_assign_directly() { +	mut a := map[string]int{} +	a['aaa'] += 4 +	assert a['aaa'] == 4 +	a['aaa'] -= 2 +	assert a['aaa'] == 2 +} + +fn test_map_in_directly() { +	for k, v in map{ +		'aa': 1 +	} { +		assert k == 'aa' +		assert v == 1 +	} +} + +fn test_plus_assign_string() { +	mut m := map{ +		'one': '' +	} +	m['one'] += '1' +	assert m.len == 1 +	assert m['one'] == '1' +} + +fn test_map_keys_to_array() { +	m := map{ +		'a': 'b' +		'c': 'd' +	} +	mut arr := []string{} +	for k, _ in m { +		arr << k +	} +	sarr := arr.str() +	println(sarr) +	assert sarr == "['a', 'c']" +} + +fn map_in_mut(mut m map[string]int) { +	if 'one' in m { +		m['one'] = 2 +	} +} + +fn test_map_in_mut() { +	mut m := map{ +		'one': 1 +	} +	map_in_mut(mut m) +	assert m['one'] == 2 +} + +fn test_map_in() { +	m := map{ +		'Foo': 'bar' +	} +	if 'foo'.capitalize() in m { +		println('ok') +	} else { +		assert false +	} +} + +fn mut_map_with_relation_op_in_fn(mut m map[string]int) { +	if m['one'] == 1 { +		m['three'] = 3 +	} +	if m['two'] != 1 { +		m['four'] = 4 +	} +	if m['one'] > 0 { +		m['five'] = 5 +	} +	if m['one'] < 2 { +		m['six'] = 6 +	} +	if m['two'] >= 2 { +		m['seven'] = 7 +	} +	if m['two'] <= 2 { +		m['eight'] = 8 +	} +} + +fn test_mut_map_with_relation_op_in_fn() { +	mut m := map{ +		'one': 1 +		'two': 2 +	} +	mut_map_with_relation_op_in_fn(mut m) +	assert 'three' in m +	assert 'four' in m +	assert 'five' in m +	assert 'six' in m +	assert 'seven' in m +	assert 'eight' in m +} + +fn test_map_str_after_delete() { +	mut m := map{ +		'first':  1 +		'second': 2 +		'third':  3 +	} +	osm := '$m' +	m.delete('second') +	nsm := '$m' +	println('m: $m') +	assert osm == "{'first': 1, 'second': 2, 'third': 3}" +	assert nsm == "{'first': 1, 'third': 3}" +} + +fn test_modify_map_value() { +	mut m1 := map{ +		'foo': 3 +		'bar': -7 +	} +	m1['foo'] += 5 +	m1['bar'] *= -2 +	assert m1['foo'] == 8 +	assert m1['bar'] == 14 +} + +fn test_map_clone() { +	mut nums := map{ +		'foo': 1 +		'bar': 2 +	} +	mut nums2 := nums.clone() +	nums2['foo']++ +	nums2['bar'] *= 4 +	assert nums['foo'] == 1 +	assert nums['bar'] == 2 +	assert nums2['foo'] == 2 +	assert nums2['bar'] == 8 +} + +struct MValue { +	name string +	misc map[string]string +} + +fn test_map_default_zero() { +	m := map[string]MValue{} +	v := m['unknown'] +	x := v.misc['x'] +	println(x) +	assert x == '' +} + +fn test_map_or() { +	m := map{ +		'first':  1 +		'second': 2 +		'third':  3 +	} +	_ = m +	// num := m['first'] or { return } +} + +fn test_int_keys() { +	mut m := map[int]int{} +	m[3] = 9 +	m[4] = 16 +	assert m.len == 2 +	assert m[3] == 9 +	assert m[4] == 16 +	m[5] += 24 +	m[5]++ +	assert m[5] == 25 +	mut m2 := map{ +		3: 9 +		4: 16 +		5: 25 +	} + +	four := 4 +	m2.delete(3) +	m2.delete(four) +	m2.delete(5) +	assert m2.len == 0 +	assert m2[3] == 0 +	assert m2[4] == 0 +	assert m2[5] == 0 +	assert m2.keys() == [] + +	m2 = map{ +		3: 9 +		4: 16 +		5: 25 +	} + +	assert m2.len == 3 +	// clone +	mc := m.clone() +	same := mc == m +	assert same +	assert mc.len == 3 +	assert mc.keys() == [3, 4, 5] +	mut all := []int{} +	for k, v in mc { +		assert m[k] == v +		all << k +		all << v +	} +	assert all == [3, 9, 4, 16, 5, 25] + +	mut m3 := map{ +		1: 'one' +		2: 'two' +	} +	assert m3[1] == 'one' +	m3.delete(1) +} + +enum Color { +	red +	green +	blue +} + +type ColorAlias = Color + +fn test_alias_enum() { +	mut m := map[ColorAlias]string{} +	m[Color.red] = 'hi' +	assert m[Color.red] == 'hi' +} + +fn test_enum_in_map() { +	mut m := map[Color]string{} +	m[Color.red] = 'hi' +	assert Color.red in m +	assert Color.green !in m +	assert Color.blue !in m +} + +fn test_voidptr_keys() { +	mut m := map[voidptr]string{} +	v := 5 +	m[&v] = 'var' +	m[&m] = 'map' +	assert m[&v] == 'var' +	assert m[&m] == 'map' +	assert m.len == 2 +} + +fn test_rune_keys() { +	mut m := map{ +		`!`: 2 +		`%`: 3 +	} +	assert typeof(m).name == 'map[rune]int' +	assert m[`!`] == 2 +	m[`@`] = 7 +	assert m.len == 3 +	println(m) +	assert '$m' == '{`!`: 2, `%`: 3, `@`: 7}' + +	mut a := []rune{} +	for k, v in m { +		a << k +		a << rune(v) + `0` +	} +	assert a == [`!`, `2`, `%`, `3`, `@`, `7`] +} + +fn test_eq() { +	a := map{ +		'a': 1 +		'b': 2 +	} +	assert a == map{ +		'a': 1 +		'b': 2 +	} +	b := map{ +		'a': [[1]] +		'b': [[2]] +	} +	assert b == map{ +		'a': [[1]] +		'b': [[2]] +	} +	c := map{ +		'a': map{ +			'11': 1 +		} +		'b': map{ +			'22': 2 +		} +	} +	assert c == map{ +		'a': map{ +			'11': 1 +		} +		'b': map{ +			'22': 2 +		} +	} +	d := map{ +		'a': MValue{ +			name: 'aa' +			misc: map{ +				'11': '1' +			} +		} +		'b': MValue{ +			name: 'bb' +			misc: map{ +				'22': '2' +			} +		} +	} +	assert d == map{ +		'a': MValue{ +			name: 'aa' +			misc: map{ +				'11': '1' +			} +		} +		'b': MValue{ +			name: 'bb' +			misc: map{ +				'22': '2' +			} +		} +	} +} + +fn test_non_string_key_map_str() { +	assert map{ +		23: 4 +	}.str() == '{23: 4}' +	assert map{ +		`a`: 12 +		`b`: 13 +	}.str() == '{`a`: 12, `b`: 13}' +	assert map{ +		23: 'foo' +		25: 'bar' +	}.str() == "{23: 'foo', 25: 'bar'}" +} + +fn test_map_assign_empty_map_init() { +	mut a := map{ +		'one': 1 +	} +	a = map{} +	println(a) +	assert a == map[string]int{} +	assert '$a' == '{}' +} + +fn test_in_map_literal() { +	assert 1 in map{ +		1: 'one' +	} +} + +fn test_byte_keys() { +	mut m := map[byte]byte{} +	byte_max := byte(255) +	for i in byte(0) .. byte_max { +		m[i] = i +		assert m[i] == i +	} +	for k, v in m { +		assert k == v +	} +	for i in byte(0) .. 100 { +		m[i]++ +		assert m[i] == i + 1 +	} +	assert m.len == byte_max +	keys := m.keys() +	for i in byte(0) .. byte_max { +		assert keys[i] == i +	} +	for i in byte(0) .. byte_max { +		m.delete(i) +		assert m[i] == 0 +	} +	assert m.len == 0 +} + +fn test_i16_keys() { +	mut m := map[i16]i16{} +	end := i16(1000) +	for i in i16(0) .. end { +		m[i] = i +		assert m[i] == i +	} +	for k, v in m { +		assert k == v +	} +	for i in i16(0) .. 500 { +		m[i]++ +		assert m[i] == i + 1 +	} +	assert m.len == end +	keys := m.keys() +	for i in i16(0) .. end { +		assert keys[i] == i +	} +	for i in i16(0) .. end { +		m.delete(i) +		assert m[i] == 0 +	} +	assert m.len == 0 +} + +fn test_u16_keys() { +	mut m := map[u16]u16{} +	end := u16(1000) +	for i in u16(0) .. end { +		m[i] = i +		assert m[i] == i +	} +	for k, v in m { +		assert k == v +	} +	for i in u16(0) .. 500 { +		m[i]++ +		assert m[i] == i + 1 +	} +	assert m.len == end +	keys := m.keys() +	for i in u16(0) .. end { +		assert keys[i] == i +	} +	for i in u16(0) .. end { +		m.delete(i) +		assert m[i] == 0 +	} +	assert m.len == 0 +} + +fn test_u32_keys() { +	mut m := map[u32]u32{} +	end := u32(1000) +	for i in u32(0) .. end { +		m[i] = i +		assert m[i] == i +	} +	for k, v in m { +		assert k == v +	} +	for i in u32(0) .. 500 { +		m[i]++ +		assert m[i] == i + 1 +	} +	assert m.len == end +	keys := m.keys() +	for i in u32(0) .. end { +		assert keys[i] == i +	} +	for i in u32(0) .. end { +		m.delete(i) +		assert m[i] == 0 +	} +	assert m.len == 0 +} + +fn test_int_keys2() { +	mut m := map[int]int{} +	end := 1000 +	for i in int(0) .. end { +		m[i] = i +		assert m[i] == i +	} +	for k, v in m { +		assert k == v +	} +	for i in int(0) .. 500 { +		m[i]++ +		assert m[i] == i + 1 +	} +	assert m.len == end +	keys := m.keys() +	for i in int(0) .. end { +		assert keys[i] == i +	} +	for i in int(0) .. end { +		m.delete(i) +		assert m[i] == 0 +	} +	assert m.len == 0 +} + +fn test_i64_keys() { +	mut m := map[i64]i64{} +	end := i64(1000) +	for i in i64(0) .. end { +		m[i] = i +		assert m[i] == i +	} +	for k, v in m { +		assert k == v +	} +	for i in i64(0) .. 500 { +		m[i]++ +		assert m[i] == i + 1 +	} +	assert m.len == end +	keys := m.keys() +	for i in i64(0) .. end { +		assert keys[i] == i +	} +	for i in i64(0) .. end { +		m.delete(i) +		assert m[i] == 0 +	} +	assert m.len == 0 +} + +fn test_u64_keys() { +	mut m := map[u64]u64{} +	end := u64(1000) +	for i in u64(0) .. end { +		m[i] = i +		assert m[i] == i +	} +	for k, v in m { +		assert k == v +	} +	for i in u64(0) .. 500 { +		m[i]++ +		assert m[i] == i + 1 +	} +	assert m.len == end +	keys := m.keys() +	for i in u64(0) .. end { +		assert keys[i] == i +	} +	for i in u64(0) .. end { +		m.delete(i) +		assert m[i] == 0 +	} +	assert m.len == 0 +} + +fn test_map_set_fixed_array_variable() { +	mut m := map[string][2]f64{} +	m['A'] = [1.1, 2.2]! +	println(m) +	assert '$m' == "{'A': [1.1, 2.2]}" + +	mut m2 := map[string][2]f64{} +	arr := [1.1, 2.2]! +	m2['A'] = arr +	println(m2) +	assert '$m2' == "{'A': [1.1, 2.2]}" +} diff --git a/v_windows/v/old/vlib/builtin/option.v b/v_windows/v/old/vlib/builtin/option.v new file mode 100644 index 0000000..4e8a14f --- /dev/null +++ b/v_windows/v/old/vlib/builtin/option.v @@ -0,0 +1,103 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module builtin + +// IError holds information about an error instance +pub interface IError { +	msg string +	code int +} + +// Error is the default implementation of IError, that is returned by e.g. `error()` +pub struct Error { +pub: +	msg  string +	code int +} + +pub fn (err IError) str() string { +	return match err { +		None__ { 'none' } +		Error { err.msg } +		else { '$err.type_name(): $err.msg' } +	} +} + +const none__ = IError(&None__{}) + +struct None__ { +	msg  string +	code int +} + +fn (_ None__) str() string { +	return 'none' +} + +[if trace_error ?] +fn trace_error(x string) { +	eprintln('> ${@FN} | $x') +} + +// error returns a default error instance containing the error given in `message`. +// Example: `if ouch { return error('an error occurred') }` +[inline] +pub fn error(message string) IError { +	trace_error(message) +	return &Error{ +		msg: message +	} +} + +// error_with_code returns a default error instance containing the given `message` and error `code`. +// `if ouch { return error_with_code('an error occurred', 1) }` +[inline] +pub fn error_with_code(message string, code int) IError { +	trace_error('$message | code: $code') +	return &Error{ +		msg: message +		code: code +	} +} + +// Option is the base of V's internal optional return system. +struct Option { +	state byte +	err   IError = none__ +	// Data is trailing after err +	// and is not included in here but in the +	// derived Option_xxx types +} + +fn opt_ok(data voidptr, mut option Option, size int) { +	unsafe { +		*option = Option{} +		// use err to get the end of OptionBase and then memcpy into it +		C.memcpy(&byte(&option.err) + sizeof(IError), data, size) +	} +} + +[unsafe] +pub fn (e &Error) free() { +	unsafe { e.msg.free() } +} + +[unsafe] +pub fn (n &None__) free() { +	unsafe { n.msg.free() } +} + +[typedef] +struct C.IError { +	_object voidptr +} + +[unsafe] +pub fn (ie &IError) free() { +	unsafe { +		ie.msg.free() +		cie := &C.IError(ie) +		free(cie._object) +	} +} diff --git a/v_windows/v/old/vlib/builtin/prealloc.c.v b/v_windows/v/old/vlib/builtin/prealloc.c.v new file mode 100644 index 0000000..0ef66fc --- /dev/null +++ b/v_windows/v/old/vlib/builtin/prealloc.c.v @@ -0,0 +1,114 @@ +module builtin + +// With -prealloc, V calls libc's malloc to get chunks, each at least 16MB +// in size, as needed. Once a chunk is available, all malloc() calls within +// V code, that can fit inside the chunk, will use it instead, each bumping a +// pointer, till the chunk is filled. Once a chunk is filled, a new chunk will +// be allocated by calling libc's malloc, and the process continues. +// Each new chunk has a pointer to the old one, and at the end of the program, +// the entire linked list of chunks is freed. +// The goal of all this is to amortize the cost of calling libc's malloc, +// trading higher memory usage for a compiler (or any single threaded batch +// mode program), for a ~8-10% speed increase. +// NB: `-prealloc` is NOT safe to be used for multithreaded programs! + +// size of the preallocated chunk +const prealloc_block_size = 16 * 1024 * 1024 + +__global g_memory_block &VMemoryBlock +[heap] +struct VMemoryBlock { +mut: +	id        int +	cap       int +	start     &byte = 0 +	previous  &VMemoryBlock = 0 +	remaining int +	current   &byte = 0 +	mallocs   int +} + +[unsafe] +fn vmemory_block_new(prev &VMemoryBlock, at_least int) &VMemoryBlock { +	mut v := unsafe { &VMemoryBlock(C.calloc(1, sizeof(VMemoryBlock))) } +	if prev != 0 { +		v.id = prev.id + 1 +	} +	v.previous = prev +	block_size := if at_least < prealloc_block_size { prealloc_block_size } else { at_least } +	v.start = unsafe { C.malloc(block_size) } +	v.cap = block_size +	v.remaining = block_size +	v.current = v.start +	return v +} + +[unsafe] +fn vmemory_block_malloc(n int) &byte { +	unsafe { +		if g_memory_block.remaining < n { +			g_memory_block = vmemory_block_new(g_memory_block, n) +		} +		mut res := &byte(0) +		res = g_memory_block.current +		g_memory_block.remaining -= n +		g_memory_block.mallocs++ +		g_memory_block.current += n +		return res +	} +} + +///////////////////////////////////////////////// + +[unsafe] +fn prealloc_vinit() { +	unsafe { +		g_memory_block = vmemory_block_new(voidptr(0), prealloc_block_size) +		$if !freestanding { +			C.atexit(prealloc_vcleanup) +		} +	} +} + +[unsafe] +fn prealloc_vcleanup() { +	$if prealloc_stats ? { +		// NB: we do 2 loops here, because string interpolation +		// in the first loop may still use g_memory_block +		// The second loop however should *not* allocate at all. +		mut nr_mallocs := i64(0) +		mut mb := g_memory_block +		for mb != 0 { +			nr_mallocs += mb.mallocs +			eprintln('> freeing mb.id: ${mb.id:3} | cap: ${mb.cap:7} | rem: ${mb.remaining:7} | start: ${voidptr(mb.start)} | current: ${voidptr(mb.current)} | diff: ${u64(mb.current) - u64(mb.start):7} bytes | mallocs: $mb.mallocs') +			mb = mb.previous +		} +		eprintln('> nr_mallocs: $nr_mallocs') +	} +	unsafe { +		for g_memory_block != 0 { +			C.free(g_memory_block.start) +			g_memory_block = g_memory_block.previous +		} +	} +} + +[unsafe] +fn prealloc_malloc(n int) &byte { +	return unsafe { vmemory_block_malloc(n) } +} + +[unsafe] +fn prealloc_realloc(old_data &byte, old_size int, new_size int) &byte { +	new_ptr := unsafe { vmemory_block_malloc(new_size) } +	min_size := if old_size < new_size { old_size } else { new_size } +	unsafe { C.memcpy(new_ptr, old_data, min_size) } +	return new_ptr +} + +[unsafe] +fn prealloc_calloc(n int) &byte { +	new_ptr := unsafe { vmemory_block_malloc(n) } +	unsafe { C.memset(new_ptr, 0, n) } +	return new_ptr +} diff --git a/v_windows/v/old/vlib/builtin/rune.v b/v_windows/v/old/vlib/builtin/rune.v new file mode 100644 index 0000000..f756452 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/rune.v @@ -0,0 +1,62 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license that can be found in the LICENSE file. +module builtin + +// This was never working correctly, the issue is now +// fixed however the type checks in checker need to be +// updated. if you uncomment it you will see the issue +// type rune = int + +pub fn (c rune) str() string { +	return utf32_to_str(u32(c)) +	/* +	unsafe { +		fst_byte := int(c)>>8 * 3 & 0xff +		len := utf8_char_len(byte(fst_byte)) +		println('len=$len') +		mut str := string{ +			len: len +			str: malloc(len + 1) +		} +		for i in 0..len { +			str.str[i] = byte(int(c)>>8 * (3 - i) & 0xff) +		} +		str.str[len] = `\0` +		println(str) +		return str +	} +	*/ +} + +// string converts a rune array to a string +pub fn (ra []rune) string() string { +	mut res := '' +	for r in ra { +		res += r.str() +	} +	return res +} + +// Define this on byte as well, so that we can do `s[0].is_capital()` +pub fn (c byte) is_capital() bool { +	return c >= `A` && c <= `Z` +} + +pub fn (b []byte) clone() []byte { +	mut res := []byte{len: b.len} +	// mut res := make([]byte, {repeat:b.len}) +	for i in 0 .. b.len { +		res[i] = b[i] +	} +	return res +} + +// TODO: remove this once runes are implemented +pub fn (b []byte) bytestr() string { +	unsafe { +		buf := malloc_noscan(b.len + 1) +		C.memcpy(buf, b.data, b.len) +		buf[b.len] = 0 +		return tos(buf, b.len) +	} +} diff --git a/v_windows/v/old/vlib/builtin/sorted_map.v b/v_windows/v/old/vlib/builtin/sorted_map.v new file mode 100644 index 0000000..2567a3c --- /dev/null +++ b/v_windows/v/old/vlib/builtin/sorted_map.v @@ -0,0 +1,457 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +module builtin + +// import strings + +// B-trees are balanced search trees with all leaves at +// the same level. B-trees are generally faster than +// binary search trees due to the better locality of +// reference, since multiple keys are stored in one node. + +// The number for `degree` has been picked through vigor- +// ous benchmarking but can be changed to any number > 1. +// `degree` determines the maximum length of each node. +const ( +	degree         = 6 +	mid_index      = degree - 1 +	max_len        = 2 * degree - 1 +	children_bytes = sizeof(voidptr) * (max_len + 1) +) + +pub struct SortedMap { +	value_bytes int +mut: +	root &mapnode +pub mut: +	len int +} + +struct mapnode { +mut: +	children &voidptr +	len      int +	keys     [11]string  // TODO: Should use `max_len` +	values   [11]voidptr // TODO: Should use `max_len` +} + +fn new_sorted_map(n int, value_bytes int) SortedMap { // TODO: Remove `n` +	return SortedMap{ +		value_bytes: value_bytes +		root: new_node() +		len: 0 +	} +} + +fn new_sorted_map_init(n int, value_bytes int, keys &string, values voidptr) SortedMap { +	mut out := new_sorted_map(n, value_bytes) +	for i in 0 .. n { +		unsafe { +			out.set(keys[i], &byte(values) + i * value_bytes) +		} +	} +	return out +} + +// The tree is initialized with an empty node as root to +// avoid having to check whether the root is null for +// each insertion. +fn new_node() &mapnode { +	return &mapnode{ +		children: 0 +		len: 0 +	} +} + +// This implementation does proactive insertion, meaning +// that splits are done top-down and not bottom-up. +fn (mut m SortedMap) set(key string, value voidptr) { +	mut node := m.root +	mut child_index := 0 +	mut parent := &mapnode(0) +	for { +		if node.len == max_len { +			if isnil(parent) { +				parent = new_node() +				m.root = parent +			} +			parent.split_child(child_index, mut node) +			if key == parent.keys[child_index] { +				unsafe { +					C.memcpy(parent.values[child_index], value, m.value_bytes) +				} +				return +			} +			if key < parent.keys[child_index] { +				node = unsafe { &mapnode(parent.children[child_index]) } +			} else { +				node = unsafe { &mapnode(parent.children[child_index + 1]) } +			} +		} +		mut i := 0 +		for i < node.len && key > node.keys[i] { +			i++ +		} +		if i != node.len && key == node.keys[i] { +			unsafe { +				C.memcpy(node.values[i], value, m.value_bytes) +			} +			return +		} +		if isnil(node.children) { +			mut j := node.len - 1 +			for j >= 0 && key < node.keys[j] { +				node.keys[j + 1] = node.keys[j] +				node.values[j + 1] = node.values[j] +				j-- +			} +			node.keys[j + 1] = key +			unsafe { +				node.values[j + 1] = malloc(m.value_bytes) +				C.memcpy(node.values[j + 1], value, m.value_bytes) +			} +			node.len++ +			m.len++ +			return +		} +		parent = node +		child_index = i +		node = unsafe { &mapnode(node.children[child_index]) } +	} +} + +fn (mut n mapnode) split_child(child_index int, mut y mapnode) { +	mut z := new_node() +	z.len = mid_index +	y.len = mid_index +	for j := mid_index - 1; j >= 0; j-- { +		z.keys[j] = y.keys[j + degree] +		z.values[j] = y.values[j + degree] +	} +	if !isnil(y.children) { +		z.children = unsafe { &voidptr(malloc(int(children_bytes))) } +		for jj := degree - 1; jj >= 0; jj-- { +			unsafe { +				z.children[jj] = y.children[jj + degree] +			} +		} +	} +	unsafe { +		if isnil(n.children) { +			n.children = &voidptr(malloc(int(children_bytes))) +		} +		n.children[n.len + 1] = n.children[n.len] +	} +	for j := n.len; j > child_index; j-- { +		n.keys[j] = n.keys[j - 1] +		n.values[j] = n.values[j - 1] +		unsafe { +			n.children[j] = n.children[j - 1] +		} +	} +	n.keys[child_index] = y.keys[mid_index] +	n.values[child_index] = y.values[mid_index] +	unsafe { +		n.children[child_index] = voidptr(y) +		n.children[child_index + 1] = voidptr(z) +	} +	n.len++ +} + +fn (m SortedMap) get(key string, out voidptr) bool { +	mut node := m.root +	for { +		mut i := node.len - 1 +		for i >= 0 && key < node.keys[i] { +			i-- +		} +		if i != -1 && key == node.keys[i] { +			unsafe { +				C.memcpy(out, node.values[i], m.value_bytes) +			} +			return true +		} +		if isnil(node.children) { +			break +		} +		node = unsafe { &mapnode(node.children[i + 1]) } +	} +	return false +} + +fn (m SortedMap) exists(key string) bool { +	if isnil(m.root) { // TODO: find out why root can be nil +		return false +	} +	mut node := m.root +	for { +		mut i := node.len - 1 +		for i >= 0 && key < node.keys[i] { +			i-- +		} +		if i != -1 && key == node.keys[i] { +			return true +		} +		if isnil(node.children) { +			break +		} +		node = unsafe { &mapnode(node.children[i + 1]) } +	} +	return false +} + +fn (n &mapnode) find_key(k string) int { +	mut idx := 0 +	for idx < n.len && n.keys[idx] < k { +		idx++ +	} +	return idx +} + +fn (mut n mapnode) remove_key(k string) bool { +	idx := n.find_key(k) +	if idx < n.len && n.keys[idx] == k { +		if isnil(n.children) { +			n.remove_from_leaf(idx) +		} else { +			n.remove_from_non_leaf(idx) +		} +		return true +	} else { +		if isnil(n.children) { +			return false +		} +		flag := if idx == n.len { true } else { false } +		if unsafe { &mapnode(n.children[idx]) }.len < degree { +			n.fill(idx) +		} + +		mut node := &mapnode(0) +		if flag && idx > n.len { +			node = unsafe { &mapnode(n.children[idx - 1]) } +		} else { +			node = unsafe { &mapnode(n.children[idx]) } +		} +		return node.remove_key(k) +	} +} + +fn (mut n mapnode) remove_from_leaf(idx int) { +	for i := idx + 1; i < n.len; i++ { +		n.keys[i - 1] = n.keys[i] +		n.values[i - 1] = n.values[i] +	} +	n.len-- +} + +fn (mut n mapnode) remove_from_non_leaf(idx int) { +	k := n.keys[idx] +	if unsafe { &mapnode(n.children[idx]) }.len >= degree { +		mut current := unsafe { &mapnode(n.children[idx]) } +		for !isnil(current.children) { +			current = unsafe { &mapnode(current.children[current.len]) } +		} +		predecessor := current.keys[current.len - 1] +		n.keys[idx] = predecessor +		n.values[idx] = current.values[current.len - 1] +		mut node := unsafe { &mapnode(n.children[idx]) } +		node.remove_key(predecessor) +	} else if unsafe { &mapnode(n.children[idx + 1]) }.len >= degree { +		mut current := unsafe { &mapnode(n.children[idx + 1]) } +		for !isnil(current.children) { +			current = unsafe { &mapnode(current.children[0]) } +		} +		successor := current.keys[0] +		n.keys[idx] = successor +		n.values[idx] = current.values[0] +		mut node := unsafe { &mapnode(n.children[idx + 1]) } +		node.remove_key(successor) +	} else { +		n.merge(idx) +		mut node := unsafe { &mapnode(n.children[idx]) } +		node.remove_key(k) +	} +} + +fn (mut n mapnode) fill(idx int) { +	if idx != 0 && unsafe { &mapnode(n.children[idx - 1]) }.len >= degree { +		n.borrow_from_prev(idx) +	} else if idx != n.len && unsafe { &mapnode(n.children[idx + 1]) }.len >= degree { +		n.borrow_from_next(idx) +	} else if idx != n.len { +		n.merge(idx) +	} else { +		n.merge(idx - 1) +	} +} + +fn (mut n mapnode) borrow_from_prev(idx int) { +	mut child := unsafe { &mapnode(n.children[idx]) } +	mut sibling := unsafe { &mapnode(n.children[idx - 1]) } +	for i := child.len - 1; i >= 0; i-- { +		child.keys[i + 1] = child.keys[i] +		child.values[i + 1] = child.values[i] +	} +	if !isnil(child.children) { +		for i := child.len; i >= 0; i-- { +			unsafe { +				child.children[i + 1] = child.children[i] +			} +		} +	} +	child.keys[0] = n.keys[idx - 1] +	child.values[0] = n.values[idx - 1] +	if !isnil(child.children) { +		unsafe { +			child.children[0] = sibling.children[sibling.len] +		} +	} +	n.keys[idx - 1] = sibling.keys[sibling.len - 1] +	n.values[idx - 1] = sibling.values[sibling.len - 1] +	child.len++ +	sibling.len-- +} + +fn (mut n mapnode) borrow_from_next(idx int) { +	mut child := unsafe { &mapnode(n.children[idx]) } +	mut sibling := unsafe { &mapnode(n.children[idx + 1]) } +	child.keys[child.len] = n.keys[idx] +	child.values[child.len] = n.values[idx] +	if !isnil(child.children) { +		unsafe { +			child.children[child.len + 1] = sibling.children[0] +		} +	} +	n.keys[idx] = sibling.keys[0] +	n.values[idx] = sibling.values[0] +	for i := 1; i < sibling.len; i++ { +		sibling.keys[i - 1] = sibling.keys[i] +		sibling.values[i - 1] = sibling.values[i] +	} +	if !isnil(sibling.children) { +		for i := 1; i <= sibling.len; i++ { +			unsafe { +				sibling.children[i - 1] = sibling.children[i] +			} +		} +	} +	child.len++ +	sibling.len-- +} + +fn (mut n mapnode) merge(idx int) { +	mut child := unsafe { &mapnode(n.children[idx]) } +	sibling := unsafe { &mapnode(n.children[idx + 1]) } +	child.keys[mid_index] = n.keys[idx] +	child.values[mid_index] = n.values[idx] +	for i in 0 .. sibling.len { +		child.keys[i + degree] = sibling.keys[i] +		child.values[i + degree] = sibling.values[i] +	} +	if !isnil(child.children) { +		for i := 0; i <= sibling.len; i++ { +			unsafe { +				child.children[i + degree] = sibling.children[i] +			} +		} +	} +	for i := idx + 1; i < n.len; i++ { +		n.keys[i - 1] = n.keys[i] +		n.values[i - 1] = n.values[i] +	} +	for i := idx + 2; i <= n.len; i++ { +		unsafe { +			n.children[i - 1] = n.children[i] +		} +	} +	child.len += sibling.len + 1 +	n.len-- +	// free(sibling) +} + +pub fn (mut m SortedMap) delete(key string) { +	if m.root.len == 0 { +		return +	} + +	removed := m.root.remove_key(key) +	if removed { +		m.len-- +	} + +	if m.root.len == 0 { +		// tmp := t.root +		if isnil(m.root.children) { +			return +		} else { +			m.root = unsafe { &mapnode(m.root.children[0]) } +		} +		// free(tmp) +	} +} + +// Insert all keys of the subtree into array `keys` +// starting at `at`. Keys are inserted in order. +fn (n &mapnode) subkeys(mut keys []string, at int) int { +	mut position := at +	if !isnil(n.children) { +		// Traverse children and insert +		// keys inbetween children +		for i in 0 .. n.len { +			child := unsafe { &mapnode(n.children[i]) } +			position += child.subkeys(mut keys, position) +			keys[position] = n.keys[i] +			position++ +		} +		// Insert the keys of the last child +		child := unsafe { &mapnode(n.children[n.len]) } +		position += child.subkeys(mut keys, position) +	} else { +		// If leaf, insert keys +		for i in 0 .. n.len { +			keys[position + i] = n.keys[i] +		} +		position += n.len +	} +	// Return # of added keys +	return position - at +} + +pub fn (m &SortedMap) keys() []string { +	mut keys := []string{len: m.len} +	if isnil(m.root) || m.root.len == 0 { +		return keys +	} +	m.root.subkeys(mut keys, 0) +	return keys +} + +fn (mut n mapnode) free() { +	println('TODO') +} + +pub fn (mut m SortedMap) free() { +	if isnil(m.root) { +		return +	} +	m.root.free() +} + +pub fn (m SortedMap) print() { +	println('TODO') +} + +// pub fn (m map_string) str() string { +// 	if m.len == 0 { +// 		return '{}' +// 	} +// 	mut sb := strings.new_builder(50) +// 	sb.writeln('{') +// 	for key, val  in m { +// 		sb.writeln('  "$key" => "$val"') +// 	} +// 	sb.writeln('}') +// 	return sb.str() +// } diff --git a/v_windows/v/old/vlib/builtin/sorting_test.v b/v_windows/v/old/vlib/builtin/sorting_test.v new file mode 100644 index 0000000..4d0ff9f --- /dev/null +++ b/v_windows/v/old/vlib/builtin/sorting_test.v @@ -0,0 +1,84 @@ +const ( +	unsorted    = [2, 30, 10, 20, 1] +	sorted_asc  = [1, 2, 10, 20, 30] +	sorted_desc = [30, 20, 10, 2, 1] +) + +fn test_sorting_simple() { +	mut a := unsorted.clone() +	a.sort() +	eprintln(' a: $a') +	assert a == sorted_asc +} + +fn test_sorting_with_condition_expression() { +	mut a := unsorted.clone() +	a.sort(a > b) +	eprintln(' a: $a') +	assert a == sorted_desc +} + +fn test_sorting_primitives_with_condition_expression() { +	mut x := ['9', '87', '3210', '654'] +	x.sort(a.len < b.len) +	assert x == ['9', '87', '654', '3210'] +} + +// fn get_score(word string) int { +// 	mut total := 0 +// 	for letter in word { +// 		total += int(letter) - 97 +// 	} +// 	return total +// } + +// fn test_sorting_with_fn_call_in_condition_expression() { +// 	mut words := ['aaaa', 'a', 'b', 'foo', 'bar'] +// 	words.sort(get_score(a) < get_score(b)) +// } + +fn mysort(mut a []int) { +	a.sort() +} + +fn test_sorting_by_passing_a_mut_array_to_a_function() { +	mut a := unsorted.clone() +	mysort(mut a) +	eprintln(' a: $a') +	assert a == sorted_asc +} + +/* +fn test_sorting_by_passing_an_anonymous_sorting_function() { +	mut a := unsorted +	a.sort(fn(a &int, b &int) int {	return *b - *a }) +	eprintln(' a: $a') +	assert a == sort_desc +} +*/ +fn test_sorting_u64s() { +	mut a := [u64(3), 2, 1, 9, 0, 8] +	a.sort() +	eprintln(' a: $a') +	assert a == [u64(0), 1, 2, 3, 8, 9] +	a.sort(a > b) +	eprintln(' a: $a') +	assert a == [u64(9), 8, 3, 2, 1, 0] +} + +struct User { +	age  int +	name string +} + +fn g(mut users []User) { +	users.sort(a.name > b.name) +} + +fn f(mut users []User) { +	users.sort(a.name < b.name) +} + +fn z(mut users []User) { +	users.sort(a.name < b.name) +} diff --git a/v_windows/v/old/vlib/builtin/string.v b/v_windows/v/old/vlib/builtin/string.v new file mode 100644 index 0000000..169ed2d --- /dev/null +++ b/v_windows/v/old/vlib/builtin/string.v @@ -0,0 +1,1640 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module builtin + +import strconv + +/* +NB: A V string should be/is immutable from the point of view of +    V user programs after it is first created. A V string is +    also slightly larger than the equivalent C string because +    the V string also has an integer length attached. + +    This tradeoff is made, since V strings are created just *once*, +    but potentially used *many times* over their lifetime. + +    The V string implementation uses a struct, that has a .str field, +    which points to a C style 0 terminated memory block. Although not +    strictly necessary from the V point of view, that additional 0 +    is *very useful for C interoperability*. + +    The V string implementation also has an integer .len field, +    containing the length of the .str field, excluding the +    terminating 0 (just like the C's strlen(s) would do). + +    The 0 ending of .str, and the .len field, mean that in practice: +      a) a V string s can be used very easily, wherever a +         C string is needed, just by passing s.str, +         without a need for further conversion/copying. + +      b) where strlen(s) is needed, you can just pass s.len, +         without having to constantly recompute the length of s +         *over and over again* like some C programs do. This is because +         V strings are immutable and so their length does not change. + +    Ordinary V code *does not need* to be concerned with the +    additional 0 in the .str field. The 0 *must* be put there by the +    low level string creating functions inside this module. + +    Failing to do this will lead to programs that work most of the +    time, when used with pure V functions, but fail in strange ways, +    when used with modules using C functions (for example os and so on). +*/ +pub struct string { +pub: +	str &byte = 0 // points to a C style 0 terminated string of bytes. +	len int   // the length of the .str field, excluding the ending 0 byte. It is always equal to strlen(.str). +	// NB string.is_lit is an enumeration of the following: +	// .is_lit == 0 => a fresh string, should be freed by autofree +	// .is_lit == 1 => a literal string from .rodata, should NOT be freed +	// .is_lit == -98761234 => already freed string, protects against double frees. +	// ---------> ^^^^^^^^^ calling free on these is a bug. +	// Any other value means that the string has been corrupted. +mut: +	is_lit int +} + +// vstrlen returns the V length of the C string `s` (0 terminator is not counted). +[unsafe] +pub fn vstrlen(s &byte) int { +	return unsafe { C.strlen(&char(s)) } +} + +pub fn (s string) runes() []rune { +	mut runes := []rune{cap: s.len} +	for i := 0; i < s.len; i++ { +		char_len := utf8_char_len(unsafe { s.str[i] }) +		if char_len > 1 { +			end := if s.len - 1 >= i + char_len { i + char_len } else { s.len } +			mut r := unsafe { s[i..end] } +			runes << r.utf32_code() +			i += char_len - 1 +		} else { +			runes << unsafe { s.str[i] } +		} +	} +	return runes +} + +// tos converts a C string to a V string. +// String data is reused, not copied. +[unsafe] +pub fn tos(s &byte, len int) string { +	// This should never happen. +	if s == 0 { +		panic('tos(): nil string') +	} +	return string{ +		str: unsafe { s } +		len: len +	} +} + +// tos_clone returns a copy of `s`. +[unsafe] +pub fn tos_clone(s &byte) string { +	return unsafe { tos2(s) }.clone() +} + +// tos2 does the same as `tos`, but also calculates the length. Called by `string(bytes)` casts. +// Used only internally. +[unsafe] +pub fn tos2(s &byte) string { +	if s == 0 { +		panic('tos2: nil string') +	} +	return string{ +		str: unsafe { s } +		len: unsafe { vstrlen(s) } +	} +} + +// tos3 does the same as `tos2`, but for char*, to avoid warnings. +[unsafe] +pub fn tos3(s &char) string { +	if s == 0 { +		panic('tos3: nil string') +	} +	return string{ +		str: &byte(s) +		len: unsafe { C.strlen(s) } +	} +} + +// tos4 does the same as `tos2`, but returns an empty string on nil ptr. +[unsafe] +pub fn tos4(s &byte) string { +	if s == 0 { +		return '' +	} +	return unsafe { tos2(s) } +} + +// tos5 does the same as `tos4`, but for char*, to avoid warnings. +[unsafe] +pub fn tos5(s &char) string { +	if s == 0 { +		return '' +	} +	return unsafe { tos3(s) } +} + +// vstring converts a C style string to a V string. NB: the string data is reused, NOT copied. +// strings returned from this function will be normal V strings beside that (i.e. they would be +// freed by V's -autofree mechanism, when they are no longer used). +[unsafe] +pub fn (bp &byte) vstring() string { +	return string{ +		str: unsafe { bp } +		len: unsafe { C.strlen(&char(bp)) } +	} +} + +// vstring_with_len converts a C style string to a V string. +// NB: the string data is reused, NOT copied. +[unsafe] +pub fn (bp &byte) vstring_with_len(len int) string { +	return string{ +		str: unsafe { bp } +		len: len +		is_lit: 0 +	} +} + +// vstring converts C char* to V string. +// NB: the string data is reused, NOT copied. +[unsafe] +pub fn (cp &char) vstring() string { +	return string{ +		str: &byte(cp) +		len: unsafe { C.strlen(cp) } +		is_lit: 0 +	} +} + +// vstring_with_len converts C char* to V string. +// NB: the string data is reused, NOT copied. +[unsafe] +pub fn (cp &char) vstring_with_len(len int) string { +	return string{ +		str: &byte(cp) +		len: len +		is_lit: 0 +	} +} + +// vstring_literal converts a C style string to a V string. +// NB: the string data is reused, NOT copied. +// NB2: unlike vstring, vstring_literal will mark the string +// as a literal, so it will not be freed by autofree. +// This is suitable for readonly strings, C string literals etc, +// that can be read by the V program, but that should not be +// managed by it, for example `os.args` is implemented using it. +[unsafe] +pub fn (bp &byte) vstring_literal() string { +	return string{ +		str: unsafe { bp } +		len: unsafe { C.strlen(&char(bp)) } +		is_lit: 1 +	} +} + +// vstring_with_len converts a C style string to a V string. +// NB: the string data is reused, NOT copied. +[unsafe] +pub fn (bp &byte) vstring_literal_with_len(len int) string { +	return string{ +		str: unsafe { bp } +		len: len +		is_lit: 1 +	} +} + +// vstring_literal converts C char* to V string. +// See also vstring_literal defined on byteptr for more details. +// NB: the string data is reused, NOT copied. +[unsafe] +pub fn (cp &char) vstring_literal() string { +	return string{ +		str: &byte(cp) +		len: unsafe { C.strlen(cp) } +		is_lit: 1 +	} +} + +// vstring_literal_with_len converts C char* to V string. +// See also vstring_literal_with_len defined on byteptr. +// NB: the string data is reused, NOT copied. +[unsafe] +pub fn (cp &char) vstring_literal_with_len(len int) string { +	return string{ +		str: &byte(cp) +		len: len +		is_lit: 1 +	} +} + +// clone_static returns an independent copy of a given array. +// It should be used only in -autofree generated code. +fn (a string) clone_static() string { +	return a.clone() +} + +// clone returns a copy of the V string `a`. +pub fn (a string) clone() string { +	if a.len == 0 { +		return '' +	} +	mut b := string{ +		str: unsafe { malloc_noscan(a.len + 1) } +		len: a.len +	} +	unsafe { +		C.memcpy(b.str, a.str, a.len) +		b.str[a.len] = 0 +	} +	return b +} + +// cstring_to_vstring creates a copy of cstr and turns it into a v string. +[unsafe] +pub fn cstring_to_vstring(cstr &char) string { +	return unsafe { tos_clone(&byte(cstr)) } +} + +// replace_once replaces the first occurence of `rep` with the string passed in `with`. +pub fn (s string) replace_once(rep string, with string) string { +	idx := s.index_(rep) +	if idx == -1 { +		return s.clone() +	} +	return s.substr(0, idx) + with + s.substr(idx + rep.len, s.len) +} + +// replace replaces all occurences of `rep` with the string passed in `with`. +[direct_array_access] +pub fn (s string) replace(rep string, with string) string { +	if s.len == 0 || rep.len == 0 || rep.len > s.len { +		return s.clone() +	} +	if !s.contains(rep) { +		return s.clone() +	} +	// TODO PERF Allocating ints is expensive. Should be a stack array +	// Get locations of all reps within this string +	mut idxs := []int{cap: s.len / rep.len} +	defer { +		unsafe { idxs.free() } +	} +	mut idx := 0 +	for { +		idx = s.index_after(rep, idx) +		if idx == -1 { +			break +		} +		idxs << idx +		idx += rep.len +	} +	// Dont change the string if there's nothing to replace +	if idxs.len == 0 { +		return s.clone() +	} +	// Now we know the number of replacements we need to do and we can calc the len of the new string +	new_len := s.len + idxs.len * (with.len - rep.len) +	mut b := unsafe { malloc_noscan(new_len + 1) } // add space for the null byte at the end +	// Fill the new string +	mut b_i := 0 +	mut s_idx := 0 +	for _, rep_pos in idxs { +		for i in s_idx .. rep_pos { // copy everything up to piece being replaced +			unsafe { +				b[b_i] = s[i] +			} +			b_i++ +		} +		s_idx = rep_pos + rep.len // move string index past replacement +		for i in 0 .. with.len { // copy replacement piece +			unsafe { +				b[b_i] = with[i] +			} +			b_i++ +		} +	} +	if s_idx < s.len { // if any original after last replacement, copy it +		for i in s_idx .. s.len { +			unsafe { +				b[b_i] = s[i] +			} +			b_i++ +		} +	} +	unsafe { +		b[new_len] = 0 +		return tos(b, new_len) +	} +} + +struct RepIndex { +	idx     int +	val_idx int +} + +// compare_rep_index returns the result of comparing RepIndex `a` and `b`. +fn compare_rep_index(a &RepIndex, b &RepIndex) int { +	if a.idx < b.idx { +		return -1 +	} +	if a.idx > b.idx { +		return 1 +	} +	return 0 +} + +// sort2 sorts the RepIndex array using `compare_rep_index`. +fn (mut a []RepIndex) sort2() { +	a.sort_with_compare(compare_rep_index) +} + +// replace_each replaces all occurences of the string pairs given in `vals`. +// Example: assert 'ABCD'.replace_each(['B','C/','C','D','D','C']) == 'AC/DC' +[direct_array_access] +pub fn (s string) replace_each(vals []string) string { +	if s.len == 0 || vals.len == 0 { +		return s.clone() +	} +	if vals.len % 2 != 0 { +		eprintln('string.replace_each(): odd number of strings') +		return s.clone() +	} +	// `rep` - string to replace +	// `with` - string to replace with +	// Remember positions of all rep strings, and calculate the length +	// of the new string to do just one allocation. +	mut new_len := s.len +	mut idxs := []RepIndex{} +	mut idx := 0 +	s_ := s.clone() +	for rep_i := 0; rep_i < vals.len; rep_i += 2 { +		// vals: ['rep1, 'with1', 'rep2', 'with2'] +		rep := vals[rep_i] +		with := vals[rep_i + 1] +		for { +			idx = s_.index_after(rep, idx) +			if idx == -1 { +				break +			} +			// The string already found is set to `/del`, to avoid duplicate searches. +			for i in 0 .. rep.len { +				unsafe { +					s_.str[idx + i] = 127 +				} +			} +			// We need to remember both the position in the string, +			// and which rep/with pair it refers to. +			idxs << RepIndex{ +				idx: idx +				val_idx: rep_i +			} +			idx += rep.len +			new_len += with.len - rep.len +		} +	} +	// Dont change the string if there's nothing to replace +	if idxs.len == 0 { +		return s.clone() +	} +	idxs.sort2() +	mut b := unsafe { malloc_noscan(new_len + 1) } // add space for 0 terminator +	// Fill the new string +	mut idx_pos := 0 +	mut cur_idx := idxs[idx_pos] +	mut b_i := 0 +	for i := 0; i < s.len; i++ { +		if i == cur_idx.idx { +			// Reached the location of rep, replace it with "with" +			rep := vals[cur_idx.val_idx] +			with := vals[cur_idx.val_idx + 1] +			for j in 0 .. with.len { +				unsafe { +					b[b_i] = with[j] +				} +				b_i++ +			} +			// Skip the length of rep, since we just replaced it with "with" +			i += rep.len - 1 +			// Go to the next index +			idx_pos++ +			if idx_pos < idxs.len { +				cur_idx = idxs[idx_pos] +			} +		} else { +			// Rep doesnt start here, just copy +			unsafe { +				b[b_i] = s.str[i] +			} +			b_i++ +		} +	} +	unsafe { +		b[new_len] = 0 +		return tos(b, new_len) +	} +} + +// bool returns `true` if the string equals the word "true" it will return `false` otherwise. +pub fn (s string) bool() bool { +	return s == 'true' || s == 't' // TODO t for pg, remove +} + +// int returns the value of the string as an integer `'1'.int() == 1`. +pub fn (s string) int() int { +	return int(strconv.common_parse_int(s, 0, 32, false, false) or { 0 }) +} + +// i64 returns the value of the string as i64 `'1'.i64() == i64(1)`. +pub fn (s string) i64() i64 { +	return strconv.common_parse_int(s, 0, 64, false, false) or { 0 } +} + +// i8 returns the value of the string as i8 `'1'.i8() == i8(1)`. +pub fn (s string) i8() i8 { +	return i8(strconv.common_parse_int(s, 0, 8, false, false) or { 0 }) +} + +// i16 returns the value of the string as i16 `'1'.i16() == i16(1)`. +pub fn (s string) i16() i16 { +	return i16(strconv.common_parse_int(s, 0, 16, false, false) or { 0 }) +} + +// f32 returns the value of the string as f32 `'1.0'.f32() == f32(1)`. +pub fn (s string) f32() f32 { +	// return C.atof(&char(s.str)) +	return f32(strconv.atof64(s)) +} + +// f64 returns the value of the string as f64 `'1.0'.f64() == f64(1)`. +pub fn (s string) f64() f64 { +	// return C.atof(&char(s.str)) +	return strconv.atof64(s) +} + +// u16 returns the value of the string as u16 `'1'.u16() == u16(1)`. +pub fn (s string) u16() u16 { +	return u16(strconv.common_parse_uint(s, 0, 16, false, false) or { 0 }) +} + +// u32 returns the value of the string as u32 `'1'.u32() == u32(1)`. +pub fn (s string) u32() u32 { +	return u32(strconv.common_parse_uint(s, 0, 32, false, false) or { 0 }) +} + +// u64 returns the value of the string as u64 `'1'.u64() == u64(1)`. +pub fn (s string) u64() u64 { +	return strconv.common_parse_uint(s, 0, 64, false, false) or { 0 } +} + +[direct_array_access] +fn (s string) == (a string) bool { +	if s.str == 0 { +		// should never happen +		panic('string.eq(): nil string') +	} +	if s.len != a.len { +		return false +	} +	if s.len > 0 { +		last_idx := s.len - 1 +		if s[last_idx] != a[last_idx] { +			return false +		} +	} +	unsafe { +		return C.memcmp(s.str, a.str, a.len) == 0 +	} +} + +fn (s string) < (a string) bool { +	for i in 0 .. s.len { +		if i >= a.len || s[i] > a[i] { +			return false +		} else if s[i] < a[i] { +			return true +		} +	} +	if s.len < a.len { +		return true +	} +	return false +} + +fn (s string) + (a string) string { +	new_len := a.len + s.len +	mut res := string{ +		str: unsafe { malloc_noscan(new_len + 1) } +		len: new_len +	} +	for j in 0 .. s.len { +		unsafe { +			res.str[j] = s.str[j] +		} +	} +	for j in 0 .. a.len { +		unsafe { +			res.str[s.len + j] = a.str[j] +		} +	} +	unsafe { +		res.str[new_len] = 0 // V strings are not null terminated, but just in case +	} +	return res +} + +// split splits the string to an array by `delim`. +// Example: assert 'A B C'.split(' ') == ['A','B','C'] +// If `delim` is empty the string is split by it's characters. +// Example: assert 'DEF'.split('') == ['D','E','F'] +pub fn (s string) split(delim string) []string { +	return s.split_nth(delim, 0) +} + +// split_nth splits the string based on the passed `delim` substring. +// It returns the first Nth parts. When N=0, return all the splits. +// The last returned element has the remainder of the string, even if +// the remainder contains more `delim` substrings. +[direct_array_access] +pub fn (s string) split_nth(delim string, nth int) []string { +	mut res := []string{} +	mut i := 0 + +	match delim.len { +		0 { +			i = 1 +			for ch in s { +				if nth > 0 && i >= nth { +					res << s[i..] +					break +				} +				res << ch.ascii_str() +				i++ +			} +			return res +		} +		1 { +			mut start := 0 +			delim_byte := delim[0] + +			for i < s.len { +				if s[i] == delim_byte { +					was_last := nth > 0 && res.len == nth - 1 +					if was_last { +						break +					} +					val := s.substr(start, i) +					res << val +					start = i + delim.len +					i = start +				} else { +					i++ +				} +			} + +			// Then the remaining right part of the string +			if nth < 1 || res.len < nth { +				res << s[start..] +			} +			return res +		} +		else { +			mut start := 0 +			// Take the left part for each delimiter occurence +			for i <= s.len { +				is_delim := i + delim.len <= s.len && s.substr(i, i + delim.len) == delim +				if is_delim { +					was_last := nth > 0 && res.len == nth - 1 +					if was_last { +						break +					} +					val := s.substr(start, i) +					res << val +					start = i + delim.len +					i = start +				} else { +					i++ +				} +			} +			// Then the remaining right part of the string +			if nth < 1 || res.len < nth { +				res << s[start..] +			} +			return res +		} +	} +} + +// split_into_lines splits the string by newline characters. +// newlines are stripped. +// Both `\n` and `\r\n` newline endings are supported. +[direct_array_access] +pub fn (s string) split_into_lines() []string { +	mut res := []string{} +	if s.len == 0 { +		return res +	} +	mut start := 0 +	mut end := 0 +	for i := 0; i < s.len; i++ { +		if s[i] == 10 { +			end = if i > 0 && s[i - 1] == 13 { i - 1 } else { i } +			res << if start == end { '' } else { s[start..end] } +			start = i + 1 +		} +	} +	if start < s.len { +		res << s[start..] +	} +	return res +} + +// used internally for [2..4] +fn (s string) substr2(start int, _end int, end_max bool) string { +	end := if end_max { s.len } else { _end } +	return s.substr(start, end) +} + +// substr returns the string between index positions `start` and `end`. +// Example: assert 'ABCD'.substr(1,3) == 'BC' +pub fn (s string) substr(start int, end int) string { +	$if !no_bounds_checking ? { +		if start > end || start > s.len || end > s.len || start < 0 || end < 0 { +			panic('substr($start, $end) out of bounds (len=$s.len)') +		} +	} +	len := end - start +	if len == s.len { +		return s.clone() +	} +	mut res := string{ +		str: unsafe { malloc_noscan(len + 1) } +		len: len +	} +	for i in 0 .. len { +		unsafe { +			res.str[i] = s.str[start + i] +		} +	} +	unsafe { +		res.str[len] = 0 +	} +	return res +} + +// index returns the position of the first character of the input string. +// It will return `-1` if the input string can't be found. +fn (s string) index_(p string) int { +	if p.len > s.len || p.len == 0 { +		return -1 +	} +	if p.len > 2 { +		return s.index_kmp(p) +	} +	mut i := 0 +	for i < s.len { +		mut j := 0 +		for j < p.len && unsafe { s.str[i + j] == p.str[j] } { +			j++ +		} +		if j == p.len { +			return i +		} +		i++ +	} +	return -1 +} + +// index returns the position of the first character of the input string. +// It will return `none` if the input string can't be found. +pub fn (s string) index(p string) ?int { +	idx := s.index_(p) +	if idx == -1 { +		return none +	} +	return idx +} + +// index_kmp does KMP search. +[direct_array_access; manualfree] +fn (s string) index_kmp(p string) int { +	if p.len > s.len { +		return -1 +	} +	mut prefix := []int{len: p.len} +	defer { +		unsafe { prefix.free() } +	} +	mut j := 0 +	for i := 1; i < p.len; i++ { +		for unsafe { p.str[j] != p.str[i] } && j > 0 { +			j = prefix[j - 1] +		} +		if unsafe { p.str[j] == p.str[i] } { +			j++ +		} +		prefix[i] = j +	} +	j = 0 +	for i in 0 .. s.len { +		for unsafe { p.str[j] != s.str[i] } && j > 0 { +			j = prefix[j - 1] +		} +		if unsafe { p.str[j] == s.str[i] } { +			j++ +		} +		if j == p.len { +			return i - p.len + 1 +		} +	} +	return -1 +} + +// index_any returns the position of any of the characters in the input string - if found. +pub fn (s string) index_any(chars string) int { +	for c in chars { +		idx := s.index_(c.ascii_str()) +		if idx == -1 { +			continue +		} +		return idx +	} +	return -1 +} + +// last_index returns the position of the last occurence of the input string. +fn (s string) last_index_(p string) int { +	if p.len > s.len || p.len == 0 { +		return -1 +	} +	mut i := s.len - p.len +	for i >= 0 { +		mut j := 0 +		for j < p.len && unsafe { s.str[i + j] == p.str[j] } { +			j++ +		} +		if j == p.len { +			return i +		} +		i-- +	} +	return -1 +} + +// last_index returns the position of the last occurence of the input string. +pub fn (s string) last_index(p string) ?int { +	idx := s.last_index_(p) +	if idx == -1 { +		return none +	} +	return idx +} + +// index_after returns the position of the input string, starting search from `start` position. +pub fn (s string) index_after(p string, start int) int { +	if p.len > s.len { +		return -1 +	} +	mut strt := start +	if start < 0 { +		strt = 0 +	} +	if start >= s.len { +		return -1 +	} +	mut i := strt +	for i < s.len { +		mut j := 0 +		mut ii := i +		for j < p.len && unsafe { s.str[ii] == p.str[j] } { +			j++ +			ii++ +		} +		if j == p.len { +			return i +		} +		i++ +	} +	return -1 +} + +// index_byte returns the index of byte `c` if found in the string. +// index_byte returns -1 if the byte can not be found. +pub fn (s string) index_byte(c byte) int { +	for i in 0 .. s.len { +		if unsafe { s.str[i] } == c { +			return i +		} +	} +	return -1 +} + +// last_index_byte returns the index of the last occurence of byte `c` if found in the string. +// last_index_byte returns -1 if the byte is not found. +pub fn (s string) last_index_byte(c byte) int { +	for i := s.len - 1; i >= 0; i-- { +		if unsafe { s.str[i] == c } { +			return i +		} +	} +	return -1 +} + +// count returns the number of occurrences of `substr` in the string. +// count returns -1 if no `substr` could be found. +pub fn (s string) count(substr string) int { +	if s.len == 0 || substr.len == 0 { +		return 0 +	} +	if substr.len > s.len { +		return 0 +	} + +	mut n := 0 + +	if substr.len == 1 { +		target := substr[0] + +		for letter in s { +			if letter == target { +				n++ +			} +		} + +		return n +	} + +	mut i := 0 +	for { +		i = s.index_after(substr, i) +		if i == -1 { +			return n +		} +		i += substr.len +		n++ +	} +	return 0 // TODO can never get here - v doesn't know that +} + +// contains returns `true` if the string contains `substr`. +pub fn (s string) contains(substr string) bool { +	if substr.len == 0 { +		return true +	} +	if s.index_(substr) == -1 { +		return false +	} +	return true +} + +// contains_any returns `true` if the string contains any chars in `chars`. +pub fn (s string) contains_any(chars string) bool { +	for c in chars { +		if s.contains(c.ascii_str()) { +			return true +		} +	} +	return false +} + +// contains_any_substr returns `true` if the string contains any of the strings in `substrs`. +pub fn (s string) contains_any_substr(substrs []string) bool { +	if substrs.len == 0 { +		return true +	} +	for sub in substrs { +		if s.contains(sub) { +			return true +		} +	} +	return false +} + +// starts_with returns `true` if the string starts with `p`. +pub fn (s string) starts_with(p string) bool { +	if p.len > s.len { +		return false +	} +	for i in 0 .. p.len { +		if unsafe { s.str[i] != p.str[i] } { +			return false +		} +	} +	return true +} + +// ends_with returns `true` if the string ends with `p`. +pub fn (s string) ends_with(p string) bool { +	if p.len > s.len { +		return false +	} +	for i in 0 .. p.len { +		if unsafe { p.str[i] != s.str[s.len - p.len + i] } { +			return false +		} +	} +	return true +} + +// to_lower returns the string in all lowercase characters. +// TODO only works with ASCII +pub fn (s string) to_lower() string { +	unsafe { +		mut b := malloc_noscan(s.len + 1) +		for i in 0 .. s.len { +			if s.str[i] >= `A` && s.str[i] <= `Z` { +				b[i] = s.str[i] + 32 +			} else { +				b[i] = s.str[i] +			} +		} +		b[s.len] = 0 +		return tos(b, s.len) +	} +} + +// is_lower returns `true` if all characters in the string is lowercase. +// Example: assert 'hello developer'.is_lower() == true +[direct_array_access] +pub fn (s string) is_lower() bool { +	for i in 0 .. s.len { +		if s[i] >= `A` && s[i] <= `Z` { +			return false +		} +	} +	return true +} + +// to_upper returns the string in all uppercase characters. +// Example: assert 'Hello V'.to_upper() == 'HELLO V' +pub fn (s string) to_upper() string { +	unsafe { +		mut b := malloc_noscan(s.len + 1) +		for i in 0 .. s.len { +			if s.str[i] >= `a` && s.str[i] <= `z` { +				b[i] = s.str[i] - 32 +			} else { +				b[i] = s.str[i] +			} +		} +		b[s.len] = 0 +		return tos(b, s.len) +	} +} + +// is_upper returns `true` if all characters in the string is uppercase. +// Example: assert 'HELLO V'.is_upper() == true +[direct_array_access] +pub fn (s string) is_upper() bool { +	for i in 0 .. s.len { +		if s[i] >= `a` && s[i] <= `z` { +			return false +		} +	} +	return true +} + +// capitalize returns the string with the first character capitalized. +// Example: assert 'hello'.capitalize() == 'Hello' +[direct_array_access] +pub fn (s string) capitalize() string { +	if s.len == 0 { +		return '' +	} +	s0 := s[0] +	letter := s0.ascii_str() +	uletter := letter.to_upper() +	if s.len == 1 { +		return uletter +	} +	srest := s[1..] +	res := uletter + srest +	return res +} + +// is_capital returns `true` if the first character in the string is a capital letter. +// Example: assert 'Hello'.is_capital() == true +[direct_array_access] +pub fn (s string) is_capital() bool { +	if s.len == 0 || !(s[0] >= `A` && s[0] <= `Z`) { +		return false +	} +	for i in 1 .. s.len { +		if s[i] >= `A` && s[i] <= `Z` { +			return false +		} +	} +	return true +} + +// title returns the string with each word capitalized. +// Example: assert 'hello v developer'.title() == 'Hello V Developer' +pub fn (s string) title() string { +	words := s.split(' ') +	mut tit := []string{} +	for word in words { +		tit << word.capitalize() +	} +	title := tit.join(' ') +	return title +} + +// is_title returns true if all words of the string is capitalized. +// Example: assert 'Hello V Developer'.is_title() == true +pub fn (s string) is_title() bool { +	words := s.split(' ') +	for word in words { +		if !word.is_capital() { +			return false +		} +	} +	return true +} + +// find_between returns the string found between `start` string and `end` string. +// Example: assert 'hey [man] how you doin'.find_between('[', ']') == 'man' +pub fn (s string) find_between(start string, end string) string { +	start_pos := s.index_(start) +	if start_pos == -1 { +		return '' +	} +	// First get everything to the right of 'start' +	val := s[start_pos + start.len..] +	end_pos := val.index_(end) +	if end_pos == -1 { +		return val +	} +	return val[..end_pos] +} + +// trim_space strips any of ` `, `\n`, `\t`, `\v`, `\f`, `\r` from the start and end of the string. +// Example: assert ' Hello V '.trim_space() == 'Hello V' +pub fn (s string) trim_space() string { +	return s.trim(' \n\t\v\f\r') +} + +// trim strips any of the characters given in `cutset` from the start and end of the string. +// Example: assert ' ffHello V ffff'.trim(' f') == 'Hello V' +[direct_array_access] +pub fn (s string) trim(cutset string) string { +	if s.len < 1 || cutset.len < 1 { +		return s.clone() +	} +	mut pos_left := 0 +	mut pos_right := s.len - 1 +	mut cs_match := true +	for pos_left <= s.len && pos_right >= -1 && cs_match { +		cs_match = false +		for cs in cutset { +			if s[pos_left] == cs { +				pos_left++ +				cs_match = true +				break +			} +		} +		for cs in cutset { +			if s[pos_right] == cs { +				pos_right-- +				cs_match = true +				break +			} +		} +		if pos_left > pos_right { +			return '' +		} +	} +	return s.substr(pos_left, pos_right + 1) +} + +// trim_left strips any of the characters given in `cutset` from the left of the string. +// Example: assert 'd Hello V developer'.trim_left(' d') == 'Hello V developer' +[direct_array_access] +pub fn (s string) trim_left(cutset string) string { +	if s.len < 1 || cutset.len < 1 { +		return s.clone() +	} +	mut pos := 0 +	for pos < s.len { +		mut found := false +		for cs in cutset { +			if s[pos] == cs { +				found = true +				break +			} +		} +		if !found { +			break +		} +		pos++ +	} +	return s[pos..] +} + +// trim_right strips any of the characters given in `cutset` from the right of the string. +// Example: assert ' Hello V d'.trim_right(' d') == ' Hello V' +[direct_array_access] +pub fn (s string) trim_right(cutset string) string { +	if s.len < 1 || cutset.len < 1 { +		return s.clone() +	} +	mut pos := s.len - 1 +	for pos >= 0 { +		mut found := false +		for cs in cutset { +			if s[pos] == cs { +				found = true +			} +		} +		if !found { +			break +		} +		pos-- +	} +	if pos < 0 { +		return '' +	} +	return s[..pos + 1] +} + +// trim_prefix strips `str` from the start of the string. +// Example: assert 'WorldHello V'.trim_prefix('World') == 'Hello V' +pub fn (s string) trim_prefix(str string) string { +	if s.starts_with(str) { +		return s[str.len..] +	} +	return s.clone() +} + +// trim_suffix strips `str` from the end of the string. +// Example: assert 'Hello VWorld'.trim_suffix('World') == 'Hello V' +pub fn (s string) trim_suffix(str string) string { +	if s.ends_with(str) { +		return s[..s.len - str.len] +	} +	return s.clone() +} + +// compare_strings returns `-1` if `a < b`, `1` if `a > b` else `0`. +pub fn compare_strings(a &string, b &string) int { +	if a < b { +		return -1 +	} +	if a > b { +		return 1 +	} +	return 0 +} + +// compare_strings_reverse returns `1` if `a < b`, `-1` if `a > b` else `0`. +fn compare_strings_reverse(a &string, b &string) int { +	if a < b { +		return 1 +	} +	if a > b { +		return -1 +	} +	return 0 +} + +// compare_strings_by_len returns `-1` if `a.len < b.len`, `1` if `a.len > b.len` else `0`. +fn compare_strings_by_len(a &string, b &string) int { +	if a.len < b.len { +		return -1 +	} +	if a.len > b.len { +		return 1 +	} +	return 0 +} + +// compare_lower_strings returns the same as compare_strings but converts `a` and `b` to lower case before comparing. +fn compare_lower_strings(a &string, b &string) int { +	aa := a.to_lower() +	bb := b.to_lower() +	return compare_strings(&aa, &bb) +} + +// sort sorts the string array. +pub fn (mut s []string) sort() { +	s.sort_with_compare(compare_strings) +} + +// sort_ignore_case sorts the string array using case insesitive comparing. +pub fn (mut s []string) sort_ignore_case() { +	s.sort_with_compare(compare_lower_strings) +} + +// sort_by_len sorts the the string array by each string's `.len` length. +pub fn (mut s []string) sort_by_len() { +	s.sort_with_compare(compare_strings_by_len) +} + +// str returns a copy of the string +pub fn (s string) str() string { +	return s.clone() +} + +// at returns the byte at index `idx`. +// Example: assert 'ABC'.at(1) == byte(`B`) +fn (s string) at(idx int) byte { +	$if !no_bounds_checking ? { +		if idx < 0 || idx >= s.len { +			panic('string index out of range: $idx / $s.len') +		} +	} +	unsafe { +		return s.str[idx] +	} +} + +// version of `at()` that is used in `a[i] or {` +// return an error when the index is out of range +fn (s string) at_with_check(idx int) ?byte { +	if idx < 0 || idx >= s.len { +		return error('string index out of range') +	} +	unsafe { +		return s.str[idx] +	} +} + +// is_space returns `true` if the byte is a white space character. +// The following list is considered white space characters: ` `, `\t`, `\n`, `\v`, `\f`, `\r`, 0x85, 0xa0 +// Example: assert byte(` `).is_space() == true +[inline] +pub fn (c byte) is_space() bool { +	// 0x85 is NEXT LINE (NEL) +	// 0xa0 is NO-BREAK SPACE +	return c == 32 || (c > 8 && c < 14) || (c == 0x85) || (c == 0xa0) +} + +// is_digit returns `true` if the byte is in range 0-9 and `false` otherwise. +// Example: assert byte(`9`) == true +[inline] +pub fn (c byte) is_digit() bool { +	return c >= `0` && c <= `9` +} + +// is_hex_digit returns `true` if the byte is either in range 0-9, a-f or A-F and `false` otherwise. +// Example: assert byte(`F`) == true +[inline] +pub fn (c byte) is_hex_digit() bool { +	return c.is_digit() || (c >= `a` && c <= `f`) || (c >= `A` && c <= `F`) +} + +// is_oct_digit returns `true` if the byte is in range 0-7 and `false` otherwise. +// Example: assert byte(`7`) == true +[inline] +pub fn (c byte) is_oct_digit() bool { +	return c >= `0` && c <= `7` +} + +// is_bin_digit returns `true` if the byte is a binary digit (0 or 1) and `false` otherwise. +// Example: assert byte(`0`) == true +[inline] +pub fn (c byte) is_bin_digit() bool { +	return c == `0` || c == `1` +} + +// is_letter returns `true` if the byte is in range a-z or A-Z and `false` otherwise. +// Example: assert byte(`V`) == true +[inline] +pub fn (c byte) is_letter() bool { +	return (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) +} + +// free allows for manually freeing the memory occupied by the string +[manualfree; unsafe] +pub fn (s &string) free() { +	$if prealloc { +		return +	} +	if s.is_lit == -98761234 { +		double_free_msg := unsafe { &byte(c'double string.free() detected\n') } +		double_free_msg_len := unsafe { vstrlen(double_free_msg) } +		$if freestanding { +			bare_eprint(double_free_msg, u64(double_free_msg_len)) +		} $else { +			_write_buf_to_fd(1, double_free_msg, double_free_msg_len) +		} +		return +	} +	if s.is_lit == 1 || s.str == 0 { +		return +	} +	unsafe { +		free(s.str) +	} +	s.is_lit = -98761234 +} + +// before returns the contents before `sub` in the string. +// If the substring is not found, it returns the full input string. +// Example: assert '23:34:45.234'.before('.') == '23:34:45' +// Example: assert 'abcd'.before('.') == 'abcd' +// TODO: deprecate and remove either .before or .all_before +pub fn (s string) before(sub string) string { +	pos := s.index_(sub) +	if pos == -1 { +		return s.clone() +	} +	return s[..pos] +} + +// all_before returns the contents before `sub` in the string. +// If the substring is not found, it returns the full input string. +// Example: assert '23:34:45.234'.all_before('.') == '23:34:45' +// Example: assert 'abcd'.all_before('.') == 'abcd' +pub fn (s string) all_before(sub string) string { +	// TODO remove dup method +	pos := s.index_(sub) +	if pos == -1 { +		return s.clone() +	} +	return s[..pos] +} + +// all_before_last returns the contents before the last occurence of `sub` in the string. +// If the substring is not found, it returns the full input string. +// Example: assert '23:34:45.234'.all_before_last(':') == '23:34' +// Example: assert 'abcd'.all_before_last('.') == 'abcd' +pub fn (s string) all_before_last(sub string) string { +	pos := s.last_index_(sub) +	if pos == -1 { +		return s.clone() +	} +	return s[..pos] +} + +// all_after returns the contents after `sub` in the string. +// If the substring is not found, it returns the full input string. +// Example: assert '23:34:45.234'.all_after('.') == '234' +// Example: assert 'abcd'.all_after('z') == 'abcd' +pub fn (s string) all_after(sub string) string { +	pos := s.index_(sub) +	if pos == -1 { +		return s.clone() +	} +	return s[pos + sub.len..] +} + +// all_after_last returns the contents after the last occurence of `sub` in the string. +// If the substring is not found, it returns the full input string. +// Example: assert '23:34:45.234'.all_after_last(':') == '45.234' +// Example: assert 'abcd'.all_after_last('z') == 'abcd' +pub fn (s string) all_after_last(sub string) string { +	pos := s.last_index_(sub) +	if pos == -1 { +		return s.clone() +	} +	return s[pos + sub.len..] +} + +// after returns the contents after the last occurence of `sub` in the string. +// If the substring is not found, it returns the full input string. +// Example: assert '23:34:45.234'.after(':') == '45.234' +// Example: assert 'abcd'.after('z') == 'abcd' +// TODO: deprecate either .all_after_last or .after +pub fn (s string) after(sub string) string { +	return s.all_after_last(sub) +} + +// after_char returns the contents after the first occurence of `sub` character in the string. +// If the substring is not found, it returns the full input string. +// Example: assert '23:34:45.234'.after_char(`:`) == '34:45.234' +// Example: assert 'abcd'.after_char(`:`) == 'abcd' +pub fn (s string) after_char(sub byte) string { +	mut pos := -1 +	for i, c in s { +		if c == sub { +			pos = i +			break +		} +	} +	if pos == -1 { +		return s.clone() +	} +	return s[pos + 1..] +} + +// join joins a string array into a string using `sep` separator. +// Example: assert ['Hello','V'].join(' ') == 'Hello V' +pub fn (a []string) join(sep string) string { +	if a.len == 0 { +		return '' +	} +	mut len := 0 +	for val in a { +		len += val.len + sep.len +	} +	len -= sep.len +	// Allocate enough memory +	mut res := string{ +		str: unsafe { malloc_noscan(len + 1) } +		len: len +	} +	mut idx := 0 +	for i, val in a { +		unsafe { +			C.memcpy(res.str + idx, val.str, val.len) +			idx += val.len +		} +		// Add sep if it's not last +		if i != a.len - 1 { +			unsafe { +				C.memcpy(res.str + idx, sep.str, sep.len) +				idx += sep.len +			} +		} +	} +	unsafe { +		res.str[res.len] = 0 +	} +	return res +} + +// join joins a string array into a string using a `\n` newline delimiter. +pub fn (s []string) join_lines() string { +	return s.join('\n') +} + +// reverse returns a reversed string. +// Example: assert 'Hello V'.reverse() == 'V olleH' +pub fn (s string) reverse() string { +	if s.len == 0 || s.len == 1 { +		return s.clone() +	} +	mut res := string{ +		str: unsafe { malloc_noscan(s.len + 1) } +		len: s.len +	} +	for i := s.len - 1; i >= 0; i-- { +		unsafe { +			res.str[s.len - i - 1] = s[i] +		} +	} +	unsafe { +		res.str[res.len] = 0 +	} +	return res +} + +// limit returns a portion of the string, starting at `0` and extending for a given number of characters afterward. +// 'hello'.limit(2) => 'he' +// 'hi'.limit(10) => 'hi' +pub fn (s string) limit(max int) string { +	u := s.runes() +	if u.len <= max { +		return s.clone() +	} +	return u[0..max].string() +} + +// hash returns an integer hash of the string. +pub fn (s string) hash() int { +	mut h := u32(0) +	if h == 0 && s.len > 0 { +		for c in s { +			h = h * 31 + u32(c) +		} +	} +	return int(h) +} + +// bytes returns the string converted to a byte array. +pub fn (s string) bytes() []byte { +	if s.len == 0 { +		return [] +	} +	mut buf := []byte{len: s.len} +	unsafe { C.memcpy(buf.data, s.str, s.len) } +	return buf +} + +// repeat returns a new string with `count` number of copies of the string it was called on. +pub fn (s string) repeat(count int) string { +	if count < 0 { +		panic('string.repeat: count is negative: $count') +	} else if count == 0 { +		return '' +	} else if count == 1 { +		return s.clone() +	} +	mut ret := unsafe { malloc_noscan(s.len * count + 1) } +	for i in 0 .. count { +		for j in 0 .. s.len { +			unsafe { +				ret[i * s.len + j] = s[j] +			} +		} +	} +	new_len := s.len * count +	unsafe { +		ret[new_len] = 0 +	} +	return unsafe { ret.vstring_with_len(new_len) } +} + +// fields returns a string array of the string split by `\t` and ` ` +// Example: assert '\t\tv = v'.fields() == ['v', '=', 'v'] +// Example: assert '  sss   ssss'.fields() == ['sss', 'ssss'] +pub fn (s string) fields() []string { +	mut res := []string{} +	mut word_start := 0 +	mut word_len := 0 +	mut is_in_word := false +	mut is_space := false +	for i, c in s { +		is_space = c in [32, 9, 10] +		if !is_space { +			word_len++ +		} +		if !is_in_word && !is_space { +			word_start = i +			is_in_word = true +			continue +		} +		if is_space && is_in_word { +			res << s[word_start..word_start + word_len] +			is_in_word = false +			word_len = 0 +			word_start = 0 +			continue +		} +	} +	if is_in_word && word_len > 0 { +		// collect the remainder word at the end +		res << s[word_start..s.len] +	} +	return res +} + +// strip_margin allows multi-line strings to be formatted in a way that removes white-space +// before a delimeter. by default `|` is used. +// Note: the delimiter has to be a byte at this time. That means surrounding +// the value in ``. +// +// Example: +// st := 'Hello there, +// |this is a string, +// |    Everything before the first | is removed'.strip_margin() +// Returns: +// Hello there, +// this is a string, +// Everything before the first | is removed +pub fn (s string) strip_margin() string { +	return s.strip_margin_custom(`|`) +} + +// strip_margin_custom does the same as `strip_margin` but will use `del` as delimiter instead of `|` +[direct_array_access] +pub fn (s string) strip_margin_custom(del byte) string { +	mut sep := del +	if sep.is_space() { +		eprintln('Warning: `strip_margin` cannot use white-space as a delimiter') +		eprintln('    Defaulting to `|`') +		sep = `|` +	} +	// don't know how much space the resulting string will be, but the max it +	// can be is this big +	mut ret := unsafe { malloc_noscan(s.len + 1) } +	mut count := 0 +	for i := 0; i < s.len; i++ { +		if s[i] in [10, 13] { +			unsafe { +				ret[count] = s[i] +			} +			count++ +			// CRLF +			if s[i] == 13 && i < s.len - 1 && s[i + 1] == 10 { +				unsafe { +					ret[count] = s[i + 1] +				} +				count++ +				i++ +			} +			for s[i] != sep { +				i++ +				if i >= s.len { +					break +				} +			} +		} else { +			unsafe { +				ret[count] = s[i] +			} +			count++ +		} +	} +	unsafe { +		ret[count] = 0 +		return ret.vstring_with_len(count) +	} +} diff --git a/v_windows/v/old/vlib/builtin/string_charptr_byteptr_helpers.v b/v_windows/v/old/vlib/builtin/string_charptr_byteptr_helpers.v new file mode 100644 index 0000000..e738ee2 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/string_charptr_byteptr_helpers.v @@ -0,0 +1,104 @@ +module builtin + +// NB: this file will be removed soon  + +// byteptr.vbytes() - makes a V []byte structure from a C style memory buffer. NB: the data is reused, NOT copied! +[unsafe] +pub fn (data byteptr) vbytes(len int) []byte { +	return unsafe { voidptr(data).vbytes(len) } +} + +// vstring converts a C style string to a V string. NB: the string data is reused, NOT copied. +// strings returned from this function will be normal V strings beside that (i.e. they would be +// freed by V's -autofree mechanism, when they are no longer used). +[unsafe] +pub fn (bp byteptr) vstring() string { +	return string{ +		str: bp +		len: unsafe { C.strlen(&char(bp)) } +	} +} + +// vstring_with_len converts a C style string to a V string. +// NB: the string data is reused, NOT copied. +[unsafe] +pub fn (bp byteptr) vstring_with_len(len int) string { +	return string{ +		str: bp +		len: len +		is_lit: 0 +	} +} + +// vstring converts C char* to V string. +// NB: the string data is reused, NOT copied. +[unsafe] +pub fn (cp charptr) vstring() string { +	return string{ +		str: byteptr(cp) +		len: unsafe { C.strlen(&char(cp)) } +		is_lit: 0 +	} +} + +// vstring_with_len converts C char* to V string. +// NB: the string data is reused, NOT copied. +[unsafe] +pub fn (cp charptr) vstring_with_len(len int) string { +	return string{ +		str: byteptr(cp) +		len: len +		is_lit: 0 +	} +} + +// vstring_literal converts a C style string to a V string. +// NB: the string data is reused, NOT copied. +// NB2: unlike vstring, vstring_literal will mark the string +// as a literal, so it will not be freed by autofree. +// This is suitable for readonly strings, C string literals etc, +// that can be read by the V program, but that should not be +// managed by it, for example `os.args` is implemented using it. +[unsafe] +pub fn (bp byteptr) vstring_literal() string { +	return string{ +		str: bp +		len: unsafe { C.strlen(&char(bp)) } +		is_lit: 1 +	} +} + +// vstring_with_len converts a C style string to a V string. +// NB: the string data is reused, NOT copied. +[unsafe] +pub fn (bp byteptr) vstring_literal_with_len(len int) string { +	return string{ +		str: bp +		len: len +		is_lit: 1 +	} +} + +// vstring_literal converts C char* to V string. +// See also vstring_literal defined on byteptr for more details. +// NB: the string data is reused, NOT copied. +[unsafe] +pub fn (cp charptr) vstring_literal() string { +	return string{ +		str: byteptr(cp) +		len: unsafe { C.strlen(&char(cp)) } +		is_lit: 1 +	} +} + +// vstring_literal_with_len converts C char* to V string. +// See also vstring_literal_with_len defined on byteptr. +// NB: the string data is reused, NOT copied. +[unsafe] +pub fn (cp charptr) vstring_literal_with_len(len int) string { +	return string{ +		str: byteptr(cp) +		len: len +		is_lit: 1 +	} +} diff --git a/v_windows/v/old/vlib/builtin/string_int_test.v b/v_windows/v/old/vlib/builtin/string_int_test.v new file mode 100644 index 0000000..a17563d --- /dev/null +++ b/v_windows/v/old/vlib/builtin/string_int_test.v @@ -0,0 +1,221 @@ +import strconv + +fn test_common_atoi() { +	// test common cases +	assert '70zzz'.int() == 70 +	assert '2901issue'.int() == 2901 +	assert '234232w'.int() == 234232 +	assert '-9009x'.int() == -9009 +	assert '0y'.int() == 0 + +	// test lead zeros +	assert '0000012'.int() == 12 +	assert '-0000012'.int() == -12 +	assert '0x001F'.int() == 31 +	assert '-0x001F'.int() == -31 +	assert '0x001f'.int() == 31 +	assert '0o00011'.int() == 9 +	assert '0b00001001'.int() == 9 + +	// test underscore in string +	assert '-10_000'.int() == -10000 +	assert '-0x00_0_f_ff'.int() == -0xfff +	assert '10_000_000'.int() == 10000000 + +	for n in -10000 .. 100000 { +		s := n.str() + 'z' +		assert s.int() == n +	} +} + +fn test_unsigned_cast() { +	// tests for u16 + +	// test common cases +	assert '70zzz'.u16() == 70 +	assert '2901issue'.u16() == 2901 +	assert '0y'.u16() == 0 + +	// test lead zeros +	assert '0000012'.u16() == 12 +	assert '0x001F'.u16() == 31 +	assert '0x001f'.u16() == 31 +	assert '0o00011'.u16() == 9 +	assert '0b00001001'.u16() == 9 + +	// tests for u32 + +	// test common cases +	assert '70zzz'.u32() == 70 +	assert '2901issue'.u32() == 2901 +	assert '234232w'.u32() == 234232 +	assert '-9009x'.u32() == 0 +	assert '0y'.u32() == 0 + +	// test lead zeros +	assert '0000012'.u32() == 12 +	assert '-0000012'.u32() == 0 +	assert '0x001F'.u32() == 31 +	assert '-0x001F'.u32() == 0 +	assert '0x001f'.u32() == 31 +	assert '0o00011'.u32() == 9 +	assert '0b00001001'.u32() == 9 + +	// test underscore in string +	assert '-10_000'.u32() == 0 +	assert '-0x00_0_f_ff'.u32() == 0 +	assert '10_000_000'.u32() == 10000000 + +	for n in 0 .. u32(100) { +		s := n.str() + 'z' +		assert s.u32() == n +	} + +	// tests for u64 + +	// test common cases +	assert '70zzz'.u64() == 70 +	assert '2901issue'.u64() == 2901 +	assert '234232w'.u64() == 234232 +	assert '-9009x'.u64() == 0 +	assert '0y'.u64() == 0 + +	// test lead zeros +	assert '0000012'.u64() == 12 +	assert '-0000012'.u64() == 0 +	assert '0x001F'.u64() == 31 +	assert '-0x001F'.u64() == 0 +	assert '0x001f'.u64() == 31 +	assert '0o00011'.u64() == 9 +	assert '0b00001001'.u64() == 9 + +	// test underscore in string +	assert '-10_000'.u64() == 0 +	assert '-0x00_0_f_ff'.u64() == 0 +	assert '10_000_000'.u64() == 10000000 + +	for n in 0 .. u64(10000) { +		s := n.str() + 'z' +		assert s.u64() == n +	} +} + +fn test_signed_cast() { +	// tests for i64 + +	// test common cases +	assert '70zzz'.i64() == 70 +	assert '2901issue'.i64() == 2901 +	assert '234232w'.i64() == 234232 +	assert '-9009x'.i64() == -9009 +	assert '0y'.i64() == 0 + +	// test lead zeros +	assert '0000012'.i64() == 12 +	assert '-0000012'.i64() == -12 +	assert '0x001F'.i64() == 31 +	assert '-0x001F'.i64() == -31 +	assert '0x001f'.i64() == 31 +	assert '0o00011'.i64() == 9 +	assert '0b00001001'.i64() == 9 + +	// test underscore in string +	assert '-10_000'.i64() == -10000 +	assert '-0x00_0_f_ff'.i64() == -0xfff +	assert '10_000_000'.i64() == 10000000 + +	for n in -10000 .. 100000 { +		s := n.str() + 'z' +		assert s.i64() == n +	} + +	// tests for i8 + +	// test common cases +	assert '70zzz'.i8() == 70 +	assert '29issue'.i8() == 29 +	assert '22w'.i8() == 22 +	assert '-90x'.i8() == -90 +	assert '0y'.i8() == 0 + +	// test lead zeros +	assert '0000012'.i8() == 12 +	assert '-0000012'.i8() == -12 +	assert '0x001F'.i8() == 31 +	assert '-0x001F'.i8() == -31 +	assert '0x001f'.i8() == 31 +	assert '0o00011'.i8() == 9 +	assert '0b000011'.i8() == 3 + +	// test underscore in string +	assert '-10_0'.i8() == -100 +	assert '-0x0_0_f'.i8() == -0xf +	assert '10_0'.i8() == 100 + +	for n in -10 .. 100 { +		s := n.str() + 'z' +		assert s.i8() == n +	} + +	// tests for i16 + +	// test common cases +	assert '70zzz'.i16() == 70 +	assert '2901issue'.i16() == 2901 +	assert '2342w'.i16() == 2342 +	assert '-9009x'.i16() == -9009 +	assert '0y'.i16() == 0 + +	// test lead zeros +	assert '0000012'.i16() == 12 +	assert '-0000012'.i16() == -12 +	assert '0x001F'.i16() == 31 +	assert '-0x001F'.i16() == -31 +	assert '0x001f'.i16() == 31 +	assert '0o00011'.i16() == 9 +	assert '0b00001001'.i16() == 9 + +	// test underscore in string +	assert '-10_0'.i16() == -100 +	assert '-0x00_0_fff'.i16() == -0xfff +	assert '10_0'.i16() == 100 + +	for n in -100 .. 100 { +		s := n.str() + 'z' +		assert s.i16() == n +	} + +	// test g format +	unsafe { +		mut u := strconv.Float64u{ +			u: strconv.double_plus_zero +		} +		assert '${u.f:g}' == '0' +		assert '${u.f:G}' == '0' +		u.u = strconv.double_minus_zero +		assert '${u.f:g}' == '0' +		assert '${u.f:G}' == '0' +		u.u = strconv.double_plus_infinity +		assert '${u.f:g}' == '+inf' +		assert '${u.f:G}' == '+INF' +		u.u = strconv.double_minus_infinity +		assert '${u.f:g}' == '-inf' +		assert '${u.f:G}' == '-INF' +	} +	unsafe { +		mut u := strconv.Float32u{ +			u: strconv.single_plus_zero +		} +		assert '${u.f:g}' == '0' +		assert '${u.f:G}' == '0' +		u.u = strconv.single_minus_zero +		assert '${u.f:g}' == '0' +		assert '${u.f:G}' == '0' +		u.u = strconv.single_plus_infinity +		assert '${u.f:g}' == '+inf' +		assert '${u.f:G}' == '+INF' +		u.u = strconv.single_minus_infinity +		assert '${u.f:g}' == '-inf' +		assert '${u.f:G}' == '-INF' +	} +} diff --git a/v_windows/v/old/vlib/builtin/string_interpolation.v b/v_windows/v/old/vlib/builtin/string_interpolation.v new file mode 100644 index 0000000..10064ac --- /dev/null +++ b/v_windows/v/old/vlib/builtin/string_interpolation.v @@ -0,0 +1,713 @@ +module builtin + +import strconv +import strings + +/*============================================================================= +Copyright (c) 2019-2021 Dario Deledda. All rights reserved. +Use of this source code is governed by an MIT license +that can be found in the LICENSE file. + +This file contains string interpolation V functions +=============================================================================*/ + +//============================================================================= +// Enum format types max 0x1F => 32 types +//============================================================================= +pub enum StrIntpType { +	si_no_str = 0 // no parameter to print only fix string +	si_c +	si_u8 +	si_i8 +	si_u16 +	si_i16 +	si_u32 +	si_i32 +	si_u64 +	si_i64 +	si_e32 +	si_e64 +	si_f32 +	si_f64 +	si_g32 +	si_g64 +	si_s +	si_p +	si_vp +} + +pub fn (x StrIntpType) str() string { +	match x { +		.si_no_str { return 'no_str' } +		.si_c { return 'c' } +		.si_u8 { return 'u8' } +		.si_i8 { return 'i8' } +		.si_u16 { return 'u16' } +		.si_i16 { return 'i16' } +		.si_u32 { return 'u32' } +		.si_i32 { return 'i32' } +		.si_u64 { return 'u64' } +		.si_i64 { return 'i64' } +		.si_f32 { return 'f32' } +		.si_f64 { return 'f64' } +		.si_g32 { return 'f32' } // g32 format use f32 data +		.si_g64 { return 'f64' } // g64 format use f64 data +		.si_e32 { return 'f32' } // e32 format use f32 data +		.si_e64 { return 'f64' } // e64 format use f64 data +		.si_s { return 's' } +		.si_p { return 'p' } +		.si_vp { return 'vp' } +	} +} + +//============================================================================= +// Union data +//============================================================================= +pub union StrIntpMem { +pub mut: +	d_c   u32 +	d_u8  byte +	d_i8  i8 +	d_u16 u16 +	d_i16 i16 +	d_u32 u32 +	d_i32 int +	d_u64 u64 +	d_i64 i64 +	d_f32 f32 +	d_f64 f64 +	d_s   string +	d_p   voidptr +	d_vp  voidptr +} + +[inline] +fn fabs32(x f32) f32 { +	return if x < 0 { -x } else { x } +} + +[inline] +fn fabs64(x f64) f64 { +	return if x < 0 { -x } else { x } +} + +[inline] +fn abs64(x i64) u64 { +	return if x < 0 { u64(-x) } else { u64(x) } +} + +//========================================= +// +//  u32/u64 bit compact format +// +//___     32      24      16       8 +//___      |       |       |       | +//_3333333333222222222211111111110000000000 +//_9876543210987654321098765432109876543210 +//_nPPPPPPPPBBBBWWWWWWWWWWTDDDDDDDSUAA===== +// = data type  5 bit  max 32 data type +// A allign     2 bit  Note: for now only 1 used! +// U uppercase  1 bit  0 do nothing, 1 do to_upper() +// S sign       1 bit  show the sign if positive +// D decimals   7 bit  number of decimals digit to show +// T tail zeros 1 bit  1 remove tail zeros, 0 do nothing +// W Width     10 bit  number of char for padding and indentation +// B num base   4 bit  start from 2, 0 for base 10 +// P pad char 1/8 bit  padding char (in u32 format reduced to 1 bit as flag for `0` padding) +//     -------------- +//     TOTAL:  39/32 bit +//========================================= + +// convert from data format to compact u64 +pub fn get_str_intp_u64_format(fmt_type StrIntpType, in_width int, in_precision int, in_tail_zeros bool, in_sign bool, in_pad_ch byte, in_base int, in_upper_case bool) u64 { +	width := if in_width != 0 { abs64(in_width) } else { u64(0) } +	allign := if in_width > 0 { u64(1 << 5) } else { u64(0) } // two bit 0 .left 1 .rigth, for now we use only one +	upper_case := if in_upper_case { u64(1 << 7) } else { u64(0) } +	sign := if in_sign { u64(1 << 8) } else { u64(0) } +	precision := if in_precision != 987698 { +		(u64(in_precision & 0x7F) << 9) +	} else { +		u64(0x7F) << 9 +	} +	tail_zeros := if in_tail_zeros { u32(1) << 16 } else { u32(0) } +	base := u64((in_base & 0xf) << 27) +	res := u64((u64(fmt_type) & 0x1F) | allign | upper_case | sign | precision | tail_zeros | (u64(width & 0x3FF) << 17) | base | (u64(in_pad_ch) << 31)) +	return res +} + +// convert from data format to compact u32 +pub fn get_str_intp_u32_format(fmt_type StrIntpType, in_width int, in_precision int, in_tail_zeros bool, in_sign bool, in_pad_ch byte, in_base int, in_upper_case bool) u32 { +	width := if in_width != 0 { abs64(in_width) } else { u32(0) } +	allign := if in_width > 0 { u32(1 << 5) } else { u32(0) } // two bit 0 .left 1 .rigth, for now we use only one +	upper_case := if in_upper_case { u32(1 << 7) } else { u32(0) } +	sign := if in_sign { u32(1 << 8) } else { u32(0) } +	precision := if in_precision != 987698 { +		(u32(in_precision & 0x7F) << 9) +	} else { +		u32(0x7F) << 9 +	} +	tail_zeros := if in_tail_zeros { u32(1) << 16 } else { u32(0) } +	base := u32((in_base & 0xf) << 27) +	res := u32((u32(fmt_type) & 0x1F) | allign | upper_case | sign | precision | tail_zeros | (u32(width & 0x3FF) << 17) | base | (u32(in_pad_ch & 1) << 31)) +	return res +} + +// convert from struct to formated string +[manualfree] +fn (data StrIntpData) get_fmt_format(mut sb strings.Builder) { +	x := data.fmt +	typ := StrIntpType(x & 0x1F) +	allign := int((x >> 5) & 0x01) +	upper_case := if ((x >> 7) & 0x01) > 0 { true } else { false } +	sign := int((x >> 8) & 0x01) +	precision := int((x >> 9) & 0x7F) +	tail_zeros := if ((x >> 16) & 0x01) > 0 { true } else { false } +	width := int(i16((x >> 17) & 0x3FF)) +	mut base := int(x >> 27) & 0xF +	fmt_pad_ch := byte((x >> 31) & 0xFF) + +	// no string interpolation is needed, return empty string +	if typ == .si_no_str { +		return +	} + +	// if width > 0 { println("${x.hex()} Type: ${x & 0x7F} Width: ${width} Precision: ${precision} allign:${allign}") } + +	// manage base if any +	if base > 0 { +		base += 2 // we start from 2, 0 == base 10 +	} + +	// mange pad char, for now only 0 allowed +	mut pad_ch := byte(` `) +	if fmt_pad_ch > 0 { +		// pad_ch = fmt_pad_ch +		pad_ch = `0` +	} + +	len0_set := if width > 0 { width } else { -1 } +	len1_set := if precision == 0x7F { -1 } else { precision } +	sign_set := if sign == 1 { true } else { false } + +	mut bf := strconv.BF_param{ +		pad_ch: pad_ch // padding char +		len0: len0_set // default len for whole the number or string +		len1: len1_set // number of decimal digits, if needed +		positive: true // mandatory: the sign of the number passed +		sign_flag: sign_set // flag for print sign as prefix in padding +		allign: .left // alignment of the string +		rm_tail_zero: tail_zeros // false // remove the tail zeros from floats +	} + +	// allign +	if fmt_pad_ch == 0 { +		match allign { +			0 { bf.allign = .left } +			1 { bf.allign = .right } +			// 2 { bf.allign = .center } +			else { bf.allign = .left } +		} +	} else { +		bf.allign = .right +	} + +	unsafe { +		// strings +		if typ == .si_s { +			mut s := '' +			if upper_case { +				s = data.d.d_s.to_upper() +			} else { +				s = data.d.d_s.clone() +			} +			if width == 0 { +				sb.write_string(s) +			} else { +				strconv.format_str_sb(s, bf, mut sb) +			} +			s.free() +			return +		} + +		// signed int +		if typ in [.si_i8, .si_i16, .si_i32, .si_i64] { +			mut d := data.d.d_i64 +			if typ == .si_i8 { +				d = i64(data.d.d_i8) +			} else if typ == .si_i16 { +				d = i64(data.d.d_i16) +			} else if typ == .si_i32 { +				d = i64(data.d.d_i32) +			} + +			if base == 0 { +				if width == 0 { +					d_str := d.str() +					sb.write_string(d_str) +					d_str.free() +					return +				} +				if d < 0 { +					bf.positive = false +				} +				strconv.format_dec_sb(abs64(d), bf, mut sb) +			} else { +				mut hx := strconv.format_int(d, base) +				if upper_case { +					tmp := hx +					hx = hx.to_upper() +					tmp.free() +				} +				if width == 0 { +					sb.write_string(hx) +				} else { +					strconv.format_str_sb(hx, bf, mut sb) +				} +				hx.free() +			} +			return +		} + +		// unsigned int and pointers +		if typ in [.si_u8, .si_u16, .si_u32, .si_u64] { +			mut d := data.d.d_u64 +			if typ == .si_u8 { +				d = u64(data.d.d_u8) +			} else if typ == .si_u16 { +				d = u64(data.d.d_u16) +			} else if typ == .si_u32 { +				d = u64(data.d.d_u32) +			} +			if base == 0 { +				if width == 0 { +					d_str := d.str() +					sb.write_string(d_str) +					d_str.free() +					return +				} +				strconv.format_dec_sb(d, bf, mut sb) +			} else { +				mut hx := strconv.format_uint(d, base) +				if upper_case { +					tmp := hx +					hx = hx.to_upper() +					tmp.free() +				} +				if width == 0 { +					sb.write_string(hx) +				} else { +					strconv.format_str_sb(hx, bf, mut sb) +				} +				hx.free() +			} +			return +		} + +		// pointers +		if typ == .si_p { +			mut d := data.d.d_u64 +			base = 16 // TODO: **** decide the behaviour of this flag! **** +			if base == 0 { +				if width == 0 { +					d_str := d.str() +					sb.write_string(d_str) +					d_str.free() +					return +				} +				strconv.format_dec_sb(d, bf, mut sb) +			} else { +				mut hx := strconv.format_uint(d, base) +				if upper_case { +					tmp := hx +					hx = hx.to_upper() +					tmp.free() +				} +				if width == 0 { +					sb.write_string(hx) +				} else { +					strconv.format_str_sb(hx, bf, mut sb) +				} +				hx.free() +			} +			return +		} + +		// default settings for floats +		mut use_default_str := false +		if width == 0 && precision == 0x7F { +			bf.len1 = 3 +			use_default_str = true +		} +		if bf.len1 < 0 { +			bf.len1 = 3 +		} + +		match typ { +			// floating point +			.si_f32 { +				// println("HERE: f32") +				if use_default_str { +					mut f := data.d.d_f32.str() +					if upper_case { +						tmp := f +						f = f.to_upper() +						tmp.free() +					} +					sb.write_string(f) +					f.free() +				} else { +					// println("HERE: f32 format") +					// println(data.d.d_f32) +					if data.d.d_f32 < 0 { +						bf.positive = false +					} +					mut f := strconv.format_fl(data.d.d_f32, bf) +					if upper_case { +						tmp := f +						f = f.to_upper() +						tmp.free() +					} +					sb.write_string(f) +					f.free() +				} +			} +			.si_f64 { +				// println("HERE: f64") +				if use_default_str { +					mut f := data.d.d_f64.str() +					if upper_case { +						tmp := f +						f = f.to_upper() +						tmp.free() +					} +					sb.write_string(f) +					f.free() +				} else { +					if data.d.d_f64 < 0 { +						bf.positive = false +					} +					f_union := strconv.Float64u{ +						f: data.d.d_f64 +					} +					if f_union.u == strconv.double_minus_zero { +						bf.positive = false +					} + +					mut f := strconv.format_fl(data.d.d_f64, bf) +					if upper_case { +						tmp := f +						f = f.to_upper() +						tmp.free() +					} +					sb.write_string(f) +					f.free() +				} +			} +			.si_g32 { +				// println("HERE: g32") +				if use_default_str { +					mut f := data.d.d_f32.strg() +					if upper_case { +						tmp := f +						f = f.to_upper() +						tmp.free() +					} +					sb.write_string(f) +					f.free() +				} else { +					// Manage +/-0 +					if data.d.d_f32 == strconv.single_plus_zero { +						tmp_str := '0' +						strconv.format_str_sb(tmp_str, bf, mut sb) +						tmp_str.free() +						return +					} +					if data.d.d_f32 == strconv.single_minus_zero { +						tmp_str := '-0' +						strconv.format_str_sb(tmp_str, bf, mut sb) +						tmp_str.free() +						return +					} +					// Manage +/-INF +					if data.d.d_f32 == strconv.single_plus_infinity { +						mut tmp_str := '+inf' +						if upper_case { +							tmp_str = '+INF' +						} +						strconv.format_str_sb(tmp_str, bf, mut sb) +						tmp_str.free() +					} +					if data.d.d_f32 == strconv.single_minus_infinity { +						mut tmp_str := '-inf' +						if upper_case { +							tmp_str = '-INF' +						} +						strconv.format_str_sb(tmp_str, bf, mut sb) +						tmp_str.free() +					} + +					if data.d.d_f32 < 0 { +						bf.positive = false +					} +					d := fabs32(data.d.d_f32) +					if d < 999_999.0 && d >= 0.00001 { +						mut f := strconv.format_fl(data.d.d_f32, bf) +						if upper_case { +							tmp := f +							f = f.to_upper() +							tmp.free() +						} +						sb.write_string(f) +						f.free() +						return +					} +					mut f := strconv.format_es(data.d.d_f32, bf) +					if upper_case { +						tmp := f +						f = f.to_upper() +						tmp.free() +					} +					sb.write_string(f) +					f.free() +				} +			} +			.si_g64 { +				// println("HERE: g64") +				if use_default_str { +					mut f := data.d.d_f64.strg() +					if upper_case { +						tmp := f +						f = f.to_upper() +						tmp.free() +					} +					sb.write_string(f) +					f.free() +				} else { +					// Manage +/-0 +					if data.d.d_f64 == strconv.double_plus_zero { +						tmp_str := '0' +						strconv.format_str_sb(tmp_str, bf, mut sb) +						tmp_str.free() +						return +					} +					if data.d.d_f64 == strconv.double_minus_zero { +						tmp_str := '-0' +						strconv.format_str_sb(tmp_str, bf, mut sb) +						tmp_str.free() +						return +					} +					// Manage +/-INF +					if data.d.d_f64 == strconv.double_plus_infinity { +						mut tmp_str := '+inf' +						if upper_case { +							tmp_str = '+INF' +						} +						strconv.format_str_sb(tmp_str, bf, mut sb) +						tmp_str.free() +					} +					if data.d.d_f64 == strconv.double_minus_infinity { +						mut tmp_str := '-inf' +						if upper_case { +							tmp_str = '-INF' +						} +						strconv.format_str_sb(tmp_str, bf, mut sb) +						tmp_str.free() +					} + +					if data.d.d_f64 < 0 { +						bf.positive = false +					} +					d := fabs64(data.d.d_f64) +					if d < 999_999.0 && d >= 0.00001 { +						mut f := strconv.format_fl(data.d.d_f64, bf) +						if upper_case { +							tmp := f +							f = f.to_upper() +							tmp.free() +						} +						sb.write_string(f) +						f.free() +						return +					} +					mut f := strconv.format_es(data.d.d_f64, bf) +					if upper_case { +						tmp := f +						f = f.to_upper() +						tmp.free() +					} +					sb.write_string(f) +					f.free() +				} +			} +			.si_e32 { +				// println("HERE: e32") +				bf.len1 = 6 +				if use_default_str { +					mut f := data.d.d_f32.str() +					if upper_case { +						tmp := f +						f = f.to_upper() +						tmp.free() +					} +					sb.write_string(f) +					f.free() +				} else { +					if data.d.d_f32 < 0 { +						bf.positive = false +					} +					mut f := strconv.format_es(data.d.d_f32, bf) +					if upper_case { +						tmp := f +						f = f.to_upper() +						tmp.free() +					} +					sb.write_string(f) +					f.free() +				} +			} +			.si_e64 { +				// println("HERE: e64") +				bf.len1 = 6 +				if use_default_str { +					mut f := data.d.d_f64.str() +					if upper_case { +						tmp := f +						f = f.to_upper() +						tmp.free() +					} +					sb.write_string(f) +					f.free() +				} else { +					if data.d.d_f64 < 0 { +						bf.positive = false +					} +					mut f := strconv.format_es(data.d.d_f64, bf) +					if upper_case { +						tmp := f +						f = f.to_upper() +						tmp.free() +					} +					sb.write_string(f) +					f.free() +				} +			} +			// runes +			.si_c { +				ss := utf32_to_str(data.d.d_c) +				sb.write_string(ss) +				ss.free() +			} +			// v pointers +			.si_vp { +				ss := u64(data.d.d_vp).hex() +				sb.write_string(ss) +				ss.free() +			} +			else { +				sb.write_string('***ERROR!***') +			} +		} +	} +} + +//==================================================================================== + +// storing struct used by cgen +pub struct StrIntpCgenData { +pub: +	str string +	fmt string +	d   string +} + +// NOTE: LOW LEVEL struct +// storing struct passed to V in the C code +pub struct StrIntpData { +pub: +	str string +	// fmt     u64  // expanded version for future use, 64 bit +	fmt u32 +	d   StrIntpMem +} + +// interpolation function +[manualfree] +pub fn str_intp(data_len int, in_data voidptr) string { +	mut res := strings.new_builder(256) +	unsafe { +		mut i := 0 +		for i < data_len { +			data := &StrIntpData(&byte(in_data) + (int(sizeof(StrIntpData)) * i)) +			// avoid empty strings +			if data.str.len != 0 { +				res.write_string(data.str) +			} +			// skip empty data +			if data.fmt != 0 { +				data.get_fmt_format(mut &res) +			} +			i++ +		} +	} +	ret := res.str() +	unsafe { res.free() } +	return ret +} + +//==================================================================================== +// Utility for the compiler "auto_str_methods.v" +//==================================================================================== + +// substitute old _STR calls + +pub const ( +	// BUG: this const is not released from the memory! use a const for now +	// si_s_code = "0x" + int(StrIntpType.si_s).hex() // code for a simple string +	si_s_code   = '0xfe10' +	si_g32_code = '0xfe0e' +	si_g64_code = '0xfe0f' +) + +[inline] +pub fn str_intp_sq(in_str string) string { +	return 'str_intp(2, _MOV((StrIntpData[]){{_SLIT("\'"), $si_s_code, {.d_s = $in_str}},{_SLIT("\'"), 0, {.d_c = 0 }}}))' +} + +[inline] +pub fn str_intp_rune(in_str string) string { +	return 'str_intp(2, _MOV((StrIntpData[]){{_SLIT("\`"), $si_s_code, {.d_s = $in_str}},{_SLIT("\`"), 0, {.d_c = 0 }}}))' +} + +[inline] +pub fn str_intp_g32(in_str string) string { +	return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, $si_g32_code, {.d_f32 = $in_str }}}))' +} + +[inline] +pub fn str_intp_g64(in_str string) string { +	return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, $si_g64_code, {.d_f64 = $in_str }}}))' +} + +// replace %% with the in_str +[manualfree] +pub fn str_intp_sub(base_str string, in_str string) string { +	index := base_str.index('%%') or { +		eprintln('No strin interpolation %% parameteres') +		exit(1) +	} +	// return base_str[..index] + in_str + base_str[index+2..] + +	unsafe { +		st_str := base_str[..index] +		if index + 2 < base_str.len { +			en_str := base_str[index + 2..] +			res_str := 'str_intp(2, _MOV((StrIntpData[]){{_SLIT("$st_str"), $si_s_code, {.d_s = $in_str }},{_SLIT("$en_str"), 0, {.d_c = 0}}}))' +			st_str.free() +			en_str.free() +			return res_str +		} +		res2_str := 'str_intp(1, _MOV((StrIntpData[]){{_SLIT("$st_str"), $si_s_code, {.d_s = $in_str }}}))' +		st_str.free() +		return res2_str +	} +} diff --git a/v_windows/v/old/vlib/builtin/string_strip_margin_test.v b/v_windows/v/old/vlib/builtin/string_strip_margin_test.v new file mode 100644 index 0000000..372b8af --- /dev/null +++ b/v_windows/v/old/vlib/builtin/string_strip_margin_test.v @@ -0,0 +1,95 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +fn test_strip_margins_no_tabs() { +	no_tabs := ['Hello there', 'This is a string', 'With multiple lines'].join('\n') +	no_tabs_stripped := 'Hello there +	                    |This is a string +						|With multiple lines'.strip_margin() +	assert no_tabs == no_tabs_stripped +} + +fn test_strip_margins_text_before() { +	text_before := ['There is text', 'before the delimiter', 'that should be removed as well'].join('\n') +	text_before_stripped := 'There is text +	f lasj  asldfj j lksjdf |before the delimiter +	Which is removed hello  |that should be removed as well'.strip_margin() +	assert text_before_stripped == text_before +} + +fn test_strip_margins_white_space_after_delim() { +	tabs := ['	Tab', '    spaces', '	another tab'].join('\n') +	tabs_stripped := '	Tab +	                 |    spaces +					 |	another tab'.strip_margin() +	assert tabs == tabs_stripped +} + +fn test_strip_margins_alternate_delim() { +	alternate_delimiter := ['This has a different delim,', 'but that is ok', +		'because everything works', +	].join('\n') +	alternate_delimiter_stripped := 'This has a different delim, +	                                #but that is ok +                                    #because everything works'.strip_margin_custom(`#`) +	assert alternate_delimiter_stripped == alternate_delimiter +} + +fn test_strip_margins_multiple_delims_after_first() { +	delim_after_first_instance := ['The delimiter used', +		'only matters the |||| First time it is seen', 'not any | other | times'].join('\n') +	delim_after_first_instance_stripped := 'The delimiter used +	                                       |only matters the |||| First time it is seen +	                                       |not any | other | times'.strip_margin() +	assert delim_after_first_instance_stripped == delim_after_first_instance +} + +fn test_strip_margins_uneven_delims() { +	uneven_delims := ["It doesn't matter if the delims are uneven,", +		'The text will still be delimited correctly.', 'Maybe not everything needs 3 lines?', +		'Let us go for 4 then', +	].join('\n') +	uneven_delims_stripped := "It doesn't matter if the delims are uneven, +           |The text will still be delimited correctly. +                      |Maybe not everything needs 3 lines? +				|Let us go for 4 then".strip_margin() +	assert uneven_delims_stripped == uneven_delims +} + +fn test_strip_margins_multiple_blank_lines() { +	multi_blank_lines := ['Multiple blank lines will be removed.', +		'	I actually consider this a feature.', +	].join('\n') +	multi_blank_lines_stripped := 'Multiple blank lines will be removed. + + + +		|	I actually consider this a feature.'.strip_margin() +	assert multi_blank_lines == multi_blank_lines_stripped +} + +fn test_strip_margins_end_newline() { +	end_with_newline := ['This line will end with a newline', 'Something cool or something.', ''].join('\n') +	end_with_newline_stripped := 'This line will end with a newline +	                             |Something cool or something. + +					'.strip_margin() +	assert end_with_newline_stripped == end_with_newline +} + +fn test_strip_margins_space_delimiter() { +	space_delimiter := ['Using a white-space char will', 'revert back to default behavior.'].join('\n') +	space_delimiter_stripped := 'Using a white-space char will +		|revert back to default behavior.'.strip_margin_custom(`\n`) +	assert space_delimiter == space_delimiter_stripped +} + +fn test_strip_margins_crlf() { +	crlf := ["This string's line endings have CR as well as LFs.", 'This should pass', 'Definitely'].join('\r\n') +	crlf_stripped := "This string's line endings have CR as well as LFs.\r +	                 |This should pass\r +					 |Definitely".strip_margin() + +	assert crlf == crlf_stripped +} diff --git a/v_windows/v/old/vlib/builtin/string_test.v b/v_windows/v/old/vlib/builtin/string_test.v new file mode 100644 index 0000000..8a5ee66 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/string_test.v @@ -0,0 +1,912 @@ +import strings + +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +struct Foo { +	bar int +mut: +	str string +} + +fn test_add() { +	mut a := 'a' +	a += 'b' +	assert a == ('ab') +	a = 'a' +	for i := 1; i < 1000; i++ { +		a += 'b' +	} +	assert a.len == 1000 +	assert a.ends_with('bbbbb') +	a += '123' +	assert a.ends_with('3') +} + +fn test_ends_with() { +	a := 'browser.v' +	assert a.ends_with('.v') + +	s := 'V Programming Language' +	assert s.ends_with('guage') == true +	assert s.ends_with('Language') == true +	assert s.ends_with('Programming Language') == true +	assert s.ends_with('V') == false +} + +fn test_between() { +	s := 'hello [man] how you doing' +	assert s.find_between('[', ']') == 'man' +} + +fn test_compare() { +	a := 'Music' +	b := 'src' +	assert b >= a +} + +fn test_lt() { +	a := '' +	b := 'a' +	c := 'a' +	d := 'b' +	e := 'aa' +	f := 'ab' +	assert a < b +	assert !(b < c) +	assert c < d +	assert !(d < e) +	assert c < e +	assert e < f +} + +fn test_ge() { +	a := 'aa' +	b := 'aa' +	c := 'ab' +	d := 'abc' +	e := 'aaa' +	assert b >= a +	assert c >= b +	assert d >= c +	assert !(c >= d) +	assert e >= a +} + +fn test_compare_strings() { +	a := 'aa' +	b := 'aa' +	c := 'ab' +	d := 'abc' +	e := 'aaa' +	assert compare_strings(a, b) == 0 +	assert compare_strings(b, c) == -1 +	assert compare_strings(c, d) == -1 +	assert compare_strings(d, e) == 1 +	assert compare_strings(a, e) == -1 +	assert compare_strings(e, a) == 1 +} + +fn test_sort() { +	mut vals := [ +		'arr', +		'an', +		'a', +		'any', +	] +	len := vals.len +	vals.sort() +	assert len == vals.len +	assert vals[0] == 'a' +	assert vals[1] == 'an' +	assert vals[2] == 'any' +	assert vals[3] == 'arr' +} + +fn test_sort_reverse() { +	mut vals := [ +		'arr', +		'an', +		'a', +		'any', +	] +	len := vals.len +	vals.sort(b > a) +	assert len == vals.len +	assert vals[0] == 'a' +	assert vals[1] == 'an' +	assert vals[2] == 'any' +	assert vals[3] == 'arr' +} + +fn test_split_nth() { +	a := '1,2,3' +	assert a.split(',').len == 3 +	assert a.split_nth(',', -1).len == 3 +	assert a.split_nth(',', 0).len == 3 +	assert a.split_nth(',', 1).len == 1 +	assert a.split_nth(',', 2).len == 2 +	assert a.split_nth(',', 10).len == 3 +	b := '1::2::3' +	assert b.split('::').len == 3 +	assert b.split_nth('::', -1).len == 3 +	assert b.split_nth('::', 0).len == 3 +	assert b.split_nth('::', 1).len == 1 +	assert b.split_nth('::', 2).len == 2 +	assert b.split_nth('::', 10).len == 3 +	c := 'ABCDEF' +	println(c.split('').len) +	assert c.split('').len == 6 +	assert c.split_nth('', 3).len == 3 +	assert c.split_nth('BC', -1).len == 2 +	d := ',' +	assert d.split(',').len == 2 +	assert d.split_nth('', 3).len == 1 +	assert d.split_nth(',', -1).len == 2 +	assert d.split_nth(',', 3).len == 2 +	e := ',,,0,,,,,a,,b,' +	assert e.split(',,').len == 5 +	assert e.split_nth(',,', 3).len == 3 +	assert e.split_nth(',', -1).len == 12 +	assert e.split_nth(',', 3).len == 3 +} + +fn test_split_nth_values() { +	line := 'CMD=eprintln(phase=1)' + +	a0 := line.split_nth('=', 0) +	assert a0.len == 3 +	assert a0[0] == 'CMD' +	assert a0[1] == 'eprintln(phase' +	assert a0[2] == '1)' + +	a1 := line.split_nth('=', 1) +	assert a1.len == 1 +	assert a1[0] == 'CMD=eprintln(phase=1)' + +	a2 := line.split_nth('=', 2) +	assert a2.len == 2 +	assert a2[0] == 'CMD' +	assert a2[1] == 'eprintln(phase=1)' + +	a3 := line.split_nth('=', 3) +	assert a3.len == 3 +	assert a3[0] == 'CMD' +	assert a3[1] == 'eprintln(phase' +	assert a3[2] == '1)' + +	a4 := line.split_nth('=', 4) +	assert a4.len == 3 +	assert a4[0] == 'CMD' +	assert a4[1] == 'eprintln(phase' +	assert a4[2] == '1)' +} + +fn test_split() { +	mut s := 'volt/twitch.v:34' +	mut vals := s.split(':') +	assert vals.len == 2 +	assert vals[0] == 'volt/twitch.v' +	assert vals[1] == '34' +	// ///////// +	s = '2018-01-01z13:01:02' +	vals = s.split('z') +	assert vals.len == 2 +	assert vals[0] == '2018-01-01' +	assert vals[1] == '13:01:02' +	// ////////// +	s = '4627a862c3dec29fb3182a06b8965e0025759e18___1530207969___blue' +	vals = s.split('___') +	assert vals.len == 3 +	assert vals[0] == '4627a862c3dec29fb3182a06b8965e0025759e18' +	assert vals[1] == '1530207969' +	assert vals[2] == 'blue' +	// ///////// +	s = 'lalala' +	vals = s.split('a') +	assert vals.len == 4 +	assert vals[0] == 'l' +	assert vals[1] == 'l' +	assert vals[2] == 'l' +	assert vals[3] == '' +	// ///////// +	s = 'awesome' +	a := s.split('') +	assert a.len == 7 +	assert a[0] == 'a' +	assert a[1] == 'w' +	assert a[2] == 'e' +	assert a[3] == 's' +	assert a[4] == 'o' +	assert a[5] == 'm' +	assert a[6] == 'e' +	// ///////// +	s = 'wavy turquoise bags' +	vals = s.split(' bags') +	assert vals.len == 2 +	assert vals[0] == 'wavy turquoise' +	assert vals[1] == '' +} + +fn test_trim_space() { +	a := ' a ' +	assert a.trim_space() == 'a' +	code := ' + +fn main() { +        println(2) +} + +' +	code_clean := 'fn main() { +        println(2) +}' +	assert code.trim_space() == code_clean +} + +fn test_join() { +	mut strings := ['a', 'b', 'c'] +	mut s := strings.join(' ') +	assert s == 'a b c' +	strings = [ +		'one +two ', +		'three! +four!', +	] +	s = strings.join(' ') +	assert s.contains('one') && s.contains('two ') && s.contains('four') +	empty := []string{len: 0} +	assert empty.join('A') == '' +} + +fn test_clone() { +	mut a := 'a' +	a += 'a' +	a += 'a' +	b := a +	c := a.clone() +	assert c == a +	assert c == 'aaa' +	assert b == 'aaa' +} + +fn test_replace() { +	a := 'hello man!' +	mut b := a.replace('man', 'world') +	assert b == ('hello world!') +	b = b.replace('!', '') +	assert b == ('hello world') +	b = b.replace('h', 'H') +	assert b == ('Hello world') +	b = b.replace('foo', 'bar') +	assert b == ('Hello world') +	s := 'hey man how are you' +	assert s.replace('man ', '') == 'hey how are you' +	lol := 'lol lol lol' +	assert lol.replace('lol', 'LOL') == 'LOL LOL LOL' +	b = 'oneBtwoBBthree' +	assert b.replace('B', '') == 'onetwothree' +	b = '*charptr' +	assert b.replace('charptr', 'byteptr') == '*byteptr' +	c := 'abc' +	assert c.replace('', '-') == c +	v := 'a   b c d' +	assert v.replace('  ', ' ') == 'a  b c d' +} + +fn test_replace_each() { +	s := 'hello man man :)' +	q := s.replace_each([ +		'man', +		'dude', +		'hello', +		'hey', +	]) +	assert q == 'hey dude dude :)' +	bb := '[b]bold[/b] [code]code[/code]' +	assert bb.replace_each([ +		'[b]', +		'<b>', +		'[/b]', +		'</b>', +		'[code]', +		'<code>', +		'[/code]', +		'</code>', +	]) == '<b>bold</b> <code>code</code>' +	bb2 := '[b]cool[/b]' +	assert bb2.replace_each([ +		'[b]', +		'<b>', +		'[/b]', +		'</b>', +	]) == '<b>cool</b>' +	t := 'aaaaaaaa' +	y := t.replace_each([ +		'aa', +		'b', +	]) +	assert y == 'bbbb' +	s2 := 'hello_world hello' +	assert s2.replace_each(['hello_world', 'aaa', 'hello', 'bbb']) == 'aaa bbb' +} + +fn test_itoa() { +	num := 777 +	assert num.str() == '777' +	big := 7779998 +	assert big.str() == '7779998' +	a := 3 +	assert a.str() == '3' +	b := 5555 +	assert b.str() == '5555' +	zero := 0 +	assert zero.str() == '0' +	neg := -7 +	assert neg.str() == '-7' +} + +fn test_reassign() { +	a := 'hi' +	mut b := a +	b += '!' +	assert a == 'hi' +	assert b == 'hi!' +} + +fn test_runes() { +	s := 'привет' +	assert s.len == 12 +	s2 := 'privet' +	assert s2.len == 6 +	u := s.runes() +	assert u.len == 6 +	assert s2.substr(1, 4).len == 3 +	assert s2.substr(1, 4) == 'riv' +	assert s2[1..4].len == 3 +	assert s2[1..4] == 'riv' +	assert s2[..4].len == 4 +	assert s2[..4] == 'priv' +	assert s2[2..].len == 4 +	assert s2[2..] == 'ivet' +	assert u[1..4].string().len == 6 +	assert u[1..4].string() == 'рив' +	assert s2.substr(1, 2) == 'r' +	assert u[1..2].string() == 'р' +	assert s2.runes()[1] == `r` +	assert u[1] == `р` +	first := u[0] +	last := u[u.len - 1] +	assert first.str().len == 2 +	assert last.str().len == 2 +} + +fn test_contains() { +	s := 'view.v' +	assert s.contains('vi') +	assert !s.contains('random') +	assert ''.contains('') +	assert 'abc'.contains('') +} + +fn test_contains_any() { +	assert !'team'.contains_any('i') +	assert 'fail'.contains_any('ui') +	assert 'ure'.contains_any('ui') +	assert 'failure'.contains_any('ui') +	assert !'foo'.contains_any('') +	assert !''.contains_any('') +} + +fn test_contains_any_substr() { +	s := 'Some random text' +	assert s.contains_any_substr(['false', 'not', 'rand']) +	assert !s.contains_any_substr(['ABC', 'invalid']) +	assert ''.contains_any_substr([]) +	assert 'abc'.contains_any_substr(['']) +} + +fn test_arr_contains() { +	a := ['a', 'b', 'c'] +	assert a.contains('b') +	ints := [1, 2, 3] +	assert ints.contains(2) +} + +fn test_to_num() { +	s := '7' +	assert s.int() == 7 +	assert s.u64() == 7 +	f := '71.5 hasdf' +	// QTODO +	assert f.f32() == 71.5 +	vals := ['9'] +	assert vals[0].int() == 9 +	big := '93993993939322' +	assert big.u64() == 93993993939322 +	assert big.i64() == 93993993939322 +} + +fn test_inter_format_string() { +	float_num := 1.52345 +	float_num_string := '-${float_num:.3f}-' +	assert float_num_string == '-1.523-' +	int_num := 7 +	int_num_string := '-${int_num:03d}-' +	assert int_num_string == '-007-' +	ch := `a` +	ch_string := '-${ch:c}-' +	assert ch_string == '-a-' +	hex_n := 192 +	hex_n_string := '-${hex_n:x}-' +	assert hex_n_string == '-c0-' +	oct_n := 192 +	oct_n_string := '-${oct_n:o}-' +	assert oct_n_string == '-300-' +	str := 'abc' +	str_string := '-${str:s}-' +	assert str_string == '-abc-' +} + +fn test_hash() { +	s := '10000' +	assert s.hash() == 46730161 +	s2 := '24640' +	assert s2.hash() == 47778736 +	s3 := 'Content-Type' +	assert s3.hash() == 949037134 +	s4 := 'bad_key' +	assert s4.hash() == -346636507 +	s5 := '24640' +	// From a map collision test +	assert s5.hash() % ((1 << 20) - 1) == s.hash() % ((1 << 20) - 1) +	assert s5.hash() % ((1 << 20) - 1) == 592861 +} + +fn test_trim() { +	assert 'banana'.trim('bna') == '' +	assert 'abc'.trim('ac') == 'b' +	assert 'aaabccc'.trim('ac') == 'b' +} + +fn test_trim_left() { +	mut s := 'module main' +	assert s.trim_left(' ') == 'module main' +	s = ' module main' +	assert s.trim_left(' ') == 'module main' +	// test cutset +	s = 'banana' +	assert s.trim_left('ba') == 'nana' +	assert s.trim_left('ban') == '' +} + +fn test_trim_right() { +	mut s := 'module main' +	assert s.trim_right(' ') == 'module main' +	s = 'module main ' +	assert s.trim_right(' ') == 'module main' +	// test cutset +	s = 'banana' +	assert s.trim_right('na') == 'b' +	assert s.trim_right('ban') == '' +} + +fn test_all_before() { +	s := 'fn hello fn' +	assert s.all_before(' ') == 'fn' +	assert s.all_before('2') == s +	assert s.all_before('') == s +} + +fn test_all_before_last() { +	s := 'fn hello fn' +	assert s.all_before_last(' ') == 'fn hello' +	assert s.all_before_last('2') == s +	assert s.all_before_last('') == s +} + +fn test_all_after() { +	s := 'fn hello' +	assert s.all_after('fn ') == 'hello' +	assert s.all_after('test') == s +	assert s.all_after('') == s +	assert s.after('e') == 'llo' +	x := s.after('e') +	assert x == 'llo' +} + +fn test_reverse() { +	assert 'hello'.reverse() == 'olleh' +	assert ''.reverse() == '' +	assert 'a'.reverse() == 'a' +} + +fn test_bytes_to_string() { +	mut buf := vcalloc(10) +	unsafe { +		buf[0] = `h` +		buf[1] = `e` +		buf[2] = `l` +		buf[3] = `l` +		buf[4] = `o` +	} +	assert unsafe { buf.vstring() } == 'hello' +	assert unsafe { buf.vstring_with_len(2) } == 'he' +	bytes := [byte(`h`), `e`, `l`, `l`, `o`] +	assert bytes.bytestr() == 'hello' +} + +fn test_charptr() { +	foo := &char('VLANG'.str) +	println(typeof(foo).name) +	assert typeof(foo).name == '&char' +	assert unsafe { foo.vstring() } == 'VLANG' +	assert unsafe { foo.vstring_with_len(3) } == 'VLA' +} + +fn test_count() { +	assert ''.count('') == 0 +	assert ''.count('a') == 0 +	assert 'a'.count('') == 0 +	assert 'aa'.count('a') == 2 +	assert 'aa'.count('aa') == 1 +	assert 'aabbaa'.count('aa') == 2 +	assert 'bbaabb'.count('aa') == 1 +} + +fn test_lower() { +	mut s := 'A' +	assert !s.is_lower() +	assert s.to_lower() == 'a' +	assert s.to_lower().len == 1 +	s = 'HELLO' +	assert !s.is_lower() +	assert s.to_lower() == 'hello' +	assert s.to_lower().len == 5 +	s = 'Aloha' +	assert !s.is_lower() +	assert s.to_lower() == 'aloha' +	s = 'Have A nice Day!' +	assert !s.is_lower() +	assert s.to_lower() == 'have a nice day!' +	s = 'hi' +	assert s.is_lower() +	assert s.to_lower() == 'hi' +	assert 'aloha!'[0] == `a` +	assert 'aloha!'[5] == `!` +} + +fn test_upper() { +	mut s := 'a' +	assert !s.is_upper() +	assert s.to_upper() == 'A' +	assert s.to_upper().len == 1 +	s = 'hello' +	assert !s.is_upper() +	assert s.to_upper() == 'HELLO' +	assert s.to_upper().len == 5 +	s = 'Aloha' +	assert !s.is_upper() +	assert s.to_upper() == 'ALOHA' +	s = 'have a nice day!' +	assert !s.is_upper() +	assert s.to_upper() == 'HAVE A NICE DAY!' +	s = 'HI' +	assert s.is_upper() +	assert s.to_upper() == 'HI' +} + +fn test_capitalize() { +	mut s := 'hello' +	assert !s.is_capital() +	assert s.capitalize() == 'Hello' +	s = 'test' +	assert !s.is_capital() +	assert s.capitalize() == 'Test' +	s = 'i am ray' +	assert !s.is_capital() +	assert s.capitalize() == 'I am ray' +	s = '' +	assert !s.is_capital() +	assert s.capitalize() == '' +	s = 'TEST IT' +	assert !s.is_capital() +	assert s.capitalize() == 'TEST IT' +	s = 'Test it' +	assert s.is_capital() +	assert s.capitalize() == 'Test it' +	assert 'GameMission_t'.capitalize() == 'GameMission_t' +} + +fn test_title() { +	mut s := 'hello world' +	assert !s.is_title() +	assert s.title() == 'Hello World' +	s = 'HELLO WORLD' +	assert !s.is_title() +	assert s.title() == 'HELLO WORLD' +	s = 'Hello World' +	assert s.is_title() +	assert s.title() == 'Hello World' +} + +fn test_for_loop() { +	mut i := 0 +	s := 'abcd' + +	for c in s { +		assert c == s[i] +		i++ +	} +} + +fn test_for_loop_two() { +	s := 'abcd' + +	for i, c in s { +		assert c == s[i] +	} +} + +fn test_quote() { +	a := `\'` +	println('testing double quotes') +	b := 'hi' +	assert b == 'hi' +	assert a.str() == "'" +} + +fn test_limit() { +	s := 'hello' +	assert s.limit(2) == 'he' +	assert s.limit(9) == s +	assert s.limit(0) == '' +	// assert s.limit(-1) == '' +} + +fn test_repeat() { +	s1 := 'V! ' +	assert s1.repeat(5) == 'V! V! V! V! V! ' +	assert s1.repeat(1) == s1 +	assert s1.repeat(0) == '' +	s2 := '' +	assert s2.repeat(5) == s2 +	assert s2.repeat(1) == s2 +	assert s2.repeat(0) == s2 +	// TODO Add test for negative values +} + +fn test_starts_with() { +	s := 'V Programming Language' +	assert s.starts_with('V') == true +	assert s.starts_with('V Programming') == true +	assert s.starts_with('Language') == false +} + +fn test_trim_prefix() { +	s := 'V Programming Language' +	assert s.trim_prefix('V ') == 'Programming Language' +	assert s.trim_prefix('V Programming ') == 'Language' +	assert s.trim_prefix('Language') == s + +	s2 := 'TestTestTest' +	assert s2.trim_prefix('Test') == 'TestTest' +	assert s2.trim_prefix('TestTest') == 'Test' + +	s3 := '123Test123Test' +	assert s3.trim_prefix('123') == 'Test123Test' +	assert s3.trim_prefix('123Test') == '123Test' +} + +fn test_trim_suffix() { +	s := 'V Programming Language' +	assert s.trim_suffix(' Language') == 'V Programming' +	assert s.trim_suffix(' Programming Language') == 'V' +	assert s.trim_suffix('V') == s + +	s2 := 'TestTestTest' +	assert s2.trim_suffix('Test') == 'TestTest' +	assert s2.trim_suffix('TestTest') == 'Test' + +	s3 := '123Test123Test' +	assert s3.trim_suffix('123') == s3 +	assert s3.trim_suffix('123Test') == '123Test' +} + +fn test_raw() { +	raw := r'raw\nstring' +	lines := raw.split('\n') +	println(lines) +	assert lines.len == 1 +	println('raw string: "$raw"') + +	raw2 := r'Hello V\0' +	assert raw2[7] == `\\` +	assert raw2[8] == `0` + +	raw3 := r'Hello V\x00' +	assert raw3[7] == `\\` +	assert raw3[8] == `x` +	assert raw3[9] == `0` +	assert raw3[10] == `0` +} + +fn test_raw_with_quotes() { +	raw := r"some'" + r'"thing' // " should be escaped in the generated C code +	assert raw[0] == `s` +	assert raw[5] == `"` +	assert raw[6] == `t` +} + +fn test_escape() { +	a := 10 +	println("\"$a") +	assert "\"$a" == '"10' +} + +fn test_atoi() { +	assert '234232'.int() == 234232 +	assert '-9009'.int() == -9009 +	assert '0'.int() == 0 +	for n in -10000 .. 100000 { +		s := n.str() +		assert s.int() == n +	} +} + +fn test_raw_inter() { +	world := 'world' +	println(world) +	s := r'hello\n$world' +	assert s == r'hello\n$world' +	assert s.contains('$') +} + +fn test_c_r() { +	// This used to break because of r'' and c'' +	c := 42 +	println('$c') +	r := 50 +	println('$r') +} + +fn test_inter_before_comp_if() { +	s := '123' +	// This used to break ('123 $....') +	$if linux { +		println(s) +	} +	assert s == '123' +} + +fn test_double_quote_inter() { +	a := 1 +	b := 2 +	println('$a $b') +	assert '$a $b' == '1 2' +	assert '$a $b' == '1 2' +} + +fn foo(b byte) byte { +	return b - 10 +} + +fn filter(b byte) bool { +	return b != `a` +} + +fn test_split_into_lines() { +	line_content := 'Line' +	text_crlf := '$line_content\r\n$line_content\r\n$line_content' +	lines_crlf := text_crlf.split_into_lines() + +	assert lines_crlf.len == 3 +	for line in lines_crlf { +		assert line == line_content +	} + +	text_lf := '$line_content\n$line_content\n$line_content' +	lines_lf := text_lf.split_into_lines() + +	assert lines_lf.len == 3 +	for line in lines_lf { +		assert line == line_content +	} +} + +fn test_string_literal_with_backslash() { +	a := 'HelloWorld' +	assert a == 'HelloWorld' + +	b := 'OneTwoThree' +	assert b == 'OneTwoThree' +} + +/* +type MyString = string + +fn test_string_alias() { +	s := MyString('hi') +	ss := s + '!' +} +*/ + +// sort an array of structs, by their string field values + +struct Ka { +	s string +	i int +} + +fn test_sorter() { +	mut arr := [ +		Ka{ +			s: 'bbb' +			i: 100 +		}, +		Ka{ +			s: 'aaa' +			i: 101 +		}, +		Ka{ +			s: 'ccc' +			i: 102 +		}, +	] +	cmp := fn (a &Ka, b &Ka) int { +		return compare_strings(a.s, b.s) +	} +	arr.sort_with_compare(cmp) +	assert arr[0].s == 'aaa' +	assert arr[0].i == 101 +	assert arr[1].s == 'bbb' +	assert arr[1].i == 100 +	assert arr[2].s == 'ccc' +	assert arr[2].i == 102 +} + +fn test_fields() { +	assert 'a bcde'.fields() == ['a', 'bcde'] +	assert '  sss \t  ssss '.fields() == ['sss', 'ssss'] +	assert '\n xyz \t abc   def'.fields() == ['xyz', 'abc', 'def'] +	assert 'hello'.fields() == ['hello'] +	assert ''.fields() == [] +} + +fn test_interpolation_after_quoted_variable_still_works() { +	rr := 'abc' +	tt := 'xyz' + +	// Basic interpolation, no internal quotes +	yy := 'Replacing $rr with $tt' +	assert yy == 'Replacing abc with xyz' + +	// Interpolation after quoted variable ending with 'r'quote +	// that may be mistaken with the start of a raw string, +	// ensure that it is not. +	ss := 'Replacing "$rr" with "$tt"' +	assert ss == 'Replacing "abc" with "xyz"' +	zz := "Replacing '$rr' with '$tt'" +	assert zz == "Replacing 'abc' with 'xyz'" + +	// Interpolation after quoted variable ending with 'c'quote +	// may be mistaken with the start of a c string, so +	// check it is not. +	cc := 'abc' +	ccc := "Replacing '$cc' with '$tt'" +	assert ccc == "Replacing 'abc' with 'xyz'" +	cccq := 'Replacing "$cc" with "$tt"' +	assert cccq == 'Replacing "abc" with "xyz"' +} + +fn test_emoji_to_runes() { +	x := '👋' +	assert x.runes()[0] == `👋` +} + +fn test_string_to_rune() { +	x := 'Hello World 👋' +	assert x.runes().len == 13 +} diff --git a/v_windows/v/old/vlib/builtin/utf8.c.v b/v_windows/v/old/vlib/builtin/utf8.c.v new file mode 100644 index 0000000..f2ead3a --- /dev/null +++ b/v_windows/v/old/vlib/builtin/utf8.c.v @@ -0,0 +1,79 @@ +module builtin + +const ( +	cp_utf8 = 65001 +) + +pub fn (_str string) to_wide() &u16 { +	$if windows { +		unsafe { +			num_chars := (C.MultiByteToWideChar(cp_utf8, 0, &char(_str.str), _str.len, +				0, 0)) +			mut wstr := &u16(malloc_noscan((num_chars + 1) * 2)) // sizeof(wchar_t) +			if wstr != 0 { +				C.MultiByteToWideChar(cp_utf8, 0, &char(_str.str), _str.len, wstr, num_chars) +				C.memset(&byte(wstr) + num_chars * 2, 0, 2) +			} +			return wstr +		} +	} $else { +		return 0 +	} +} + +[unsafe] +pub fn string_from_wide(_wstr &u16) string { +	$if windows { +		unsafe { +			wstr_len := C.wcslen(_wstr) +			return string_from_wide2(_wstr, wstr_len) +		} +	} $else { +		return '' +	} +} + +[unsafe] +pub fn string_from_wide2(_wstr &u16, len int) string { +	$if windows { +		unsafe { +			num_chars := C.WideCharToMultiByte(cp_utf8, 0, _wstr, len, 0, 0, 0, 0) +			mut str_to := malloc_noscan(num_chars + 1) +			if str_to != 0 { +				C.WideCharToMultiByte(cp_utf8, 0, _wstr, len, &char(str_to), num_chars, +					0, 0) +				C.memset(str_to + num_chars, 0, 1) +			} +			return tos2(str_to) +		} +	} $else { +		return '' +	} +} + +// Reads an utf8 character from standard input +pub fn utf8_getchar() int { +	c := C.getchar() +	len := utf8_len(byte(~c)) +	if c < 0 { +		return 0 +	} else if len == 0 { +		return c +	} else if len == 1 { +		return -1 +	} else { +		mut uc := c & ((1 << (7 - len)) - 1) +		for i := 0; i + 1 < len; i++ { +			c2 := C.getchar() +			if c2 != -1 && (c2 >> 6) == 2 { +				uc <<= 6 +				uc |= (c2 & 63) +			} else if c2 == -1 { +				return 0 +			} else { +				return -1 +			} +		} +		return uc +	} +} diff --git a/v_windows/v/old/vlib/builtin/utf8.v b/v_windows/v/old/vlib/builtin/utf8.v new file mode 100644 index 0000000..6f3745a --- /dev/null +++ b/v_windows/v/old/vlib/builtin/utf8.v @@ -0,0 +1,188 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module builtin + +pub fn utf8_char_len(b byte) int { +	return ((0xe5000000 >> ((b >> 3) & 0x1e)) & 3) + 1 +} + +// Convert utf32 to utf8 +// utf32 == Codepoint +pub fn utf32_to_str(code u32) string { +	unsafe { +		mut buffer := malloc_noscan(5) +		return utf32_to_str_no_malloc(code, buffer) +	} +} + +[unsafe] +pub fn utf32_to_str_no_malloc(code u32, buf voidptr) string { +	icode := int(code) // Prevents doing casts everywhere +	mut res := '' +	unsafe { +		mut buffer := &byte(buf) +		if icode <= 127 { +			// 0x7F +			buffer[0] = byte(icode) +			buffer[1] = 0 +			res = tos(buffer, 1) +		} else if icode <= 2047 { +			// 0x7FF +			buffer[0] = 192 | byte(icode >> 6) // 0xC0 - 110xxxxx +			buffer[1] = 128 | byte(icode & 63) // 0x80 - 0x3F - 10xxxxxx +			buffer[2] = 0 +			res = tos(buffer, 2) +		} else if icode <= 65535 { +			// 0xFFFF +			buffer[0] = 224 | byte(icode >> 12) // 0xE0 - 1110xxxx +			buffer[1] = 128 | (byte(icode >> 6) & 63) // 0x80 - 0x3F - 10xxxxxx +			buffer[2] = 128 | byte(icode & 63) // 0x80 - 0x3F - 10xxxxxx +			buffer[3] = 0 +			res = tos(buffer, 3) +		} +		// 0x10FFFF +		else if icode <= 1114111 { +			buffer[0] = 240 | byte(icode >> 18) // 0xF0 - 11110xxx +			buffer[1] = 128 | (byte(icode >> 12) & 63) // 0x80 - 0x3F - 10xxxxxx +			buffer[2] = 128 | (byte(icode >> 6) & 63) // 0x80 - 0x3F - 10xxxxxx +			buffer[3] = 128 | byte(icode & 63) // 0x80 - 0x3F - 10xxxxxx +			buffer[4] = 0 +			res = tos(buffer, 4) +		} +	} +	res.is_lit = 1 // let autofree know this string doesn't have to be freed +	return res +} + +// Convert utf8 to utf32 +pub fn (_rune string) utf32_code() int { +	if _rune.len == 0 { +		return 0 +	} +	// save ASC symbol as is +	if _rune.len == 1 { +		return int(_rune[0]) +	} +	mut b := byte(int(_rune[0])) +	// TODO should be +	// res := int( rune[0] << rune.len) +	b = b << _rune.len +	mut res := int(b) +	mut shift := 6 - _rune.len +	for i := 1; i < _rune.len; i++ { +		c := int(_rune[i]) +		res = res << shift +		res |= c & 63 // 0x3f +		shift = 6 +	} +	return res +} + +// Calculate length to read from the first byte +fn utf8_len(c byte) int { +	mut b := 0 +	mut x := c +	if (x & 240) != 0 { +		// 0xF0 +		x >>= 4 +	} else { +		b += 4 +	} +	if (x & 12) != 0 { +		// 0x0C +		x >>= 2 +	} else { +		b += 2 +	} +	if (x & 2) == 0 { +		// 0x02 +		b++ +	} +	return b +} + +// Calculate string length for in number of codepoints +pub fn utf8_str_len(s string) int { +	mut l := 0 +	mut i := 0 +	for i < s.len { +		l++ +		i += ((0xe5000000 >> ((unsafe { s.str[i] } >> 3) & 0x1e)) & 3) + 1 +	} +	return l +} + +// Calculate string length for formatting, i.e. number of "characters" +// This is simplified implementation. if you need specification compliant width, +// use utf8.east_asian.display_width. +pub fn utf8_str_visible_length(s string) int { +	mut l := 0 +	mut ul := 1 +	for i := 0; i < s.len; i += ul { +		c := unsafe { s.str[i] } +		ul = ((0xe5000000 >> ((unsafe { s.str[i] } >> 3) & 0x1e)) & 3) + 1 +		if i + ul > s.len { // incomplete UTF-8 sequence +			return l +		} +		l++ +		// avoid the match if not needed +		if ul == 1 { +			continue +		} +		// recognize combining characters and wide characters +		match ul { +			2 { +				r := u64((u16(c) << 8) | unsafe { s.str[i + 1] }) +				if r >= 0xcc80 && r < 0xcdb0 { +					// diacritical marks +					l-- +				} +			} +			3 { +				r := u64((u32(c) << 16) | unsafe { (u32(s.str[i + 1]) << 8) | s.str[i + 2] }) +				// diacritical marks extended +				// diacritical marks supplement +				// diacritical marks for symbols +				if (r >= 0xe1aab0 && r <= 0xe1ac7f) +					|| (r >= 0xe1b780 && r <= 0xe1b87f) +					|| (r >= 0xe28390 && r <= 0xe2847f) +					|| (r >= 0xefb8a0 && r <= 0xefb8af) { +					// diacritical marks +					l-- +				} +				// Hangru +				// CJK Unified Ideographics +				// Hangru +				// CJK +				else if (r >= 0xe18480 && r <= 0xe1859f) +					|| (r >= 0xe2ba80 && r <= 0xe2bf95) +					|| (r >= 0xe38080 && r <= 0xe4b77f) +					|| (r >= 0xe4b880 && r <= 0xea807f) +					|| (r >= 0xeaa5a0 && r <= 0xeaa79f) +					|| (r >= 0xeab080 && r <= 0xed9eaf) +					|| (r >= 0xefa480 && r <= 0xefac7f) +					|| (r >= 0xefb8b8 && r <= 0xefb9af) { +					// half marks +					l++ +				} +			} +			4 { +				r := u64((u32(c) << 24) | unsafe { +					(u32(s.str[i + 1]) << 16) | (u32(s.str[i + 2]) << 8) | s.str[i + 3] +				}) +				// Enclosed Ideographic Supplement +				// Emoji +				// CJK Unified Ideographs Extension B-G +				if (r >= 0x0f9f8880 && r <= 0xf09f8a8f) +					|| (r >= 0xf09f8c80 && r <= 0xf09f9c90) +					|| (r >= 0xf09fa490 && r <= 0xf09fa7af) +					|| (r >= 0xf0a08080 && r <= 0xf180807f) { +					l++ +				} +			} +			else {} +		} +	} +	return l +} diff --git a/v_windows/v/old/vlib/builtin/utf8_test.v b/v_windows/v/old/vlib/builtin/utf8_test.v new file mode 100644 index 0000000..46983f1 --- /dev/null +++ b/v_windows/v/old/vlib/builtin/utf8_test.v @@ -0,0 +1,28 @@ +fn test_utf8_char_len() { +	assert utf8_char_len(`a`) == 1 +	println(utf8_char_len(`a`)) +	s := 'п' +	assert utf8_char_len(s[0]) == 2 +} + +fn test_utf8_wide_char() { +	$if msvc { +		// TODO: make this test pass msvc too +		return +	} +	r := `✔` +	s := '✔' +	println('r: $r') +	println('s: $s') +	rstr := r.str() +	println('rstr: $rstr') +	assert utf8_char_len(r) == 1 +	assert utf8_char_len(s[0]) == 3 +	assert s == rstr +	val := rstr.str +	unsafe { +		assert val[0].hex() == 'e2' +		assert val[1].hex() == '9c' +		assert val[2].hex() == '94' +	} +} | 
