Browse Source

Merge branch 'master' of https://github.com/odin-lang/Odin

gingerBill 1 year ago
parent
commit
7673d478b6

+ 46 - 0
core/container/intrusive/list/doc.odin

@@ -0,0 +1,46 @@
+/*
+Package list implements an intrusive doubly-linked list.
+
+An intrusive container requires a `Node` to be embedded in your own structure, like this:
+
+	My_String :: struct {
+		node:  list.Node,
+		value: string,
+	}
+
+Embedding the members of a `list.Node` in your structure with the `using` keyword is also allowed:
+
+	My_String :: struct {
+		using node: list.Node,
+		value: string,
+	}
+
+Here is a full example:
+
+	package test
+	
+	import "core:fmt"
+	import "core:container/intrusive/list"
+	
+	main :: proc() {
+	    l: list.List
+	
+	    one := My_String{value="Hello"}
+	    two := My_String{value="World"}
+	
+	    list.push_back(&l, &one.node)
+	    list.push_back(&l, &two.node)
+	
+	    iter := list.iterator_head(l, My_String, "node")
+	    for s in list.iterate_next(&iter) {
+	        fmt.println(s.value)
+	    }
+	}
+	
+	My_String :: struct {
+	    node:  list.Node,
+	    value: string,
+	}
+
+*/
+package container_intrusive_list

+ 169 - 2
core/container/intrusive/list/intrusive_list.odin

@@ -18,11 +18,18 @@ List :: struct {
 	tail: ^Node,
 }
 
-
+// The list link you must include in your own structure.
 Node :: struct {
 	prev, next: ^Node,
 }
 
+/*
+Inserts a new element at the front of the list with O(1) time complexity.
+
+**Inputs**
+- list: The container list
+- node: The node member of the user-defined element structure
+*/
 push_front :: proc "contextless" (list: ^List, node: ^Node) {
 	if list.head != nil {
 		list.head.prev = node
@@ -33,7 +40,13 @@ push_front :: proc "contextless" (list: ^List, node: ^Node) {
 		node.prev, node.next = nil, nil
 	}
 }
+/*
+Inserts a new element at the back of the list with O(1) time complexity.
 
+**Inputs**
+- list: The container list
+- node: The node member of the user-defined element structure
+*/
 push_back :: proc "contextless" (list: ^List, node: ^Node) {
 	if list.tail != nil {
 		list.tail.next = node
@@ -45,6 +58,13 @@ push_back :: proc "contextless" (list: ^List, node: ^Node) {
 	}
 }
 
+/*
+Removes an element from a list with O(1) time complexity.
+
+**Inputs**
+- list: The container list
+- node: The node member of the user-defined element structure to be removed
+*/
 remove :: proc "contextless" (list: ^List, node: ^Node) {
 	if node != nil {
 		if node.next != nil {
@@ -61,7 +81,13 @@ remove :: proc "contextless" (list: ^List, node: ^Node) {
 		}
 	}
 }
+/*
+Removes from the given list all elements that satisfy a condition with O(N) time complexity.
 
+**Inputs**
+- list: The container list
+- to_erase: The condition procedure. It should return `true` if a node should be removed, `false` otherwise
+*/
 remove_by_proc :: proc(list: ^List, to_erase: proc(^Node) -> bool) {
 	for node := list.head; node != nil; {
 		next := node.next
@@ -82,7 +108,13 @@ remove_by_proc :: proc(list: ^List, to_erase: proc(^Node) -> bool) {
 		node = next
 	}
 }
+/*
+Removes from the given list all elements that satisfy a condition with O(N) time complexity.
 
+**Inputs**
+- list: The container list
+- to_erase: The _contextless_ condition procedure. It should return `true` if a node should be removed, `false` otherwise
+*/
 remove_by_proc_contextless :: proc(list: ^List, to_erase: proc "contextless" (^Node) -> bool) {
 	for node := list.head; node != nil; {
 		next := node.next
@@ -104,12 +136,26 @@ remove_by_proc_contextless :: proc(list: ^List, to_erase: proc "contextless" (^N
 	}
 }
 
+/*
+Checks whether the given list does not contain any element.
 
+**Inputs**
+- list: The container list
 
+**Returns** `true` if `list` is empty, `false` otherwise
+*/
 is_empty :: proc "contextless" (list: ^List) -> bool {
 	return list.head == nil
 }
 
+/*
+Removes and returns the element at the front of the list with O(1) time complexity.
+
+**Inputs**
+- list: The container list
+
+**Returns** The node member of the user-defined element structure, or `nil` if the list is empty
+*/
 pop_front :: proc "contextless" (list: ^List) -> ^Node {
 	link := list.head
 	if link == nil {
@@ -130,6 +176,14 @@ pop_front :: proc "contextless" (list: ^List) -> ^Node {
 	return link
 
 }
+/*
+Removes and returns the element at the back of the list with O(1) time complexity.
+
+**Inputs**
+- list: The container list
+
+**Returns** The node member of the user-defined element structure, or `nil` if the list is empty
+*/
 pop_back :: proc "contextless" (list: ^List) -> ^Node {
 	link := list.tail
 	if link == nil {
@@ -151,29 +205,102 @@ pop_back :: proc "contextless" (list: ^List) -> ^Node {
 }
 
 
+
 Iterator :: struct($T: typeid) {
 	curr:   ^Node,
 	offset: uintptr,
 }
 
+/*
+Creates an iterator pointing at the head of the given list. For an example, see `iterate_next`.
+
+**Inputs**
+- list: The container list
+- T: The type of the list's elements
+- field_name: The name of the node field in the `T` structure
+
+**Returns** An iterator pointing at the head of `list`
+
+*/
 iterator_head :: proc "contextless" (list: List, $T: typeid, $field_name: string) -> Iterator(T)
 	where intrinsics.type_has_field(T, field_name),
 	      intrinsics.type_field_type(T, field_name) == Node {
 	return {list.head, offset_of_by_string(T, field_name)}
 }
+/*
+Creates an iterator pointing at the tail of the given list. For an example, see `iterate_prev`.
+
+**Inputs**
+- list: The container list
+- T: The type of the list's elements
+- field_name: The name of the node field in the `T` structure
 
+**Returns** An iterator pointing at the tail of `list`
+
+*/
 iterator_tail :: proc "contextless" (list: List, $T: typeid, $field_name: string) -> Iterator(T)
 	where intrinsics.type_has_field(T, field_name),
 	      intrinsics.type_field_type(T, field_name) == Node {
 	return {list.tail, offset_of_by_string(T, field_name)}
 }
+/*
+Creates an iterator pointing at the specified node of a list.
+
+**Inputs**
+- node: a list node
+- T: The type of the list's elements
+- field_name: The name of the node field in the `T` structure
+
+**Returns** An iterator pointing at `node`
 
+*/
 iterator_from_node :: proc "contextless" (node: ^Node, $T: typeid, $field_name: string) -> Iterator(T)
 	where intrinsics.type_has_field(T, field_name),
 	      intrinsics.type_field_type(T, field_name) == Node {
 	return {node, offset_of_by_string(T, field_name)}
 }
 
+/*
+Retrieves the next element in a list and advances the iterator.
+
+**Inputs**  
+- it: The iterator
+
+**Returns**
+- ptr: The next list element
+- ok: `true` if the element is valid (the iterator could advance), `false` otherwise
+
+Example:
+
+	import "core:fmt"
+	import "core:container/intrusive/list"
+
+	iterate_next_example :: proc() {
+		l: list.List
+
+		one := My_Struct{value=1}
+		two := My_Struct{value=2}
+
+		list.push_back(&l, &one.node)
+		list.push_back(&l, &two.node)
+
+		it := list.iterator_head(l, My_Struct, "node")
+		for num in list.iterate_next(&it) {
+			fmt.println(num.value)
+		}
+	}
+
+	My_Struct :: struct {
+		node : list.Node,
+		value: int,
+	}
+
+Output:
+
+	1
+	2
+
+*/
 iterate_next :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
 	node := it.curr
 	if node == nil {
@@ -183,7 +310,47 @@ iterate_next :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
 
 	return (^T)(uintptr(node) - it.offset), true
 }
+/*
+Retrieves the previous element in a list and recede the iterator.
+
+**Inputs**  
+- it: The iterator
+
+**Returns**
+- ptr: The previous list element
+- ok: `true` if the element is valid (the iterator could recede), `false` otherwise
+
+Example:
+
+	import "core:fmt"
+	import "core:container/intrusive/list"
 
+	iterate_next_example :: proc() {
+		l: list.List
+
+		one := My_Struct{value=1}
+		two := My_Struct{value=2}
+
+		list.push_back(&l, &one.node)
+		list.push_back(&l, &two.node)
+
+		it := list.iterator_tail(l, My_Struct, "node")
+		for num in list.iterate_prev(&it) {
+			fmt.println(num.value)
+		}
+	}
+
+	My_Struct :: struct {
+		node : list.Node,
+		value: int,
+	}
+
+Output:
+
+	2
+	1
+
+*/
 iterate_prev :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
 	node := it.curr
 	if node == nil {
@@ -192,4 +359,4 @@ iterate_prev :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
 	it.curr = node.prev
 
 	return (^T)(uintptr(node) - it.offset), true
-}
+}