lib/std: more efficient Collection::to_a
[nit.git] / lib / standard / collection / array.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2004-2008 Jean Privat <jean@pryen.org>
4 # Copyright 2008 Floréal Morandat <morandat@lirmm.fr>
5 #
6 # This file is free software, which comes along with NIT. This software is
7 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
9 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
10 # is kept unaltered, and a notification of the changes is added.
11 # You are allowed to redistribute it and sell it, alone or is a part of
12 # another product.
13
14 # This module introduces the standard array structure.
15 # It also implements two other abstract collections : ArrayMap and ArraySet
16 module array
17
18 import abstract_collection
19
20 # One dimension array of objects.
21 abstract class AbstractArrayRead[E]
22 super SequenceRead[E]
23
24 var _length: Int = 0
25 redef fun length do return _length
26
27 redef fun is_empty do return _length == 0
28
29 redef fun has(item)
30 do
31 var i = 0
32 var l = length
33 while i < l do
34 if self[i] == item then return true
35 i += 1
36 end
37 return false
38 end
39
40 redef fun has_only(item)
41 do
42 var i = 0
43 var l = length
44 while i < l do
45 if self[i] != item then return false
46 i += 1
47 end
48 return true
49 end
50
51 redef fun count(item)
52 do
53 var res = 0
54 var i = 0
55 var l = length
56 while i < l do
57 if self[i] == item then res += 1
58 i += 1
59 end
60 return res
61 end
62
63 redef fun index_of(item) do return index_of_from(item, 0)
64
65 redef fun last_index_of(item: E): Int do return last_index_of_from(item, length-1)
66
67 redef fun index_of_from(item: E, pos: Int): Int
68 do
69 var i = pos
70 var len = length
71 while i < len do
72 if self[i] == item then
73 return i
74 end
75 i += 1
76 end
77 return -1
78 end
79
80 redef fun last_index_of_from(item: E, pos: Int): Int
81 do
82 var i = pos
83 while i >= 0 do
84 if self[i] == item then
85 return i
86 else
87 i -= 1
88 end
89 end
90 return -1
91 end
92
93 # Return a new array that is the reverse of `self`
94 #
95 # assert [1,2,3].reversed == [3, 2, 1]
96 fun reversed: Array[E]
97 do
98 var cmp = _length
99 var result = new Array[E].with_capacity(cmp)
100 while cmp > 0 do
101 cmp -= 1
102 result.add(self[cmp])
103 end
104 return result
105 end
106
107 # Copy a portion of `self` to an other array.
108 #
109 # var a = [1, 2, 3, 4]
110 # var b = [10, 20, 30, 40, 50]
111 # a.copy_to(1, 2, b, 2)
112 # assert b == [10, 20, 2, 3, 50]
113 protected fun copy_to(start: Int, len: Int, dest: AbstractArray[E], new_start: Int)
114 do
115 # TODO native one
116 var i = len
117 while i > 0 do
118 i -= 1
119 dest[new_start+i] = self[start+i]
120 end
121 end
122
123 redef fun output
124 do
125 var i = 0
126 var l = length
127 while i < l do
128 var e = self[i]
129 if e != null then e.output
130 i += 1
131 end
132 end
133
134 redef fun iterator: ArrayIterator[E] do return new ArrayIterator[E](self)
135 redef fun reverse_iterator do return new ArrayReverseIterator[E](self)
136 end
137
138 # Resizable one dimension array of objects.
139 abstract class AbstractArray[E]
140 super AbstractArrayRead[E]
141 super Sequence[E]
142
143 # Force the capacity to be at least `cap`.
144 # The capacity of the array is an internal information.
145 # However, this method can be used to prepare a large amount of add
146 fun enlarge(cap: Int) is abstract
147
148 redef fun push(item) do add(item)
149
150 redef fun pop
151 do
152 assert not_empty: not is_empty
153 var r = last
154 _length -= 1
155 return r
156 end
157
158 redef fun shift
159 do
160 assert not_empty: not is_empty
161 var r = first
162 var i = 1
163 var l = length
164 while i < l do
165 self[i-1] = self[i]
166 i += 1
167 end
168 _length = l - 1
169 return r
170 end
171
172 redef fun unshift(item)
173 do
174 var i = length - 1
175 while i >= 0 do
176 self[i+1] = self[i]
177 i -= 1
178 end
179 self[0] = item
180 end
181
182 redef fun insert(item: E, pos: Int)
183 do
184 enlarge(length + 1)
185 copy_to(pos, length-pos, self, pos + 1)
186 self[pos] = item
187 end
188
189 redef fun add(item) do self[length] = item
190
191 redef fun clear do _length = 0
192
193 redef fun remove(item) do remove_at(index_of(item))
194
195 redef fun remove_all(item)
196 do
197 var i = index_of(item)
198 while i >= 0 do
199 remove_at(i)
200 i = index_of_from(item, i)
201 end
202 end
203
204 redef fun remove_at(i)
205 do
206 var l = length
207 if i >= 0 and i < l then
208 var j = i + 1
209 while j < l do
210 self[j-1] = self[j]
211 j += 1
212 end
213 _length = l - 1
214 end
215 end
216
217 # Invert two elements in the array
218 #
219 # var a = [10, 20, 30, 40]
220 # a.swap_at(1, 3)
221 # assert a == [10, 40, 30, 20]
222 fun swap_at(a: Int,b: Int)
223 do
224 var e = self[a]
225 self[a] = self[b]
226 self[b] = e
227 end
228 end
229
230 # Resizable one dimension array of objects.
231 #
232 # Arrays have a literal representation.
233 # var a = [12, 32, 8]
234 # # is equivalent with:
235 # var b = new Array[Int]
236 # b.push(12)
237 # b.push(32)
238 # b.push(8)
239 # assert a == b
240 class Array[E]
241 super AbstractArray[E]
242 super ArrayCapable[E]
243
244 redef fun [](index)
245 do
246 assert index: index >= 0 and index < _length
247 return _items[index]
248 end
249
250 redef fun []=(index, item)
251 do
252 assert index: index >= 0 and index < _length + 1
253 if _capacity <= index then
254 enlarge(index + 1)
255 end
256 if _length <= index then
257 _length = index + 1
258 end
259 _items[index] = item
260 end
261
262 redef fun add(item)
263 do
264 var l = _length
265 if _capacity <= l then
266 enlarge(l + 1)
267 end
268 _length = l + 1
269 _items[l] = item
270 end
271
272 redef fun enlarge(cap)
273 do
274 var c = _capacity
275 if cap <= c then return
276 while c <= cap do c = c * 2 + 2
277 var a = calloc_array(c)
278 if _capacity > 0 then _items.copy_to(a, _length)
279 _items = a
280 _capacity = c
281 end
282
283 # Create an empty array.
284 init
285 do
286 _capacity = 0
287 _length = 0
288 end
289
290 # Create an array from a collection.
291 init from(items: Collection[E]) do
292 with_capacity(items.length)
293 self.add_all(items)
294 end
295
296 # Create an array with some `objects`.
297 init with_items(objects: E...)
298 do
299 _items = objects._items
300 _capacity = objects._capacity
301 _length = objects.length
302 end
303
304 # Create an empty array with a given capacity.
305 init with_capacity(cap: Int)
306 do
307 assert positive: cap >= 0
308 _items = calloc_array(cap)
309 _capacity = cap
310 _length = 0
311 end
312
313 # Create an array of `count` elements
314 init filled_with(value: E, count: Int)
315 do
316 assert positive: count >= 0
317 _items = calloc_array(count)
318 _capacity = count
319 _length = count
320 var i = 0
321 while i < count do
322 self[i] = value
323 i += 1
324 end
325 end
326
327 # Create a array filled with a given native array.
328 init with_native(nat: NativeArray[E], size: Int)
329 do
330 assert positive: size >= 0
331 _items = nat
332 _capacity = size
333 _length = size
334 end
335
336 # The internal storage.
337 var _items: nullable NativeArray[E] = null
338
339 # Do not use this method
340 # FIXME: Remove it once modules can intrude non local modules
341 fun intern_items: NativeArray[E] do return _items.as(not null)
342
343 # The size of `_items`.
344 var _capacity: Int = 0
345 end
346
347 # An `Iterator` on `AbstractArray`
348 private class ArrayIterator[E]
349 super IndexedIterator[E]
350
351 redef fun item do return _array[_index]
352
353 # redef fun item=(e) do _array[_index] = e
354
355 redef fun is_ok do return _index < _array.length
356
357 redef fun next do _index += 1
358
359 init(a: AbstractArrayRead[E])
360 do
361 _array = a
362 _index = 0
363 end
364
365 var _index: Int = 0
366 redef fun index do return _index
367 var _array: AbstractArrayRead[E]
368 end
369
370 private class ArrayReverseIterator[E]
371 super ArrayIterator[E]
372
373 redef fun is_ok do return _index >= 0
374
375 redef fun next do _index -= 1
376
377 init(a: AbstractArrayRead[E])
378 do
379 _array = a
380 _index = a.length - 1
381 end
382 end
383
384 # Others collections ##########################################################
385
386 # A set implemented with an Array.
387 class ArraySet[E: Object]
388 super Set[E]
389
390 # The stored elements.
391 var _array: Array[E]
392
393 redef fun has(e) do return _array.has(e)
394
395 redef fun add(e) do if not _array.has(e) then _array.add(e)
396
397 redef fun is_empty do return _array.is_empty
398
399 redef fun length do return _array.length
400
401 redef fun first
402 do
403 assert _array.length > 0
404 return _array.first
405 end
406
407 redef fun remove(item)
408 do
409 var i = _array.index_of(item)
410 if i >= 0 then remove_at(i)
411 end
412
413 redef fun remove_all(item) do remove(item)
414
415 redef fun clear do _array.clear
416
417 redef fun iterator do return new ArraySetIterator[E](_array.iterator)
418
419 # Assume the capacity is at least `cap`.
420 fun enlarge(cap: Int) do _array.enlarge(cap)
421
422 private fun remove_at(i: Int)
423 do
424 _array[i] = _array.last
425 _array.pop
426 end
427
428 # Create an empty set
429 init do _array = new Array[E]
430
431 # Create an empty set with a given capacity.
432 init with_capacity(i: Int) do _array = new Array[E].with_capacity(i)
433
434 redef fun new_set do return new ArraySet[E]
435 end
436
437 # Iterators on sets implemented with arrays.
438 private class ArraySetIterator[E: Object]
439 super Iterator[E]
440
441 redef fun is_ok do return _iter.is_ok
442
443 redef fun next do _iter.next
444
445 redef fun item: E do return _iter.item
446
447 init(iter: ArrayIterator[E]) do _iter = iter
448
449 var _iter: ArrayIterator[E]
450 end
451
452
453 # Associative arrays implemented with an array of (key, value) pairs.
454 class ArrayMap[K: Object, E]
455 super CoupleMap[K, E]
456
457 # O(n)
458 redef fun [](key)
459 do
460 var i = index(key)
461 if i >= 0 then
462 return _items[i].second
463 else
464 return provide_default_value(key)
465 end
466 end
467
468 # O(n)
469 redef fun []=(key, item)
470 do
471 var i = index(key)
472 if i >= 0 then
473 _items[i].second = item
474 else
475 _items.push(new Couple[K,E](key, item))
476 end
477 end
478
479 redef var keys: RemovableCollection[K] = new ArrayMapKeys[K, E](self)
480 redef var values: RemovableCollection[E] = new ArrayMapValues[K, E](self)
481
482 # O(1)
483 redef fun length do return _items.length
484
485 redef fun couple_iterator do return _items.iterator
486
487 redef fun is_empty do return _items.is_empty
488
489 redef fun clear do _items.clear
490
491 # Assume the capacity to be at least `cap`.
492 fun enlarge(cap: Int) do _items.enlarge(cap)
493
494 redef fun couple_at(key)
495 do
496 var i = index(key)
497 if i >= 0 then
498 return _items[i]
499 else
500 return null
501 end
502 end
503
504 # Internal storage.
505 var _items: Array[Couple[K,E]]
506
507 # fast remove the ith element of the array
508 private fun remove_at_index(i: Int)
509 do
510 _items[i] = _items.last
511 _items.pop
512 end
513
514 # The last positive result given by a index(1) call
515 var _last_index: Int = 0
516
517 # Where is the `key` in `_item`?
518 # return -1 if not found
519 private fun index(key: K): Int
520 do
521 var l = _last_index
522 if l < _items.length and _items[l].first == key then return l
523
524 var i = 0
525 while i < _items.length do
526 if _items[i].first == key then
527 _last_index = i
528 return i
529 end
530 i += 1
531 end
532 return -1
533 end
534
535 # A new empty map.
536 init
537 do
538 _items = new Array[Couple[K,E]]
539 end
540 end
541
542 private class ArrayMapKeys[K: Object, E]
543 super RemovableCollection[K]
544 # The original map
545 var map: ArrayMap[K, E]
546 redef fun count(k) do if self.has(k) then return 1 else return 0
547 redef fun first do return self.map._items.first.first
548 redef fun has(k) do return self.map.index(k) >= 0
549 redef fun has_only(k) do return (self.has(k) and self.length == 1) or self.is_empty
550 redef fun is_empty do return self.map.is_empty
551 redef fun length do return self.map.length
552 redef fun iterator do return new MapKeysIterator[K, E](self.map.iterator)
553 redef fun clear do self.map.clear
554 redef fun remove(key)
555 do
556 var i = self.map.index(key)
557 if i >= 0 then self.map.remove_at_index(i)
558 end
559 redef fun remove_all(key) do self.remove(key)
560 end
561
562 private class ArrayMapValues[K: Object, E]
563 super RemovableCollection[E]
564 # The original map
565 var map: ArrayMap[K, E]
566 redef fun first do return self.map._items.first.second
567 redef fun is_empty do return self.map.is_empty
568 redef fun length do return self.map.length
569 redef fun iterator do return new MapValuesIterator[K, E](self.map.iterator)
570
571 # O(n)
572 redef fun has(item)
573 do
574 for i in self.map._items do if i.second == item then return true
575 return false
576 end
577
578 # O(n)
579 redef fun has_only(item)
580 do
581 for i in self.map._items do if i.second != item then return false
582 return true
583 end
584
585 # O(n)
586 redef fun count(item)
587 do
588 var nb = 0
589 for i in self.map._items do if i.second == item then nb += 1
590 return nb
591 end
592
593 redef fun clear do self.map.clear
594
595 redef fun remove(item)
596 do
597 var map = self.map
598 var i = map._items.length - 1
599 while i >= 0 do
600 if map._items[i].second == item then
601 map.remove_at_index(i)
602 return
603 end
604 i -= 1
605 end
606 end
607
608 redef fun remove_all(item)
609 do
610 var map = self.map
611 var i = map._items.length - 1
612 while i >= 0 do
613 if map._items[i].second == item then
614 map.remove_at_index(i)
615 end
616 i -= 1
617 end
618 end
619 end
620
621
622 # Others tools ################################################################
623
624 redef class Iterator[E]
625 # Interate on `self` and build an array
626 fun to_a: Array[E]
627 do
628 var res = new Array[E]
629 while is_ok do
630 res.add(item)
631 next
632 end
633 return res
634 end
635 end
636
637 redef class Collection[E]
638 # Build a new array from a collection
639 fun to_a: Array[E]
640 do
641 var res = new Array[E].with_capacity(length)
642 res.add_all(self)
643 return res
644 end
645 end
646
647 # Native classes ##############################################################
648
649 # Subclasses of this class can create native arrays
650 interface ArrayCapable[E]
651 # Get a new array of `size` elements.
652 protected fun calloc_array(size: Int): NativeArray[E] is intern
653 end
654
655 # Native Nit array
656 # Access are unchecked and it has a fixed size
657 # Not for public use: may become private.
658 universal NativeArray[E]
659 # The length of the array
660 fun length: Int is intern
661 # Use `self` to initialize a standard Nit Array.
662 fun to_a: Array[E] do return new Array[E].with_native(self, length)
663 fun [](index: Int): E is intern
664 fun []=(index: Int, item: E) is intern
665 fun copy_to(dest: NativeArray[E], length: Int) is intern
666 #fun =(o: NativeArray[E]): Bool is intern
667 #fun !=(o: NativeArray[E]): Bool is intern
668 end