critbit 0.5.0-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
+
@@ -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
+
@@ -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
+
@@ -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
@@ -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