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.
@@ -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