cursor 0.6 → 0.8
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.
- data/cursor.rb +626 -1143
- data/cursor/buffered.rb +89 -0
- data/cursor/circular.rb +245 -0
- data/cursor/circular/indexed.rb +51 -0
- data/cursor/circular/linked.rb +98 -0
- data/cursor/circular/position.rb +105 -0
- data/cursor/circular/shifting.rb +48 -0
- data/cursor/circular/split.rb +106 -0
- data/cursor/indexed.rb +52 -0
- data/cursor/io.rb +342 -0
- data/cursor/lined.rb +49 -0
- data/cursor/linked.rb +62 -0
- data/cursor/position.rb +145 -0
- data/cursor/reversed.rb +122 -0
- data/cursor/shifting.rb +40 -0
- data/cursor/split.rb +45 -0
- data/cursor/test.rb +519 -0
- data/cursor/test_circulars.rb +87 -0
- data/cursor/test_cursors.rb +112 -0
- data/cursor/usedeleteinsert.rb +150 -0
- data/cursor/usenext.rb +145 -0
- data/cursor/usenext/position.rb +71 -0
- data/cursor/useposition.rb +42 -0
- data/cursor/usereadwrite.rb +126 -0
- data/duck.rb +31 -0
- data/regexp_cursor.rb +50 -0
- data/weakrefset.rb +130 -0
- metadata +35 -7
@@ -0,0 +1,71 @@
|
|
1
|
+
# $Id: position.rb,v 1.3 2005/07/18 14:46:28 eric_mahurin Exp $
|
2
|
+
|
3
|
+
require 'cursor'
|
4
|
+
|
5
|
+
class Cursor
|
6
|
+
module UseNext
|
7
|
+
class Position < Cursor::Position # :nodoc:
|
8
|
+
def initialize(parent,reverse=false)
|
9
|
+
@parent = parent
|
10
|
+
@anchor_after = reverse
|
11
|
+
if @anchor_after && !@parent.skip1after
|
12
|
+
@pos = nil
|
13
|
+
else
|
14
|
+
@pos = @parent.__send__(:pos)
|
15
|
+
end
|
16
|
+
prop(nil,@parent.prop)
|
17
|
+
end
|
18
|
+
def pos(reverse=false)
|
19
|
+
if reverse.nil? ? @anchor_after : reverse
|
20
|
+
@pos && (@pos.to_i-@parent.size).nonzero? || -0.0
|
21
|
+
else
|
22
|
+
@pos || @parent.size
|
23
|
+
end
|
24
|
+
end
|
25
|
+
def pos=(p)
|
26
|
+
if (p.nonzero?||1.0/p)<0
|
27
|
+
@pos = p.to_i.nonzero?
|
28
|
+
@pos += @parent.size if @pos
|
29
|
+
@anchor_after = true
|
30
|
+
p
|
31
|
+
else
|
32
|
+
@anchor_after = false
|
33
|
+
@pos = p
|
34
|
+
end
|
35
|
+
end
|
36
|
+
protected
|
37
|
+
def _deletion(pos,len=1,reverse=false,eof=nil)
|
38
|
+
if @pos
|
39
|
+
if @pos==pos
|
40
|
+
@anchor_after = false
|
41
|
+
elsif @pos>pos
|
42
|
+
@pos -= len
|
43
|
+
if @pos<pos
|
44
|
+
@pos = pos
|
45
|
+
if reverse
|
46
|
+
@anchor_after=true
|
47
|
+
eof = !@parent.skip1after if eof.nil?
|
48
|
+
@pos = nil if eof
|
49
|
+
else
|
50
|
+
@anchor_after = false
|
51
|
+
end
|
52
|
+
elsif @pos==pos && !@anchor_after
|
53
|
+
@anchor_after = true
|
54
|
+
eof = !@parent.skip1after if eof.nil?
|
55
|
+
@pos = nil if eof
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
eof
|
60
|
+
end
|
61
|
+
def _insertion(pos,len=1,dummy=nil)
|
62
|
+
if @pos and @pos>=pos+(@anchor_after ? 0 : 1)
|
63
|
+
@pos += len
|
64
|
+
end
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# $Id: useposition.rb,v 1.10 2005/07/15 22:34:42 eric_mahurin Exp $
|
2
|
+
|
3
|
+
;
|
4
|
+
|
5
|
+
class Cursor
|
6
|
+
# Mixin for derived classes to use #position as the basis for After/Before methods.
|
7
|
+
# See Cursor for a description of these methods.
|
8
|
+
module UsePosition # :nodoc:
|
9
|
+
def read1after
|
10
|
+
position(false) { read1next }
|
11
|
+
end
|
12
|
+
def read1before
|
13
|
+
position(true) { read1prev }
|
14
|
+
end
|
15
|
+
def skip1after
|
16
|
+
position(false) { skip1next }
|
17
|
+
end
|
18
|
+
def skip1before
|
19
|
+
position(true) { skip1prev }
|
20
|
+
end
|
21
|
+
def write1after(v)
|
22
|
+
position(false) { write1next(v) }
|
23
|
+
end
|
24
|
+
def write1before(v)
|
25
|
+
position(true) { write1prev(v) }
|
26
|
+
end
|
27
|
+
def write1after!(v)
|
28
|
+
position(false) { write1next!(v) }
|
29
|
+
end
|
30
|
+
def write1before!(v)
|
31
|
+
position(true) { write1prev!(v) }
|
32
|
+
end
|
33
|
+
def write1after?(v)
|
34
|
+
position(false) { write1next?(v) }
|
35
|
+
end
|
36
|
+
def write1before?(v)
|
37
|
+
position(true) { write1prev?(v) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# $Id: usereadwrite.rb,v 1.13 2005/07/15 22:34:42 eric_mahurin Exp $
|
2
|
+
|
3
|
+
;
|
4
|
+
|
5
|
+
class Cursor
|
6
|
+
# Mixin for derived classes to use these methods as the basis for others:
|
7
|
+
# #read1next, #read1prev, #write1next, #write1prev,
|
8
|
+
# #_delete1after?, #delete1before?, #_insert1before, #_insert1after.
|
9
|
+
# See Cursor for a description of these methods.
|
10
|
+
module UseReadWrite # :nodoc:
|
11
|
+
protected
|
12
|
+
def _delete1after
|
13
|
+
_delete1after?.nil? ? nil : true
|
14
|
+
end
|
15
|
+
def _delete1before
|
16
|
+
_delete1before?.nil? ? nil : true
|
17
|
+
end
|
18
|
+
public
|
19
|
+
def delete1after
|
20
|
+
_delete1after && (@positions && _adjust_delete;true)
|
21
|
+
end
|
22
|
+
def delete1before
|
23
|
+
_delete1before && (@positions && _adjust_delete;true)
|
24
|
+
end
|
25
|
+
def delete1after?
|
26
|
+
v0 = _delete1after?
|
27
|
+
v0.nil? || @positions && _adjust_delete
|
28
|
+
v0
|
29
|
+
end
|
30
|
+
def delete1before?
|
31
|
+
v0 = _delete1before?
|
32
|
+
v0.nil? || @positions && _adjust_delete
|
33
|
+
v0
|
34
|
+
end
|
35
|
+
def insert1before(v)
|
36
|
+
@positions && _adjust_insert
|
37
|
+
_insert1before(v)
|
38
|
+
end
|
39
|
+
def insert1after(v)
|
40
|
+
@positions && _adjust_insert
|
41
|
+
_insert1after(v)
|
42
|
+
end
|
43
|
+
def write1next!(v)
|
44
|
+
write1next(v) || insert1before(v)
|
45
|
+
end
|
46
|
+
def write1prev!(v)
|
47
|
+
write1prev(v) || insert1after(v)
|
48
|
+
end
|
49
|
+
|
50
|
+
def skip1next
|
51
|
+
read1next.nil? ? nil : true
|
52
|
+
end
|
53
|
+
def skip1prev
|
54
|
+
read1prev.nil? ? nil : true
|
55
|
+
end
|
56
|
+
def write1next?(v)
|
57
|
+
v0 = read1after
|
58
|
+
v0.nil? || write1next(v)
|
59
|
+
v0
|
60
|
+
end
|
61
|
+
def write1prev?(v)
|
62
|
+
v0 = read1before
|
63
|
+
v0.nil? || write1prev(v)
|
64
|
+
v0
|
65
|
+
end
|
66
|
+
|
67
|
+
def read1after
|
68
|
+
v0 = read1next
|
69
|
+
v0.nil? || skip1prev
|
70
|
+
v0
|
71
|
+
end
|
72
|
+
def read1before
|
73
|
+
v0 = read1prev
|
74
|
+
v0.nil? || skip1next
|
75
|
+
v0
|
76
|
+
end
|
77
|
+
def skip1after
|
78
|
+
skip1next && skip1prev
|
79
|
+
end
|
80
|
+
def skip1before
|
81
|
+
skip1prev && skip1next
|
82
|
+
end
|
83
|
+
def write1after(v)
|
84
|
+
write1next(v) && skip1prev
|
85
|
+
end
|
86
|
+
def write1after!(v)
|
87
|
+
write1next!(v)
|
88
|
+
skip1prev
|
89
|
+
end
|
90
|
+
def write1before(v)
|
91
|
+
write1prev(v) && skip1next
|
92
|
+
end
|
93
|
+
def write1before!(v)
|
94
|
+
write1prev!(v)
|
95
|
+
skip1next
|
96
|
+
end
|
97
|
+
def write1after?(v)
|
98
|
+
v0 = write1next?(v)
|
99
|
+
v0.nil? || skip1prev
|
100
|
+
v0
|
101
|
+
end
|
102
|
+
def write1before?(v)
|
103
|
+
v0 = write1prev?(v)
|
104
|
+
v0.nil? || skip1next
|
105
|
+
v0
|
106
|
+
end
|
107
|
+
def scan1next(v)
|
108
|
+
v0 = read1next
|
109
|
+
(v0.nil? || v==v0) ? v0 : (skip1prev;nil)
|
110
|
+
end
|
111
|
+
def scan1prev(v)
|
112
|
+
v0 = read1prev
|
113
|
+
(v0.nil? || v==v0) ? v0 : (skip1next;nil)
|
114
|
+
end
|
115
|
+
def modify1next(r)
|
116
|
+
v0 = read1after
|
117
|
+
(v0.nil? || (v = r[v0]).nil?) ? nil : (write1next(v);v0)
|
118
|
+
end
|
119
|
+
def modify1prev(r)
|
120
|
+
v0 = read1before
|
121
|
+
(v0.nil? || (v = r[v0]).nil?) ? nil : (write1prev(v);v0)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
|
data/duck.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# $Id: duck.rb,v 1.3 2005/07/21 15:15:38 eric_mahurin Exp $
|
2
|
+
|
3
|
+
class Object
|
4
|
+
# Return a new object that maps methods the original object to different
|
5
|
+
# names. The arguments are a list alternating new and old method names
|
6
|
+
# (strings or symbols). If an odd number (usually one) of arguments is given,
|
7
|
+
# the last old method is assumed to be the original object itself -
|
8
|
+
# hopefully a Proc or Method and it is used to map to the new name in the
|
9
|
+
# new object.
|
10
|
+
def duck(*new_old)
|
11
|
+
obj = Object.new
|
12
|
+
klass = (class << obj;self;end)
|
13
|
+
until new_old.empty?
|
14
|
+
new,old = new_old.slice!(0,2)
|
15
|
+
klass.__send__(:define_method,new,&(old ? self.method(old) : self))
|
16
|
+
end
|
17
|
+
obj
|
18
|
+
end
|
19
|
+
# Return a new object that maps a hash of name=>proc to the methods of the
|
20
|
+
# object.
|
21
|
+
def self.duck(methods)
|
22
|
+
obj = self.new
|
23
|
+
klass = (class << obj;self;end)
|
24
|
+
methods.each { |name,proc|
|
25
|
+
klass.__send__(:define_method,name,&proc)
|
26
|
+
}
|
27
|
+
obj
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
data/regexp_cursor.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# $Id: regexp_cursor.rb,v 1.2 2005/07/21 15:20:48 eric_mahurin Exp $
|
2
|
+
|
3
|
+
require 'strscan'
|
4
|
+
|
5
|
+
class Regexp
|
6
|
+
# Scan the cursor for the regexp and return what was matched or +nil+ for
|
7
|
+
# a mismatch. The regexp will be implicitly anchored at the cursor location.
|
8
|
+
# Unless +hold+ or a mismatch, the cursor will be advanced to a point right
|
9
|
+
# after the match. +len+ should be the max length that the regexp can match or
|
10
|
+
# zero to look at everything. A negative +len+ (including -0.0) will scan
|
11
|
+
# the cursor in reverse.
|
12
|
+
def scan_cursor(cursor,len=0,hold=false)
|
13
|
+
reverse = (len.nonzero?||1.0/len)<0
|
14
|
+
buffer = len.zero? ? cursor.read!(reverse,true,"") : cursor.read(len,true,"")
|
15
|
+
buffer or return
|
16
|
+
scanner = StringScanner.new(buffer)
|
17
|
+
ret = scanner.scan(self)
|
18
|
+
if ret
|
19
|
+
len = scanner.pos
|
20
|
+
cursor.skip(reverse ? -len : +len) if !hold
|
21
|
+
end
|
22
|
+
ret
|
23
|
+
end
|
24
|
+
# Scan the cursor until it matches the regexp and what was scanned up to and
|
25
|
+
# including the match or +nil+ if it never matched.
|
26
|
+
# Unless +hold+ or a mismatch, the cursor will be advanced to a point right
|
27
|
+
# after the match. +len+ should be the start buffer size of what to look at
|
28
|
+
# from the cursor or zero to look at everything at once. A negative +len+
|
29
|
+
# (including -0.0) will scan the cursor in reverse.
|
30
|
+
def scan_cursor_until(cursor,len=1,hold=false)
|
31
|
+
reverse = (len.nonzero?||1.0/len)<0
|
32
|
+
buffer = ""
|
33
|
+
scanner = StringScanner.new(buffer)
|
34
|
+
if len.zero?
|
35
|
+
buffer = cursor.read!(reverse,true,buffer) or return
|
36
|
+
ret = scanner.scan_until(self)
|
37
|
+
else
|
38
|
+
while cursor.read(len,false,buffer)
|
39
|
+
ret = scanner.scan_until(self) and break(ret)
|
40
|
+
len *= 2
|
41
|
+
end
|
42
|
+
len = buffer.length
|
43
|
+
end
|
44
|
+
len = (hold ? 0 : scanner.pos)-len
|
45
|
+
cursor.skip(reverse ? -len : +len) if len.nonzero?
|
46
|
+
ret
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
data/weakrefset.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
# $Id: weakrefset.rb,v 1.5 2005/06/29 15:22:38 eric_mahurin Exp $
|
2
|
+
|
3
|
+
# WeakRefSet implements an unordered collection of weak references to objects.
|
4
|
+
# These references don't prevent garbage collection on these objects. As these
|
5
|
+
# objects are thrown away so does their entry in a WeakRefSet. Immmediate
|
6
|
+
# objects are not handled by this class (and wouldn't be useful).
|
7
|
+
class WeakRefSet
|
8
|
+
include Enumerable
|
9
|
+
private
|
10
|
+
def finalizer(id)
|
11
|
+
@ids.delete(id >> 1)
|
12
|
+
end
|
13
|
+
public
|
14
|
+
# create a new WeakRefSet from an optional Enumerable (of objects)
|
15
|
+
# which is optionally processed through a block
|
16
|
+
def initialize(enum=[],&block) # :yield: obj
|
17
|
+
replace(enum.collect(&block))
|
18
|
+
end
|
19
|
+
# add a weak reference to the set
|
20
|
+
def add(obj)
|
21
|
+
@ids[obj.__id__ >> 1] = true
|
22
|
+
ObjectSpace.define_finalizer(obj,method(:finalizer))
|
23
|
+
self
|
24
|
+
end
|
25
|
+
alias << add
|
26
|
+
# iterate over remaining valid objects in the set
|
27
|
+
def each(&block)
|
28
|
+
@ids.each_key { |id|
|
29
|
+
begin
|
30
|
+
o = ObjectSpace._id2ref(id << 1)
|
31
|
+
rescue RangeError
|
32
|
+
next
|
33
|
+
end
|
34
|
+
block.call(o) if @ids.include?(id)
|
35
|
+
}
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
# clear the set (return self)
|
39
|
+
def clear
|
40
|
+
@ids = {}
|
41
|
+
self
|
42
|
+
end
|
43
|
+
# merge some more objects into the set (return self)
|
44
|
+
def merge(enum)
|
45
|
+
enum.each { |obj| add(obj) }
|
46
|
+
self
|
47
|
+
end
|
48
|
+
# replace the objects in the set (return self)
|
49
|
+
def replace(enum)
|
50
|
+
clear
|
51
|
+
merge(enum)
|
52
|
+
self
|
53
|
+
end
|
54
|
+
# delete an object in the set (return self)
|
55
|
+
def delete(obj)
|
56
|
+
@ids.delete(obj.__id__ >> 1)
|
57
|
+
self
|
58
|
+
end
|
59
|
+
# delete an object in the set (return self or nil if nothing deleted)
|
60
|
+
def delete?(obj)
|
61
|
+
@ids.delete(obj.__id__ >> 1)&&self
|
62
|
+
end
|
63
|
+
# any objects in the set still valid?
|
64
|
+
def empty?
|
65
|
+
each { return(false) }
|
66
|
+
true
|
67
|
+
end
|
68
|
+
# is this object in the set?
|
69
|
+
def include?(obj)
|
70
|
+
@ids.include?(obj.__id__ >> 1)
|
71
|
+
end
|
72
|
+
alias member? include?
|
73
|
+
# return a string showing the object classes and ids
|
74
|
+
def inspect
|
75
|
+
s = sprintf("#<#{self.class}:0x%x {",__id__ << 1)
|
76
|
+
s += collect { |obj| obj.inspect }.join(", ")
|
77
|
+
s + "}>"
|
78
|
+
end
|
79
|
+
# remove some objects from the set (return self)
|
80
|
+
def subtract(enum)
|
81
|
+
enum.each { |obj| delete(obj) }
|
82
|
+
self
|
83
|
+
end
|
84
|
+
# number of objects in the set still valid
|
85
|
+
def size
|
86
|
+
n=0
|
87
|
+
each { n+=1 }
|
88
|
+
n
|
89
|
+
end
|
90
|
+
alias length size
|
91
|
+
end
|
92
|
+
|
93
|
+
# :stopdoc:
|
94
|
+
|
95
|
+
if __FILE__==$0
|
96
|
+
require 'benchmark'
|
97
|
+
MyString = Class.new(String)
|
98
|
+
weakrefs = WeakRefSet.new
|
99
|
+
$stdout.sync=true
|
100
|
+
obj = nil
|
101
|
+
times = Benchmark.measure {
|
102
|
+
10000.times { |i|
|
103
|
+
print(".")
|
104
|
+
obj = MyString.new("X"*rand(i+1))
|
105
|
+
weakrefs << obj
|
106
|
+
weakrefs.each { |o|
|
107
|
+
MyString==o.class or raise
|
108
|
+
}
|
109
|
+
weakrefs.include?(obj) or raise
|
110
|
+
if rand(10).zero?
|
111
|
+
weakrefs.delete?(obj) or raise
|
112
|
+
!weakrefs.include?(obj) or raise
|
113
|
+
end
|
114
|
+
}
|
115
|
+
}
|
116
|
+
puts
|
117
|
+
p(weakrefs)
|
118
|
+
p((weakrefs.size.nonzero? or raise))
|
119
|
+
weakrefs.empty? and raise
|
120
|
+
GC.start
|
121
|
+
p(weakrefs)
|
122
|
+
p(weakrefs.clear)
|
123
|
+
weakrefs.size.zero? or raise
|
124
|
+
weakrefs.empty? or raise
|
125
|
+
puts(times)
|
126
|
+
end
|
127
|
+
|
128
|
+
# :stopdoc:
|
129
|
+
|
130
|
+
|