sequence 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +58 -0
- data/GPL +340 -0
- data/Manifest.txt +36 -0
- data/README.txt +320 -0
- data/Rakefile +32 -0
- data/lib/assert.rb +16 -0
- data/lib/sequence/arraylike.rb +57 -0
- data/lib/sequence/buffered.rb +188 -0
- data/lib/sequence/circular.rb +272 -0
- data/lib/sequence/enum.rb +260 -0
- data/lib/sequence/file.rb +172 -0
- data/lib/sequence/functional.rb +152 -0
- data/lib/sequence/generator.rb +290 -0
- data/lib/sequence/indexed.rb +234 -0
- data/lib/sequence/io.rb +102 -0
- data/lib/sequence/list.rb +292 -0
- data/lib/sequence/ofhash.rb +38 -0
- data/lib/sequence/ofobjectivars.rb +29 -0
- data/lib/sequence/ofobjectmethods.rb +87 -0
- data/lib/sequence/position.rb +100 -0
- data/lib/sequence/reversed.rb +180 -0
- data/lib/sequence/shifting.rb +190 -0
- data/lib/sequence/singleitem.rb +50 -0
- data/lib/sequence/stringlike.rb +482 -0
- data/lib/sequence/subseq.rb +90 -0
- data/lib/sequence/usedata.rb +35 -0
- data/lib/sequence/version.rb +5 -0
- data/lib/sequence.rb +721 -0
- data/lib/weakrefset.rb +254 -0
- data/test/test.rb +609 -0
- data/test/test_all.rb +6 -0
- data/test/test_changes.rb +44 -0
- data/test/test_circulars.rb +89 -0
- data/test/test_rexscan.rb +899 -0
- data/test/test_seqrex.rb +204 -0
- data/test/test_sequences.rb +106 -0
- metadata +90 -0
data/lib/weakrefset.rb
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
# $Id$
|
2
|
+
# Copyright (C) 2006 Caleb Clausen
|
3
|
+
# Distributed under the terms of Ruby's license.
|
4
|
+
|
5
|
+
require 'yaml'
|
6
|
+
require 'assert'
|
7
|
+
|
8
|
+
# WeakRefSet implements an unordered collection of weak references to objects.
|
9
|
+
# These references don't prevent garbage collection on these objects. As these
|
10
|
+
# objects are thrown away so does their entry in a WeakRefSet. Immmediate
|
11
|
+
# objects are not handled by this class (and wouldn't be useful).
|
12
|
+
class WeakRefSet
|
13
|
+
include Enumerable
|
14
|
+
# create a new WeakRefSet from an optional Enumerable (of objects)
|
15
|
+
# which is optionally processed through a block
|
16
|
+
def initialize(items) # :yield: obj
|
17
|
+
replace(items)
|
18
|
+
end
|
19
|
+
class<<self
|
20
|
+
def [] *items
|
21
|
+
new(items)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def finalizer(id)
|
27
|
+
@ids.delete(id)
|
28
|
+
end
|
29
|
+
|
30
|
+
public
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
# add a weak reference to the set
|
35
|
+
def add(obj)
|
36
|
+
Symbol===obj || Fixnum===obj || nil==obj || true==obj || false==obj and
|
37
|
+
raise ArgumentError, "no immediates in weakrefset"
|
38
|
+
id=obj.object_id
|
39
|
+
case (o2=ObjectSpace._id2ref id) #test id for validity
|
40
|
+
when Symbol,Fixnum,true,false,nil: id=obj #hopefully rare
|
41
|
+
else obj.equal? o2 or raise
|
42
|
+
ObjectSpace.define_finalizer(obj,method(:finalizer))
|
43
|
+
end
|
44
|
+
@ids[id] = true
|
45
|
+
self
|
46
|
+
end
|
47
|
+
alias << add
|
48
|
+
# iterate over remaining valid objects in the set
|
49
|
+
def each
|
50
|
+
@ids.each_key { |id|
|
51
|
+
case id
|
52
|
+
when Integer:
|
53
|
+
begin
|
54
|
+
o = ObjectSpace._id2ref(id)
|
55
|
+
rescue RangeError
|
56
|
+
next
|
57
|
+
end
|
58
|
+
@ids.include?(id) or next
|
59
|
+
#i don't know where the random symbols come from, but at least they're always symbols...
|
60
|
+
else
|
61
|
+
o=id
|
62
|
+
end
|
63
|
+
case o
|
64
|
+
when Symbol,Fixnum,true,false,nil: warn "immediate value #{o.inspect} found in weakrefset"
|
65
|
+
else yield(o)
|
66
|
+
end
|
67
|
+
}
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def == other
|
72
|
+
size==other.size and
|
73
|
+
each{|x|
|
74
|
+
other.include? x or return
|
75
|
+
}
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
# clear the set (return self)
|
80
|
+
def clear
|
81
|
+
@ids = {}
|
82
|
+
self
|
83
|
+
end
|
84
|
+
# merge some more objects into the set (return self)
|
85
|
+
def merge(enum)
|
86
|
+
enum.each { |obj| add(obj) }
|
87
|
+
self
|
88
|
+
end
|
89
|
+
# replace the objects in the set (return self)
|
90
|
+
def replace(enum)
|
91
|
+
clear
|
92
|
+
merge(enum)
|
93
|
+
self
|
94
|
+
end
|
95
|
+
# delete an object in the set (return self)
|
96
|
+
def delete(obj)
|
97
|
+
delete?(obj)
|
98
|
+
self
|
99
|
+
end
|
100
|
+
# delete an object in the set (return self or nil if nothing deleted)
|
101
|
+
def delete?(obj)
|
102
|
+
x=include?(obj) and @ids.delete(x.__id__)||@ids.delete(x) and self
|
103
|
+
end
|
104
|
+
# is this object in the set?
|
105
|
+
def include?(obj)
|
106
|
+
find{|x| obj==x}
|
107
|
+
end
|
108
|
+
alias member? include?
|
109
|
+
|
110
|
+
# return a human-readable string showing the set
|
111
|
+
def inspect
|
112
|
+
#unless $weakrefset_verbose_inspect
|
113
|
+
# return sprintf('#<%s:0x%x {...}>', self.class.name, object_id)
|
114
|
+
#end
|
115
|
+
ids = (Thread.current[:__weakrefset__inspect_key__] ||= [])
|
116
|
+
|
117
|
+
if ids.include?(object_id)
|
118
|
+
return sprintf('#<%s {...}>', self.class.name)
|
119
|
+
end
|
120
|
+
|
121
|
+
begin
|
122
|
+
ids << object_id
|
123
|
+
return sprintf('#<%s {%s}>', self.class.name, to_a.inspect[1..-2])
|
124
|
+
ensure
|
125
|
+
ids.pop
|
126
|
+
Thread.current[:__weakrefset__inspect_key__].empty? and
|
127
|
+
Thread.current[:__weakrefset__inspect_key__]=nil
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
if false #this is broken; emits yaml for a hash.
|
132
|
+
|
133
|
+
YAML::add_domain_type( "inforadical.net,2005", "object:WeakRefSet" ) do |type, val|
|
134
|
+
WeakRefSet.new( *val["items"] )
|
135
|
+
end
|
136
|
+
|
137
|
+
def is_complex_yaml?; true end
|
138
|
+
|
139
|
+
def to_yaml_type; "!inforadical.net,2005/object:WeakRefSet" end
|
140
|
+
|
141
|
+
alias to_yaml_properties to_a
|
142
|
+
|
143
|
+
def to_yaml( opts = {} )
|
144
|
+
YAML::quick_emit( object_id, opts ) { |out|
|
145
|
+
out.map( to_yaml_type ) { |map|
|
146
|
+
map.add( "items", to_yaml_properties)
|
147
|
+
}
|
148
|
+
}
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# remove some objects from the set (return self)
|
153
|
+
def subtract(enum)
|
154
|
+
enum.each { |obj| delete(obj) }
|
155
|
+
self
|
156
|
+
end
|
157
|
+
# any objects in the set still valid?
|
158
|
+
def empty?
|
159
|
+
@ids.empty?
|
160
|
+
end
|
161
|
+
# number of objects in the set still valid
|
162
|
+
def size
|
163
|
+
@ids.size
|
164
|
+
end
|
165
|
+
alias length size
|
166
|
+
end
|
167
|
+
|
168
|
+
# :stopdoc:
|
169
|
+
|
170
|
+
if __FILE__==$0
|
171
|
+
require 'benchmark'
|
172
|
+
class MyString <String;
|
173
|
+
def initialize(*)
|
174
|
+
@owner=0
|
175
|
+
super
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
class MyObject; end
|
180
|
+
class MyClass < Module; end
|
181
|
+
weakrefsets = (1..10).map {WeakRefSet[]}
|
182
|
+
$stdout.sync=true
|
183
|
+
obj = nil
|
184
|
+
arr=[]
|
185
|
+
# srand(2389547343)
|
186
|
+
classes=[]
|
187
|
+
ObjectSpace.each_object(Class){|ob| classes<<ob}
|
188
|
+
classes-=[Symbol,Integer,NilClass,FalseClass,TrueClass,Numeric,Data,Bignum,Fixnum,
|
189
|
+
Float,Struct,Method,UnboundMethod,Proc,Thread,Binding,Continuation]
|
190
|
+
classes.delete_if{|k| begin k.allocate; rescue; true else false end}
|
191
|
+
def shuffle!(arr)
|
192
|
+
arr.sort_by{rand}
|
193
|
+
end
|
194
|
+
times = Benchmark.measure {
|
195
|
+
100000.times { |i|
|
196
|
+
# print(weakrefs.size>70?"|":((60..70)===weakrefs.size ? ":" : (weakrefs.size>50?',':'.')))
|
197
|
+
print "." if 0==i%128
|
198
|
+
#obj = (k=classes[rand(classes.size)]).allocate
|
199
|
+
obj = (k=MyString).new "X" #*rand(i+1)
|
200
|
+
# obj= (k=Object).new
|
201
|
+
# obj= (k=MyObject).new
|
202
|
+
#obj= (k=MyClass).new
|
203
|
+
k==obj.class or raise
|
204
|
+
weakrefs=weakrefsets[rand(weakrefsets.size)]
|
205
|
+
obj.instance_eval{@owner=weakrefs}
|
206
|
+
obj.instance_eval{@owner}.equal? weakrefs or raise
|
207
|
+
weakrefs.each { |o|
|
208
|
+
# k==o.class or raise "set contained a #{o.class}. i=#{i}. size=#{weakrefs.size}"
|
209
|
+
(o2=o.instance_eval{@owner})==weakrefs or
|
210
|
+
raise "expected owner #{weakrefs.map{|w| w.__id__}.inspect}, "+
|
211
|
+
"got #{o2.inspect}, item #{o}, id #{o.__id__}, obj #{obj.__id__}"
|
212
|
+
}
|
213
|
+
weakrefs << obj
|
214
|
+
weakrefs.each { |o|
|
215
|
+
# k==o.class or raise "set contained a #{o.class}. i=#{i}. size=#{weakrefs.size}"
|
216
|
+
(o2=o.instance_eval{@owner})==weakrefs or
|
217
|
+
raise "expected owner #{weakrefs.map{|w| w.__id__}.inspect}, "+
|
218
|
+
"got #{o2.inspect}, item #{o}, id #{o.__id__}, obj #{obj.__id__}"
|
219
|
+
}
|
220
|
+
weakrefs.include?(obj) or raise
|
221
|
+
weakrefs.each { |o|
|
222
|
+
# k==o.class or raise "set contained a #{o.class}. i=#{i}. size=#{weakrefs.size}"
|
223
|
+
(o2=o.instance_eval{@owner})==weakrefs or
|
224
|
+
raise "expected owner #{weakrefs.map{|w| w.__id__}.inspect}, "+
|
225
|
+
"got #{o2.inspect}, item #{o}, id #{o.__id__}, obj #{obj.__id__}"
|
226
|
+
}
|
227
|
+
weakrefs.include?(obj) or raise
|
228
|
+
if rand(10).zero?
|
229
|
+
weakrefs.delete?(obj) or raise
|
230
|
+
!weakrefs.include?(obj) or raise
|
231
|
+
elsif rand(4).zero?
|
232
|
+
arr<<obj #prevent garbage collection
|
233
|
+
end
|
234
|
+
if rand(1000).zero?
|
235
|
+
shuffle! arr
|
236
|
+
arr.slice!(0..rand(arr.size))
|
237
|
+
end
|
238
|
+
arr.each{|o| o.instance_eval{@owner}.include? o or raise }
|
239
|
+
#rand(100).zero? and GC.start
|
240
|
+
}
|
241
|
+
}
|
242
|
+
puts
|
243
|
+
GC.start
|
244
|
+
weakrefsets.each{|weakrefs|
|
245
|
+
weakrefs.clear
|
246
|
+
weakrefs.size.zero? or raise
|
247
|
+
weakrefs.empty? or raise
|
248
|
+
}
|
249
|
+
puts(times)
|
250
|
+
end
|
251
|
+
|
252
|
+
# :stopdoc:
|
253
|
+
|
254
|
+
|