cast 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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