sequence 0.1.0
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/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
|
+
|