cast 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,842 @@
1
+ ###
2
+ ### ##################################################################
3
+ ###
4
+ ### NodeList and subclasses.
5
+ ###
6
+ ### ##################################################################
7
+ ###
8
+
9
+ module C
10
+ ## Declare all the classes, so we don't have to declare the
11
+ ## inheritances later.
12
+ class NodeList < Node; abstract; end
13
+ class NodeArray < NodeList; end
14
+ class NodeChain < NodeList; end
15
+
16
+ ###
17
+ ### ================================================================
18
+ ###
19
+ ### NodeList
20
+ ###
21
+ ### Abstract base class of the Node list classes.
22
+ ###
23
+ ### ================================================================
24
+ ###
25
+ class NodeList
26
+ def self.[] *args
27
+ new.concat(args)
28
+ end
29
+
30
+ include Enumerable
31
+ def size
32
+ length
33
+ end
34
+
35
+ def == other
36
+ return false if !other.is_a? C::NodeList
37
+
38
+ ## none of the NodeList classes here have fields, but there's no
39
+ ## reason why one can't subclass one to have fields
40
+ fields.each do |field|
41
+ mine = self .send(field.reader)
42
+ yours = other.send(field.reader)
43
+ mine == yours or return false
44
+ end
45
+
46
+ other = other.to_a
47
+ return false if other.length != self.length
48
+ each_with_index do |node, i|
49
+ return false if node != other[i]
50
+ end
51
+ return true
52
+ end
53
+
54
+ def hash
55
+ hash = 0
56
+ each do |node|
57
+ hash ^= node.hash
58
+ end
59
+ return hash
60
+ end
61
+
62
+ def to_s
63
+ self.join ', '
64
+ end
65
+
66
+ def inspect
67
+ "#{self.class}[#{self.join(', ')}]"
68
+ end
69
+
70
+ protected # -----------------------------------------------------
71
+
72
+ ###
73
+ ### Return `[i, n, splat?]', where if `args' is used as an index
74
+ ### to ::Array#[]=, it is equivalent to calling:
75
+ ###
76
+ ### val = args.pop
77
+ ### if splat?
78
+ ### array[i, n] = *val
79
+ ### else
80
+ ### array[i, n] = val
81
+ ### end
82
+ ###
83
+ def parse_index *args
84
+ ## what we must do:
85
+ ##
86
+ ## -- move numbers into range 0..length-1
87
+ ## -- i..j --> i...j+1
88
+ ## -- i...j --> i, j-i
89
+ case args.length
90
+ when 1
91
+ arg = args.first
92
+ if arg.is_a? ::Range
93
+ if arg.exclude_end?
94
+ i = wrap_index(arg.begin)
95
+ j = wrap_index(arg.begin)
96
+ return [i, j-1, true]
97
+ else
98
+ i = wrap_index(arg.begin)
99
+ j = wrap_index(arg.begin)
100
+ return [i, j+1-i, true]
101
+ end
102
+ else
103
+ i = wrap_index(arg)
104
+ return [i, 1, false]
105
+ end
106
+ when 2
107
+ return [args[0], args[1], true]
108
+ else
109
+ raise ArgumentError, "wrong number of arguments"
110
+ end
111
+ end
112
+
113
+ ###
114
+ ### Wrap the given index if less than 0, and return it.
115
+ ###
116
+ def wrap_index i
117
+ i < 0 ? (i + length) : i
118
+ end
119
+
120
+ ###
121
+ ### Prepare the given nodes for addition. This means:
122
+ ### -- clone any attached nodes as necessary
123
+ ### -- set the nodes' parents to self.
124
+ ###
125
+ ### `oldnodes' are the nodes that will be replaced. These aren't
126
+ ### cloned the first time they appear in `nodes'.
127
+ ###
128
+ ### Return the list of nodes to add.
129
+ ###
130
+ def add_prep nodes, oldnodes=nil
131
+ if oldnodes
132
+ oldnodes = oldnodes.map{|n| n.object_id}
133
+ nodes.map! do |node|
134
+ if node.attached? && oldnodes.delete(node.object_id).nil?
135
+ node = node.clone
136
+ end
137
+ set_parent node, self
138
+ node
139
+ end
140
+ else
141
+ nodes.map! do |node|
142
+ node = node.clone if node.attached?
143
+ set_parent node, self
144
+ node
145
+ end
146
+ end
147
+ return nodes
148
+ end
149
+
150
+ ###
151
+ ### Set the parent of `node' to `val'.
152
+ ###
153
+ def set_parent node, val
154
+ node.send(:parent=, val)
155
+ end
156
+ end
157
+
158
+ class NodeArray
159
+ def assert_invariants testcase
160
+ super
161
+ testcase.assert_same(::Array, @array)
162
+ @array.each_with_index do |node, i|
163
+ assert_same(i, node.instance_variable_get(:@parent_index))
164
+ end
165
+ end
166
+
167
+ def initialize
168
+ super
169
+ @array = []
170
+ end
171
+
172
+ def dup
173
+ ret = super
174
+ ret.instance_variable_set(:@array, [])
175
+ dupes = self.map{|n| n.dup}
176
+ return ret.push(*dupes)
177
+ end
178
+
179
+ def clone
180
+ ret = super
181
+ ret.instance_variable_set(:@array, [])
182
+ clones = self.map{|n| n.clone}
183
+ return ret.push(*clones)
184
+ end
185
+ end
186
+
187
+ class NodeChain
188
+ def assert_invariants testcase
189
+ super
190
+ assert_same(@length.zero?, @first.nil?)
191
+ assert_same(@length.zero?, @last.nil?)
192
+ unless @length.zero?
193
+ assert_same(@first, self[0])
194
+ assert_same(@last, self[@length-1])
195
+ (0...@length.times).each do |i|
196
+ nodeprev = self[i].instance_variable_get(:@prev)
197
+ nodenext = self[i].instance_variable_get(:@next)
198
+ if i == 0
199
+ assert_nil(nodeprev)
200
+ else
201
+ assert_same(self[i-1], nodeprev)
202
+ end
203
+
204
+ if i == @length-1
205
+ assert_nil(nodenext)
206
+ else
207
+ assert_same(self[i+1], nodenext)
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ def initialize
214
+ super
215
+ @first = nil
216
+ @last = nil
217
+ @length = 0
218
+ end
219
+
220
+ def dup
221
+ ret = super
222
+ ret.instance_variable_set(:@first, nil)
223
+ ret.instance_variable_set(:@last, nil)
224
+ ret.instance_variable_set(:@length, 0)
225
+ dupes = self.map{|n| n.dup}
226
+ ret.push(*dupes)
227
+ return ret
228
+ end
229
+
230
+ def clone
231
+ ret = super
232
+ ret.instance_variable_set(:@first, nil)
233
+ ret.instance_variable_set(:@last, nil)
234
+ ret.instance_variable_set(:@length, 0)
235
+ clones = self.map{|n| n.clone}
236
+ ret.push(*clones)
237
+ return ret
238
+ end
239
+ end
240
+
241
+ ###
242
+ ### ----------------------------------------------------------------
243
+ ### Methods called from children
244
+ ### ----------------------------------------------------------------
245
+ ###
246
+
247
+ class NodeArray
248
+ def node_after node
249
+ node.parent.equal? self or
250
+ raise ArgumentError, "node is not a child"
251
+ @array[index = node.instance_variable_get(:@parent_index)+1]
252
+ end
253
+
254
+ def node_before node
255
+ node.parent.equal? self or
256
+ raise ArgumentError, "node is not a child"
257
+ index = node.instance_variable_get(:@parent_index)
258
+ if index.zero?
259
+ return nil
260
+ else
261
+ return @array[index-1]
262
+ end
263
+ end
264
+
265
+ def remove_node node
266
+ node.parent.equal? self or
267
+ raise ArgumentError, "node is not a child"
268
+ index = node.instance_variable_get(:@parent_index)
269
+ index.instance_variable_set(:@parent_index, nil)
270
+ removed_(@array[index])
271
+ @array.delete_at(index)
272
+ adjust_indices_(index)
273
+ return self
274
+ end
275
+
276
+ def insert_after node, *newnodes
277
+ node.parent.equal? self or
278
+ raise ArgumentError, "node is not a child"
279
+ index = node.instance_variable_get(:@parent_index) + 1
280
+ insert(index, *newnodes)
281
+ return self
282
+ end
283
+ def insert_before node, *newnodes
284
+ node.parent.equal? self or
285
+ raise ArgumentError, "node is not a child"
286
+ index = node.instance_variable_get(:@parent_index)
287
+ insert(index, *newnodes)
288
+ return self
289
+ end
290
+ def replace_node oldnode, *newnodes
291
+ oldnode.parent.equal? self or
292
+ raise ArgumentError, "node is not a child"
293
+ index = oldnode.instance_variable_get(:@parent_index)
294
+ self[index, 1] = newnodes
295
+ return self
296
+ end
297
+
298
+ private
299
+
300
+ ###
301
+ ### Adjust the indices of all elements from index `from_i' to the
302
+ ### end.
303
+ ###
304
+ def adjust_indices_ from_i
305
+ (from_i...@array.length).each do |i|
306
+ @array[i].instance_variable_set(:@parent_index, i)
307
+ end
308
+ end
309
+ ###
310
+ ### Called when something was added.
311
+ ###
312
+ def added_ *nodes
313
+ nodes.each do |n|
314
+ n.instance_variable_set(:@parent, self)
315
+ end
316
+ end
317
+ ###
318
+ ### Called when something was removed.
319
+ ###
320
+ def removed_ *nodes
321
+ nodes.each do |n|
322
+ n.instance_variable_set(:@parent, nil)
323
+ end
324
+ end
325
+ end
326
+
327
+ class NodeChain
328
+ def node_after node
329
+ node.parent.equal? self or
330
+ raise ArgumentError, "node is not a child"
331
+ return node.instance_variable_get(:@next)
332
+ end
333
+ def node_before node
334
+ node.parent.equal? self or
335
+ raise ArgumentError, "node is not a child"
336
+ return node.instance_variable_get(:@prev)
337
+ end
338
+ def remove_node node
339
+ node.parent.equal? self or
340
+ raise ArgumentError, "node is not a child"
341
+ node_prev = node.instance_variable_get(:@prev)
342
+ node_next = node.instance_variable_get(:@next)
343
+ removed_(node)
344
+ link2_(node_prev, node_next)
345
+ return self
346
+ end
347
+ def insert_after node, *newnodes
348
+ node.parent.equal? self or
349
+ raise ArgumentError, "node is not a child"
350
+ newnodes = add_prep(newnodes)
351
+ node_next = node.instance_variable_get(:@next)
352
+ link_(node, newnodes, node_next)
353
+ added_(*newnodes)
354
+ return self
355
+ end
356
+ def insert_before node, *newnodes
357
+ node.parent.equal? self or
358
+ raise ArgumentError, "node is not a child"
359
+ newnodes = add_prep(newnodes)
360
+ node_prev = node.instance_variable_get(:@prev)
361
+ link_(node_prev, newnodes, node)
362
+ added_(*newnodes)
363
+ return self
364
+ end
365
+ def replace_node oldnode, *newnodes
366
+ oldnode.parent.equal? self or
367
+ raise ArgumentError, "node is not a child"
368
+ newnodes = add_prep(newnodes, [oldnode])
369
+ prev_node = oldnode.instance_variable_get(:@prev)
370
+ next_node = oldnode.instance_variable_get(:@next)
371
+ link_(prev_node, newnodes, next_node)
372
+ removed_(oldnode)
373
+ added_(*newnodes)
374
+ return self
375
+ end
376
+ ###
377
+ ### Called when something was added.
378
+ ###
379
+ def added_ *newnodes
380
+ newnodes.each{|n| n.instance_variable_set(:@parent, self)}
381
+ @length += newnodes.length
382
+ end
383
+ ###
384
+ ### Called when something was removed.
385
+ ###
386
+ def removed_ *nodes
387
+ nodes.each{|n| n.instance_variable_set(:@parent, nil)}
388
+ @length -= nodes.length
389
+ end
390
+ end
391
+
392
+ ###
393
+ ### ----------------------------------------------------------------
394
+ ### Array methods
395
+ ### ----------------------------------------------------------------
396
+ ###
397
+
398
+ class NodeArray
399
+ %w[
400
+ first
401
+ last
402
+ length
403
+ []
404
+ empty?
405
+ index
406
+ rindex
407
+ values_at
408
+ join
409
+ ].each do |m|
410
+ eval "
411
+ def #{m} *args, &blk
412
+ @array.#{m} *args, &blk
413
+ end
414
+ "
415
+ end
416
+
417
+ %w[
418
+ each
419
+ reverse_each
420
+ each_index
421
+ ].each do |m|
422
+ eval "
423
+ def #{m} *args, &blk
424
+ @array.#{m} *args, &blk
425
+ return self
426
+ end
427
+ "
428
+ end
429
+
430
+ def to_a
431
+ @array.dup
432
+ end
433
+ def push *nodes
434
+ nodes = add_prep(nodes)
435
+ i = @array.length
436
+ @array.push(*nodes)
437
+ added_(*nodes)
438
+ adjust_indices_(i)
439
+ return self
440
+ end
441
+ def unshift *nodes
442
+ nodes = add_prep(nodes)
443
+ @array.unshift(*nodes)
444
+ added_(*nodes)
445
+ adjust_indices_(0)
446
+ return self
447
+ end
448
+ def pop *args
449
+ if args.empty?
450
+ ret = @array.pop
451
+ removed_(ret)
452
+ return ret
453
+ else
454
+ ret = @array.pop(*args)
455
+ removed_ *ret
456
+ return ret
457
+ end
458
+ end
459
+ def shift *args
460
+ if args.empty?
461
+ ret = @array.shift
462
+ removed_ ret
463
+ else
464
+ ret = @array.shift(*args)
465
+ removed_ *ret
466
+ end
467
+ adjust_indices_(0)
468
+ return ret
469
+ end
470
+ def insert i, *newnodes
471
+ (0..@array.length).include? i or
472
+ raise IndexError, "index #{i} out of NodeList (length #{@array.length})"
473
+ newnodes = add_prep(newnodes)
474
+ @array.insert(i, *newnodes)
475
+ added_(*newnodes)
476
+ adjust_indices_(i)
477
+ return self
478
+ end
479
+ def << newnode
480
+ newnode = *add_prep([newnode])
481
+ @array << newnode
482
+ added_(newnode)
483
+ adjust_indices_(@array.length - 1)
484
+ return self
485
+ end
486
+ def []= *args
487
+ newnodes = args.pop
488
+ i, n, splat = parse_index(*args)
489
+ oldnodes = @array[i, n] or
490
+ raise IndexError, "index #{i} out of NodeList"
491
+ if splat
492
+ newnodes = add_prep(newnodes, oldnodes)
493
+ else
494
+ ## newnodes is a single node (not an Array)
495
+ newnodes = add_prep([newnodes], [oldnodes])
496
+ end
497
+ @array[i, n] = newnodes
498
+ if splat
499
+ removed_(*oldnodes)
500
+ added_(*newnodes)
501
+ else
502
+ removed_(oldnodes)
503
+ added_(newnodes)
504
+ end
505
+ adjust_indices_(i)
506
+ return newnodes
507
+ end
508
+ def concat other
509
+ other = other.to_a
510
+ other = add_prep(other)
511
+ len = @array.length
512
+ @array.concat(other)
513
+ added_(*other)
514
+ adjust_indices_(len)
515
+ return self
516
+ end
517
+ def delete_at index
518
+ if index < @array.length
519
+ ret = @array.delete_at(index)
520
+ removed_(ret)
521
+ adjust_indices_(index)
522
+ return ret
523
+ else
524
+ return nil
525
+ end
526
+ end
527
+ def clear
528
+ nodes = @array.dup
529
+ @array.clear
530
+ removed_(*nodes)
531
+ return self
532
+ end
533
+ def replace other
534
+ other = other.to_a
535
+ other = add_prep(other)
536
+ oldnodes = @array.dup
537
+ @array.replace(other)
538
+ removed_(*oldnodes)
539
+ added_(*@array)
540
+ adjust_indices_(0)
541
+ return self
542
+ end
543
+ end
544
+
545
+ class NodeChain
546
+ ###
547
+ ### const methods
548
+ ###
549
+ def first n=nil
550
+ if n.nil?
551
+ return @first
552
+ else
553
+ n = length if n > length
554
+ node = @first
555
+ ret = ::Array.new(n) do
556
+ r = node
557
+ node = node.instance_variable_get(:@next)
558
+ r
559
+ end
560
+ return ret
561
+ end
562
+ end
563
+ def last n=nil
564
+ if n.nil?
565
+ return @last
566
+ else
567
+ n = length if n > length
568
+ node = @last
569
+ ret = ::Array.new(n)
570
+ (n-1).downto(0) do |i|
571
+ ret[i] = node
572
+ node = node.instance_variable_get(:@prev)
573
+ end
574
+ return ret
575
+ end
576
+ end
577
+ def length
578
+ @length
579
+ end
580
+ def each
581
+ node = @first
582
+ until node.nil?
583
+ yield node
584
+ node = node.instance_variable_get(:@next)
585
+ end
586
+ return self
587
+ end
588
+ def reverse_each
589
+ node = @last
590
+ until node.nil?
591
+ yield node
592
+ node = node.instance_variable_get(:@prev)
593
+ end
594
+ return self
595
+ end
596
+ def to_a
597
+ node = @first
598
+ ret = ::Array.new(@length) do
599
+ r = node
600
+ node = node.instance_variable_get(:@next)
601
+ r
602
+ end
603
+ return ret
604
+ end
605
+ def [] *args
606
+ i, n, splat = parse_index(*args)
607
+ return nil if i >= @length
608
+ node = get_(i)
609
+ if splat
610
+ ## return an array of Nodes
611
+ n = length-i if n > length-i
612
+ ret = ::Array.new(n) do
613
+ r = node
614
+ node = node.next
615
+ r
616
+ end
617
+ return ret
618
+ else
619
+ ## return a Node
620
+ return node
621
+ end
622
+ end
623
+ def each_index
624
+ @length.times{|i| yield i}
625
+ return self
626
+ end
627
+ def empty?
628
+ @length.zero?
629
+ end
630
+ def index node
631
+ curr = @first
632
+ i = 0
633
+ while curr
634
+ return i if curr == node
635
+ curr = curr.instance_variable_get(:@next)
636
+ i += 1
637
+ end
638
+ return nil
639
+ end
640
+ def rindex node
641
+ curr = @last
642
+ i = @length - 1
643
+ while curr
644
+ return i if curr == node
645
+ curr = curr.instance_variable_get(:@prev)
646
+ i -= 1
647
+ end
648
+ return nil
649
+ end
650
+ def values_at *args
651
+ args.map!{|i| self[i]}
652
+ end
653
+ def join *args
654
+ self.to_a.join(*args)
655
+ end
656
+
657
+ ###
658
+ ### non-const methods
659
+ ###
660
+ def push *newnodes
661
+ newnodes = add_prep(newnodes)
662
+ added_(*newnodes)
663
+ link_(@last, newnodes, nil)
664
+ return self
665
+ end
666
+ def << newnode
667
+ return push(newnode)
668
+ end
669
+ def unshift *newnodes
670
+ newnodes = add_prep(newnodes)
671
+ added_(*newnodes)
672
+ link_(nil, newnodes, @first)
673
+ return self
674
+ end
675
+ def pop n=nil
676
+ if n
677
+ ## return an Array of Nodes
678
+ ret = last(n)
679
+ return ret if ret.empty?
680
+ link2_(ret.first.instance_variable_get(:@prev), nil)
681
+ removed_(*ret)
682
+ return ret
683
+ else
684
+ return nil if empty?
685
+ ## return a Node
686
+ ret = @last
687
+ link2_(@last.instance_variable_get(:@prev), nil)
688
+ removed_(ret)
689
+ return ret
690
+ end
691
+ end
692
+ def shift n=nil
693
+ if n
694
+ ## return an Array of Nodes
695
+ ret = first(n)
696
+ return ret if ret.empty?
697
+ link2_(nil, ret.last.instance_variable_get(:@next))
698
+ removed_(*ret)
699
+ return ret
700
+ else
701
+ return nil if empty?
702
+ ## return a Node
703
+ ret = @first
704
+ link2_(nil, @first.instance_variable_get(:@next))
705
+ removed_(ret)
706
+ return ret
707
+ end
708
+ end
709
+ def insert i, *newnodes
710
+ (0..@length).include? i or
711
+ raise IndexError, "index #{i} out of NodeList"
712
+ if i == @length
713
+ return push(*newnodes)
714
+ else
715
+ insert_before(self[i], *newnodes)
716
+ end
717
+ end
718
+ def []= *args
719
+ newnodes = args.pop
720
+ i, n, splat = parse_index(*args)
721
+ oldnodes = self[i, n] or
722
+ raise IndexError, "index #{i} out of NodeList"
723
+ unless n.zero?
724
+ prev_node = n.instance_variable_get(:@prev)
725
+ next_node = n.instance_variable_get(:@next)
726
+ link2_(prev, next_node)
727
+ removed_(*oldnodes)
728
+ end
729
+ if i == @length
730
+ if splat
731
+ push(*newnodes)
732
+ else
733
+ push(newnodes)
734
+ end
735
+ else
736
+ node = get_(i)
737
+ if splat
738
+ insert_before(node, *newnodes)
739
+ else
740
+ insert_before(node, newnodes)
741
+ end
742
+ end
743
+ return newnodes
744
+ end
745
+ def concat other
746
+ return push(*other.to_a)
747
+ end
748
+ def delete_at index
749
+ node = self[index]
750
+ remove_node(node)
751
+ return node
752
+ end
753
+ def clear
754
+ each{|n| set_parent(n, nil)}
755
+ @first = @last = nil
756
+ @length = 0
757
+ return self
758
+ end
759
+ def replace other
760
+ return clear.push(*other.to_a)
761
+ end
762
+
763
+ private
764
+ ###
765
+ ### Link up `nodes' between `a' and `b'.
766
+ ###
767
+ def link_ a, nodes, b
768
+ if nodes.empty?
769
+ if a.nil?
770
+ @first = b
771
+ else
772
+ a.instance_variable_set(:@next, b)
773
+ end
774
+ if b.nil?
775
+ @last = a
776
+ else
777
+ b.instance_variable_set(:@prev, a)
778
+ end
779
+ else
780
+ ## connect `a' and `b'
781
+ first = nodes.first
782
+ if a.nil?
783
+ @first = first
784
+ else
785
+ a.instance_variable_set(:@next, first)
786
+ end
787
+ last = nodes.last
788
+ if b.nil?
789
+ @last = last
790
+ else
791
+ b.instance_variable_set(:@prev, last)
792
+ end
793
+
794
+ ## connect `nodes'
795
+ if nodes.length == 1
796
+ node = nodes[0]
797
+ node.instance_variable_set(:@prev, a)
798
+ node.instance_variable_set(:@next, b)
799
+ else
800
+ first.instance_variable_set(:@next, nodes[ 1])
801
+ first.instance_variable_set(:@prev, a)
802
+ last. instance_variable_set(:@prev, nodes[-2])
803
+ last. instance_variable_set(:@next, b)
804
+ (1...nodes.length-1).each do |i|
805
+ n = nodes[i]
806
+ n.instance_variable_set(:@prev, nodes[i-1])
807
+ n.instance_variable_set(:@next, nodes[i+1])
808
+ end
809
+ end
810
+ end
811
+ end
812
+ ### Special case for 2
813
+ def link2_ a, b
814
+ if a.nil?
815
+ @first = b
816
+ else
817
+ a.instance_variable_set(:@next, b) unless a.nil?
818
+ end
819
+ if b.nil?
820
+ @last = a
821
+ else
822
+ b.instance_variable_set(:@prev, a) unless b.nil?
823
+ end
824
+ end
825
+ ###
826
+ ### Return the `i'th Node. Assume `i' is in 0...length.
827
+ ###
828
+ def get_ i
829
+ ## return a Node
830
+ if i < (@length >> 1)
831
+ ## go from the beginning
832
+ node = @first
833
+ i.times{node = node.next}
834
+ else
835
+ ## go from the end
836
+ node = @last
837
+ (@length - 1 - i).times{node = node.prev}
838
+ end
839
+ return node
840
+ end
841
+ end
842
+ end