hashery 1.0.0 → 1.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/HISTORY +21 -0
- data/lib/hashery/association.rb +160 -0
- data/lib/hashery/ini.rb +267 -0
- data/lib/hashery/linkedlist.rb +195 -0
- data/lib/hashery/opencascade.rb +3 -2
- data/lib/hashery/openhash.rb +1 -1
- data/lib/hashery/openobject.rb +5 -5
- data/lib/hashery/orderedhash.rb +120 -370
- data/lib/hashery/sparsearray.rb +586 -0
- data/meta/version +1 -1
- data/test/case_association.rb +28 -0
- metadata +8 -3
@@ -0,0 +1,586 @@
|
|
1
|
+
#--
|
2
|
+
# SparseArray
|
3
|
+
#
|
4
|
+
# Copyright (c) 2004,2005 Thomas Sawyer
|
5
|
+
#
|
6
|
+
# Ruby License
|
7
|
+
#
|
8
|
+
# This module is free software. You may use, modify, and/or redistribute this
|
9
|
+
# software under the same terms as Ruby.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
12
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
13
|
+
# FOR A PARTICULAR PURPOSE.
|
14
|
+
#
|
15
|
+
# ==========================================================================
|
16
|
+
# Revision History ::
|
17
|
+
# --------------------------------------------------------------------------
|
18
|
+
# 04.09 Trans * 99% Compatible with Array
|
19
|
+
# ==========================================================================
|
20
|
+
#++
|
21
|
+
|
22
|
+
# = SparseArray
|
23
|
+
#
|
24
|
+
# SparseArray is an implemenation of the Array class using only Hashes.
|
25
|
+
# Regular Arrays are never used except once to delegate the #pack method,
|
26
|
+
# (and *args parameters of course). SparseArray is almost fully compatible
|
27
|
+
# with Array. There are still a few missing methods that came in with
|
28
|
+
# Ruby 1.9 that need to be added, and negative indexes are not quite fully
|
29
|
+
# supported yet.
|
30
|
+
#
|
31
|
+
# SparseArray is slower then the built in Array class, but not as slow
|
32
|
+
# as one might expect, since a Hash is generally faster than an Array.
|
33
|
+
# It would interesting to see how this would perform if it were
|
34
|
+
# written in C.
|
35
|
+
#
|
36
|
+
class SparseArray < Hash
|
37
|
+
|
38
|
+
def self.[](*args)
|
39
|
+
nha = new
|
40
|
+
args.each { |a| nha << a } #.set(nha.length,a) }
|
41
|
+
nha
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.new_h(hsh)
|
45
|
+
nha = new
|
46
|
+
nha.replace(hsh)
|
47
|
+
#nha.reindex!
|
48
|
+
end
|
49
|
+
|
50
|
+
def initialize(i=0,e=nil)
|
51
|
+
if i > 0
|
52
|
+
i.times { set(self.length,e) }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def &(ha)
|
57
|
+
nha = self.class.new
|
58
|
+
(0..self.length-1).each do |i|
|
59
|
+
if ha.has_value?(self.fetch(i)) and !nha.has_value?(self.fetch(i))
|
60
|
+
nha.set(nha.length,self.fetch(i))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
nha
|
64
|
+
end
|
65
|
+
|
66
|
+
def *(j)
|
67
|
+
if j.kind_of?(String)
|
68
|
+
return self.join(j)
|
69
|
+
else
|
70
|
+
nha = self.class.new
|
71
|
+
j.times { (0...self.length).each { |i| nha.set(nha.length,self.fetch(i)) } }
|
72
|
+
return nha
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def +(ha)
|
77
|
+
nha = self.dup
|
78
|
+
(0..ha.length-1).each { |i| nha.set(nha.length,ha.fetch(i)) }
|
79
|
+
nha
|
80
|
+
end
|
81
|
+
|
82
|
+
def -(ha)
|
83
|
+
nha = self.class.new
|
84
|
+
self.each { |v| nha << v if !ha.has_value?(v) }
|
85
|
+
#ha.each { |v| nha << i if !self.include?(v) }
|
86
|
+
nha
|
87
|
+
end
|
88
|
+
|
89
|
+
def <<(e)
|
90
|
+
set(length,e)
|
91
|
+
self
|
92
|
+
end
|
93
|
+
|
94
|
+
def <=>(ha)
|
95
|
+
(0..self.length-1).each do |i|
|
96
|
+
ieq = (self.fetch(i) <=> ha.fetch(i))
|
97
|
+
return ieq if ieq != 0
|
98
|
+
end
|
99
|
+
self.length <=> ha.length
|
100
|
+
end
|
101
|
+
|
102
|
+
def ===(ha)
|
103
|
+
self.==(ha)
|
104
|
+
end
|
105
|
+
|
106
|
+
alias_method :get, :[]
|
107
|
+
private :get
|
108
|
+
|
109
|
+
# TODO: Ranges with negative indexes not yet supported.
|
110
|
+
def [](i,l=nil)
|
111
|
+
if l
|
112
|
+
i = size + i if i < 0
|
113
|
+
i = i...i+l
|
114
|
+
elsif ! i.kind_of?(Range)
|
115
|
+
return self.at(i)
|
116
|
+
end
|
117
|
+
nha = self.class.new
|
118
|
+
i.each { |j| nha.set(nha.length,get(j)) if has_key?(j) }
|
119
|
+
nha
|
120
|
+
end
|
121
|
+
|
122
|
+
alias set []=
|
123
|
+
protected :set
|
124
|
+
|
125
|
+
def []=(i,b,c=nil)
|
126
|
+
if c
|
127
|
+
rng = (Integer(i)..Integer(i+b))
|
128
|
+
b = c
|
129
|
+
elsif i.kind_of? Range
|
130
|
+
rng = i
|
131
|
+
else
|
132
|
+
self.set(Integer(i),b)
|
133
|
+
return b
|
134
|
+
end
|
135
|
+
if b == nil
|
136
|
+
rng.each { |i| qdelete(i) }
|
137
|
+
self.reindex!
|
138
|
+
elsif b.kind_of?(Array) or b.kind_of?(self.class)
|
139
|
+
j = 0
|
140
|
+
rng.each { |i| self[i] = b[j]; j+=1 }
|
141
|
+
else
|
142
|
+
rng.each { |i| qdelete(i) }
|
143
|
+
self[rng.fist] = b
|
144
|
+
self.reindex!
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def |(ha)
|
149
|
+
nha = self.dup
|
150
|
+
ha.each { |v| nha << v if !nha.has_value?(v) }
|
151
|
+
nha
|
152
|
+
end
|
153
|
+
|
154
|
+
def assoc(k)
|
155
|
+
(0...self.length).each { |i| return self.fetch(i) if self.fetch(i)[0] == k }
|
156
|
+
return nil
|
157
|
+
end
|
158
|
+
|
159
|
+
def at(i)
|
160
|
+
i = self.length + i if i <= -1
|
161
|
+
get(i)
|
162
|
+
#return nil if i < 0 or i >= self.length
|
163
|
+
#return self.fetch(i)
|
164
|
+
end
|
165
|
+
|
166
|
+
#def choice
|
167
|
+
#end
|
168
|
+
|
169
|
+
# clear okay
|
170
|
+
|
171
|
+
#
|
172
|
+
def collect
|
173
|
+
nha = self.class.new
|
174
|
+
(0...self.length).each { |i| nha << yield(self.fetch(i)) }
|
175
|
+
nha
|
176
|
+
end
|
177
|
+
|
178
|
+
def collect!
|
179
|
+
nha = self.class.new
|
180
|
+
(0...self.length).each { |i| nha << yield(self.fetch(i)) }
|
181
|
+
self.replace(nha)
|
182
|
+
end
|
183
|
+
|
184
|
+
#def combination
|
185
|
+
#end
|
186
|
+
|
187
|
+
#
|
188
|
+
def compact
|
189
|
+
nha, j = self.class.new, 0
|
190
|
+
(0..self.length-1).each do |i|
|
191
|
+
if self.fetch(i) != nil
|
192
|
+
nha.set(j,self.fetch(i))
|
193
|
+
j+=1
|
194
|
+
end
|
195
|
+
end
|
196
|
+
nha
|
197
|
+
end
|
198
|
+
|
199
|
+
def compact!
|
200
|
+
if self.has_value?(nil)
|
201
|
+
nha, j = self.class.new, 0
|
202
|
+
(0..self.length-1).each do |i|
|
203
|
+
if self.fetch(i) != nil
|
204
|
+
nha.set(j,self.fetch(i))
|
205
|
+
j+=1
|
206
|
+
end
|
207
|
+
end
|
208
|
+
return self.replace(nha)
|
209
|
+
else
|
210
|
+
return nil
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
#
|
215
|
+
def concat(ha)
|
216
|
+
(0...ha.length).each { |i| self.set(self.length,ha.fetch(i)) }
|
217
|
+
self
|
218
|
+
end
|
219
|
+
|
220
|
+
def count(e=nil)
|
221
|
+
if block_given?
|
222
|
+
cnt = 0
|
223
|
+
(0...self.length).each { |i| cnt += 1 if yield(self.fetch(i)) }
|
224
|
+
return cnt
|
225
|
+
else
|
226
|
+
cnt = 0
|
227
|
+
(0...self.length).each { |i| cnt += 1 if self.fetch(i) == e }
|
228
|
+
return cnt
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
#
|
233
|
+
alias qdelete delete
|
234
|
+
private :qdelete
|
235
|
+
|
236
|
+
#
|
237
|
+
def delete(e)
|
238
|
+
if has_value?(e)
|
239
|
+
qdelete_if { |i,v| v == e }
|
240
|
+
reindex!
|
241
|
+
return e
|
242
|
+
else
|
243
|
+
return yield if block_given?
|
244
|
+
return nil
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
#
|
249
|
+
def delete_at(i)
|
250
|
+
if self.has_key?(i)
|
251
|
+
e = self.fetch(i)
|
252
|
+
qdelete(i)
|
253
|
+
reindex!
|
254
|
+
return e
|
255
|
+
else
|
256
|
+
return nil
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
alias qdelete_if delete_if
|
261
|
+
private :qdelete_if
|
262
|
+
|
263
|
+
#
|
264
|
+
def delete_if
|
265
|
+
qdelete_if { |i,v| yield(v) }
|
266
|
+
reindex!
|
267
|
+
end
|
268
|
+
|
269
|
+
def each
|
270
|
+
(0...self.length).each { |i| yield(self.fetch(i)) }
|
271
|
+
end
|
272
|
+
|
273
|
+
def each_index
|
274
|
+
(0...self.length).each { |i| yield(i) }
|
275
|
+
end
|
276
|
+
|
277
|
+
# empty? okay as is
|
278
|
+
|
279
|
+
def eql?(ha)
|
280
|
+
return false if self.length != ha.length
|
281
|
+
return true if (0...self.length).all? { |i| self.fetch(i).eql?(ha.fetch(i)) }
|
282
|
+
return false
|
283
|
+
end
|
284
|
+
|
285
|
+
def fill(f,s=nil,l=nil)
|
286
|
+
if s.kind_of?(Range)
|
287
|
+
r = s
|
288
|
+
else
|
289
|
+
s = 0 if !s
|
290
|
+
l = self.length - s if !l
|
291
|
+
r = s...(s+l)
|
292
|
+
end
|
293
|
+
r.each{ |i| self.set(i,f) }
|
294
|
+
self
|
295
|
+
end
|
296
|
+
|
297
|
+
def first
|
298
|
+
return nil if self.empty?
|
299
|
+
self.fetch(0)
|
300
|
+
end
|
301
|
+
|
302
|
+
def flatten
|
303
|
+
nha = self.class.new
|
304
|
+
(0...self.length).each do |i|
|
305
|
+
sfi = self.fetch(i)
|
306
|
+
if sfi.kind_of?(self.class) or sfi.kind_of?(Array)
|
307
|
+
nha.concat(sfi.flatten)
|
308
|
+
else
|
309
|
+
nha.set(nha.length,sfi)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
nha
|
313
|
+
end
|
314
|
+
|
315
|
+
def flatten!
|
316
|
+
return nil if !self.any? { |e| e.kind_of?(self.class) or e.kind_of?(Array) }
|
317
|
+
self.replace(self.flatten)
|
318
|
+
end
|
319
|
+
|
320
|
+
def include?(v)
|
321
|
+
self.has_value?(v)
|
322
|
+
end
|
323
|
+
|
324
|
+
#
|
325
|
+
def insert(index, *objs)
|
326
|
+
index = size + index + 1 if index < 0
|
327
|
+
tail = self[index...size]
|
328
|
+
objs.each_with_index do |obj, i|
|
329
|
+
set(index + i, obj)
|
330
|
+
end
|
331
|
+
tail.each_with_index do |obj, i|
|
332
|
+
set(objs.size + index + i, obj)
|
333
|
+
end
|
334
|
+
self
|
335
|
+
end
|
336
|
+
|
337
|
+
# index okay
|
338
|
+
|
339
|
+
#
|
340
|
+
def join(sep='')
|
341
|
+
s = ''
|
342
|
+
(0...self.length).each { |i| s << "#{self.fetch(i)}#{sep}" }
|
343
|
+
return s.chomp(sep)
|
344
|
+
end
|
345
|
+
|
346
|
+
#
|
347
|
+
def last
|
348
|
+
self[self.length-1]
|
349
|
+
end
|
350
|
+
|
351
|
+
# length okay
|
352
|
+
|
353
|
+
#
|
354
|
+
alias map! collect!
|
355
|
+
|
356
|
+
#
|
357
|
+
def nitems
|
358
|
+
cnt = 0
|
359
|
+
(0...self.length).each { |i| cnt += 1 if self.fetch(i) != nil }
|
360
|
+
cnt
|
361
|
+
end
|
362
|
+
|
363
|
+
def pack(*args)
|
364
|
+
self.to_a.pack(*args)
|
365
|
+
end
|
366
|
+
|
367
|
+
#def permutation
|
368
|
+
#end
|
369
|
+
|
370
|
+
#
|
371
|
+
def pop
|
372
|
+
self.delete_at(self.length-1)
|
373
|
+
end
|
374
|
+
|
375
|
+
#def product
|
376
|
+
#end
|
377
|
+
|
378
|
+
#
|
379
|
+
def push(*e)
|
380
|
+
self.concat(e)
|
381
|
+
end
|
382
|
+
|
383
|
+
def rassoc(k)
|
384
|
+
(0...self.length).each { |i| return self.fetch(i) if self.fetch(i)[1] == k }
|
385
|
+
return nil
|
386
|
+
end
|
387
|
+
|
388
|
+
def reindex
|
389
|
+
nha, j, k, tl = self.class.new, 0, 0, self.length
|
390
|
+
while k < tl
|
391
|
+
if self.has_key?(j)
|
392
|
+
nha.set(k,self.fetch(j))
|
393
|
+
j+=1; k+=1
|
394
|
+
else
|
395
|
+
j+=1
|
396
|
+
end
|
397
|
+
end
|
398
|
+
nha
|
399
|
+
end
|
400
|
+
|
401
|
+
def reindex!
|
402
|
+
self.replace(self.reindex)
|
403
|
+
end
|
404
|
+
|
405
|
+
def reject!
|
406
|
+
chg=nil
|
407
|
+
qdelete_if { |i,v| r=yield(v); chg=true if r; r }
|
408
|
+
return nil if !chg
|
409
|
+
reindex!
|
410
|
+
end
|
411
|
+
|
412
|
+
#def replace(ha)
|
413
|
+
# if ha.length < self.length
|
414
|
+
# (ha.length..self.length-1).each { |i| self.delete(i) }
|
415
|
+
# (0..ha.length-1).each { |i| self.set(i,ha[i]) }
|
416
|
+
# end
|
417
|
+
#end
|
418
|
+
|
419
|
+
def reverse
|
420
|
+
nha = self.class.new
|
421
|
+
(0...self.length).each { |i| nha.set(self.length-1-i,self.fetch(i)) }
|
422
|
+
nha
|
423
|
+
end
|
424
|
+
|
425
|
+
def reverse!
|
426
|
+
(0...self.length/2).each do |i|
|
427
|
+
ri = self.length-1-i
|
428
|
+
tmp = self.fetch(ri)
|
429
|
+
self.set(ri,self.fetch(i))
|
430
|
+
self.set(i,tmp)
|
431
|
+
end
|
432
|
+
self
|
433
|
+
end
|
434
|
+
|
435
|
+
def reverse_each
|
436
|
+
i = self.length - 1
|
437
|
+
while i >= 0
|
438
|
+
yield(self.fetch(i))
|
439
|
+
i -= 1
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
def rindex(e)
|
444
|
+
i = self.length - 1
|
445
|
+
while i >= 0
|
446
|
+
return i if self.fetch(i) == e
|
447
|
+
i -= 1
|
448
|
+
end
|
449
|
+
return nil
|
450
|
+
end
|
451
|
+
|
452
|
+
def shift
|
453
|
+
e1 = self[0]
|
454
|
+
tl = self.length - 1
|
455
|
+
(1..tl).each { |i| self.set(i-1,self.fetch(i)) }
|
456
|
+
self.delete_at(tl)
|
457
|
+
e1
|
458
|
+
end
|
459
|
+
|
460
|
+
#
|
461
|
+
def shuffle
|
462
|
+
dup.shuffle!
|
463
|
+
end
|
464
|
+
|
465
|
+
#
|
466
|
+
def shuffle!
|
467
|
+
size.times do
|
468
|
+
a = rand(size).to_i
|
469
|
+
b = rand(size).to_i
|
470
|
+
self[a], self[b] = self[b], self[a]
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
# size okay
|
475
|
+
|
476
|
+
#
|
477
|
+
def slice(*args)
|
478
|
+
self[*args]
|
479
|
+
end
|
480
|
+
|
481
|
+
def slice!(*args)
|
482
|
+
result = self[*args]
|
483
|
+
self[*args] = nil
|
484
|
+
result
|
485
|
+
end
|
486
|
+
|
487
|
+
def sort
|
488
|
+
raise "SparseArray does not currently support sorting with blocks" if block_given?
|
489
|
+
nha = self.dup
|
490
|
+
qsort(nha,0,nha.length-1)
|
491
|
+
end
|
492
|
+
|
493
|
+
def qsort(ha, l, r)
|
494
|
+
l_hold = l
|
495
|
+
r_hold = r
|
496
|
+
pivot = ha[l]
|
497
|
+
while l < r
|
498
|
+
r -= 1 while (ha[r] <=> pivot) >= 0 and l < r
|
499
|
+
if l != r
|
500
|
+
ha[l] = ha[r]
|
501
|
+
l += 1
|
502
|
+
end
|
503
|
+
l += 1 while (ha[l] <=> pivot) <= 0 and l < r
|
504
|
+
if l != r
|
505
|
+
ha[r] = ha[l]
|
506
|
+
r -= 1
|
507
|
+
end
|
508
|
+
end
|
509
|
+
ha[l] = pivot
|
510
|
+
pivot = l
|
511
|
+
l = l_hold
|
512
|
+
r = r_hold
|
513
|
+
qsort(ha,l,pivot-1) if l < pivot
|
514
|
+
qsort(ha,pivot+1,r) if r > pivot
|
515
|
+
ha
|
516
|
+
end
|
517
|
+
|
518
|
+
def sort!
|
519
|
+
raise "SparseArray does not currently support sorting with blocks" if block_given?
|
520
|
+
qsort(self,0,self.length-1)
|
521
|
+
end
|
522
|
+
|
523
|
+
def to_a
|
524
|
+
a = []
|
525
|
+
(0..self.length-1).each { |i| a << self.fetch(i) }
|
526
|
+
a
|
527
|
+
end
|
528
|
+
|
529
|
+
def to_ary
|
530
|
+
self
|
531
|
+
end
|
532
|
+
|
533
|
+
def to_h
|
534
|
+
h = Hash.new
|
535
|
+
self.each { |k,v| h[k] = v }
|
536
|
+
h
|
537
|
+
end
|
538
|
+
|
539
|
+
def to_s
|
540
|
+
self.join
|
541
|
+
end
|
542
|
+
|
543
|
+
#
|
544
|
+
#def transpose
|
545
|
+
#end
|
546
|
+
|
547
|
+
#
|
548
|
+
def uniq
|
549
|
+
nha = self.class.new
|
550
|
+
(0..self.length-1).each do |i|
|
551
|
+
nha[nha.length] = self[i] if !nha.has_value?(self[i])
|
552
|
+
end
|
553
|
+
nha
|
554
|
+
end
|
555
|
+
|
556
|
+
#
|
557
|
+
def uniq!
|
558
|
+
j = 0
|
559
|
+
(1..self.length-1).each do |i|
|
560
|
+
if !self[0..j].has_value?(self[i])
|
561
|
+
self[j+1] = self[i]
|
562
|
+
j+=1
|
563
|
+
end
|
564
|
+
end
|
565
|
+
(j+1..self.length-1).each { |i| qdelete(i) }
|
566
|
+
end
|
567
|
+
|
568
|
+
def unshift(e)
|
569
|
+
i = self.length - 1
|
570
|
+
while i >= 0
|
571
|
+
self.set(i+1,self.fetch(i))
|
572
|
+
return i if self.fetch(i) == e
|
573
|
+
i -= 1
|
574
|
+
end
|
575
|
+
self.set(0,e)
|
576
|
+
self
|
577
|
+
end
|
578
|
+
|
579
|
+
def values_at(*ix)
|
580
|
+
nha = self.class.new
|
581
|
+
ix.each {|i| nha[nha.length] = self.at(i)}
|
582
|
+
nha
|
583
|
+
end
|
584
|
+
|
585
|
+
end
|
586
|
+
|