critbit 0.5.0-java
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.
- checksums.yaml +7 -0
- data/LICENSE.txt +23 -0
- data/README.md +153 -0
- data/Rakefile +46 -0
- data/config.rb +173 -0
- data/lib/critbit.rb +726 -0
- data/lib/env.rb +12 -0
- data/target/critbit.jar +0 -0
- data/test/crit.rb +6 -0
- data/test/test_critbit.rb +451 -0
- data/version.rb +2 -0
- metadata +121 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4a9cf126486194ddb19ade53ae5d7f6ee8236e54
|
4
|
+
data.tar.gz: 157dca8040f2d55f98a98928af6c39b716a770f3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5236e06a4c9a09e054dd6b4d5eb92eb8d756f690db8015f0ddfed0019d585022bda53108306cad1b8798a132baed1f2873d165b617424eb81566e2ba93104ab3
|
7
|
+
data.tar.gz: 7850a8a2add0fe4ea6c43e57859832e09f6a7ecd99e2f8f87e11d5a64ddb63736b05a10e385c0ae8e0d14de359d9e5e88f495bd9ff66ce75ad96064eec3903f9
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
The MIT License (MIT)
|
4
|
+
|
5
|
+
Copyright (c) 2015 Rodrigo Botafogo
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
8
|
+
this software and associated documentation files (the "Software"), to deal in
|
9
|
+
the Software without restriction, including without limitation the rights to
|
10
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
11
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
12
|
+
subject to the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
15
|
+
copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
19
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
20
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
21
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
22
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
data/README.md
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
Announcement
|
2
|
+
============
|
3
|
+
|
4
|
+
Critbit version 0.5 has been realeased. A crit bit tree, also known as a Binary Patricia
|
5
|
+
Trie is a trie (https://en.wikipedia.org/wiki/Trie), also called digital tree and sometimes
|
6
|
+
radix tree or prefix tree (as they
|
7
|
+
can be searched by prefixes), is an ordered tree data structure that is used to store a
|
8
|
+
dynamic set or associative array where the keys are usually strings. Unlike a binary search
|
9
|
+
tree, no node in the tree stores the key associated with that node; instead, its position
|
10
|
+
in the tree defines the key with which it is associated. All the descendants of a node have
|
11
|
+
a common prefix of the string associated with that node, and the root is associated with
|
12
|
+
the empty string. Values are normally not associated with every node, only with leaves and
|
13
|
+
some inner nodes that correspond to keys of interest. For the space-optimized presentation
|
14
|
+
of prefix tree, see compact prefix tree.
|
15
|
+
|
16
|
+
[The following is from: http://cr.yp.to/critbit.html]
|
17
|
+
|
18
|
+
A crit-bit tree supports the following operations (and more!) at high speed:
|
19
|
+
|
20
|
+
+ See whether a string x is in the tree.
|
21
|
+
+ Add x to the tree.
|
22
|
+
+ Remove x from the tree.
|
23
|
+
+ Find the lexicographically smallest string in the tree larger than x, if there is one.
|
24
|
+
+ Find all suffixes of x in the tree, i.e., all strings in the tree that have x as a prefix. Of course, this can take a long time if there are many such strings, but each string is found quickly.
|
25
|
+
|
26
|
+
A crit-bit tree can be used as a high-speed associative array. For example, an array mapping
|
27
|
+
54 to 1, 19 to 2, 99 to 3, 85 to 4, and 88 to 5 can be stored as a crit-bit tree containing
|
28
|
+
54=1, 19=2, 99=3, 85=4, and 88=5. The smallest string in the crit-bit tree larger than 85= is
|
29
|
+
85=4.
|
30
|
+
|
31
|
+
The standard strategy for many years has been to store searchable data sets as hash tables,
|
32
|
+
in applications that need exact searches but not lexicographic searches; or as heaps, in
|
33
|
+
applications that need to search for the minimum; or as AVL trees, red-black trees, etc. in
|
34
|
+
applications that do not fit the restrictions of hash tables and heaps.
|
35
|
+
|
36
|
+
In Python, for example, the built-in "dict" data type is a hash table. Hash tables don't
|
37
|
+
provide fast access to the smallest entry, so there's also a standard "heapq" library
|
38
|
+
providing heaps. Heaps don't provide fast lookups of other entries, so there are various
|
39
|
+
add-on libraries providing AVL trees and so on. A programmer who's happy creating a "dict"
|
40
|
+
will simply do so, but then another programmer who wants fancier operations on the resulting
|
41
|
+
database has to do an expensive conversion of the "dict" to a fancier data structure.
|
42
|
+
|
43
|
+
I (D. J. Bernstein) have become convinced that this strategy should change. The revised
|
44
|
+
strategy is much simpler: there should be one fundamental set-storage type, namely a crit-bit
|
45
|
+
tree. Here's how a crit-bit tree stacks up against the competition:
|
46
|
+
|
47
|
+
A hash table supports insertion, deletion, and exact searches. A crit-bit tree supports
|
48
|
+
insertion, deletion, exact searches, and ordered operations such as finding the minimum.
|
49
|
+
Another advantage is that a crit-bit tree guarantees good performance: it doesn't have any
|
50
|
+
tricky slowdowns for unusual (or malicious) data.
|
51
|
+
|
52
|
+
A heap supports insertion, deletion, and finding the minimum. A crit-bit tree supports
|
53
|
+
insertion, deletion, finding the minimum, and exact searches, and general suffix searches.
|
54
|
+
|
55
|
+
General-purpose comparison-based structures such as AVL trees and B-trees support exactly the
|
56
|
+
same operations as a crit-bit tree. However, crit-bit trees are faster and simpler, especially
|
57
|
+
for variable-length strings. B-trees advertise a memory layout that's friendly to your disk,
|
58
|
+
but with less effort one can use a similar "clustering" organization for nodes in a crit-bit
|
59
|
+
tree.
|
60
|
+
|
61
|
+
If you're designing a programming language, imagine how much happier your programmers will be
|
62
|
+
if your basic built-in data type allows not just looking up x, but also enumerating the
|
63
|
+
strings after x in sorted order. You can't do this with hash tables. You could do it with an
|
64
|
+
AVL tree, but your operations will be simpler and faster if you use a crit-bit tree.
|
65
|
+
|
66
|
+
Critbit Interface
|
67
|
+
=================
|
68
|
+
|
69
|
+
This version of Critbit implements a very similar interface as the Hash interface with minor
|
70
|
+
modifications when it makes sense to do so. Besides implementing the Hash interface it also
|
71
|
+
provides features for searching for keys that have a common prefix that are not possible
|
72
|
+
with hashes.
|
73
|
+
|
74
|
+
Here is an example of using Critbit:
|
75
|
+
|
76
|
+
crit = Critbit.new
|
77
|
+
|
78
|
+
# crit is space efficient and stores prefixes only once and can be used to
|
79
|
+
# find only strings that match a certain prefix
|
80
|
+
items = ["u", "un", "unh", "uni", "unj", "unim", "unin", "unio",
|
81
|
+
"uninc", "unind", "unine", "unindd", "uninde", "unindf",
|
82
|
+
"unindew", "unindex", "unindey", "a", "z"]
|
83
|
+
|
84
|
+
# add items to the container
|
85
|
+
items.each do |item|
|
86
|
+
crit[item] = item
|
87
|
+
end
|
88
|
+
|
89
|
+
# Does each for all elements in the critbit
|
90
|
+
print "["
|
91
|
+
crit.each do |key, value|
|
92
|
+
print "[#{key}, #{value}] "
|
93
|
+
end
|
94
|
+
print "]"
|
95
|
+
|
96
|
+
Prints:
|
97
|
+
|
98
|
+
[[a, a] [u, u] [un, un] [unh, unh] [uni, uni] [unim, unim] [unin, unin] [uninc, uninc]
|
99
|
+
[unind, unind] [unindd, unindd] [uninde, uninde] [unindew, unindew] [unindex, unindex]
|
100
|
+
[unindey, unindey] [unindf, unindf] [unine, unine] [unio, unio] [unj, unj] [z, z] ].
|
101
|
+
|
102
|
+
Observe that all elements are printed in sorted order, this is because critbit is
|
103
|
+
naturally sorted. This is one of the benefits of critbit over hashes.
|
104
|
+
|
105
|
+
Critbits also allow for doing prefix traversal. In the next code example the critbit is
|
106
|
+
traversed by only selecting strings that have "unin" as prefix, by passing the prefix as
|
107
|
+
argument to 'each':
|
108
|
+
|
109
|
+
# Does each for all elements in the critbit
|
110
|
+
print "["
|
111
|
+
crit.each("unin") do |key, value|
|
112
|
+
print "[#{key}, #{value}] "
|
113
|
+
end
|
114
|
+
print "]"
|
115
|
+
|
116
|
+
[[unin, unin] [uninc, uninc] [unind, unind] [unindd, unindd] [uninde, uninde]
|
117
|
+
[unindew, unindew] [unindex, unindex] [unindey, unindey] [unindf, unindf]
|
118
|
+
[unine, unine] ].
|
119
|
+
|
120
|
+
A critbit prefix can also be set by using method 'prefix=':
|
121
|
+
|
122
|
+
crit.prefix = "unin"
|
123
|
+
|
124
|
+
# Does each for all elements in the critbit
|
125
|
+
print "["
|
126
|
+
crit.each do |key, value|
|
127
|
+
print "[#{key}, #{value}] "
|
128
|
+
end
|
129
|
+
print "]"
|
130
|
+
|
131
|
+
|
132
|
+
Critbit installation and download:
|
133
|
+
==================================
|
134
|
+
|
135
|
+
+ Install Jruby
|
136
|
+
+ jruby –S gem install critbit
|
137
|
+
|
138
|
+
Critbit Homepages:
|
139
|
+
==================
|
140
|
+
|
141
|
+
+ http://rubygems.org/gems/critbit
|
142
|
+
+ https://github.com/rbotafogo/critbit/wiki
|
143
|
+
|
144
|
+
Contributors:
|
145
|
+
=============
|
146
|
+
|
147
|
+
Contributors are welcome.
|
148
|
+
|
149
|
+
Critbit History:
|
150
|
+
================
|
151
|
+
|
152
|
+
+ 05/04/2013: Version 0.5.0 – Initial release.
|
153
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require_relative 'version'
|
3
|
+
|
4
|
+
name = "#{$gem_name}-#{$version}.gem"
|
5
|
+
|
6
|
+
rule '.class' => '.java' do |t|
|
7
|
+
sh "javac #{t.source}"
|
8
|
+
end
|
9
|
+
|
10
|
+
desc 'default task'
|
11
|
+
task :default => [:install_gem]
|
12
|
+
|
13
|
+
desc 'Makes a Gem'
|
14
|
+
task :make_gem do
|
15
|
+
sh "gem build #{$gem_name}.gemspec"
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'Install the gem in the standard location'
|
19
|
+
task :install_gem => [:make_gem] do
|
20
|
+
sh "gem install #{$gem_name}-#{$version}-java.gem"
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'Make documentation'
|
24
|
+
task :make_doc do
|
25
|
+
sh "yard doc lib/*.rb lib/**/*.rb"
|
26
|
+
end
|
27
|
+
|
28
|
+
desc 'Push project to github'
|
29
|
+
task :push do
|
30
|
+
sh "git push origin master"
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'Push gem to rubygem'
|
34
|
+
task :push_gem do
|
35
|
+
sh "push #{name} -p $http_proxy"
|
36
|
+
end
|
37
|
+
|
38
|
+
Rake::TestTask.new do |t|
|
39
|
+
t.libs << "test"
|
40
|
+
t.test_files = FileList['test/complete.rb']
|
41
|
+
t.ruby_opts = ["--server", "-Xinvokedynamic.constants=true", "-J-Xmn512m",
|
42
|
+
"-J-Xms1024m", "-J-Xmx1024m"]
|
43
|
+
t.verbose = true
|
44
|
+
t.warning = true
|
45
|
+
end
|
46
|
+
|
data/config.rb
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
##########################################################################################
|
4
|
+
# Configuration. Remove setting before publishing Gem.
|
5
|
+
##########################################################################################
|
6
|
+
|
7
|
+
# set to true if development environment
|
8
|
+
# $DVLP = true
|
9
|
+
|
10
|
+
# Set development dependency: those are gems that are also in development and thus not
|
11
|
+
# installed in the gem directory. Need a way of accessing them
|
12
|
+
# $DVLP_DEPEND=["critbit"]
|
13
|
+
|
14
|
+
# Set dependencies from other local gems provided in the vendor directory.
|
15
|
+
# $VENDOR_DEPEND=[]
|
16
|
+
|
17
|
+
##########################################################################################
|
18
|
+
|
19
|
+
# the platform
|
20
|
+
@platform =
|
21
|
+
case RUBY_PLATFORM
|
22
|
+
when /mswin/ then 'windows'
|
23
|
+
when /mingw/ then 'windows'
|
24
|
+
when /bccwin/ then 'windows'
|
25
|
+
when /cygwin/ then 'windows-cygwin'
|
26
|
+
when /java/
|
27
|
+
require 'java' #:nodoc:
|
28
|
+
if java.lang.System.getProperty("os.name") =~ /[Ww]indows/
|
29
|
+
'windows-java'
|
30
|
+
else
|
31
|
+
'default-java'
|
32
|
+
end
|
33
|
+
else 'default'
|
34
|
+
end
|
35
|
+
|
36
|
+
#---------------------------------------------------------------------------------------
|
37
|
+
# Add path to load path
|
38
|
+
#---------------------------------------------------------------------------------------
|
39
|
+
|
40
|
+
def mklib(path, home_path = true)
|
41
|
+
|
42
|
+
if (home_path)
|
43
|
+
lib = path + "/lib"
|
44
|
+
else
|
45
|
+
lib = path
|
46
|
+
end
|
47
|
+
|
48
|
+
$LOAD_PATH.insert(0, lib)
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
##########################################################################################
|
53
|
+
# Prepare environment to work inside Cygwin
|
54
|
+
##########################################################################################
|
55
|
+
|
56
|
+
if @platform == 'windows-cygwin'
|
57
|
+
|
58
|
+
#---------------------------------------------------------------------------------------
|
59
|
+
# Return the cygpath of a path
|
60
|
+
#---------------------------------------------------------------------------------------
|
61
|
+
|
62
|
+
def set_path(path)
|
63
|
+
`cygpath -a -p -m #{path}`.tr("\n", "")
|
64
|
+
end
|
65
|
+
|
66
|
+
else
|
67
|
+
|
68
|
+
#---------------------------------------------------------------------------------------
|
69
|
+
# Return the path
|
70
|
+
#---------------------------------------------------------------------------------------
|
71
|
+
|
72
|
+
def set_path(path)
|
73
|
+
path
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
#---------------------------------------------------------------------------------------
|
79
|
+
# Set the project directories
|
80
|
+
#---------------------------------------------------------------------------------------
|
81
|
+
|
82
|
+
class CritbitRB
|
83
|
+
|
84
|
+
@home_dir = File.expand_path File.dirname(__FILE__)
|
85
|
+
|
86
|
+
class << self
|
87
|
+
attr_reader :home_dir
|
88
|
+
end
|
89
|
+
|
90
|
+
@project_dir = CritbitRB.home_dir + "/.."
|
91
|
+
@doc_dir = CritbitRB.home_dir + "/doc"
|
92
|
+
@lib_dir = CritbitRB.home_dir + "/lib"
|
93
|
+
@src_dir = CritbitRB.home_dir + "/src"
|
94
|
+
@target_dir = CritbitRB.home_dir + "/target"
|
95
|
+
@test_dir = CritbitRB.home_dir + "/test"
|
96
|
+
@vendor_dir = CritbitRB.home_dir + "/vendor"
|
97
|
+
|
98
|
+
class << self
|
99
|
+
attr_reader :project_dir
|
100
|
+
attr_reader :doc_dir
|
101
|
+
attr_reader :lib_dir
|
102
|
+
attr_reader :src_dir
|
103
|
+
attr_reader :target_dir
|
104
|
+
attr_reader :test_dir
|
105
|
+
attr_reader :vendor_dir
|
106
|
+
end
|
107
|
+
|
108
|
+
@build_dir = CritbitRB.src_dir + "/build"
|
109
|
+
|
110
|
+
class << self
|
111
|
+
attr_reader :build_dir
|
112
|
+
end
|
113
|
+
|
114
|
+
@classes_dir = CritbitRB.build_dir + "/classes"
|
115
|
+
|
116
|
+
class << self
|
117
|
+
attr_reader :classes_dir
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
#---------------------------------------------------------------------------------------
|
123
|
+
# Set dependencies
|
124
|
+
#---------------------------------------------------------------------------------------
|
125
|
+
|
126
|
+
def depend(name)
|
127
|
+
|
128
|
+
dependency_dir = CritbitRB.project_dir + "/" + name
|
129
|
+
mklib(dependency_dir)
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
$VENDOR_DEPEND.each do |dep|
|
134
|
+
vendor_depend(dep)
|
135
|
+
end if $VENDOR_DEPEND
|
136
|
+
|
137
|
+
##########################################################################################
|
138
|
+
# Config gem
|
139
|
+
##########################################################################################
|
140
|
+
|
141
|
+
if ($DVLP == true)
|
142
|
+
|
143
|
+
#---------------------------------------------------------------------------------------
|
144
|
+
# Set development dependencies
|
145
|
+
#---------------------------------------------------------------------------------------
|
146
|
+
|
147
|
+
def depend(name)
|
148
|
+
dependency_dir = CritbitRB.project_dir + "/" + name
|
149
|
+
mklib(dependency_dir)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Add dependencies here
|
153
|
+
# depend(<other_gems>)
|
154
|
+
$DVLP_DEPEND.each do |dep|
|
155
|
+
depend(dep)
|
156
|
+
end if $DVLP_DEPEND
|
157
|
+
|
158
|
+
#----------------------------------------------------------------------------------------
|
159
|
+
# If we need to test for coverage
|
160
|
+
#----------------------------------------------------------------------------------------
|
161
|
+
|
162
|
+
if $COVERAGE == 'true'
|
163
|
+
|
164
|
+
require 'simplecov'
|
165
|
+
|
166
|
+
SimpleCov.start do
|
167
|
+
@filters = []
|
168
|
+
add_group "CritbitRB", "lib/mdarray"
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
data/lib/critbit.rb
ADDED
@@ -0,0 +1,726 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
##########################################################################################
|
4
|
+
# @author Rodrigo Botafogo
|
5
|
+
#
|
6
|
+
# Copyright © 2013 Rodrigo Botafogo. All Rights Reserved. Permission to use, copy, modify,
|
7
|
+
# and distribute this software and its documentation, without fee and without a signed
|
8
|
+
# licensing agreement, is hereby granted, provided that the above copyright notice, this
|
9
|
+
# paragraph and the following two paragraphs appear in all copies, modifications, and
|
10
|
+
# distributions.
|
11
|
+
#
|
12
|
+
# IN NO EVENT SHALL RODRIGO BOTAFOGO BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
|
13
|
+
# INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
|
14
|
+
# THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RODRIGO BOTAFOGO HAS BEEN ADVISED OF THE
|
15
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
16
|
+
#
|
17
|
+
# RODRIGO BOTAFOGO SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
18
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
|
19
|
+
# SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
|
20
|
+
# RODRIGO BOTAFOGO HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
|
21
|
+
# OR MODIFICATIONS.
|
22
|
+
##########################################################################################
|
23
|
+
|
24
|
+
require 'java'
|
25
|
+
require_relative 'env'
|
26
|
+
|
27
|
+
|
28
|
+
##########################################################################################
|
29
|
+
#
|
30
|
+
##########################################################################################
|
31
|
+
|
32
|
+
class Critbit
|
33
|
+
include_package "io.prelink.critbit"
|
34
|
+
include_package "org.ardverk.collection"
|
35
|
+
include Enumerable
|
36
|
+
|
37
|
+
attr_reader :java_critbit
|
38
|
+
attr_reader :default
|
39
|
+
attr_reader :default_proc
|
40
|
+
attr_reader :prefix
|
41
|
+
|
42
|
+
# Critbit[ key, value, ... ] → new_hash
|
43
|
+
#
|
44
|
+
# Critbit[ [ [key, value], ... ] ] → new_hash
|
45
|
+
#
|
46
|
+
# Critbit[ object ] → new_hash
|
47
|
+
#
|
48
|
+
# Creates a new critbit populated with the given objects.
|
49
|
+
#
|
50
|
+
# Similar to the literal hash { key => value, ... }. In the first form, keys and values
|
51
|
+
# occur in pairs, so there must be an even number of arguments.
|
52
|
+
#
|
53
|
+
# The second and third form take a single argument which is either an array of
|
54
|
+
# key-value pairs or an object convertible to a hash.
|
55
|
+
#
|
56
|
+
# @param args [Args] list of arguments in any of the above formats
|
57
|
+
# @return a new Critbit
|
58
|
+
|
59
|
+
def self.[](*args)
|
60
|
+
|
61
|
+
crit = Critbit.new
|
62
|
+
|
63
|
+
if args.size == 1
|
64
|
+
|
65
|
+
if ((args[0].is_a? Hash) || (args[0].is_a? Critbit))
|
66
|
+
args[0].each do |k, v|
|
67
|
+
crit[k] = v
|
68
|
+
end
|
69
|
+
elsif (args[0].is_a? Array)
|
70
|
+
args[0].each do |key_pair|
|
71
|
+
if ((key_pair.is_a? Array) && (key_pair.size == 2))
|
72
|
+
crit[key_pair[0]] = key_pair[1]
|
73
|
+
else
|
74
|
+
raise "Illegal argument for Critbit #{key_pair}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
else
|
78
|
+
raise "illegal argument for Critbit"
|
79
|
+
end
|
80
|
+
|
81
|
+
return crit
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
if (args.size % 2 != 0)
|
86
|
+
raise "odd number of arguments for Critbit"
|
87
|
+
else
|
88
|
+
i = 0
|
89
|
+
begin
|
90
|
+
crit[args[i]] = args[i+1]
|
91
|
+
i += 2
|
92
|
+
end while i < args.size
|
93
|
+
end
|
94
|
+
|
95
|
+
return crit
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
#------------------------------------------------------------------------------------
|
100
|
+
#
|
101
|
+
#------------------------------------------------------------------------------------
|
102
|
+
|
103
|
+
def self.try_convert(arg)
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
# new → new_critbit
|
108
|
+
#
|
109
|
+
# new(obj) → new_critbit
|
110
|
+
#
|
111
|
+
# new {|critbit, key| block } → new_critbit
|
112
|
+
#
|
113
|
+
# Returns a new, empty critbit. If this critbit is subsequently accessed by a key
|
114
|
+
# that doesn’t correspond to a critbit entry, the value returned depends on the
|
115
|
+
# style of new used to create the critbit. In the first form, the access returns
|
116
|
+
# nil. If obj is specified, this single object will be used for all default values.
|
117
|
+
# If a block is specified, it will be called with the critbit object and the key,
|
118
|
+
# and should return the default value. It is the block’s responsibility to store
|
119
|
+
# the value in the critbit if required.
|
120
|
+
# @param default [Default] the default return value if the key is not found
|
121
|
+
# @param block [Block] the default block to be executed if key is not found
|
122
|
+
# @return a new critbit
|
123
|
+
|
124
|
+
def initialize(default = nil, &block)
|
125
|
+
@default = default
|
126
|
+
@default_proc = block
|
127
|
+
@prefix = nil
|
128
|
+
@java_critbit = MCritBitTree.new(StringKeyAnalyzer.new)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Element Reference—Retrieves the value object corresponding to the key object. If
|
132
|
+
# not found, returns the default value (see Hash::new for details).
|
133
|
+
# @param key (key) the key to be retrieved
|
134
|
+
# @return the value reference by this key or the default value or result of executing
|
135
|
+
# the default_proc
|
136
|
+
|
137
|
+
def[](key)
|
138
|
+
|
139
|
+
val = retrieve(key)
|
140
|
+
if (val == nil)
|
141
|
+
val = @default
|
142
|
+
val = @default_proc.call(self, key, val) if @default_proc
|
143
|
+
end
|
144
|
+
val
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
# Associates the value given by value with the key given by key.
|
149
|
+
# @param key [Key] the key element
|
150
|
+
# @param val [Value] the value associated with the key
|
151
|
+
# @return the value associated with the key
|
152
|
+
|
153
|
+
def[]=(key, val)
|
154
|
+
key = key.to_s if key.is_a? Symbol
|
155
|
+
@java_critbit.put(key, val)
|
156
|
+
end
|
157
|
+
|
158
|
+
alias store :[]=
|
159
|
+
|
160
|
+
# Searches through the critbit comparing obj with the key using ==. Returns the
|
161
|
+
# key-value pair (two elements array) or nil if no match is found. See
|
162
|
+
# Array#assoc.
|
163
|
+
# @param key [Key] the key to search for
|
164
|
+
# @return Array with two elements [key, value]
|
165
|
+
|
166
|
+
def assoc(key)
|
167
|
+
[key, retrieve(key)]
|
168
|
+
end
|
169
|
+
|
170
|
+
# Removes all key-value pairs from critbit
|
171
|
+
|
172
|
+
def clear
|
173
|
+
@java_critbit.clear
|
174
|
+
end
|
175
|
+
|
176
|
+
# Returns the default value, the value that would be returned by critbit if key did
|
177
|
+
# not exist in critbit. See also Critbit::new and Critbit#default=
|
178
|
+
# @param val [Value] the default value to return
|
179
|
+
|
180
|
+
def default=(val)
|
181
|
+
@default = val
|
182
|
+
end
|
183
|
+
|
184
|
+
# Sets the default proc to be executed on each failed key lookup.
|
185
|
+
# @param proc [Proc] the Proc to set as default_proc
|
186
|
+
|
187
|
+
def default_proc=(proc)
|
188
|
+
@default_proc = proc
|
189
|
+
end
|
190
|
+
|
191
|
+
# Deletes the key-value pair and returns the value from critbit whose key is equal to
|
192
|
+
# key. If the key is not found, returns the default value. If the optional code block
|
193
|
+
# is given and the key is not found, pass in the key and return the result of block.
|
194
|
+
# @param key [Key]
|
195
|
+
# @return the value, the default value, or the result of applying the default block
|
196
|
+
# to key
|
197
|
+
|
198
|
+
def delete(key)
|
199
|
+
|
200
|
+
val = @java_critbit.remove(key)
|
201
|
+
# key not found
|
202
|
+
if (val == nil)
|
203
|
+
if block_given?
|
204
|
+
yield key
|
205
|
+
end
|
206
|
+
@default
|
207
|
+
end
|
208
|
+
val
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
# Deletes every key-value pair from hsh for which block evaluates to true.
|
213
|
+
#
|
214
|
+
# If no block is given, an enumerator is returned instead.
|
215
|
+
|
216
|
+
def delete_if(prefix = nil, &block)
|
217
|
+
|
218
|
+
if block_given?
|
219
|
+
cursor = Critbit::DeleteCursor.new(self, true, &block)
|
220
|
+
_get(cursor, prefix)
|
221
|
+
else
|
222
|
+
to_enum(:each, prefix)
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
alias reject! :delete_if
|
228
|
+
|
229
|
+
# Calls block once for each key in critbit, passing the key-value pair as parameters.
|
230
|
+
#
|
231
|
+
# If no block is given, an enumerator is returned instead.
|
232
|
+
|
233
|
+
def each(prefix = nil, &block)
|
234
|
+
|
235
|
+
if block_given?
|
236
|
+
cursor = Critbit::EachCursor.new(&block)
|
237
|
+
_get(cursor, prefix)
|
238
|
+
else
|
239
|
+
to_enum(:each, prefix)
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
alias each_pair :each
|
245
|
+
|
246
|
+
|
247
|
+
# Calls block once for each key in critbit, passing the key as a parameter.
|
248
|
+
#
|
249
|
+
# If no block is given, an enumerator is returned instead.
|
250
|
+
|
251
|
+
def each_key(prefix = nil, &block)
|
252
|
+
|
253
|
+
if block_given?
|
254
|
+
cursor = Critbit::EachKeyCursor.new(&block)
|
255
|
+
_get(cursor, prefix)
|
256
|
+
else
|
257
|
+
to_enum(:each, prefix)
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|
261
|
+
|
262
|
+
# Calls block once for each value in critbit, passing the value as a parameter.
|
263
|
+
#
|
264
|
+
# If no block is given, an enumerator is returned instead.
|
265
|
+
|
266
|
+
def each_value(prefix = nil, &block)
|
267
|
+
|
268
|
+
if block_given?
|
269
|
+
cursor = Critbit::EachValueCursor.new(&block)
|
270
|
+
_get(cursor, prefix)
|
271
|
+
else
|
272
|
+
to_enum(:each, prefix)
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|
276
|
+
|
277
|
+
# Returns true if critbit contains no key-value pairs.
|
278
|
+
|
279
|
+
def empty?
|
280
|
+
@size == 0
|
281
|
+
end
|
282
|
+
|
283
|
+
|
284
|
+
def eql?(other)
|
285
|
+
|
286
|
+
cr1 = each
|
287
|
+
cr2 = other.each
|
288
|
+
|
289
|
+
begin
|
290
|
+
p1 = cr1.next
|
291
|
+
p2 = cr2.next
|
292
|
+
if ((p1[0] != p2[0]) || (p1[1] != p2[1]))
|
293
|
+
return false
|
294
|
+
end
|
295
|
+
rescue StopIteration
|
296
|
+
break
|
297
|
+
end while true
|
298
|
+
|
299
|
+
i = 0
|
300
|
+
begin
|
301
|
+
cr1.next
|
302
|
+
rescue StopIteration
|
303
|
+
i += 1
|
304
|
+
end
|
305
|
+
|
306
|
+
begin
|
307
|
+
cr2.next
|
308
|
+
rescue StopIteration
|
309
|
+
i += 1
|
310
|
+
end
|
311
|
+
|
312
|
+
return false if i != 2
|
313
|
+
|
314
|
+
return true
|
315
|
+
|
316
|
+
end
|
317
|
+
|
318
|
+
# Returns a value from the critbit for the given key. If the key can’t be found,
|
319
|
+
# there are several options: With no other arguments, it will raise an KeyError exception;
|
320
|
+
# if default is given, then that will be returned; if the optional code block is
|
321
|
+
# specified, then that will be run and its result returned.
|
322
|
+
|
323
|
+
def fetch(key, default = nil, &block)
|
324
|
+
|
325
|
+
key = key.to_s if key.is_a? Symbol
|
326
|
+
res = @java_critbit.get(key)
|
327
|
+
|
328
|
+
if (res == nil)
|
329
|
+
if (default != nil)
|
330
|
+
return default
|
331
|
+
elsif (block_given?)
|
332
|
+
block.call(key)
|
333
|
+
else
|
334
|
+
raise KeyError, "key '#{key}' not found"
|
335
|
+
end
|
336
|
+
end
|
337
|
+
res
|
338
|
+
|
339
|
+
end
|
340
|
+
|
341
|
+
# Returns a new array that is a one-dimensional flattening of this critbit. That is, for
|
342
|
+
# every key or value that is an array, extract its elements into the new array. The
|
343
|
+
# optional level argument determines the level of recursion to flatten if the value is
|
344
|
+
# a hash. If value is an Array it will call array.flatten
|
345
|
+
|
346
|
+
def flatten(level = nil)
|
347
|
+
|
348
|
+
res = Array.new
|
349
|
+
each do |key, value|
|
350
|
+
res << key
|
351
|
+
case value
|
352
|
+
when (Array || Hash || Critbit)
|
353
|
+
(level)? res.concat(value.flatten(level)) : res.concat(value.flatten)
|
354
|
+
else
|
355
|
+
(value.respond_to?(:flatten))? res << value.flatten : res << value
|
356
|
+
end
|
357
|
+
end
|
358
|
+
res
|
359
|
+
|
360
|
+
end
|
361
|
+
|
362
|
+
# Returns true if the given key is present in critbit
|
363
|
+
|
364
|
+
def has_key?(key)
|
365
|
+
@java_critbit.containsKey(key)
|
366
|
+
end
|
367
|
+
|
368
|
+
# Returns true if the given key is present in critbit. Identical to has_key?
|
369
|
+
|
370
|
+
alias include? :has_key?
|
371
|
+
alias member? :has_key?
|
372
|
+
alias key? :has_key?
|
373
|
+
|
374
|
+
# Returns true if the given value is present for some key in critbit.
|
375
|
+
|
376
|
+
def has_value?(val)
|
377
|
+
@java_critbit.containsValue(val)
|
378
|
+
end
|
379
|
+
|
380
|
+
# Return the contents of this critbit as a string.
|
381
|
+
|
382
|
+
def inspect
|
383
|
+
|
384
|
+
res = "{"
|
385
|
+
each do |key, value|
|
386
|
+
res << "\"#{key}\"=>#{value},"
|
387
|
+
end
|
388
|
+
res[-1] = "}"
|
389
|
+
return res
|
390
|
+
|
391
|
+
end
|
392
|
+
|
393
|
+
# Return the contents of this critbit as a string.
|
394
|
+
|
395
|
+
alias to_s :inspect
|
396
|
+
|
397
|
+
# Returns a new critbit created by using critbit’s values as keys, and the keys as
|
398
|
+
# values.
|
399
|
+
|
400
|
+
def invert
|
401
|
+
|
402
|
+
crit = Critbit.new
|
403
|
+
each do |key, value|
|
404
|
+
crit[value.to_s] = key
|
405
|
+
end
|
406
|
+
crit
|
407
|
+
|
408
|
+
end
|
409
|
+
|
410
|
+
# Deletes every key-value pair from critbit for which block evaluates to false.
|
411
|
+
|
412
|
+
def keep_if(prefix = nil, &block)
|
413
|
+
|
414
|
+
if block_given?
|
415
|
+
cursor = Critbit::DeleteCursor.new(self, false, &block)
|
416
|
+
_get(cursor, prefix)
|
417
|
+
else
|
418
|
+
to_enum(:each, prefix)
|
419
|
+
end
|
420
|
+
|
421
|
+
end
|
422
|
+
|
423
|
+
alias select! :keep_if
|
424
|
+
|
425
|
+
# Returns the key of an occurrence of a given value. If the value is not found,
|
426
|
+
# returns nil.
|
427
|
+
|
428
|
+
def key(val)
|
429
|
+
|
430
|
+
each do |key, value|
|
431
|
+
return key if (value == val)
|
432
|
+
end
|
433
|
+
return nil
|
434
|
+
|
435
|
+
end
|
436
|
+
|
437
|
+
# Returns a new array populated with the keys from this critbit
|
438
|
+
|
439
|
+
def keys(prefix = nil)
|
440
|
+
cursor = Critbit::ListCursor.new(:key)
|
441
|
+
_get(cursor, prefix).list
|
442
|
+
end
|
443
|
+
|
444
|
+
# Returns a new critbit containing the contents of other_critbit and the contents
|
445
|
+
# of critbit. If no block is specified, the value for entries with duplicate keys will be
|
446
|
+
# that of other_critbit. Otherwise the value for each duplicate key is determined by
|
447
|
+
# calling the block with the key, its value in critbit and its value in other_critbit.
|
448
|
+
|
449
|
+
def merge(other_critbit, &block)
|
450
|
+
|
451
|
+
crit = Critbit[self]
|
452
|
+
if (block_given?)
|
453
|
+
other_critbit.each do |key, value|
|
454
|
+
value = block.call(key, self[key], value) if has_key?(key)
|
455
|
+
crit[key] = value
|
456
|
+
end
|
457
|
+
else
|
458
|
+
other_critbit.each do |key, value|
|
459
|
+
crit[key] = value
|
460
|
+
end
|
461
|
+
end
|
462
|
+
crit
|
463
|
+
|
464
|
+
end
|
465
|
+
|
466
|
+
alias update :merge
|
467
|
+
|
468
|
+
# Returns a new critbit containing the contents of other_critbit and the contents
|
469
|
+
# of critbit. If no block is specified, the value for entries with duplicate keys will be
|
470
|
+
# that of other_critbit. Otherwise the value for each duplicate key is determined by
|
471
|
+
# calling the block with the key, its value in critbit and its value in other_critbit.
|
472
|
+
|
473
|
+
def merge!(other_critbit, &block)
|
474
|
+
|
475
|
+
if (block_given?)
|
476
|
+
other_critbit.each do |key, value|
|
477
|
+
value = block.call(key, self[key], value) if has_key?(key)
|
478
|
+
self[key] = value
|
479
|
+
end
|
480
|
+
else
|
481
|
+
other_critbit.each do |key, value|
|
482
|
+
self[key] = value
|
483
|
+
end
|
484
|
+
end
|
485
|
+
self
|
486
|
+
|
487
|
+
end
|
488
|
+
|
489
|
+
#------------------------------------------------------------------------------------
|
490
|
+
#
|
491
|
+
#------------------------------------------------------------------------------------
|
492
|
+
|
493
|
+
def prefix=(pre)
|
494
|
+
@prefix = pre
|
495
|
+
end
|
496
|
+
|
497
|
+
# Searches through the critbit comparing obj with the value using ==. Returns the first
|
498
|
+
# key-value pair (two-element array) that matches. See also Array#rassoc.
|
499
|
+
|
500
|
+
def rassoc(obj)
|
501
|
+
|
502
|
+
each do |key, value|
|
503
|
+
return [key, value] if obj == value
|
504
|
+
end
|
505
|
+
nil
|
506
|
+
|
507
|
+
end
|
508
|
+
|
509
|
+
#------------------------------------------------------------------------------------
|
510
|
+
#
|
511
|
+
#------------------------------------------------------------------------------------
|
512
|
+
|
513
|
+
def size
|
514
|
+
@java_critbit.size()
|
515
|
+
end
|
516
|
+
|
517
|
+
alias length :size
|
518
|
+
|
519
|
+
#------------------------------------------------------------------------------------
|
520
|
+
#
|
521
|
+
#------------------------------------------------------------------------------------
|
522
|
+
|
523
|
+
def values(prefix = nil)
|
524
|
+
cursor = Critbit::ListCursor.new(:value)
|
525
|
+
_get(cursor, prefix).list
|
526
|
+
end
|
527
|
+
|
528
|
+
#------------------------------------------------------------------------------------
|
529
|
+
#
|
530
|
+
#------------------------------------------------------------------------------------
|
531
|
+
|
532
|
+
# Methods that are not in Hash interface
|
533
|
+
|
534
|
+
#------------------------------------------------------------------------------------
|
535
|
+
#
|
536
|
+
#------------------------------------------------------------------------------------
|
537
|
+
|
538
|
+
def min
|
539
|
+
@java_critbit.min
|
540
|
+
end
|
541
|
+
|
542
|
+
#------------------------------------------------------------------------------------
|
543
|
+
#
|
544
|
+
#------------------------------------------------------------------------------------
|
545
|
+
|
546
|
+
def max
|
547
|
+
@java_critbit.max
|
548
|
+
end
|
549
|
+
|
550
|
+
#------------------------------------------------------------------------------------
|
551
|
+
# Merges the two critbits. Should be significantly faster than method merge.
|
552
|
+
#------------------------------------------------------------------------------------
|
553
|
+
|
554
|
+
def put_all(other_critbit)
|
555
|
+
@java_critbit.putAll(other_critbit.java_critbit)
|
556
|
+
end
|
557
|
+
|
558
|
+
#------------------------------------------------------------------------------------
|
559
|
+
# Removes the key value pair from the critbit. If no key is found, nil is returned.
|
560
|
+
#------------------------------------------------------------------------------------
|
561
|
+
|
562
|
+
def remove(key)
|
563
|
+
@java_critbit.remove(key)
|
564
|
+
end
|
565
|
+
|
566
|
+
#------------------------------------------------------------------------------------
|
567
|
+
#
|
568
|
+
#------------------------------------------------------------------------------------
|
569
|
+
|
570
|
+
private
|
571
|
+
|
572
|
+
#------------------------------------------------------------------------------------
|
573
|
+
#
|
574
|
+
#------------------------------------------------------------------------------------
|
575
|
+
|
576
|
+
def retrieve(key)
|
577
|
+
key = key.to_s if key.is_a? Symbol
|
578
|
+
@java_critbit.get(key)
|
579
|
+
end
|
580
|
+
|
581
|
+
#------------------------------------------------------------------------------------
|
582
|
+
#
|
583
|
+
#------------------------------------------------------------------------------------
|
584
|
+
|
585
|
+
def _get(cursor, prefix = nil)
|
586
|
+
prefix ||= @prefix
|
587
|
+
(prefix)? @java_critbit.traverseWithPrefix(prefix, cursor) :
|
588
|
+
@java_critbit.traverse(cursor)
|
589
|
+
cursor
|
590
|
+
end
|
591
|
+
|
592
|
+
##########################################################################################
|
593
|
+
#
|
594
|
+
##########################################################################################
|
595
|
+
|
596
|
+
class Cursor
|
597
|
+
include org.ardverk.collection.Cursor
|
598
|
+
|
599
|
+
attr_reader :key
|
600
|
+
attr_reader :value
|
601
|
+
|
602
|
+
#------------------------------------------------------------------------------------
|
603
|
+
#
|
604
|
+
#------------------------------------------------------------------------------------
|
605
|
+
|
606
|
+
def initialize(&block)
|
607
|
+
@block = block
|
608
|
+
end
|
609
|
+
|
610
|
+
end
|
611
|
+
|
612
|
+
##########################################################################################
|
613
|
+
#
|
614
|
+
##########################################################################################
|
615
|
+
|
616
|
+
class EachCursor < Cursor
|
617
|
+
|
618
|
+
#------------------------------------------------------------------------------------
|
619
|
+
#
|
620
|
+
#------------------------------------------------------------------------------------
|
621
|
+
|
622
|
+
def select(entry)
|
623
|
+
@block.call(entry.getKey(), entry.getValue())
|
624
|
+
Decision::CONTINUE
|
625
|
+
end
|
626
|
+
|
627
|
+
end
|
628
|
+
|
629
|
+
##########################################################################################
|
630
|
+
#
|
631
|
+
##########################################################################################
|
632
|
+
|
633
|
+
class EachKeyCursor < Cursor
|
634
|
+
|
635
|
+
#------------------------------------------------------------------------------------
|
636
|
+
#
|
637
|
+
#------------------------------------------------------------------------------------
|
638
|
+
|
639
|
+
def select(entry)
|
640
|
+
@block.call(entry.getKey())
|
641
|
+
Decision::CONTINUE
|
642
|
+
end
|
643
|
+
|
644
|
+
end
|
645
|
+
|
646
|
+
##########################################################################################
|
647
|
+
#
|
648
|
+
##########################################################################################
|
649
|
+
|
650
|
+
class EachValueCursor < Cursor
|
651
|
+
|
652
|
+
#------------------------------------------------------------------------------------
|
653
|
+
#
|
654
|
+
#------------------------------------------------------------------------------------
|
655
|
+
|
656
|
+
def select(entry)
|
657
|
+
@block.call(entry.getValue())
|
658
|
+
Decision::CONTINUE
|
659
|
+
end
|
660
|
+
|
661
|
+
end
|
662
|
+
|
663
|
+
##########################################################################################
|
664
|
+
#
|
665
|
+
##########################################################################################
|
666
|
+
|
667
|
+
class DeleteCursor < Cursor
|
668
|
+
|
669
|
+
#------------------------------------------------------------------------------------
|
670
|
+
#
|
671
|
+
#------------------------------------------------------------------------------------
|
672
|
+
|
673
|
+
def initialize(critbit, t_val = true, &block)
|
674
|
+
@critbit = critbit
|
675
|
+
@t_val = t_val
|
676
|
+
super(&block)
|
677
|
+
end
|
678
|
+
|
679
|
+
#------------------------------------------------------------------------------------
|
680
|
+
#
|
681
|
+
#------------------------------------------------------------------------------------
|
682
|
+
|
683
|
+
def select(entry)
|
684
|
+
@critbit.delete(entry.getKey()) if (@block.call(entry.getKey(),
|
685
|
+
entry.getValue()) == @t_val)
|
686
|
+
Decision::CONTINUE
|
687
|
+
end
|
688
|
+
|
689
|
+
end
|
690
|
+
|
691
|
+
##########################################################################################
|
692
|
+
#
|
693
|
+
##########################################################################################
|
694
|
+
|
695
|
+
class ListCursor < Cursor
|
696
|
+
|
697
|
+
attr_reader :list
|
698
|
+
attr_reader :type
|
699
|
+
|
700
|
+
#------------------------------------------------------------------------------------
|
701
|
+
#
|
702
|
+
#------------------------------------------------------------------------------------
|
703
|
+
|
704
|
+
def initialize(type)
|
705
|
+
|
706
|
+
if (type != :key && type != :value)
|
707
|
+
raise "Illegal type #{type}"
|
708
|
+
end
|
709
|
+
|
710
|
+
@type = type
|
711
|
+
@list = Array.new
|
712
|
+
|
713
|
+
end
|
714
|
+
|
715
|
+
#------------------------------------------------------------------------------------
|
716
|
+
#
|
717
|
+
#------------------------------------------------------------------------------------
|
718
|
+
|
719
|
+
def select(entry)
|
720
|
+
@list << ((@type == :key)? entry.getKey() : entry.getValue())
|
721
|
+
Decision::CONTINUE
|
722
|
+
end
|
723
|
+
|
724
|
+
end
|
725
|
+
|
726
|
+
end
|