├── src ├── Lists.jl ├── list.jl └── slist.jl ├── test ├── runtests.jl ├── testslist.jl └── testlist.jl ├── .travis.yml ├── LICENSE.md └── README.md /src/Lists.jl: -------------------------------------------------------------------------------- 1 | module Lists 2 | 3 | include("slist.jl") 4 | include("list.jl") 5 | 6 | end # module 7 | -------------------------------------------------------------------------------- /test/runtests.jl: -------------------------------------------------------------------------------- 1 | using Lists 2 | using Base.Test 3 | 4 | include("testslist.jl") 5 | include("testlist.jl") 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | compiler: 3 | - clang 4 | notifications: 5 | email: false 6 | env: 7 | matrix: 8 | - JULIAVERSION="juliareleases" 9 | - JULIAVERSION="julianightlies" 10 | before_install: 11 | - sudo add-apt-repository ppa:staticfloat/julia-deps -y 12 | - sudo add-apt-repository ppa:staticfloat/${JULIAVERSION} -y 13 | - sudo apt-get update -qq -y 14 | - sudo apt-get install libpcre3-dev julia -y 15 | - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi 16 | script: 17 | - julia -e 'Pkg.init(); Pkg.clone(pwd()); Pkg.test("Lists")' 18 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The Lists.jl package is licensed under the MIT "Expat" License: 2 | 3 | > Copyright (c) 2014: Andrew Dolgert. 4 | > 5 | > Permission is hereby granted, free of charge, to any person obtaining 6 | > a copy of this software and associated documentation files (the 7 | > "Software"), to deal in the Software without restriction, including 8 | > without limitation the rights to use, copy, modify, merge, publish, 9 | > distribute, sublicense, and/or sell copies of the Software, and to 10 | > permit persons to whom the Software is furnished to do so, subject to 11 | > the following conditions: 12 | > 13 | > The above copyright notice and this permission notice shall be 14 | > included in all copies or substantial portions of the Software. 15 | > 16 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | > IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /test/testslist.jl: -------------------------------------------------------------------------------- 1 | using Lists 2 | 3 | function compare(array, list) 4 | # Iterate over items in container. 5 | for (ridx, d) in enumerate(list) 6 | @assert(d==array[ridx]) 7 | end 8 | end 9 | 10 | function compare_iterator(array, list) 11 | # Iterate over indices of container, which are nodes. 12 | for (ridx, iter) in enumerate(indexed(list)) 13 | @assert(getindex(list, iter)==array[ridx]) 14 | end 15 | end 16 | 17 | function walkthrough() 18 | l=SList{Int}() 19 | @assert(isempty(l)) 20 | @assert(length(l)==0) 21 | vals=[3,2,7,7,9] 22 | 23 | prepend!(l, vals) 24 | println(l) 25 | println(vals) 26 | compare(vals, l) 27 | compare_iterator(vals, l) 28 | 29 | @assert(!isempty(l)) 30 | show(l) 31 | 32 | unshift!(vals, 8) 33 | unshift!(l, 8) 34 | compare(vals, l) 35 | 36 | @assert(length(l)==6) 37 | 38 | @assert(findin([2,3], l)==findin([2,3], vals)) 39 | @assert(indexin([2,3,12], l)==indexin([2,3,12], vals)) 40 | 41 | @assert(unique(l)==unique(vals)) 42 | 43 | @assert(getindex(l, endof(l))==9) 44 | 45 | @assert(!in(13, l)) 46 | @assert(in(2, l)) 47 | @assert(2 in l) 48 | @assert(eltype(l)==Int64) 49 | @assert(first(l)==8) 50 | @assert(last(l)==9) 51 | show(l) 52 | push!(l, 11) 53 | println(l) 54 | println(vals) 55 | @assert(pop!(l)==11) 56 | @assert(shift!(l)==8) 57 | shift!(vals) 58 | 59 | two=find(l, 2) 60 | insert!(l, two, 6) 61 | insert!(vals, 3, 6) 62 | compare(vals, l) 63 | deleteat!(l, two) 64 | deleteat!(vals, 2) 65 | compare(vals, l) 66 | splice!(l, find(l, 9)) 67 | deleteat!(vals, 5) 68 | compare(vals, l) 69 | splice!(l, find(l,6), 12) 70 | vals[2]=12 71 | compare(vals, l) 72 | append!(l, [23, 24]) 73 | append!(vals, [23, 24]) 74 | compare(vals, l) 75 | prepend!(l, [17, 16]) 76 | prepend!(vals, [17, 16]) 77 | println(l) 78 | println(vals) 79 | compare(vals, l) 80 | end 81 | 82 | walkthrough() 83 | -------------------------------------------------------------------------------- /test/testlist.jl: -------------------------------------------------------------------------------- 1 | using Lists 2 | 3 | function consistent{T}(l::List{T}) 4 | node=l.node 5 | while node.next!=l.node 6 | @assert(node.next.prev==node) 7 | @assert(node.prev.next==node) 8 | node=node.next 9 | end 10 | end 11 | 12 | function walkthrough_list() 13 | l=List{Int}() 14 | @assert(isempty(l)) 15 | @assert(length(l)==0) 16 | vals=[3,2,7,7,9] 17 | 18 | prepend!(l, vals) 19 | consistent(l) 20 | 21 | println(l) 22 | println(vals) 23 | compare(vals, l) 24 | compare_iterator(vals, l) 25 | 26 | @assert(!isempty(l)) 27 | show(l) 28 | 29 | unshift!(vals, 8) 30 | unshift!(l, 8) 31 | compare(vals, l) 32 | consistent(l) 33 | 34 | @assert(length(l)==6) 35 | 36 | @assert(findin([2,3], l)==findin([2,3], vals)) 37 | @assert(indexin([2,3,12], l)==indexin([2,3,12], vals)) 38 | 39 | @assert(unique(l)==unique(vals)) 40 | 41 | @assert(getindex(l, endof(l))==9) 42 | 43 | @assert(!in(13, l)) 44 | @assert(in(2, l)) 45 | @assert(eltype(l)==Int64) 46 | @assert(first(l)==8) 47 | @assert(last(l)==9) 48 | show(l) 49 | println() 50 | push!(l, 11) 51 | consistent(l) 52 | @assert(pop!(l)==11) 53 | compare(vals, l) 54 | consistent(l) 55 | @assert(shift!(l)==8) 56 | shift!(vals) 57 | compare(vals, l) 58 | consistent(l) 59 | 60 | two=find(l, 2) 61 | insert!(l, two, 6) 62 | insert!(vals, 2, 6) 63 | consistent(l) 64 | println(l) 65 | println(vals) 66 | compare(vals, l) 67 | deleteat!(l, two) 68 | deleteat!(vals, 3) 69 | compare(vals, l) 70 | splice!(l, find(l, 9)) 71 | deleteat!(vals, 5) 72 | compare(vals, l) 73 | splice!(l, find(l,6), 12) 74 | vals[2]=12 75 | compare(vals, l) 76 | append!(l, [23, 24]) 77 | append!(vals, [23, 24]) 78 | compare(vals, l) 79 | prepend!(l, [17, 16]) 80 | prepend!(vals, [17, 16]) 81 | println(l) 82 | println(vals) 83 | compare(vals, l) 84 | end 85 | 86 | walkthrough_list() 87 | -------------------------------------------------------------------------------- /src/list.jl: -------------------------------------------------------------------------------- 1 | # Doubly linked list 2 | # Imports from Base have been done already. 3 | 4 | export List, ListNode 5 | 6 | type ListNode{T} 7 | prev::ListNode{T} 8 | next::ListNode{T} 9 | data::T 10 | ListNode()=(x=new(); x.prev=x; x.next=x; x) 11 | ListNode(p, n, d)=new(p, n, d) 12 | end 13 | 14 | 15 | # Doubly linked list. 16 | type List{T} 17 | node::ListNode{T} 18 | List()=new(ListNode{T}()) 19 | end 20 | 21 | 22 | function show{T}(io::IO, l::List{T}) 23 | print(io, "List{", string(T), "}(") 24 | middle=false 25 | for item in l 26 | if middle 27 | print(io, ", ") 28 | end 29 | show(io, item) 30 | middle=true 31 | end 32 | print(io, ")") 33 | end 34 | 35 | 36 | # The section titles work through sections of the manual. 37 | #### Iteration 38 | 39 | start{T}(l::List{T})=l.node.next 40 | done{T}(l::List{T}, n::ListNode{T})=(n==l.node) 41 | next{T}(l::List{T}, n::ListNode{T})=(n.data, n.next) 42 | 43 | immutable type ListIndexIterator{T} 44 | l::List{T} 45 | end 46 | 47 | # Returns an iterator over indices. 48 | # Use getindex, setindex! to find the item at this index. 49 | indexed{T}(l::List{T})=ListIndexIterator{T}(l) 50 | start{T}(liter::ListIndexIterator{T})=liter.l.node.next 51 | done{T}(liter::ListIndexIterator{T}, n::ListNode{T})=(n==liter.l.node) 52 | next{T}(liter::ListIndexIterator{T}, n::ListNode{T})=(n, n.next) 53 | 54 | 55 | #### General Collections 56 | isempty{T}(l::List{T})=(l.node.next==l.node) 57 | 58 | function empty!{T}(l::List{T}) 59 | l.node.next=l.node 60 | end 61 | 62 | function length{T}(l::List{T}) 63 | cnt=0 64 | for n in l 65 | cnt+=1 66 | end 67 | cnt 68 | end 69 | 70 | # This is supposed to be an integer index, but 71 | # we return the node as an index. 72 | function endof{T}(l::List{T}) 73 | l.node.prev 74 | end 75 | 76 | 77 | 78 | #### Iterable Collections 79 | 80 | function in{T}(item::T, l::List{T}) 81 | for node in l 82 | if isequal(node.data, item) 83 | return true 84 | end 85 | end 86 | false 87 | end 88 | 89 | eltype{T}(l::List{T})=T 90 | 91 | # Highest index in list for each value in a that is 92 | # a member of the list. 93 | function indexin{T}(a, l::List{T}) 94 | highest=zeros(Int, length(a)) 95 | for (lidx, d) in enumerate(l) 96 | for (xidx, x) in enumerate(a) 97 | if isequal(x, d) 98 | highest[xidx]=lidx 99 | break 100 | end 101 | end 102 | end 103 | highest 104 | end 105 | 106 | first{T}(l::List{T})=l.node.next.data 107 | 108 | function last{T}(l::List{T}) 109 | l.node.prev.data::T 110 | end 111 | 112 | 113 | #### Indexable Collections 114 | 115 | # Treat the node as an index. It is also what 116 | # is used for the state in iterators. 117 | getindex{T}(l::List{T}, n::ListNode{T})=n.data 118 | function setindex!{T}(l::List{T}, n::ListNode{T}, d::T) 119 | n.data=d 120 | end 121 | 122 | 123 | #### Dequeues 124 | 125 | # Breaking interface expectation to push multiple items 126 | # so that we can return an index of the pushed item. 127 | # Use append! for multiple items. 128 | function push!{T}(l::List{T}, item::T) 129 | toadd=ListNode{T}(l.node.prev, l.node, item) 130 | l.node.prev.next=toadd 131 | l.node.prev=toadd 132 | toadd 133 | end 134 | 135 | function pop!{T}(l::List{T}) 136 | d=l.node.prev.data 137 | l.node.prev.prev.next=l.node 138 | l.node.prev=l.node.prev.prev 139 | d 140 | end 141 | 142 | # Breaking interface expectation because: 143 | # Returns an index to the item instead of the collection. 144 | # Takes only one value at a time. Use prepend! for multiple. 145 | function unshift!{T}(l::List{T}, d) 146 | toadd=ListNode{T}(l.node, l.node.next, d) 147 | l.node.next.prev=toadd 148 | l.node.next=toadd 149 | toadd 150 | end 151 | 152 | function shift!{T}(l::List{T}) 153 | x=l.node.next.data 154 | l.node.next.next.prev=l.node 155 | l.node.next=l.node.next.next 156 | x 157 | end 158 | 159 | # Insert 160 | function insert!{T}(l::List{T}, n::ListNode{T}, d::T) 161 | toadd=ListNode{T}(n.prev, n, d) 162 | n.prev.next=toadd 163 | n.prev=toadd 164 | toadd 165 | end 166 | 167 | # Linear in the number of elements. 168 | # Second argument is the state from an iterator. 169 | function deleteat!{T}(l::List{T}, n::ListNode{T}) 170 | n.prev.next=n.next 171 | n.next.prev=n.prev 172 | l 173 | end 174 | 175 | # Removal of a node, returning the value at that node. 176 | function splice!{T}(l::List{T}, n::ListNode{T}) 177 | n.prev.next=n.next 178 | n.next.prev=n.prev 179 | n.data 180 | end 181 | 182 | # Replacement of a node. 183 | function splice!{T}(l::List{T}, n::ListNode{T}, d::T) 184 | (d, n.data)=(n.data, d) 185 | d 186 | end 187 | 188 | function append!{T}(l::List{T}, items) 189 | for i in items 190 | push!(l, i) 191 | end 192 | end 193 | 194 | function prepend!{T}(l::List{T}, items) 195 | node=l.node # Invariant: Add after the node "node." 196 | for i in items 197 | toadd=ListNode{T}(node, node.next, i) 198 | node.next.prev=toadd 199 | node.next=toadd 200 | node=toadd 201 | end 202 | l 203 | end 204 | 205 | 206 | # Adding find, to find the iterator to a given value. 207 | function find{T}(l::List{T}, d::T) 208 | find(l, l.node, d) 209 | end 210 | 211 | function find{T}(l::List{T}, n::ListNode{T}, d::T) 212 | n=n.next 213 | while n!=l.node && n.data!=d 214 | n=n.next 215 | end 216 | if n==l.node 217 | return(nothing) 218 | end 219 | n 220 | end 221 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lists 2 | 3 | [![Build Status](https://travis-ci.org/adolgert/Lists.jl.svg?branch=master)](https://travis-ci.org/adolgert/Lists.jl) 4 | 5 | **List collections for Julia** 6 | 7 | This package provides a singly linked list and a doubly linked list 8 | implementation, as Julia collections. Singly linked lists are 9 | supported with `cons`, `car`, and `cdr`, but not as a standard 10 | collection. Doubly linked lists are included in the samples but, 11 | again, not as a collection. This doesn't do anything fancy 12 | like create an array of nodes. Maybe it should. 13 | 14 | ## List 15 | 16 | `List` is a doubly linked list. Deletions happen in constant time. 17 | If code contains an index to an item in the list, then 18 | removing other items in the list won't invalidate that index. 19 | 20 | Usage: 21 | ```julia 22 | a = List{Int}() # Create a list of the given type. 23 | isempty(l) # Test whether there are any items. 24 | empty!(l) # Remove all items. 25 | length(l) # The number of entries. An O(n) operation. 26 | 2 in l # Test whether the given item is an entry in the list. O(n). 27 | eltype(l) # Returns the item type, here Int64. 28 | indexin(a, l) # Highest index in list for each value of a that is member. 29 | first(l) # First item in the list. 30 | last(l) # Last item in the list, the item value. 31 | push!(l, d) # Add item d to end of list. Returns index of item. 32 | pop!(l, d) # Remove and return item at end of list. 33 | unshift!(l, d) # Add item to start of list. Return index of item. 34 | shift!(l) # Remove first item and return value. 35 | append!(l, items) # Add items to end of list. 36 | prepend!(l, items) # Add items to start of list. 37 | ``` 38 | 39 | There can be an index into the list. It is a reference to a list 40 | node but can be treated as an opaque index. 41 | ```julia 42 | getindex(l, index) # Returns value of item at this index. 43 | setindex!(l, index, d) # Sets item value at this index. 44 | endof(l) # Returns index of last node. An O(n) operation. 45 | insert!(l, index, d) # Insert item at index, pushing values back. Return index. 46 | deleteat!(l, index) # Delete item at index. Return list. 47 | splice!(l, index) # Remove value at index, returning data value. 48 | splice!(l, index, d) # Replace item at index with data value. 49 | find(l, d) # Find first occurrence of item in list. Return its index. 50 | find(l, index, d) # Find first occurrence of d after the given index. 51 | ``` 52 | 53 | There are two kinds of iterators for `List`. One access items. 54 | The other loops over indices. 55 | ```julia 56 | l = List{Int}() 57 | prepend!(l, [2, 4, 6]) 58 | for item::Int in l 59 | println(item) 60 | end 61 | 62 | for index in indexed(l) 63 | item=getindex(l, index) 64 | println(item) 65 | end 66 | 67 | ``` 68 | 69 | ## SList 70 | 71 | `SList` is a singly linked list over items of a given type. 72 | Appending to the end of this list takes an order of the number of 73 | the items in the list. 74 | 75 | Usage: 76 | ```julia 77 | a = SList{Int}() # Create a list of the given type. 78 | isempty(l) # Test whether there are any items. 79 | empty!(l) # Remove all items. 80 | eltype(l) # Returns the item type, here Int64. 81 | first(l) # First item in the list. 82 | unshift!(l, d) # Add item to start of list. Return index of item. 83 | shift!(l) # Remove first item and return value. 84 | prepend!(l, items) # Add items to start of list. 85 | ``` 86 | 87 | There can be an index into the list. It is a reference to a list 88 | node but can be treated as an opaque index. 89 | ```julia 90 | getindex(l, index) # Returns value of item at this index. 91 | setindex!(l, index, d) # Sets item value at this index. 92 | insert!(l, index, d) # Inserts *after* the given index. Returns index. 93 | ``` 94 | 95 | The following methods are O(n) for singly linked lists. 96 | They are included for completeness, but needing these is an indication 97 | that using a doubly linked list, or Vector, might be a better choice. 98 | ```julia 99 | length(l) # The number of entries. 100 | 2 in l # Test whether the given item is an entry in the list. 101 | indexin(a, l) # Highest index in list for each value of a that is member. 102 | last(l) # Last item in the list, the item value. 103 | push!(l, d) # Add item d to end of list. Returns index of item. 104 | pop!(l, d) # Remove and return item at end of list. 105 | append!(l, items) # Add items to end of list. 106 | endof(l) # Returns index of last node. 107 | deleteat!(l, index) # Delete item at index. Return list. 108 | splice!(l, index) # Remove value at index, returning data value. 109 | splice!(l, index, d) # Replace item at index with data value. 110 | find(l, d) # Find first occurrence of item in list. Return its index. 111 | find(l, index, d) # Find first occurrence of d after the given index. 112 | ``` 113 | 114 | As with `List`, there are two kinds of iterators for `SList`. One access items. 115 | The other loops over indices. 116 | ```julia 117 | l = SList{Int}() 118 | prepend!(l, [2, 4, 6]) 119 | for item::Int in l 120 | println(item) 121 | end 122 | 123 | for index in indexed(l) 124 | item=getindex(l, index) 125 | println(item) 126 | end 127 | 128 | ``` 129 | 130 | ## Implementation Notes 131 | 132 | The code comments each time a method for these classes 133 | differs from interfaces described for collections in 134 | the manual. All differences stem from an assumption 135 | that the index to a collection will be an integer. 136 | 137 | If you have comments, or especially if I have the wrong idea 138 | about how to write good code in Julia, please send me an email. 139 | 140 | -------------------------------------------------------------------------------- /src/slist.jl: -------------------------------------------------------------------------------- 1 | # Singly linked list 2 | import Base: isempty, empty!, length, last, start, next, done 3 | import Base: contains, eltype, unshift!, shift!, deleteat! 4 | import Base: show, println, indexin, endof, push!, pop!, insert!, splice! 5 | import Base: find, append!, prepend! 6 | export SList, SListNode, indexed 7 | 8 | type SListNode{T} 9 | next::SListNode{T} 10 | data::T 11 | SListNode()=(x=new(); x.next=x; x) 12 | SListNode(n::SListNode{T}, d::T)=new(n, d) 13 | end 14 | 15 | 16 | # Singly-linked list 17 | type SList{T} 18 | # node is always the last element. Points to the first element. 19 | node::SListNode{T} 20 | SList()=new(SListNode{T}()) 21 | end 22 | 23 | function show{T}(io::IO, l::SList{T}) 24 | print(io, "SList{", string(T), "}(") 25 | middle=false 26 | for item in l 27 | if middle 28 | print(io, ", ") 29 | end 30 | show(io, item) 31 | middle=true 32 | end 33 | print(io, ")") 34 | end 35 | 36 | 37 | # The section titles work through sections of the manual. 38 | #### Iteration 39 | 40 | start{T}(l::SList{T})=l.node.next 41 | done{T}(l::SList{T}, n::SListNode{T})=(n==l.node) 42 | next{T}(l::SList{T}, n::SListNode{T})=(n.data, n.next) 43 | 44 | immutable type SListIndexIterator{T} 45 | l::SList{T} 46 | end 47 | 48 | # Returns an iterator over indices. 49 | # Use getindex, setindex! to find the item at this index. 50 | indexed{T}(l::SList{T})=SListIndexIterator{T}(l) 51 | start{T}(liter::SListIndexIterator{T})=liter.l.node.next 52 | done{T}(liter::SListIndexIterator{T}, n::SListNode{T})=(n==liter.l.node) 53 | next{T}(liter::SListIndexIterator{T}, n::SListNode{T})=(n, n.next) 54 | 55 | 56 | #### General Collections 57 | isempty{T}(l::SList{T})=(l.node.next==l.node) 58 | 59 | function empty!{T}(l::SList{T}) 60 | l.node.next=l.node 61 | end 62 | 63 | function length{T}(l::SList{T}) 64 | cnt=0 65 | for n in l 66 | cnt+=1 67 | end 68 | cnt 69 | end 70 | 71 | # This is supposed to be an integer index, but 72 | # we return the node as an index. 73 | function endof{T}(l::SList{T}) 74 | node=l.node.next::SListNode{T} 75 | while node.next!=l.node 76 | node=node.next::SListNode{T} 77 | end 78 | node 79 | end 80 | 81 | #### Iterable Collections 82 | 83 | function in{T}(item::T, l::SList{T}) 84 | for node in l 85 | if isequal(node.data, item) 86 | return true 87 | end 88 | end 89 | false 90 | end 91 | 92 | eltype{T}(l::SList{T})=T 93 | 94 | # Highest index in list for each value in a that is 95 | # a member of the list. 96 | function indexin{T}(a, l::SList{T}) 97 | highest=zeros(Int, length(a)) 98 | for (lidx, d) in enumerate(l) 99 | for (xidx, x) in enumerate(a) 100 | if isequal(x, d) 101 | highest[xidx]=lidx 102 | break 103 | end 104 | end 105 | end 106 | highest 107 | end 108 | 109 | 110 | first{T}(l::SList{T})=l.node.next.data 111 | 112 | function last{T}(l::SList{T}) 113 | lastd=l.node.data::T 114 | for d in l 115 | lastd=d::T 116 | end 117 | lastd 118 | end 119 | 120 | 121 | #### Indexable Collections 122 | 123 | # Treat the node as an index. It is also what 124 | # is used for the state in iterators. 125 | getindex{T}(l::SList{T}, n::SListNode{T})=n.data 126 | function setindex!{T}(l::SList{T}, n::SListNode{T}, d::T) 127 | n.data=d 128 | end 129 | 130 | #### Dequeues 131 | 132 | # Breaking interface expectation to push multiple items 133 | # so that we can return an index of the pushed item. 134 | # Use append! for multiple items. 135 | function push!{T}(l::SList{T}, item::T) 136 | lnode=endof(l) 137 | lnode.next=SListNode{T}(lnode.next, item) 138 | lnode.next 139 | end 140 | 141 | function pop!{T}(l::SList{T}) 142 | node=l.node::SListNode{T} 143 | while node.next.next!=l.node 144 | node=node.next::SListNode{T} 145 | end 146 | d=node.next.data 147 | node.next=node.next.next 148 | d 149 | end 150 | 151 | # Breaking interface expectation because: 152 | # Returns an index to the item instead of the collection. 153 | # Takes only one value at a time. Use prepend! for multiple. 154 | function unshift!{T}(l::SList{T}, d) 155 | l.node.next=SListNode{T}(l.node.next, d) 156 | l.node.next 157 | end 158 | 159 | function shift!{T}(l::SList{T}) 160 | d=l.node.next.data 161 | l.node.next=l.node.next.next 162 | d 163 | end 164 | 165 | # Insert-after. 166 | function insert!{T}(l::SList{T}, n::SListNode{T}, d::T) 167 | n.next=SListNode{T}(n.next, d) 168 | end 169 | 170 | # Linear in the number of elements. 171 | # Second argument is the state from an iterator. 172 | function deleteat!{T}(l::SList{T}, n::SListNode{T}) 173 | prev=l.node 174 | while prev.next!=n 175 | prev=prev.next 176 | end 177 | prev.next=n.next 178 | l 179 | end 180 | 181 | function splice!{T}(l::SList{T}, n::SListNode{T}) 182 | prev=l.node 183 | while prev.next!=n 184 | prev=prev.next 185 | end 186 | prev.next=n.next 187 | n.data 188 | end 189 | 190 | function splice!{T}(l::SList{T}, n::SListNode{T}, d::T) 191 | (d, n.data)=(n.data, d) 192 | d 193 | end 194 | 195 | function append!{T}(l::SList{T}, items) 196 | lnode=endof(l) 197 | for i in items 198 | lnode.next=SListNode{T}(lnode.next, i) 199 | lnode=lnode.next 200 | end 201 | end 202 | 203 | function prepend!{T}(l::SList{T}, items) 204 | for i in reverse(items) 205 | unshift!(l, i) 206 | end 207 | l 208 | end 209 | 210 | # Adding find, to find the iterator to a given value. 211 | function find{T}(l::SList{T}, d::T) 212 | find(l, l.node, d) 213 | end 214 | 215 | function find{T}(l::SList{T}, n::SListNode{T}, d::T) 216 | n=n.next 217 | while n!=l.node && n.data!=d 218 | n=n.next 219 | end 220 | if n==l.node 221 | return(nothing) 222 | end 223 | n 224 | end 225 | 226 | --------------------------------------------------------------------------------