├── .gitignore
├── .travis.yml
├── LICENSE
├── NOTICE
├── README.md
├── benchmarks
├── com.metamx.collections.bitmap.RangeBitmapBenchmarkTest.html
├── com.metamx.collections.bitmap.RangeBitmapBenchmarkTest.jsonp
├── com.metamx.collections.bitmap.UniformBitmapBenchmarkTest.html
└── com.metamx.collections.bitmap.UniformBitmapBenchmarkTest.jsonp
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── metamx
│ └── collections
│ ├── IntegerSet.java
│ ├── bitmap
│ ├── BitSetBitmapFactory.java
│ ├── BitmapFactory.java
│ ├── ConciseBitmapFactory.java
│ ├── ImmutableBitmap.java
│ ├── MutableBitmap.java
│ ├── RoaringBitmapFactory.java
│ ├── WrappedBitSetBitmap.java
│ ├── WrappedConciseBitmap.java
│ ├── WrappedConciseIntIterator.java
│ ├── WrappedImmutableBitSetBitmap.java
│ ├── WrappedImmutableConciseBitmap.java
│ ├── WrappedImmutableRoaringBitmap.java
│ └── WrappedRoaringBitmap.java
│ └── spatial
│ ├── ImmutableNode.java
│ ├── ImmutablePoint.java
│ ├── ImmutableRTree.java
│ ├── Node.java
│ ├── Point.java
│ ├── RTree.java
│ ├── RTreeUtils.java
│ ├── search
│ ├── Bound.java
│ ├── GutmanSearchStrategy.java
│ ├── PolygonBound.java
│ ├── RadiusBound.java
│ ├── RectangularBound.java
│ └── SearchStrategy.java
│ └── split
│ ├── GutmanSplitStrategy.java
│ ├── LinearGutmanSplitStrategy.java
│ ├── QuadraticGutmanSplitStrategy.java
│ └── SplitStrategy.java
└── test
└── java
└── com
└── metamx
├── collections
├── IntSetTestUtility.java
├── TestIntegerSet.java
├── bitmap
│ ├── BitmapBenchmark.java
│ ├── ConciseBitmapFactoryTest.java
│ ├── RangeBitmapBenchmarkTest.java
│ ├── RoaringBitmapFactoryTest.java
│ ├── UniformBitmapBenchmarkTest.java
│ ├── WrappedBitSetBitmapBitSetTest.java
│ └── WrappedRoaringBitmapTest.java
└── spatial
│ ├── ImmutableRTreeTest.java
│ ├── RTreeTest.java
│ ├── search
│ ├── PolygonBoundTest.java
│ ├── RadiusBoundTest.java
│ └── RectangularBoundTest.java
│ └── split
│ └── LinearGutmanSplitStrategyTest.java
└── test
└── annotation
├── Benchmark.java
└── Dummy.java
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | target
3 | *.iml
4 | *.ipr
5 | *.iws
6 | *.tar.gz
7 | *.swp
8 | *.swo
9 | .classpath
10 | .idea
11 | .project
12 | .settings/org.eclipse.jdt.core.prefs
13 | .settings/org.maven.ide.eclipse.prefs
14 | client/.settings/org.eclipse.jdt.core.prefs
15 | common/.settings/org.eclipse.jdt.core.prefs
16 | server/.settings/org.eclipse.jdt.core.prefs
17 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 |
3 | jdk:
4 | - oraclejdk7
5 | - oraclejdk8
6 |
7 | sudo: false
8 |
9 | cache:
10 | directories:
11 | - $HOME/.m2
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | bytebuffer-collections
2 | Copyright 2011-2015 Metamarkets Group Inc.
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | bytebuffer-collections
2 | ======================
3 |
4 | ByteBuffer collection classes for java and jvm-based languages.
5 |
6 | # Benchmarks
7 |
8 | To run benchmarks, use the maven benchmark profile:
9 | ```sh
10 | mvn test -P benchmark
11 | ```
12 |
--------------------------------------------------------------------------------
/benchmarks/com.metamx.collections.bitmap.RangeBitmapBenchmarkTest.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Benchmark results for methods in class com.metamx.collections.bitmap.RangeBitmapBenchmarkTest
6 |
7 |
8 |
12 |
13 |
50 |
51 |
101 |
102 |
103 |
104 |
105 |
Benchmark results for methods in class com.metamx.collections.bitmap.RangeBitmapBenchmarkTest
106 |
107 |
108 |
109 |
110 |
111 |
112 |
Shows historical runs: 20
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/benchmarks/com.metamx.collections.bitmap.RangeBitmapBenchmarkTest.jsonp:
--------------------------------------------------------------------------------
1 | receiveJsonpData({
2 | "cols": [
3 | {"label": "Run", "type": "string"},
4 | {"label": "Custom key", "type": "string"},
5 | {"label": "Timestamp", "type": "string"},
6 | {"label": "timeConciseUnion", "type": "string"} ,
7 | {"label": "timeGenericConciseIntersection", "type": "string"} ,
8 | {"label": "timeGenericConciseUnion", "type": "string"} ,
9 | {"label": "timeGenericRoaringIntersection", "type": "string"} ,
10 | {"label": "timeGenericRoaringUnion", "type": "string"} ,
11 | {"label": "timeImmutableRoaringUnion", "type": "string"} ,
12 | {"label": "timeOffheapConciseUnion", "type": "string"} ,
13 | {"label": "timeOffheapRoaringUnion", "type": "string"} ,
14 | {"label": "timeRoaringUnion", "type": "string"} ],
15 | "rows": [
16 | {"c": [{"v": "5"}, {"v": "0.00001"}, {"v": "2014-11-04 14:03:04.268"}, {"v": 80.304}, {"v": 79.758}, {"v": 65.896}, {"v": 0.008}, {"v": 0.278}, {"v": 0.596}, {"v": 70.89}, {"v": 0.275}, {"v": 0.202}]},
17 | {"c": [{"v": "1"}, {"v": "0.0001"}, {"v": "2014-11-04 13:32:21.752"}, {"v": 30.843}, {"v": 30.863}, {"v": 32.306}, {"v": 0.012}, {"v": 0.272}, {"v": 0.546}, {"v": 32.727}, {"v": 0.327}, {"v": 0.158}]},
18 | {"c": [{"v": "2"}, {"v": "0.0010"}, {"v": "2014-11-04 13:41:55.608"}, {"v": 3.801}, {"v": 3.441}, {"v": 3.421}, {"v": 0.019}, {"v": 0.272}, {"v": 0.524}, {"v": 3.76}, {"v": 0.271}, {"v": 0.171}]},
19 | {"c": [{"v": "3"}, {"v": "0.0100"}, {"v": "2014-11-04 13:45:36.077"}, {"v": 0.341}, {"v": 0.541}, {"v": 0.628}, {"v": 0.025}, {"v": 0.276}, {"v": 0.576}, {"v": 0.352}, {"v": 0.276}, {"v": 0.263}]},
20 | {"c": [{"v": "4"}, {"v": "0.1000"}, {"v": "2014-11-04 13:49:27.509"}, {"v": 0.051}, {"v": 0.062}, {"v": 0.046}, {"v": 0.039}, {"v": 0.295}, {"v": 0.47}, {"v": 0.045}, {"v": 0.299}, {"v": 0.181}]},
21 | {"c": [{"v": "38"}, {"v": "0.25000"}, {"v": "2014-11-04 15:22:42.446"}, {"v": 0.036}, {"v": 0.041}, {"v": 0.04}, {"v": 0.052}, {"v": 0.179}, {"v": 0.391}, {"v": 0.042}, {"v": 0.18}, {"v": 0.105}]}
22 | ]});
23 |
--------------------------------------------------------------------------------
/benchmarks/com.metamx.collections.bitmap.UniformBitmapBenchmarkTest.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Benchmark results for methods in class com.metamx.collections.bitmap.UniformBitmapBenchmarkTest
6 |
7 |
8 |
12 |
13 |
50 |
51 |
101 |
102 |
103 |
104 |
105 |
Benchmark results for methods in class com.metamx.collections.bitmap.UniformBitmapBenchmarkTest
106 |
107 |
108 |
109 |
110 |
111 |
112 |
Shows historical runs: 20
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/benchmarks/com.metamx.collections.bitmap.UniformBitmapBenchmarkTest.jsonp:
--------------------------------------------------------------------------------
1 | receiveJsonpData({
2 | "cols": [
3 | {"label": "Run", "type": "string"},
4 | {"label": "Custom key", "type": "string"},
5 | {"label": "Timestamp", "type": "string"},
6 | {"label": "timeConciseUnion", "type": "string"} ,
7 | {"label": "timeGenericConciseIntersection", "type": "string"} ,
8 | {"label": "timeGenericConciseUnion", "type": "string"} ,
9 | {"label": "timeGenericRoaringIntersection", "type": "string"} ,
10 | {"label": "timeGenericRoaringUnion", "type": "string"} ,
11 | {"label": "timeImmutableRoaringUnion", "type": "string"} ,
12 | {"label": "timeOffheapConciseUnion", "type": "string"} ,
13 | {"label": "timeOffheapRoaringUnion", "type": "string"} ,
14 | {"label": "timeRoaringUnion", "type": "string"} ],
15 | "rows": [
16 | {"c": [{"v": "6"}, {"v": "0.0001"}, {"v": "2014-11-04 11:41:24.142"}, {"v": 1.099}, {"v": 0.401}, {"v": 1.391}, {"v": 0.02}, {"v": 0.131}, {"v": 0.104}, {"v": 1.171}, {"v": 0.132}, {"v": 0.091}]},
17 | {"c": [{"v": "5"}, {"v": "0.0010"}, {"v": "2014-11-04 11:37:12.305"}, {"v": 6.989}, {"v": 0.595}, {"v": 7.4}, {"v": 0.026}, {"v": 0.144}, {"v": 0.098}, {"v": 7.95}, {"v": 0.139}, {"v": 0.066}]},
18 | {"c": [{"v": "4"}, {"v": "0.0100"}, {"v": "2014-11-04 11:23:42.26"}, {"v": 50.259}, {"v": 4.768}, {"v": 51.716}, {"v": 0.053}, {"v": 0.563}, {"v": 0.223}, {"v": 54.117}, {"v": 0.59}, {"v": 0.175}]},
19 | {"c": [{"v": "8"}, {"v": "0.1000"}, {"v": "2014-11-04 12:19:56.926"}, {"v": 64.505}, {"v": 23.741}, {"v": 63.565}, {"v": 0.031}, {"v": 0.353}, {"v": 0.528}, {"v": 59.636}, {"v": 0.352}, {"v": 0.155}]},
20 | {"c": [{"v": "7"}, {"v": "0.2500"}, {"v": "2014-11-04 11:52:42.488"}, {"v": 67.57}, {"v": 64.276}, {"v": 60.747}, {"v": 0.021}, {"v": 0.275}, {"v": 0.523}, {"v": 69.835}, {"v": 0.251}, {"v": 0.178}]},
21 | {"c": [{"v": "2"}, {"v": "0.5000"}, {"v": "2014-11-04 10:19:33.921"}, {"v": 66.058}, {"v": 67.714}, {"v": 64.162}, {"v": 0.026}, {"v": 0.264}, {"v": 0.541}, {"v": 66.445}, {"v": 0.281}, {"v": 0.168}]},
22 | {"c": [{"v": "3"}, {"v": "0.7500"}, {"v": "2014-11-04 10:44:45.546"}, {"v": 65.028}, {"v": 70.115}, {"v": 63.475}, {"v": 0.027}, {"v": 0.284}, {"v": 0.574}, {"v": 68.909}, {"v": 0.295}, {"v": 0.195}]}
23 | ]});
24 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | 4.0.0
20 |
21 |
22 | com.metamx
23 | oss-parent
24 | 2
25 |
26 |
27 | bytebuffer-collections
28 | 0.3.3-SNAPSHOT
29 |
30 | ${project.groupId}:${project.artifactId}
31 | ByteBuffer Collections
32 | https://github.com/metamx/bytebuffer-collections
33 |
34 |
35 |
36 | Apache License, Version 2.0
37 | http://www.apache.org/licenses/LICENSE-2.0
38 |
39 |
40 |
41 |
42 | scm:git:ssh://git@github.com/metamx/bytebuffer-collections.git
43 | scm:git:ssh://git@github.com/metamx/bytebuffer-collections.git
44 | https://github.com/metamx/bytebuffer-collections.git
45 | HEAD
46 |
47 |
48 |
49 |
50 | Metamarkets Open Source Team
51 | oss@metamarkets.com
52 | Metamarkets Group Inc.
53 | https://www.metamarkets.com
54 |
55 |
56 |
57 |
58 |
59 | com.metamx
60 | extendedset
61 | 1.4.2
62 |
63 |
64 | com.google.guava
65 | guava
66 | 16.0.1
67 |
68 |
69 | com.fasterxml.jackson.core
70 | jackson-annotations
71 | 2.4.6
72 |
73 |
74 | com.fasterxml.jackson.core
75 | jackson-core
76 | 2.4.6
77 |
78 |
79 | com.fasterxml.jackson.core
80 | jackson-databind
81 | 2.4.6
82 |
83 |
84 | org.roaringbitmap
85 | RoaringBitmap
86 | 0.5.18
87 |
88 |
89 |
90 |
91 | junit
92 | junit
93 | 4.12
94 | test
95 |
96 |
97 | org.easymock
98 | easymock
99 | 3.0
100 | test
101 |
102 |
103 | com.carrotsearch
104 | junit-benchmarks
105 | 0.7.2
106 | test
107 |
108 |
109 | com.h2database
110 | h2
111 | 1.4.182
112 | test
113 |
114 |
115 |
116 |
117 |
118 |
119 | org.apache.maven.plugins
120 | maven-compiler-plugin
121 | 2.5.1
122 |
123 | 1.7
124 | 1.7
125 |
126 |
127 |
128 | org.apache.maven.plugins
129 | maven-jar-plugin
130 | 2.4
131 |
132 |
133 |
134 | test-jar
135 |
136 |
137 |
138 |
139 |
140 | org.apache.maven.plugins
141 | maven-release-plugin
142 |
143 |
144 | org.apache.maven.plugins
145 | maven-surefire-plugin
146 | 2.18.1
147 |
148 | com.metamx.test.annotation.Benchmark
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 | benchmark
157 |
158 |
159 |
160 | maven-surefire-plugin
161 |
162 | -server -Xms3G -Xmx3G -Djub.consumers=CONSOLE,H2 -Djub.db.file=benchmarks/benchmarks
163 | com.metamx.test.annotation.Benchmark
164 | com.metamx.test.annotation.Dummy
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/IntegerSet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections;
18 |
19 | import com.google.common.collect.Sets;
20 | import com.metamx.collections.bitmap.MutableBitmap;
21 | import org.roaringbitmap.IntIterator;
22 |
23 | import java.util.Collection;
24 | import java.util.Iterator;
25 | import java.util.Set;
26 |
27 | /**
28 | *
29 | */
30 | public class IntegerSet implements Set
31 | {
32 | private final MutableBitmap mutableBitmap;
33 |
34 | private IntegerSet(MutableBitmap mutableBitmap)
35 | {
36 | this.mutableBitmap = mutableBitmap;
37 | }
38 |
39 | public static IntegerSet wrap(MutableBitmap mutableBitmap)
40 | {
41 | return new IntegerSet(mutableBitmap);
42 | }
43 |
44 | @Override
45 | public int size()
46 | {
47 | return this.mutableBitmap.size();
48 | }
49 |
50 | @Override
51 | public boolean isEmpty()
52 | {
53 | return this.mutableBitmap.isEmpty();
54 | }
55 |
56 |
57 | public static class BitSetIterator implements Iterator
58 | {
59 | private final IntIterator intIt;
60 | private final MutableBitmap bitSet;
61 | private Integer prior = null;
62 |
63 | public BitSetIterator(MutableBitmap bitSet)
64 | {
65 | this.intIt = bitSet.iterator();
66 | this.bitSet = bitSet;
67 | }
68 |
69 | @Override
70 | public boolean hasNext()
71 | {
72 | return intIt.hasNext();
73 | }
74 |
75 | @Override
76 | public Integer next()
77 | {
78 | prior = intIt.next();
79 | return prior;
80 | }
81 |
82 | @Override
83 | public void remove()
84 | {
85 | bitSet.remove(prior);
86 | }
87 | }
88 |
89 | @Override
90 | public boolean contains(Object o)
91 | {
92 | if (o instanceof Integer) {
93 | return mutableBitmap.get((Integer) o);
94 | } else if (o instanceof Long) {
95 | return this.contains(((Long) o).intValue());
96 | }
97 | return false;
98 | }
99 |
100 | @Override
101 | public Iterator iterator()
102 | {
103 | return new BitSetIterator(mutableBitmap);
104 | }
105 |
106 | @Override
107 | public Object[] toArray()
108 | {
109 | Integer[] retval = new Integer[mutableBitmap.size()];
110 | int pos = 0;
111 | for (Integer i : this) {
112 | retval[pos++] = i;
113 | }
114 | return retval;
115 | }
116 |
117 | @Override
118 | public T[] toArray(T[] a)
119 | {
120 | return Sets.newHashSet(this).toArray(a);
121 | }
122 |
123 | @Override
124 | public boolean add(Integer integer)
125 | {
126 | if (null == integer) {
127 | throw new NullPointerException("BitSet cannot contain null values");
128 | }
129 | if (integer < 0) {
130 | throw new IllegalArgumentException("Only positive integers or zero can be added");
131 | }
132 | boolean isSet = mutableBitmap.get(integer);
133 | mutableBitmap.add(integer.intValue());
134 | return !isSet;
135 | }
136 |
137 | @Override
138 | public boolean remove(Object o)
139 | {
140 | if (o == null) {
141 | throw new NullPointerException("BitSet cannot contain null values");
142 | }
143 | if (o instanceof Integer) {
144 | Integer integer = (Integer) o;
145 | boolean isSet = mutableBitmap.get(integer);
146 | mutableBitmap.remove(integer);
147 | return isSet;
148 | } else {
149 | throw new ClassCastException("Cannot remove non Integer from integer BitSet");
150 | }
151 | }
152 |
153 | @Override
154 | public boolean containsAll(Collection> c)
155 | {
156 | Iterator> it = c.iterator();
157 | while (it.hasNext()) {
158 | if (!this.contains(it.next())) {
159 | return false;
160 | }
161 | }
162 | return true;
163 | }
164 |
165 | @Override
166 | public boolean addAll(Collection extends Integer> c)
167 | {
168 | boolean setChanged = false;
169 | for (Integer i : c) {
170 | if (!this.contains(i)) {
171 | setChanged = true;
172 | this.add(i);
173 | }
174 | }
175 | return setChanged;
176 | }
177 |
178 | @Override
179 | public boolean retainAll(Collection> c)
180 | {
181 | // Stub
182 | throw new UnsupportedOperationException("Cannot retainAll ona an IntegerSet");
183 | }
184 |
185 | @Override
186 | public boolean removeAll(Collection> c)
187 | {
188 | Iterator> it = c.iterator();
189 | boolean changed = false;
190 | while (it.hasNext()) {
191 | Integer val = (Integer) it.next();
192 | changed = remove(val) || changed;
193 | }
194 | return changed;
195 | }
196 |
197 | @Override
198 | public void clear()
199 | {
200 | mutableBitmap.clear();
201 | }
202 | }
203 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/bitmap/BitSetBitmapFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import java.nio.ByteBuffer;
20 | import java.util.BitSet;
21 |
22 | /**
23 | * BitSetBitmapFactory implements BitmapFactory as a wrapper for java.util.BitSet
24 | */
25 | public class BitSetBitmapFactory implements BitmapFactory
26 | {
27 | @Override
28 | public MutableBitmap makeEmptyMutableBitmap()
29 | {
30 | return new WrappedBitSetBitmap();
31 | }
32 |
33 | @Override
34 | public ImmutableBitmap makeEmptyImmutableBitmap()
35 | {
36 | return makeEmptyMutableBitmap();
37 | }
38 |
39 | @Override
40 | public ImmutableBitmap makeImmutableBitmap(MutableBitmap mutableBitmap)
41 | {
42 | return mutableBitmap;
43 | }
44 |
45 | @Override
46 | public ImmutableBitmap mapImmutableBitmap(ByteBuffer b)
47 | {
48 | return new WrappedBitSetBitmap(BitSet.valueOf(b.array()));
49 | }
50 |
51 | @Override
52 | public ImmutableBitmap union(Iterable b)
53 | {
54 | WrappedBitSetBitmap newSet = null;
55 | for (ImmutableBitmap bm : b) {
56 | if (null == newSet) {
57 | newSet = new WrappedBitSetBitmap(((WrappedBitSetBitmap) bm).cloneBitSet());
58 | } else {
59 | newSet.union(bm);
60 | }
61 | }
62 | return newSet;
63 | }
64 |
65 | @Override
66 | public ImmutableBitmap intersection(Iterable b)
67 | {
68 |
69 | WrappedBitSetBitmap newSet = null;
70 | for (ImmutableBitmap bm : b) {
71 | if (null == newSet) {
72 | newSet = new WrappedBitSetBitmap(((WrappedBitSetBitmap) bm).cloneBitSet());
73 | } else {
74 | newSet.intersection(bm);
75 | }
76 | }
77 | return newSet;
78 | }
79 |
80 | @Override
81 | public ImmutableBitmap complement(ImmutableBitmap b)
82 | {
83 | BitSet bitSet = ((WrappedBitSetBitmap) b).cloneBitSet();
84 | bitSet.flip(0, bitSet.size());
85 | return new WrappedBitSetBitmap(bitSet);
86 | }
87 |
88 | @Override
89 | public ImmutableBitmap complement(
90 | ImmutableBitmap b, int length
91 | )
92 | {
93 | return null;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/bitmap/BitmapFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import java.nio.ByteBuffer;
20 |
21 | public interface BitmapFactory
22 | {
23 | /**
24 | * Create a new empty bitmap
25 | *
26 | * @return the new bitmap
27 | */
28 | public MutableBitmap makeEmptyMutableBitmap();
29 |
30 | public ImmutableBitmap makeEmptyImmutableBitmap();
31 |
32 | public ImmutableBitmap makeImmutableBitmap(MutableBitmap mutableBitmap);
33 |
34 | /**
35 | * Given a ByteBuffer pointing at a serialized version of a bitmap,
36 | * instantiate an immutable mapped bitmap.
37 | *
38 | * When using RoaringBitmap (with the RoaringBitmapFactory class), it is not
39 | * necessary for b.limit() to indicate the end of the serialized content
40 | * whereas it is critical to set b.limit() appropriately with ConciseSet (with
41 | * the ConciseBitmapFactory).
42 | *
43 | * @param b the input byte buffer
44 | *
45 | * @return the new bitmap
46 | */
47 | public ImmutableBitmap mapImmutableBitmap(ByteBuffer b);
48 |
49 | /**
50 | * Compute the union (bitwise-OR) of a set of bitmaps. They are assumed to be
51 | * instances of of the proper WrappedConciseBitmap otherwise a ClassCastException
52 | * is thrown.
53 | *
54 | * @param b input ImmutableGenericBitmap objects
55 | *
56 | * @return the union.
57 | *
58 | * @throws ClassCastException if one of the ImmutableGenericBitmap objects if not an instance
59 | * of WrappedImmutableConciseBitmap
60 | */
61 | public ImmutableBitmap union(Iterable b);
62 |
63 | /**
64 | * Compute the intersection (bitwise-AND) of a set of bitmaps. They are assumed to be
65 | * instances of of the proper WrappedConciseBitmap otherwise a ClassCastException
66 | * is thrown.
67 | *
68 | * @param b input ImmutableGenericBitmap objects
69 | *
70 | * @return the union.
71 | *
72 | * @throws ClassCastException if one of the ImmutableGenericBitmap objects if not an instance
73 | * of WrappedImmutableConciseBitmap
74 | */
75 | public ImmutableBitmap intersection(Iterable b);
76 |
77 | public ImmutableBitmap complement(ImmutableBitmap b);
78 |
79 | public ImmutableBitmap complement(ImmutableBitmap b, int length);
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/bitmap/ConciseBitmapFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import it.uniroma3.mat.extendedset.intset.ImmutableConciseSet;
20 |
21 | import java.nio.ByteBuffer;
22 | import java.util.Iterator;
23 |
24 | /**
25 | * As the name suggests, this class instantiates bitmaps of the types
26 | * WrappedConciseBitmap and WrappedImmutableConciseBitmap.
27 | */
28 | public class ConciseBitmapFactory implements BitmapFactory
29 | {
30 | private static final ImmutableConciseSet EMPTY_IMMUTABLE_BITMAP = new ImmutableConciseSet();
31 | private static final WrappedImmutableConciseBitmap WRAPPED_IMMUTABLE_CONCISE_BITMAP =
32 | new WrappedImmutableConciseBitmap(EMPTY_IMMUTABLE_BITMAP);
33 |
34 | @Override
35 | public MutableBitmap makeEmptyMutableBitmap()
36 | {
37 | return new WrappedConciseBitmap();
38 | }
39 |
40 | @Override
41 | public ImmutableBitmap makeEmptyImmutableBitmap()
42 | {
43 | return WRAPPED_IMMUTABLE_CONCISE_BITMAP;
44 | }
45 |
46 | @Override
47 | public ImmutableBitmap makeImmutableBitmap(MutableBitmap mutableBitmap)
48 | {
49 | if (!(mutableBitmap instanceof WrappedConciseBitmap)) {
50 | throw new IllegalStateException(String.format("Cannot convert [%s]", mutableBitmap.getClass()));
51 | }
52 | return new WrappedImmutableConciseBitmap(
53 | ImmutableConciseSet.newImmutableFromMutable(
54 | ((WrappedConciseBitmap) mutableBitmap).getBitmap()
55 | )
56 | );
57 | }
58 |
59 | @Override
60 | public ImmutableBitmap mapImmutableBitmap(ByteBuffer b)
61 | {
62 | return new WrappedImmutableConciseBitmap(b);
63 | }
64 |
65 | @Override
66 | public ImmutableBitmap union(Iterable b)
67 | throws ClassCastException
68 | {
69 | return new WrappedImmutableConciseBitmap(ImmutableConciseSet.union(unwrap(b)));
70 | }
71 |
72 | @Override
73 | public ImmutableBitmap intersection(Iterable b)
74 | throws ClassCastException
75 | {
76 | return new WrappedImmutableConciseBitmap(ImmutableConciseSet.intersection(unwrap(b)));
77 | }
78 |
79 | @Override
80 | public ImmutableBitmap complement(ImmutableBitmap b)
81 | {
82 | return new WrappedImmutableConciseBitmap(ImmutableConciseSet.complement(((WrappedImmutableConciseBitmap) b).getBitmap()));
83 | }
84 |
85 | @Override
86 | public ImmutableBitmap complement(ImmutableBitmap b, int length)
87 | {
88 | return new WrappedImmutableConciseBitmap(
89 | ImmutableConciseSet.complement(
90 | ((WrappedImmutableConciseBitmap) b).getBitmap(),
91 | length
92 | )
93 | );
94 | }
95 |
96 | private static Iterable unwrap(
97 | final Iterable b
98 | )
99 | {
100 | return new Iterable()
101 | {
102 | @Override
103 | public Iterator iterator()
104 | {
105 | final Iterator i = b.iterator();
106 | return new Iterator()
107 | {
108 | @Override
109 | public void remove()
110 | {
111 | throw new UnsupportedOperationException();
112 | }
113 |
114 | @Override
115 | public boolean hasNext()
116 | {
117 | return i.hasNext();
118 | }
119 |
120 | @Override
121 | public ImmutableConciseSet next()
122 | {
123 | final WrappedImmutableConciseBitmap wrappedBitmap = (WrappedImmutableConciseBitmap) i.next();
124 |
125 | if (wrappedBitmap == null) {
126 | return EMPTY_IMMUTABLE_BITMAP;
127 | }
128 |
129 | return wrappedBitmap.getBitmap();
130 | }
131 | };
132 | }
133 | };
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/bitmap/ImmutableBitmap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import org.roaringbitmap.IntIterator;
20 |
21 | /**
22 | * This class is meant to represent a simple wrapper around an immutable bitmap
23 | * class.
24 | */
25 | public interface ImmutableBitmap
26 | {
27 | /**
28 | * @return an iterator over the set bits of this bitmap
29 | */
30 | public IntIterator iterator();
31 |
32 | /**
33 | * @return The number of bits set to true in this bitmap
34 | */
35 | public int size();
36 |
37 | public byte[] toBytes();
38 |
39 | public int compareTo(ImmutableBitmap other);
40 |
41 | /**
42 | * @return True if this bitmap is empty (contains no set bit)
43 | */
44 | public boolean isEmpty();
45 |
46 | /**
47 | * Returns true if the bit at position value is set
48 | *
49 | * @param value the position to check
50 | *
51 | * @return true if bit is set
52 | */
53 | public boolean get(int value);
54 |
55 | /**
56 | * Compute the bitwise-or of this bitmap with another bitmap. A new bitmap is generated.
57 | *
58 | * Note that the other bitmap should be of the same class instance.
59 | *
60 | * @param otherBitmap other bitmap
61 | */
62 | public ImmutableBitmap union(ImmutableBitmap otherBitmap);
63 |
64 | /**
65 | * Compute the bitwise-and of this bitmap with another bitmap. A new bitmap is generated.
66 | *
67 | * Note that the other bitmap should be of the same class instance.
68 | *
69 | * @param otherBitmap other bitmap
70 | */
71 | public ImmutableBitmap intersection(ImmutableBitmap otherBitmap);
72 |
73 | /**
74 | * Compute the bitwise-andNot of this bitmap with another bitmap. A new bitmap is generated.
75 | *
76 | * Note that the other bitmap should be of the same class instance.
77 | *
78 | * @param otherBitmap other bitmap
79 | */
80 | public ImmutableBitmap difference(ImmutableBitmap otherBitmap);
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/bitmap/MutableBitmap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import java.nio.ByteBuffer;
20 |
21 | /**
22 | * This class is meant to represent a simple wrapper around a bitmap class.
23 | */
24 | public interface MutableBitmap extends ImmutableBitmap
25 | {
26 | /**
27 | * Empties the content of this bitmap.
28 | */
29 | public void clear();
30 |
31 | /**
32 | * Compute the bitwise-or of this bitmap with another bitmap. The current
33 | * bitmap is modified whereas the other bitmap is left intact.
34 | *
35 | * Note that the other bitmap should be of the same class instance.
36 | *
37 | * @param mutableBitmap other bitmap
38 | */
39 | public void or(MutableBitmap mutableBitmap);
40 |
41 | /**
42 | * Compute the bitwise-and of this bitmap with another bitmap. The current
43 | * bitmap is modified whereas the other bitmap is left intact.
44 | *
45 | * Note that the other bitmap should be of the same class instance.
46 | *
47 | * @param mutableBitmap other bitmap
48 | */
49 | public void and(MutableBitmap mutableBitmap);
50 |
51 |
52 | /**
53 | * Compute the bitwise-xor of this bitmap with another bitmap. The current
54 | * bitmap is modified whereas the other bitmap is left intact.
55 | *
56 | * Note that the other bitmap should be of the same class instance.
57 | *
58 | * @param mutableBitmap other bitmap
59 | */
60 | public void xor(MutableBitmap mutableBitmap);
61 |
62 | /**
63 | * Compute the bitwise-andNot of this bitmap with another bitmap. The current
64 | * bitmap is modified whereas the other bitmap is left intact.
65 | *
66 | * Note that the other bitmap should be of the same class instance.
67 | *
68 | * @param mutableBitmap other bitmap
69 | */
70 | public void andNot(MutableBitmap mutableBitmap);
71 |
72 | /**
73 | * Return the size in bytes for the purpose of serialization to a ByteBuffer.
74 | * Note that this is distinct from the memory usage.
75 | *
76 | * @return the total set in bytes
77 | */
78 | public int getSizeInBytes();
79 |
80 | /**
81 | * Add the specified integer to the bitmap. This is equivalent to setting the
82 | * ith bit to the value 1.
83 | *
84 | * @param entry integer to be added
85 | */
86 | public void add(int entry);
87 |
88 | /**
89 | * Remove the specified integer to the bitmap. This is equivalent to setting the
90 | * ith bit to the value 1.
91 | *
92 | * @param entry integer to be remove
93 | */
94 | public void remove(int entry);
95 |
96 | /**
97 | * Write out a serialized (Immutable) version of the bitmap to the ByteBuffer. We preprend
98 | * the serialized bitmap with a 4-byte int indicating the size in bytes. Thus
99 | * getSizeInBytes() + 4 bytes are written.
100 | *
101 | * (These 4 bytes are required by ConciseSet but not by RoaringBitmap.
102 | * Nevertheless, we always write them for the sake of simplicity, even if it
103 | * wastes 4 bytes in some instances.)
104 | *
105 | * @param buffer where we write
106 | */
107 | public void serialize(ByteBuffer buffer);
108 | }
109 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/bitmap/RoaringBitmapFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import com.google.common.base.Throwables;
20 | import org.roaringbitmap.RoaringBitmap;
21 | import org.roaringbitmap.buffer.BufferFastAggregation;
22 | import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
23 |
24 | import java.io.ByteArrayOutputStream;
25 | import java.io.DataOutputStream;
26 | import java.nio.ByteBuffer;
27 | import java.util.Iterator;
28 |
29 | /**
30 | * As the name suggests, this class instantiates bitmaps of the types
31 | * WrappedRoaringBitmap and WrappedImmutableRoaringBitmap.
32 | */
33 | public class RoaringBitmapFactory implements BitmapFactory
34 | {
35 | static final boolean DEFAULT_COMPRESS_RUN_ON_SERIALIZATION = false;
36 |
37 | private static final ImmutableRoaringBitmap EMPTY_IMMUTABLE_BITMAP;
38 |
39 | static {
40 | try {
41 | final RoaringBitmap roaringBitmap = new RoaringBitmap();
42 | final ByteArrayOutputStream out = new ByteArrayOutputStream();
43 | roaringBitmap.serialize(new DataOutputStream(out));
44 | final byte[] bytes = out.toByteArray();
45 |
46 | ByteBuffer buf = ByteBuffer.wrap(bytes);
47 | EMPTY_IMMUTABLE_BITMAP = new ImmutableRoaringBitmap(buf);
48 | }
49 | catch (Exception e) {
50 | throw Throwables.propagate(e);
51 | }
52 | }
53 |
54 | private static final WrappedImmutableRoaringBitmap WRAPPED_IMMUTABLE_ROARING_BITMAP =
55 | new WrappedImmutableRoaringBitmap(EMPTY_IMMUTABLE_BITMAP);
56 |
57 | private final boolean compressRunOnSerialization;
58 |
59 | public RoaringBitmapFactory()
60 | {
61 | this(DEFAULT_COMPRESS_RUN_ON_SERIALIZATION);
62 | }
63 |
64 | public RoaringBitmapFactory(boolean compressRunOnSerialization)
65 | {
66 | this.compressRunOnSerialization = compressRunOnSerialization;
67 | }
68 |
69 | @Override
70 | public MutableBitmap makeEmptyMutableBitmap()
71 | {
72 | return new WrappedRoaringBitmap(compressRunOnSerialization);
73 | }
74 |
75 | @Override
76 | public ImmutableBitmap makeEmptyImmutableBitmap()
77 | {
78 | return WRAPPED_IMMUTABLE_ROARING_BITMAP;
79 | }
80 |
81 | @Override
82 | public ImmutableBitmap makeImmutableBitmap(MutableBitmap mutableBitmap)
83 | {
84 | if (!(mutableBitmap instanceof WrappedRoaringBitmap)) {
85 | throw new IllegalStateException(String.format("Cannot convert [%s]", mutableBitmap.getClass()));
86 | }
87 | try {
88 | return ((WrappedRoaringBitmap) mutableBitmap).toImmutableBitmap();
89 | }
90 | catch (Exception e) {
91 | throw Throwables.propagate(e);
92 | }
93 | }
94 |
95 | @Override
96 | public ImmutableBitmap mapImmutableBitmap(ByteBuffer b)
97 | {
98 | return new WrappedImmutableRoaringBitmap(b);
99 | }
100 |
101 | @Override
102 | public ImmutableBitmap union(Iterable b)
103 | {
104 | return new WrappedImmutableRoaringBitmap(ImmutableRoaringBitmap.or(unwrap(b).iterator()));
105 | }
106 |
107 | @Override
108 | public ImmutableBitmap intersection(Iterable b)
109 | {
110 | return new WrappedImmutableRoaringBitmap(BufferFastAggregation.and(unwrap(b).iterator()));
111 | }
112 |
113 | @Override
114 | public ImmutableBitmap complement(ImmutableBitmap b)
115 | {
116 | return new WrappedImmutableRoaringBitmap(
117 | ImmutableRoaringBitmap.flip(
118 | ((WrappedImmutableRoaringBitmap) b).getBitmap(),
119 | 0,
120 | b.size()
121 | )
122 | );
123 | }
124 |
125 | @Override
126 | public ImmutableBitmap complement(
127 | ImmutableBitmap b, int length
128 | )
129 | {
130 | return new WrappedImmutableRoaringBitmap(
131 | ImmutableRoaringBitmap.flip(
132 | ((WrappedImmutableRoaringBitmap) b).getBitmap(),
133 | 0,
134 | length
135 | )
136 | );
137 | }
138 |
139 | private static Iterable unwrap(
140 | final Iterable b
141 | )
142 | {
143 | return new Iterable()
144 | {
145 | @Override
146 | public Iterator iterator()
147 | {
148 | final Iterator i = b.iterator();
149 | return new Iterator()
150 | {
151 | @Override
152 | public void remove()
153 | {
154 | throw new UnsupportedOperationException();
155 | }
156 |
157 | @Override
158 | public boolean hasNext()
159 | {
160 | return i.hasNext();
161 | }
162 |
163 | @Override
164 | public ImmutableRoaringBitmap next()
165 | {
166 | WrappedImmutableRoaringBitmap wrappedBitmap = (WrappedImmutableRoaringBitmap) i.next();
167 |
168 | if (wrappedBitmap == null) {
169 | return EMPTY_IMMUTABLE_BITMAP;
170 | }
171 |
172 | return wrappedBitmap.getBitmap();
173 | }
174 | };
175 | }
176 | };
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/bitmap/WrappedBitSetBitmap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import java.nio.ByteBuffer;
20 | import java.util.BitSet;
21 |
22 | /**
23 | * WrappedBitSetBitmap implements MutableBitmap for java.util.BitSet
24 | */
25 | public class WrappedBitSetBitmap extends WrappedImmutableBitSetBitmap implements MutableBitmap
26 | {
27 |
28 | public WrappedBitSetBitmap()
29 | {
30 | super();
31 | }
32 |
33 | public WrappedBitSetBitmap(BitSet bitSet)
34 | {
35 | super(bitSet);
36 | }
37 |
38 | public WrappedBitSetBitmap(ByteBuffer byteBuffer){
39 | super(byteBuffer);
40 | }
41 |
42 | protected BitSet cloneBitSet()
43 | {
44 | return (BitSet) bitmap.clone();
45 | }
46 |
47 | @Override
48 | public void clear()
49 | {
50 | bitmap.clear();
51 | }
52 |
53 | @Override
54 | public void or(MutableBitmap mutableBitmap)
55 | {
56 | if (mutableBitmap instanceof WrappedBitSetBitmap) {
57 | WrappedBitSetBitmap bitSet = (WrappedBitSetBitmap) mutableBitmap;
58 | this.bitmap.or(bitSet.bitmap);
59 | } else {
60 | throw new IllegalArgumentException(
61 | String.format(
62 | "Unknown class type: %s expected %s",
63 | mutableBitmap.getClass().getCanonicalName(),
64 | WrappedBitSetBitmap.class.getCanonicalName()
65 | )
66 | );
67 | }
68 | }
69 |
70 | @Override
71 | public void and(MutableBitmap mutableBitmap)
72 | {
73 | if (mutableBitmap instanceof WrappedBitSetBitmap) {
74 | WrappedBitSetBitmap bitSet = (WrappedBitSetBitmap) mutableBitmap;
75 | this.bitmap.and(bitSet.bitmap);
76 | } else {
77 | throw new IllegalArgumentException(
78 | String.format(
79 | "Unknown class type: %s expected %s",
80 | mutableBitmap.getClass().getCanonicalName(),
81 | WrappedBitSetBitmap.class.getCanonicalName()
82 | )
83 | );
84 | }
85 | }
86 |
87 | @Override
88 | public void xor(MutableBitmap mutableBitmap)
89 | {
90 | if (mutableBitmap instanceof WrappedBitSetBitmap) {
91 | WrappedBitSetBitmap bitSet = (WrappedBitSetBitmap) mutableBitmap;
92 | this.bitmap.xor(bitSet.bitmap);
93 | } else {
94 | throw new IllegalArgumentException(
95 | String.format(
96 | "Unknown class type: %s expected %s",
97 | mutableBitmap.getClass().getCanonicalName(),
98 | WrappedBitSetBitmap.class.getCanonicalName()
99 | )
100 | );
101 | }
102 | }
103 |
104 | @Override
105 | public void andNot(MutableBitmap mutableBitmap)
106 | {
107 | if (mutableBitmap instanceof WrappedBitSetBitmap) {
108 | WrappedBitSetBitmap bitSet = (WrappedBitSetBitmap) mutableBitmap;
109 | this.bitmap.andNot(bitSet.bitmap);
110 | } else {
111 | throw new IllegalArgumentException(
112 | String.format(
113 | "Unknown class type: %s expected %s",
114 | mutableBitmap.getClass().getCanonicalName(),
115 | WrappedBitSetBitmap.class.getCanonicalName()
116 | )
117 | );
118 | }
119 | }
120 |
121 | @Override
122 | public int getSizeInBytes()
123 | {
124 | // BitSet.size() returns the size in *bits*
125 | return this.bitmap.size() / Byte.SIZE;
126 | }
127 |
128 | @Override
129 | public void add(int entry)
130 | {
131 | this.bitmap.set(entry);
132 | }
133 |
134 | @Override
135 | public void remove(int entry)
136 | {
137 | this.bitmap.clear(entry);
138 | }
139 |
140 | @Override
141 | public void serialize(ByteBuffer buffer)
142 | {
143 | buffer.put(this.bitmap.toByteArray());
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/bitmap/WrappedConciseBitmap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import com.google.common.primitives.Ints;
20 | import it.uniroma3.mat.extendedset.intset.ConciseSet;
21 | import it.uniroma3.mat.extendedset.intset.ImmutableConciseSet;
22 | import org.roaringbitmap.IntIterator;
23 |
24 | import java.nio.ByteBuffer;
25 |
26 | public class WrappedConciseBitmap implements MutableBitmap
27 | {
28 | /**
29 | * Underlying bitmap.
30 | */
31 | private ConciseSet bitmap;
32 |
33 | /**
34 | * Create a new WrappedConciseBitmap wrapping an empty ConciseSet
35 | */
36 | public WrappedConciseBitmap()
37 | {
38 | this.bitmap = new ConciseSet();
39 | }
40 |
41 | /**
42 | * Create a bitmap wrappign the given bitmap
43 | *
44 | * @param conciseSet bitmap to be wrapped
45 | */
46 | public WrappedConciseBitmap(ConciseSet conciseSet)
47 | {
48 | this.bitmap = conciseSet;
49 | }
50 |
51 | ConciseSet getBitmap()
52 | {
53 | return bitmap;
54 | }
55 |
56 | @Override
57 | public byte[] toBytes()
58 | {
59 | return ImmutableConciseSet.newImmutableFromMutable(bitmap).toBytes();
60 | }
61 |
62 | @Override
63 | public int compareTo(ImmutableBitmap other)
64 | {
65 | return bitmap.compareTo(((WrappedConciseBitmap) other).getBitmap());
66 | }
67 |
68 | @Override
69 | public void clear()
70 | {
71 | bitmap.clear();
72 | }
73 |
74 | @Override
75 | public void or(MutableBitmap mutableBitmap)
76 | {
77 | WrappedConciseBitmap other = (WrappedConciseBitmap) mutableBitmap;
78 | ConciseSet unwrappedOtherBitmap = other.bitmap;
79 | bitmap.addAll(unwrappedOtherBitmap);
80 | }
81 |
82 | @Override
83 | public void and(MutableBitmap mutableBitmap)
84 | {
85 | WrappedConciseBitmap other = (WrappedConciseBitmap) mutableBitmap;
86 | ConciseSet unwrappedOtherBitmap = other.bitmap;
87 | bitmap = bitmap.intersection(unwrappedOtherBitmap);
88 | }
89 |
90 | @Override
91 | public void xor(MutableBitmap mutableBitmap)
92 | {
93 | WrappedConciseBitmap other = (WrappedConciseBitmap) mutableBitmap;
94 | ConciseSet unwrappedOtherBitmap = other.bitmap;
95 | bitmap = bitmap.symmetricDifference(unwrappedOtherBitmap);
96 | }
97 |
98 | @Override
99 | public void andNot(MutableBitmap mutableBitmap)
100 | {
101 | WrappedConciseBitmap other = (WrappedConciseBitmap) mutableBitmap;
102 | ConciseSet unwrappedOtherBitmap = other.bitmap;
103 | bitmap = bitmap.difference(unwrappedOtherBitmap);
104 | }
105 |
106 | @Override
107 | public int getSizeInBytes()
108 | {
109 | return bitmap.getWords().length * Ints.BYTES;
110 | }
111 |
112 | @Override
113 | public void add(int entry)
114 | {
115 | bitmap.add(entry);
116 | }
117 |
118 | @Override
119 | public int size()
120 | {
121 | return bitmap.size();
122 | }
123 |
124 | @Override
125 | public void serialize(ByteBuffer buffer)
126 | {
127 | buffer.put(toBytes());
128 | }
129 |
130 | @Override
131 | public String toString()
132 | {
133 | return getClass().getSimpleName() + bitmap.toString();
134 | }
135 |
136 | @Override
137 | public void remove(int entry)
138 | {
139 | bitmap.remove(entry);
140 | }
141 |
142 | @Override
143 | public IntIterator iterator()
144 | {
145 | return bitmap.iterator();
146 | }
147 |
148 | @Override
149 | public boolean isEmpty()
150 | {
151 | return bitmap.size() == 0;
152 | }
153 |
154 | @Override
155 | public ImmutableBitmap union(ImmutableBitmap otherBitmap)
156 | {
157 | WrappedConciseBitmap other = (WrappedConciseBitmap) otherBitmap;
158 | ConciseSet unwrappedOtherBitmap = other.bitmap;
159 | return new WrappedConciseBitmap(bitmap.clone().union(unwrappedOtherBitmap));
160 | }
161 |
162 | @Override
163 | public ImmutableBitmap intersection(ImmutableBitmap otherBitmap)
164 | {
165 | WrappedConciseBitmap other = (WrappedConciseBitmap) otherBitmap;
166 | ConciseSet unwrappedOtherBitmap = other.bitmap;
167 | return new WrappedConciseBitmap(bitmap.clone().intersection(unwrappedOtherBitmap));
168 | }
169 |
170 | @Override
171 | public ImmutableBitmap difference(ImmutableBitmap otherBitmap)
172 | {
173 | WrappedConciseBitmap other = (WrappedConciseBitmap) otherBitmap;
174 | ConciseSet unwrappedOtherBitmap = other.bitmap;
175 | return new WrappedConciseBitmap(bitmap.clone().difference(unwrappedOtherBitmap));
176 | }
177 |
178 | @Override
179 | public boolean get(int value)
180 | {
181 | return bitmap.contains(value);
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/bitmap/WrappedConciseIntIterator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import it.uniroma3.mat.extendedset.intset.IntSet;
20 | import org.roaringbitmap.IntIterator;
21 |
22 | /**
23 | */
24 | public class WrappedConciseIntIterator implements IntIterator
25 | {
26 | private final IntSet.IntIterator itr;
27 |
28 | public WrappedConciseIntIterator(IntSet.IntIterator itr)
29 | {
30 | this.itr = itr;
31 | }
32 |
33 | @Override
34 | public boolean hasNext()
35 | {
36 | return itr.hasNext();
37 | }
38 |
39 | @Override
40 | public int next()
41 | {
42 | return itr.next();
43 | }
44 |
45 | @Override
46 | public IntIterator clone()
47 | {
48 | return new WrappedConciseIntIterator(itr.clone());
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/bitmap/WrappedImmutableBitSetBitmap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import org.roaringbitmap.IntIterator;
20 |
21 | import java.nio.ByteBuffer;
22 | import java.util.BitSet;
23 |
24 | /**
25 | * WrappedImmutableBitSetBitmap implements ImmutableBitmap for java.util.BitSet
26 | */
27 | public class WrappedImmutableBitSetBitmap implements ImmutableBitmap
28 | {
29 | protected final BitSet bitmap;
30 |
31 | public WrappedImmutableBitSetBitmap(BitSet bitmap)
32 | {
33 | this.bitmap = bitmap;
34 | }
35 |
36 | public WrappedImmutableBitSetBitmap()
37 | {
38 | this(new BitSet());
39 | }
40 |
41 | // WARNING: the current implementation of BitSet (1.7) copies the contents of ByteBuffer to
42 | // on heap!
43 | // TODO: make a new BitSet implementation which can use ByteBuffers properly.
44 | public WrappedImmutableBitSetBitmap(ByteBuffer byteBuffer){
45 | this(BitSet.valueOf(byteBuffer));
46 | }
47 |
48 | private class BitSetIterator implements IntIterator
49 | {
50 | private int pos = -1;
51 |
52 | @Override
53 | public boolean hasNext()
54 | {
55 | return bitmap.nextSetBit(pos + 1) >= 0;
56 | }
57 |
58 | @Override
59 | public int next()
60 | {
61 | pos = bitmap.nextSetBit(pos + 1);
62 | return pos;
63 | }
64 |
65 | @Override
66 | public IntIterator clone()
67 | {
68 | BitSetIterator newIt = new BitSetIterator();
69 | newIt.pos = pos;
70 | return newIt;
71 | }
72 | }
73 |
74 | @Override
75 | public IntIterator iterator()
76 | {
77 | return new BitSetIterator();
78 | }
79 |
80 |
81 | @Override
82 | public boolean get(int value)
83 | {
84 | return bitmap.get(value);
85 | }
86 |
87 | @Override
88 | public int size()
89 | {
90 | return bitmap.cardinality();
91 | }
92 |
93 | @Override
94 | public byte[] toBytes()
95 | {
96 | return bitmap.toByteArray();
97 | }
98 |
99 |
100 | @Override
101 | public int compareTo(ImmutableBitmap other)
102 | {
103 | // TODO: find out what this is supposed to even do
104 | BitSet otherSet = ((WrappedImmutableBitSetBitmap) other).bitmap;
105 | int lengthCompare = Integer.compare(otherSet.length(), bitmap.length());
106 | if (lengthCompare != 0) {
107 | return lengthCompare;
108 | }
109 | return Integer.compare(otherSet.nextSetBit(0), bitmap.nextSetBit(0));
110 | }
111 |
112 |
113 | @Override
114 | public boolean isEmpty()
115 | {
116 | return bitmap.isEmpty();
117 | }
118 |
119 | @Override
120 | public ImmutableBitmap union(ImmutableBitmap otherBitmap)
121 | {
122 | WrappedBitSetBitmap retval = new WrappedBitSetBitmap((BitSet) bitmap.clone());
123 | retval.or((WrappedBitSetBitmap) otherBitmap);
124 | return retval;
125 | }
126 |
127 | @Override
128 | public ImmutableBitmap intersection(ImmutableBitmap otherBitmap)
129 | {
130 | WrappedBitSetBitmap retval = new WrappedBitSetBitmap((BitSet) bitmap.clone());
131 | retval.and((WrappedBitSetBitmap) otherBitmap);
132 | return retval;
133 | }
134 |
135 | @Override
136 | public ImmutableBitmap difference(ImmutableBitmap otherBitmap)
137 | {
138 | WrappedBitSetBitmap retval = new WrappedBitSetBitmap((BitSet) bitmap.clone());
139 | retval.andNot((WrappedBitSetBitmap) otherBitmap);
140 | return retval;
141 | }
142 |
143 | }
144 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/bitmap/WrappedImmutableConciseBitmap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import it.uniroma3.mat.extendedset.intset.ImmutableConciseSet;
20 | import it.uniroma3.mat.extendedset.intset.IntSet;
21 | import org.roaringbitmap.IntIterator;
22 |
23 | import java.nio.ByteBuffer;
24 |
25 | public class WrappedImmutableConciseBitmap implements ImmutableBitmap
26 | {
27 | /**
28 | * Underlying bitmap.
29 | */
30 | private final ImmutableConciseSet bitmap;
31 |
32 | public WrappedImmutableConciseBitmap(ByteBuffer byteBuffer)
33 | {
34 | this.bitmap = new ImmutableConciseSet(byteBuffer.asReadOnlyBuffer());
35 | }
36 |
37 | /**
38 | * Wrap an ImmutableConciseSet
39 | *
40 | * @param immutableConciseSet bitmap to be wrapped
41 | */
42 | public WrappedImmutableConciseBitmap(ImmutableConciseSet immutableConciseSet)
43 | {
44 | this.bitmap = immutableConciseSet;
45 | }
46 |
47 | public ImmutableConciseSet getBitmap()
48 | {
49 | return bitmap;
50 | }
51 |
52 | @Override
53 | public boolean get(int value)
54 | {
55 | return bitmap.contains(value);
56 | }
57 |
58 | @Override
59 | public byte[] toBytes()
60 | {
61 | return bitmap.toBytes();
62 | }
63 |
64 | @Override
65 | public int compareTo(ImmutableBitmap other)
66 | {
67 | return bitmap.compareTo(((WrappedImmutableConciseBitmap) other).getBitmap());
68 | }
69 |
70 | @Override
71 | public String toString()
72 | {
73 | return getClass().getSimpleName() + bitmap.toString();
74 | }
75 |
76 | @Override
77 | public IntIterator iterator()
78 | {
79 | return bitmap.iterator();
80 | }
81 |
82 | @Override
83 | public int size()
84 | {
85 | return bitmap.size();
86 | }
87 |
88 | @Override
89 | public boolean isEmpty()
90 | {
91 | return bitmap.size() == 0;
92 | }
93 |
94 | @Override
95 | public ImmutableBitmap union(ImmutableBitmap otherBitmap)
96 | {
97 | WrappedImmutableConciseBitmap other = (WrappedImmutableConciseBitmap) otherBitmap;
98 | ImmutableConciseSet unwrappedOtherBitmap = other.bitmap;
99 | return new WrappedImmutableConciseBitmap(ImmutableConciseSet.union(bitmap, unwrappedOtherBitmap));
100 | }
101 |
102 | @Override
103 | public ImmutableBitmap intersection(ImmutableBitmap otherBitmap)
104 | {
105 | WrappedImmutableConciseBitmap other = (WrappedImmutableConciseBitmap) otherBitmap;
106 | ImmutableConciseSet unwrappedOtherBitmap = other.bitmap;
107 | return new WrappedImmutableConciseBitmap(ImmutableConciseSet.intersection(bitmap, unwrappedOtherBitmap));
108 | }
109 |
110 | @Override
111 | public ImmutableBitmap difference(ImmutableBitmap otherBitmap)
112 | {
113 | WrappedImmutableConciseBitmap other = (WrappedImmutableConciseBitmap) otherBitmap;
114 | ImmutableConciseSet unwrappedOtherBitmap = other.bitmap;
115 | return new WrappedImmutableConciseBitmap(
116 | ImmutableConciseSet.intersection(
117 | bitmap,
118 | ImmutableConciseSet.complement(unwrappedOtherBitmap)
119 | )
120 | );
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/bitmap/WrappedImmutableRoaringBitmap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import com.google.common.base.Throwables;
20 | import org.roaringbitmap.IntIterator;
21 | import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
22 |
23 | import java.io.ByteArrayOutputStream;
24 | import java.io.DataOutputStream;
25 | import java.nio.ByteBuffer;
26 |
27 | public class WrappedImmutableRoaringBitmap implements ImmutableBitmap
28 | {
29 | /**
30 | * Underlying bitmap.
31 | */
32 | private final ImmutableRoaringBitmap bitmap;
33 |
34 | protected WrappedImmutableRoaringBitmap(ByteBuffer byteBuffer)
35 | {
36 | this.bitmap = new ImmutableRoaringBitmap(byteBuffer.asReadOnlyBuffer());
37 | }
38 |
39 | /**
40 | * Wrap an ImmutableRoaringBitmap
41 | *
42 | * @param immutableRoaringBitmap bitmap to be wrapped
43 | */
44 | public WrappedImmutableRoaringBitmap(ImmutableRoaringBitmap immutableRoaringBitmap)
45 | {
46 | this.bitmap = immutableRoaringBitmap;
47 | }
48 |
49 | public ImmutableRoaringBitmap getBitmap()
50 | {
51 | return bitmap;
52 | }
53 |
54 | @Override
55 | public byte[] toBytes()
56 | {
57 | try {
58 | final ByteArrayOutputStream out = new ByteArrayOutputStream();
59 | bitmap.serialize(new DataOutputStream(out));
60 | return out.toByteArray();
61 | }
62 | catch (Exception e) {
63 | throw Throwables.propagate(e);
64 | }
65 | }
66 |
67 | @Override
68 | public int compareTo(ImmutableBitmap other)
69 | {
70 | return 0;
71 | }
72 |
73 | @Override
74 | public String toString()
75 | {
76 | return getClass().getSimpleName() + bitmap.toString();
77 | }
78 |
79 | @Override
80 | public IntIterator iterator()
81 | {
82 | return bitmap.getIntIterator();
83 | }
84 |
85 | @Override
86 | public int size()
87 | {
88 | return bitmap.getCardinality();
89 | }
90 |
91 | @Override
92 | public boolean isEmpty()
93 | {
94 | return bitmap.isEmpty();
95 | }
96 |
97 | @Override
98 | public ImmutableBitmap union(ImmutableBitmap otherBitmap)
99 | {
100 | WrappedImmutableRoaringBitmap other = (WrappedImmutableRoaringBitmap) otherBitmap;
101 | ImmutableRoaringBitmap unwrappedOtherBitmap = other.bitmap;
102 | return new WrappedImmutableRoaringBitmap(ImmutableRoaringBitmap.or(bitmap, unwrappedOtherBitmap));
103 | }
104 |
105 | @Override
106 | public boolean get(int value)
107 | {
108 | return bitmap.contains(value);
109 | }
110 |
111 | @Override
112 | public ImmutableBitmap intersection(ImmutableBitmap otherBitmap)
113 | {
114 | WrappedImmutableRoaringBitmap other = (WrappedImmutableRoaringBitmap) otherBitmap;
115 | ImmutableRoaringBitmap unwrappedOtherBitmap = other.bitmap;
116 | return new WrappedImmutableRoaringBitmap(ImmutableRoaringBitmap.and(bitmap, unwrappedOtherBitmap));
117 | }
118 |
119 | @Override
120 | public ImmutableBitmap difference(ImmutableBitmap otherBitmap)
121 | {
122 | WrappedImmutableRoaringBitmap other = (WrappedImmutableRoaringBitmap) otherBitmap;
123 | ImmutableRoaringBitmap unwrappedOtherBitmap = other.bitmap;
124 | return new WrappedImmutableRoaringBitmap(ImmutableRoaringBitmap.andNot(bitmap, unwrappedOtherBitmap));
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/bitmap/WrappedRoaringBitmap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import com.google.common.base.Throwables;
20 | import org.roaringbitmap.IntIterator;
21 | import org.roaringbitmap.RoaringBitmap;
22 | import org.roaringbitmap.buffer.MutableRoaringBitmap;
23 |
24 | import java.io.ByteArrayOutputStream;
25 | import java.io.DataOutputStream;
26 | import java.io.IOException;
27 | import java.io.OutputStream;
28 | import java.nio.ByteBuffer;
29 |
30 | public class WrappedRoaringBitmap implements MutableBitmap
31 | {
32 | /**
33 | * Underlying bitmap.
34 | */
35 | private MutableRoaringBitmap bitmap;
36 |
37 | // attempt to compress long runs prior to serialization (requires RoaringBitmap version 0.5 or better)
38 | // this may improve compression greatly in some cases at the expense of slower serialization
39 | // in the worst case.
40 | private final boolean compressRunOnSerialization;
41 |
42 | /**
43 | * Creates a new WrappedRoaringBitmap wrapping an empty MutableRoaringBitmap
44 | */
45 | public WrappedRoaringBitmap()
46 | {
47 | this(RoaringBitmapFactory.DEFAULT_COMPRESS_RUN_ON_SERIALIZATION);
48 | }
49 |
50 | /**
51 | * Creates a new WrappedRoaringBitmap wrapping an empty MutableRoaringBitmap
52 | *
53 | * @param compressRunOnSerialization indicates whether to call {@link RoaringBitmap#runOptimize()} before serializing
54 | */
55 | public WrappedRoaringBitmap(boolean compressRunOnSerialization)
56 | {
57 | this.bitmap = new MutableRoaringBitmap();
58 | this.compressRunOnSerialization = compressRunOnSerialization;
59 | }
60 |
61 | ImmutableBitmap toImmutableBitmap()
62 | {
63 | MutableRoaringBitmap mrb = bitmap.clone();
64 | if (compressRunOnSerialization) {
65 | mrb.runOptimize();
66 | }
67 | return new WrappedImmutableRoaringBitmap(mrb);
68 | }
69 |
70 | @Override
71 | public byte[] toBytes()
72 | {
73 | try {
74 | final ByteArrayOutputStream out = new ByteArrayOutputStream();
75 | if (compressRunOnSerialization) {
76 | bitmap.runOptimize();
77 | }
78 | bitmap.serialize(new DataOutputStream(out));
79 | return out.toByteArray();
80 | }
81 | catch (Exception e) {
82 | throw Throwables.propagate(e);
83 | }
84 | }
85 |
86 | @Override
87 | public int compareTo(ImmutableBitmap other)
88 | {
89 | return 0;
90 | }
91 |
92 | @Override
93 | public void clear()
94 | {
95 | this.bitmap.clear();
96 | }
97 |
98 | @Override
99 | public void or(MutableBitmap mutableBitmap)
100 | {
101 | WrappedRoaringBitmap other = (WrappedRoaringBitmap) mutableBitmap;
102 | MutableRoaringBitmap unwrappedOtherBitmap = other.bitmap;
103 | bitmap.or(unwrappedOtherBitmap);
104 | }
105 |
106 | @Override
107 | public void and(MutableBitmap mutableBitmap)
108 | {
109 | WrappedRoaringBitmap other = (WrappedRoaringBitmap) mutableBitmap;
110 | MutableRoaringBitmap unwrappedOtherBitmap = other.bitmap;
111 | bitmap.and(unwrappedOtherBitmap);
112 | }
113 |
114 |
115 | @Override
116 | public void andNot(MutableBitmap mutableBitmap)
117 | {
118 | WrappedRoaringBitmap other = (WrappedRoaringBitmap) mutableBitmap;
119 | MutableRoaringBitmap unwrappedOtherBitmap = other.bitmap;
120 | bitmap.andNot(unwrappedOtherBitmap);
121 | }
122 |
123 |
124 | @Override
125 | public void xor(MutableBitmap mutableBitmap)
126 | {
127 | WrappedRoaringBitmap other = (WrappedRoaringBitmap) mutableBitmap;
128 | MutableRoaringBitmap unwrappedOtherBitmap = other.bitmap;
129 | bitmap.xor(unwrappedOtherBitmap);
130 | }
131 |
132 | @Override
133 | public int getSizeInBytes()
134 | {
135 | if (compressRunOnSerialization) {
136 | bitmap.runOptimize();
137 | }
138 | return bitmap.serializedSizeInBytes();
139 | }
140 |
141 | @Override
142 | public void add(int entry)
143 | {
144 | bitmap.add(entry);
145 | }
146 |
147 | @Override
148 | public int size()
149 | {
150 | return bitmap.getCardinality();
151 | }
152 |
153 | @Override
154 | public void serialize(ByteBuffer buffer)
155 | {
156 | if (compressRunOnSerialization) {
157 | bitmap.runOptimize();
158 | }
159 | try {
160 | bitmap.serialize(
161 | new DataOutputStream(
162 | new OutputStream()
163 | {
164 | ByteBuffer mBB;
165 |
166 | OutputStream init(ByteBuffer mbb)
167 | {
168 | mBB = mbb;
169 | return this;
170 | }
171 |
172 | @Override
173 | public void close()
174 | {
175 | // unnecessary
176 | }
177 |
178 | @Override
179 | public void flush()
180 | {
181 | // unnecessary
182 | }
183 |
184 | @Override
185 | public void write(int b)
186 | {
187 | mBB.put((byte) b);
188 | }
189 |
190 | @Override
191 | public void write(byte[] b)
192 | {
193 | mBB.put(b);
194 | }
195 |
196 | @Override
197 | public void write(byte[] b, int off, int l)
198 | {
199 | mBB.put(b, off, l);
200 | }
201 | }.init(buffer)
202 | )
203 | );
204 | }
205 | catch (IOException e) {
206 | e.printStackTrace(); // impossible in theory
207 | }
208 | }
209 |
210 | @Override
211 | public String toString()
212 | {
213 | return getClass().getSimpleName() + bitmap.toString();
214 | }
215 |
216 | @Override
217 | public void remove(int entry)
218 | {
219 | bitmap.remove(entry);
220 | }
221 |
222 | @Override
223 | public IntIterator iterator()
224 | {
225 | return bitmap.getIntIterator();
226 | }
227 |
228 | @Override
229 | public boolean isEmpty()
230 | {
231 | return bitmap.isEmpty();
232 | }
233 |
234 | @Override
235 | public ImmutableBitmap union(ImmutableBitmap otherBitmap)
236 | {
237 | WrappedRoaringBitmap other = (WrappedRoaringBitmap) otherBitmap;
238 | MutableRoaringBitmap unwrappedOtherBitmap = other.bitmap;
239 | return new WrappedImmutableRoaringBitmap(MutableRoaringBitmap.or(bitmap, unwrappedOtherBitmap));
240 | }
241 |
242 | @Override
243 | public ImmutableBitmap intersection(ImmutableBitmap otherBitmap)
244 | {
245 | WrappedRoaringBitmap other = (WrappedRoaringBitmap) otherBitmap;
246 | MutableRoaringBitmap unwrappedOtherBitmap = other.bitmap;
247 | return new WrappedImmutableRoaringBitmap(MutableRoaringBitmap.and(bitmap, unwrappedOtherBitmap));
248 | }
249 |
250 | @Override
251 | public ImmutableBitmap difference(ImmutableBitmap otherBitmap)
252 | {
253 | WrappedRoaringBitmap other = (WrappedRoaringBitmap) otherBitmap;
254 | MutableRoaringBitmap unwrappedOtherBitmap = other.bitmap;
255 | return new WrappedImmutableRoaringBitmap(MutableRoaringBitmap.andNot(bitmap, unwrappedOtherBitmap));
256 | }
257 |
258 | @Override
259 | public boolean get(int value)
260 | {
261 | return bitmap.contains(value);
262 | }
263 | }
264 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/ImmutableNode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial;
18 |
19 | import com.google.common.primitives.Floats;
20 | import com.google.common.primitives.Ints;
21 | import com.metamx.collections.bitmap.BitmapFactory;
22 | import com.metamx.collections.bitmap.ImmutableBitmap;
23 |
24 | import java.nio.ByteBuffer;
25 | import java.util.Iterator;
26 |
27 | /**
28 | * Byte layout:
29 | * Header
30 | * 0 to 1 : the MSB is a boolean flag for isLeaf, the next 15 bits represent the number of children of a node
31 | * Body
32 | * 2 to 2 + numDims * Floats.BYTES : minCoordinates
33 | * 2 + numDims * Floats.BYTES to 2 + 2 * numDims * Floats.BYTES : maxCoordinates
34 | * concise set
35 | * rest (children) : Every 4 bytes is storing an offset representing the position of a child.
36 | *
37 | * The child offset is an offset from the initialOffset
38 | */
39 | public class ImmutableNode
40 | {
41 | public static final int HEADER_NUM_BYTES = 2;
42 |
43 | private final int numDims;
44 | private final int initialOffset;
45 | private final int offsetFromInitial;
46 |
47 | private final short numChildren;
48 | private final boolean isLeaf;
49 | private final int childrenOffset;
50 |
51 | private final ByteBuffer data;
52 |
53 | private final BitmapFactory bitmapFactory;
54 |
55 | public ImmutableNode(
56 | int numDims,
57 | int initialOffset,
58 | int offsetFromInitial,
59 | ByteBuffer data,
60 | BitmapFactory bitmapFactory
61 | )
62 | {
63 | this.bitmapFactory = bitmapFactory;
64 | this.numDims = numDims;
65 | this.initialOffset = initialOffset;
66 | this.offsetFromInitial = offsetFromInitial;
67 | short header = data.getShort(initialOffset + offsetFromInitial);
68 | this.isLeaf = (header & 0x8000) != 0;
69 | this.numChildren = (short) (header & 0x7FFF);
70 | final int sizePosition = initialOffset + offsetFromInitial + HEADER_NUM_BYTES + 2 * numDims * Floats.BYTES;
71 | int bitmapSize = data.getInt(sizePosition);
72 | this.childrenOffset = initialOffset
73 | + offsetFromInitial
74 | + HEADER_NUM_BYTES
75 | + 2 * numDims * Floats.BYTES
76 | + Ints.BYTES
77 | + bitmapSize;
78 |
79 | this.data = data;
80 | }
81 |
82 | public ImmutableNode(
83 | int numDims,
84 | int initialOffset,
85 | int offsetFromInitial,
86 | short numChildren,
87 | boolean leaf,
88 | ByteBuffer data,
89 | BitmapFactory bitmapFactory
90 | )
91 | {
92 | this.bitmapFactory = bitmapFactory;
93 | this.numDims = numDims;
94 | this.initialOffset = initialOffset;
95 | this.offsetFromInitial = offsetFromInitial;
96 | this.numChildren = numChildren;
97 | this.isLeaf = leaf;
98 | final int sizePosition = initialOffset + offsetFromInitial + HEADER_NUM_BYTES + 2 * numDims * Floats.BYTES;
99 | int bitmapSize = data.getInt(sizePosition);
100 | this.childrenOffset = initialOffset
101 | + offsetFromInitial
102 | + HEADER_NUM_BYTES
103 | + 2 * numDims * Floats.BYTES
104 | + Ints.BYTES
105 | + bitmapSize;
106 |
107 | this.data = data;
108 | }
109 |
110 | public BitmapFactory getBitmapFactory()
111 | {
112 | return bitmapFactory;
113 | }
114 |
115 | public int getInitialOffset()
116 | {
117 | return initialOffset;
118 | }
119 |
120 | public int getOffsetFromInitial()
121 | {
122 | return offsetFromInitial;
123 | }
124 |
125 | public int getNumDims()
126 | {
127 | return numDims;
128 | }
129 |
130 | public int getNumChildren()
131 | {
132 | return numChildren;
133 | }
134 |
135 | public boolean isLeaf()
136 | {
137 | return isLeaf;
138 | }
139 |
140 | public float[] getMinCoordinates()
141 | {
142 | return getCoords(initialOffset + offsetFromInitial + HEADER_NUM_BYTES);
143 | }
144 |
145 | public float[] getMaxCoordinates()
146 | {
147 | return getCoords(initialOffset + offsetFromInitial + HEADER_NUM_BYTES + numDims * Floats.BYTES);
148 | }
149 |
150 | public ImmutableBitmap getImmutableBitmap()
151 | {
152 | final int sizePosition = initialOffset + offsetFromInitial + HEADER_NUM_BYTES + 2 * numDims * Floats.BYTES;
153 | int numBytes = data.getInt(sizePosition);
154 | data.position(sizePosition + Ints.BYTES);
155 | ByteBuffer tmpBuffer = data.slice();
156 | tmpBuffer.limit(numBytes);
157 | return bitmapFactory.mapImmutableBitmap(tmpBuffer.asReadOnlyBuffer());
158 | }
159 |
160 | public Iterable getChildren()
161 | {
162 | return new Iterable()
163 | {
164 | @Override
165 | public Iterator iterator()
166 | {
167 | return new Iterator()
168 | {
169 | private volatile int count = 0;
170 |
171 | @Override
172 | public boolean hasNext()
173 | {
174 | return (count < numChildren);
175 | }
176 |
177 | @Override
178 | public ImmutableNode next()
179 | {
180 | if (isLeaf) {
181 | return new ImmutablePoint(
182 | numDims,
183 | initialOffset,
184 | data.getInt(childrenOffset + (count++) * Ints.BYTES),
185 | data,
186 | bitmapFactory
187 | );
188 | }
189 | return new ImmutableNode(
190 | numDims,
191 | initialOffset,
192 | data.getInt(childrenOffset + (count++) * Ints.BYTES),
193 | data,
194 | bitmapFactory
195 | );
196 | }
197 |
198 | @Override
199 | public void remove()
200 | {
201 | throw new UnsupportedOperationException();
202 | }
203 | };
204 | }
205 | };
206 | }
207 |
208 | public ByteBuffer getData()
209 | {
210 | return data;
211 | }
212 |
213 | private float[] getCoords(int offset)
214 | {
215 | final float[] retVal = new float[numDims];
216 |
217 | final ByteBuffer readOnlyBuffer = data.asReadOnlyBuffer();
218 | readOnlyBuffer.position(offset);
219 | readOnlyBuffer.asFloatBuffer().get(retVal);
220 |
221 | return retVal;
222 | }
223 | }
224 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/ImmutablePoint.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial;
18 |
19 | import com.metamx.collections.bitmap.BitmapFactory;
20 |
21 | import java.nio.ByteBuffer;
22 |
23 | public class ImmutablePoint extends ImmutableNode
24 | {
25 | public ImmutablePoint(
26 | int numDims,
27 | int initialOffset,
28 | int offsetFromInitial,
29 | ByteBuffer data,
30 | BitmapFactory bitmapFactory
31 | )
32 | {
33 | super(numDims, initialOffset, offsetFromInitial, (short) 0, true, data, bitmapFactory);
34 | }
35 |
36 | public ImmutablePoint(ImmutableNode node)
37 | {
38 | super(
39 | node.getNumDims(),
40 | node.getInitialOffset(),
41 | node.getOffsetFromInitial(),
42 | (short) 0,
43 | true,
44 | node.getData(),
45 | node.getBitmapFactory()
46 | );
47 | }
48 |
49 | public float[] getCoords()
50 | {
51 | return super.getMinCoordinates();
52 | }
53 |
54 | @Override
55 | public Iterable getChildren()
56 | {
57 | // should never get here
58 | throw new UnsupportedOperationException();
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/ImmutableRTree.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial;
18 |
19 | import com.google.common.base.Preconditions;
20 | import com.google.common.collect.ImmutableList;
21 | import com.google.common.primitives.Ints;
22 | import com.metamx.collections.bitmap.BitmapFactory;
23 | import com.metamx.collections.bitmap.ImmutableBitmap;
24 | import com.metamx.collections.spatial.search.Bound;
25 | import com.metamx.collections.spatial.search.GutmanSearchStrategy;
26 | import com.metamx.collections.spatial.search.SearchStrategy;
27 |
28 | import java.nio.ByteBuffer;
29 |
30 | /**
31 | * An immutable representation of an {@link RTree} for spatial indexing.
32 | */
33 | public class ImmutableRTree
34 | {
35 | private static byte VERSION = 0x0;
36 |
37 | public static ImmutableRTree newImmutableFromMutable(RTree rTree)
38 | {
39 | if (rTree.getSize() == 0) {
40 | return new ImmutableRTree();
41 | }
42 |
43 | ByteBuffer buffer = ByteBuffer.wrap(new byte[calcNumBytes(rTree)]);
44 |
45 | buffer.put(VERSION);
46 | buffer.putInt(rTree.getNumDims());
47 | rTree.getRoot().storeInByteBuffer(buffer, buffer.position());
48 | buffer.position(0);
49 | return new ImmutableRTree(buffer.asReadOnlyBuffer(), rTree.getBitmapFactory());
50 | }
51 |
52 | private static int calcNumBytes(RTree tree)
53 | {
54 | int total = 1 + Ints.BYTES; // VERSION and numDims
55 |
56 | total += calcNodeBytes(tree.getRoot());
57 |
58 | return total;
59 | }
60 |
61 | private static int calcNodeBytes(Node node)
62 | {
63 | int total = 0;
64 |
65 | // find size of this node
66 | total += node.getSizeInBytes();
67 |
68 | // recursively find sizes of child nodes
69 | for (Node child : node.getChildren()) {
70 | if (node.isLeaf()) {
71 | total += child.getSizeInBytes();
72 | } else {
73 | total += calcNodeBytes(child);
74 | }
75 | }
76 |
77 | return total;
78 | }
79 |
80 | private final int numDims;
81 | private final ImmutableNode root;
82 | private final ByteBuffer data;
83 |
84 | private final SearchStrategy defaultSearchStrategy = new GutmanSearchStrategy();
85 |
86 | public ImmutableRTree()
87 | {
88 | this.numDims = 0;
89 | this.data = ByteBuffer.wrap(new byte[]{});
90 | this.root = null;
91 | }
92 |
93 | public ImmutableRTree(ByteBuffer data, BitmapFactory bitmapFactory)
94 | {
95 | final int initPosition = data.position();
96 | Preconditions.checkArgument(data.get(0) == VERSION, "Mismatching versions");
97 | this.numDims = data.getInt(1 + initPosition) & 0x7FFF;
98 | this.data = data;
99 | this.root = new ImmutableNode(numDims, initPosition, 1 + Ints.BYTES, data, bitmapFactory);
100 | }
101 |
102 | public int size()
103 | {
104 | return data.capacity();
105 | }
106 |
107 | public ImmutableNode getRoot()
108 | {
109 | return root;
110 | }
111 |
112 | public int getNumDims()
113 | {
114 | return numDims;
115 | }
116 |
117 | public Iterable search(Bound bound)
118 | {
119 | return search(defaultSearchStrategy, bound);
120 | }
121 |
122 | public Iterable search(SearchStrategy strategy, Bound bound)
123 | {
124 | if(bound.getNumDims() == numDims) {
125 | return strategy.search(root, bound);
126 | }else{
127 | // If the dimension counts don't match (for example, if this is called on a blank `new ImmutableRTree()`)
128 | return ImmutableList.of();
129 | }
130 | }
131 |
132 | public byte[] toBytes()
133 | {
134 | ByteBuffer buf = ByteBuffer.allocate(data.capacity());
135 | buf.put(data.asReadOnlyBuffer());
136 | return buf.array();
137 | }
138 |
139 | public int compareTo(ImmutableRTree other)
140 | {
141 | return this.data.compareTo(other.data);
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/Node.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial;
18 |
19 | import com.google.common.base.Preconditions;
20 | import com.google.common.collect.Lists;
21 | import com.google.common.primitives.Floats;
22 | import com.google.common.primitives.Ints;
23 | import com.metamx.collections.bitmap.MutableBitmap;
24 | import com.metamx.collections.bitmap.BitmapFactory;
25 |
26 | import java.nio.ByteBuffer;
27 | import java.util.Arrays;
28 | import java.util.List;
29 |
30 | /**
31 | */
32 | public class Node
33 | {
34 | private final float[] minCoordinates;
35 | private final float[] maxCoordinates;
36 |
37 | private final List children;
38 | private final boolean isLeaf;
39 | private final MutableBitmap bitmap;
40 |
41 | private Node parent;
42 |
43 | public Node(float[] minCoordinates, float[] maxCoordinates, boolean isLeaf, BitmapFactory bitmapFactory)
44 | {
45 | this(
46 | minCoordinates,
47 | maxCoordinates,
48 | Lists.newArrayList(),
49 | isLeaf,
50 | null,
51 | bitmapFactory.makeEmptyMutableBitmap()
52 | );
53 | }
54 |
55 | public Node(
56 | float[] minCoordinates,
57 | float[] maxCoordinates,
58 | List children,
59 | boolean isLeaf,
60 | Node parent,
61 | MutableBitmap bitmap
62 | )
63 | {
64 | Preconditions.checkArgument(minCoordinates.length == maxCoordinates.length);
65 |
66 | this.minCoordinates = minCoordinates;
67 | this.maxCoordinates = maxCoordinates;
68 | this.children = children;
69 | for (Node child : children) {
70 | child.setParent(this);
71 | }
72 | this.isLeaf = isLeaf;
73 | this.bitmap = bitmap;
74 | this.parent = parent;
75 | }
76 |
77 | public int getNumDims()
78 | {
79 | return minCoordinates.length;
80 | }
81 |
82 | public float[] getMinCoordinates()
83 | {
84 | return minCoordinates;
85 | }
86 |
87 | public float[] getMaxCoordinates()
88 | {
89 | return maxCoordinates;
90 | }
91 |
92 | public Node getParent()
93 | {
94 | return parent;
95 | }
96 |
97 | public void addChild(Node node)
98 | {
99 | node.setParent(this);
100 | children.add(node);
101 | }
102 |
103 | public List getChildren()
104 | {
105 | return children;
106 | }
107 |
108 | public boolean isLeaf()
109 | {
110 | return isLeaf;
111 | }
112 |
113 | public double getArea()
114 | {
115 | return calculateArea();
116 | }
117 |
118 | public boolean contains(Node other)
119 | {
120 | Preconditions.checkArgument(getNumDims() == other.getNumDims());
121 |
122 | for (int i = 0; i < getNumDims(); i++) {
123 | if (other.getMinCoordinates()[i] < minCoordinates[i] || other.getMaxCoordinates()[i] > maxCoordinates[i]) {
124 | return false;
125 | }
126 | }
127 | return true;
128 | }
129 |
130 | public boolean contains(float[] coords)
131 | {
132 | Preconditions.checkArgument(getNumDims() == coords.length);
133 |
134 | for (int i = 0; i < getNumDims(); i++) {
135 | if (coords[i] < minCoordinates[i] || coords[i] > maxCoordinates[i]) {
136 | return false;
137 | }
138 | }
139 | return true;
140 | }
141 |
142 | public boolean enclose()
143 | {
144 | boolean retVal = false;
145 | float[] minCoords = new float[getNumDims()];
146 | Arrays.fill(minCoords, Float.MAX_VALUE);
147 | float[] maxCoords = new float[getNumDims()];
148 | Arrays.fill(maxCoords, -Float.MAX_VALUE);
149 |
150 | for (Node child : getChildren()) {
151 | for (int i = 0; i < getNumDims(); i++) {
152 | minCoords[i] = Math.min(child.getMinCoordinates()[i], minCoords[i]);
153 | maxCoords[i] = Math.max(child.getMaxCoordinates()[i], maxCoords[i]);
154 | }
155 | }
156 |
157 | if (!Arrays.equals(minCoords, minCoordinates)) {
158 | System.arraycopy(minCoords, 0, minCoordinates, 0, minCoordinates.length);
159 | retVal = true;
160 | }
161 | if (!Arrays.equals(maxCoords, maxCoordinates)) {
162 | System.arraycopy(maxCoords, 0, maxCoordinates, 0, maxCoordinates.length);
163 | retVal = true;
164 | }
165 |
166 | return retVal;
167 | }
168 |
169 | public MutableBitmap getBitmap()
170 | {
171 | return bitmap;
172 | }
173 |
174 | public void addToBitmapIndex(Node node)
175 | {
176 | bitmap.or(node.getBitmap());
177 | }
178 |
179 | public void clear()
180 | {
181 | children.clear();
182 | bitmap.clear();
183 | }
184 |
185 | public int getSizeInBytes()
186 | {
187 | return ImmutableNode.HEADER_NUM_BYTES
188 | + 2 * getNumDims() * Floats.BYTES
189 | + Ints.BYTES // size of the set
190 | + bitmap.getSizeInBytes()
191 | + getChildren().size() * Ints.BYTES;
192 | }
193 |
194 | public int storeInByteBuffer(ByteBuffer buffer, int position)
195 | {
196 | buffer.position(position);
197 | buffer.putShort((short) (((isLeaf ? 0x1 : 0x0) << 15) | getChildren().size()));
198 | for (float v : getMinCoordinates()) {
199 | buffer.putFloat(v);
200 | }
201 | for (float v : getMaxCoordinates()) {
202 | buffer.putFloat(v);
203 | }
204 | byte[] bytes = bitmap.toBytes();
205 | buffer.putInt(bytes.length);
206 | buffer.put(bytes);
207 |
208 | int pos = buffer.position();
209 | int childStartOffset = pos + getChildren().size() * Ints.BYTES;
210 | for (Node child : getChildren()) {
211 | buffer.putInt(pos, childStartOffset);
212 | childStartOffset = child.storeInByteBuffer(buffer, childStartOffset);
213 | pos += Ints.BYTES;
214 | }
215 |
216 | return childStartOffset;
217 | }
218 |
219 | private double calculateArea()
220 | {
221 | double area = 1.0;
222 | for (int i = 0; i < minCoordinates.length; i++) {
223 | area *= (maxCoordinates[i] - minCoordinates[i]);
224 | }
225 | return area;
226 | }
227 |
228 | private void setParent(Node p)
229 | {
230 | parent = p;
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/Point.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial;
18 |
19 | import com.google.common.collect.Lists;
20 | import com.metamx.collections.bitmap.MutableBitmap;
21 | import com.metamx.collections.bitmap.BitmapFactory;
22 |
23 | import java.util.Arrays;
24 | import java.util.List;
25 |
26 | /**
27 | */
28 | public class Point extends Node
29 | {
30 | private static MutableBitmap makeBitmap(int entry, BitmapFactory bitmapFactory)
31 | {
32 | MutableBitmap retVal = bitmapFactory.makeEmptyMutableBitmap();
33 | retVal.add(entry);
34 | return retVal;
35 | }
36 |
37 | private final float[] coords;
38 | private final MutableBitmap bitmap;
39 |
40 | public Point(float[] coords, int entry, BitmapFactory bitmapFactory)
41 | {
42 | super(
43 | coords,
44 | Arrays.copyOf(coords, coords.length),
45 | Lists.newArrayList(),
46 | true,
47 | null,
48 | makeBitmap(entry, bitmapFactory)
49 | );
50 |
51 | this.coords = coords;
52 | this.bitmap = bitmapFactory.makeEmptyMutableBitmap();
53 | this.bitmap.add(entry);
54 | }
55 |
56 | public Point(float[] coords, MutableBitmap entry)
57 | {
58 | super(coords, Arrays.copyOf(coords, coords.length), Lists.newArrayList(), true, null, entry);
59 |
60 | this.coords = coords;
61 | this.bitmap = entry;
62 | }
63 |
64 | public float[] getCoords()
65 | {
66 | return coords;
67 | }
68 |
69 | @Override
70 | public MutableBitmap getBitmap()
71 | {
72 | return bitmap;
73 | }
74 |
75 | @Override
76 | public void addChild(Node node)
77 | {
78 | throw new UnsupportedOperationException();
79 | }
80 |
81 | @Override
82 | public List getChildren()
83 | {
84 | return Lists.newArrayList();
85 | }
86 |
87 | @Override
88 | public boolean isLeaf()
89 | {
90 | return true;
91 | }
92 |
93 | @Override
94 | public double getArea()
95 | {
96 | return 0;
97 | }
98 |
99 | @Override
100 | public boolean contains(Node other)
101 | {
102 | return false;
103 | }
104 |
105 | @Override
106 | public boolean enclose()
107 | {
108 | return false;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/RTree.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial;
18 |
19 | import com.google.common.base.Preconditions;
20 | import com.metamx.collections.bitmap.MutableBitmap;
21 | import com.metamx.collections.bitmap.BitmapFactory;
22 | import com.metamx.collections.spatial.split.LinearGutmanSplitStrategy;
23 | import com.metamx.collections.spatial.split.SplitStrategy;
24 |
25 | import java.util.Arrays;
26 |
27 | /**
28 | * This RTree has been optimized to work with bitmap inverted indexes.
29 | *
30 | * This code will probably make a lot more sense if you read:
31 | * http://www.sai.msu.su/~megera/postgres/gist/papers/gutman-rtree.pdf
32 | */
33 | public class RTree
34 | {
35 | private final int numDims;
36 | private final SplitStrategy splitStrategy;
37 |
38 | private Node root;
39 | private final BitmapFactory bitmapFactory;
40 |
41 | private volatile int size;
42 |
43 | public RTree(BitmapFactory bitmapFactory)
44 | {
45 | this(0, new LinearGutmanSplitStrategy(0, 0, bitmapFactory), bitmapFactory);
46 | }
47 |
48 | public RTree(int numDims, SplitStrategy splitStrategy, BitmapFactory bitmapFactory)
49 | {
50 | this.numDims = numDims;
51 | this.splitStrategy = splitStrategy;
52 | this.bitmapFactory = bitmapFactory;
53 | this.root = buildRoot(true);
54 | }
55 |
56 | public BitmapFactory getBitmapFactory()
57 | {
58 | return bitmapFactory;
59 | }
60 |
61 | /**
62 | * This description is from the original paper.
63 | *
64 | * Algorithm Insert: Insert a new index entry E into an R-tree.
65 | *
66 | * I1. [Find position for new record]. Invoke {@link #chooseLeaf(Node, Point)} to select
67 | * a leaf node L in which to place E.
68 | *
69 | * I2. [Add records to leaf node]. If L has room for another entry, install E. Otherwise invoke
70 | * {@link SplitStrategy} split methods to obtain L and LL containing E and all the old entries of L.
71 | *
72 | * I3. [Propagate changes upward]. Invoke {@link #adjustTree(Node, Node)} on L, also passing LL if a split was
73 | * performed.
74 | *
75 | * I4. [Grow tree taller]. If node split propagation caused the root to split, create a new record whose
76 | * children are the two resulting nodes.
77 | *
78 | * @param coords - the coordinates of the entry
79 | * @param entry - the integer to insert
80 | */
81 | public void insert(float[] coords, int entry)
82 | {
83 | Preconditions.checkArgument(coords.length == numDims);
84 | insertInner(new Point(coords, entry, bitmapFactory));
85 | }
86 |
87 | public void insert(float[] coords, MutableBitmap entry)
88 | {
89 | Preconditions.checkArgument(coords.length == numDims);
90 | insertInner(new Point(coords, entry));
91 | }
92 |
93 | /**
94 | * Not yet implemented.
95 | *
96 | * @param coords - the coordinates of the entry
97 | * @param entry - the integer to insert
98 | *
99 | * @return - whether the operation completed successfully
100 | */
101 | public boolean delete(double[] coords, int entry)
102 | {
103 | throw new UnsupportedOperationException();
104 | }
105 |
106 | public int getSize()
107 | {
108 | return size;
109 | }
110 |
111 | public int getNumDims()
112 | {
113 | return numDims;
114 | }
115 |
116 | public SplitStrategy getSplitStrategy()
117 | {
118 | return splitStrategy;
119 | }
120 |
121 | public Node getRoot()
122 | {
123 | return root;
124 | }
125 |
126 | private Node buildRoot(boolean isLeaf)
127 | {
128 | float[] initMinCoords = new float[numDims];
129 | float[] initMaxCoords = new float[numDims];
130 | Arrays.fill(initMinCoords, -Float.MAX_VALUE);
131 | Arrays.fill(initMaxCoords, Float.MAX_VALUE);
132 |
133 | return new Node(initMinCoords, initMaxCoords, isLeaf, bitmapFactory);
134 | }
135 |
136 | private void insertInner(Point point)
137 | {
138 | Node node = chooseLeaf(root, point);
139 | node.addChild(point);
140 |
141 | if (splitStrategy.needToSplit(node)) {
142 | Node[] groups = splitStrategy.split(node);
143 | adjustTree(groups[0], groups[1]);
144 | } else {
145 | adjustTree(node, null);
146 | }
147 |
148 | size++;
149 | }
150 |
151 |
152 | /**
153 | * This description is from the original paper.
154 | *
155 | * Algorithm ChooseLeaf. Select a leaf node in which to place a new index entry E.
156 | *
157 | * CL1. [Initialize]. Set N to be the root node.
158 | *
159 | * CL2. [Leaf check]. If N is a leaf, return N.
160 | *
161 | * CL3. [Choose subtree]. If N is not a leaf, let F be the entry in N whose rectangle
162 | * FI needs least enlargement to include EI. Resolve ties by choosing the entry with the rectangle
163 | * of smallest area.
164 | *
165 | * CL4. [Descend until a leaf is reached]. Set N to be the child node pointed to by Fp and repeated from CL2.
166 | *
167 | * @param node - current node to evaluate
168 | * @param point - point to insert
169 | *
170 | * @return - leafNode where point can be inserted
171 | */
172 | private Node chooseLeaf(Node node, Point point)
173 | {
174 | node.addToBitmapIndex(point);
175 |
176 | if (node.isLeaf()) {
177 | return node;
178 | }
179 |
180 | double minCost = Double.MAX_VALUE;
181 | Node optimal = node.getChildren().get(0);
182 | for (Node child : node.getChildren()) {
183 | double cost = RTreeUtils.getExpansionCost(child, point);
184 | if (cost < minCost) {
185 | minCost = cost;
186 | optimal = child;
187 | } else if (cost == minCost) {
188 | // Resolve ties by choosing the entry with the rectangle of smallest area
189 | if (child.getArea() < optimal.getArea()) {
190 | optimal = child;
191 | }
192 | }
193 | }
194 |
195 | return chooseLeaf(optimal, point);
196 | }
197 |
198 | /**
199 | * This description is from the original paper.
200 | *
201 | * AT1. [Initialize]. Set N=L. If L was split previously, set NN to be the resulting second node.
202 | *
203 | * AT2. [Check if done]. If N is the root, stop.
204 | *
205 | * AT3. [Adjust covering rectangle in parent entry]. Let P be the parent node of N, and let Ev(N)I be N's entry in P.
206 | * Adjust Ev(N)I so that it tightly encloses all entry rectangles in N.
207 | *
208 | * AT4. [Propagate node split upward]. If N has a partner NN resulting from an earlier split, create a new entry
209 | * Ev(NN) with Ev(NN)p pointing to NN and Ev(NN)I enclosing all rectangles in NN. Add Ev(NN) to p is there is room.
210 | * Otherwise, invoke {@link SplitStrategy} split to product p and pp containing Ev(NN) and all p's old entries.
211 | *
212 | * @param n - first node to adjust
213 | * @param nn - optional second node to adjust
214 | */
215 | private void adjustTree(Node n, Node nn)
216 | {
217 | // special case for root
218 | if (n == root) {
219 | if (nn != null) {
220 | root = buildRoot(false);
221 | root.addChild(n);
222 | root.addChild(nn);
223 | }
224 | root.enclose();
225 | return;
226 | }
227 |
228 | boolean updateParent = n.enclose();
229 |
230 | if (nn != null) {
231 | nn.enclose();
232 | updateParent = true;
233 |
234 | if (splitStrategy.needToSplit(n.getParent())) {
235 | Node[] groups = splitStrategy.split(n.getParent());
236 | adjustTree(groups[0], groups[1]);
237 | }
238 | }
239 |
240 | if (n.getParent() != null && updateParent) {
241 | adjustTree(n.getParent(), null);
242 | }
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/RTreeUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial;
18 |
19 | import com.fasterxml.jackson.databind.ObjectMapper;
20 | import com.google.common.base.Function;
21 | import com.google.common.base.Preconditions;
22 | import com.google.common.base.Throwables;
23 | import com.google.common.collect.Iterables;
24 |
25 | /**
26 | */
27 | public class RTreeUtils
28 | {
29 | private static ObjectMapper jsonMapper = new ObjectMapper();
30 |
31 | public static double getEnclosingArea(Node a, Node b)
32 | {
33 | Preconditions.checkArgument(a.getNumDims() == b.getNumDims());
34 |
35 | double[] minCoords = new double[a.getNumDims()];
36 | double[] maxCoords = new double[a.getNumDims()];
37 |
38 | for (int i = 0; i < minCoords.length; i++) {
39 | minCoords[i] = Math.min(a.getMinCoordinates()[i], b.getMinCoordinates()[i]);
40 | maxCoords[i] = Math.max(a.getMaxCoordinates()[i], b.getMaxCoordinates()[i]);
41 | }
42 |
43 | double area = 1.0;
44 | for (int i = 0; i < minCoords.length; i++) {
45 | area *= (maxCoords[i] - minCoords[i]);
46 | }
47 |
48 | return area;
49 | }
50 |
51 | public static double getExpansionCost(Node node, Point point)
52 | {
53 | Preconditions.checkArgument(node.getNumDims() == point.getNumDims());
54 |
55 | if (node.contains(point.getCoords())) {
56 | return 0;
57 | }
58 |
59 | double expanded = 1.0;
60 | for (int i = 0; i < node.getNumDims(); i++) {
61 | double min = Math.min(point.getCoords()[i], node.getMinCoordinates()[i]);
62 | double max = Math.max(point.getCoords()[i], node.getMinCoordinates()[i]);
63 | expanded *= (max - min);
64 | }
65 |
66 | return (expanded - node.getArea());
67 | }
68 |
69 | public static void enclose(Node[] nodes)
70 | {
71 | for (Node node : nodes) {
72 | node.enclose();
73 | }
74 | }
75 |
76 | public static Iterable getBitmaps(ImmutableRTree tree)
77 | {
78 | return depthFirstSearch(tree.getRoot());
79 | }
80 |
81 | public static Iterable depthFirstSearch(ImmutableNode node)
82 | {
83 | if (node.isLeaf()) {
84 | return Iterables.transform(
85 | node.getChildren(),
86 | new Function()
87 | {
88 | @Override
89 | public ImmutablePoint apply(ImmutableNode tNode)
90 | {
91 | return new ImmutablePoint(tNode);
92 | }
93 | }
94 | );
95 | } else {
96 | return Iterables.concat(
97 | Iterables.transform(
98 |
99 | node.getChildren(),
100 | new Function>()
101 | {
102 | @Override
103 | public Iterable apply(ImmutableNode child)
104 | {
105 | return depthFirstSearch(child);
106 | }
107 | }
108 | )
109 | );
110 | }
111 | }
112 |
113 | public static void print(RTree tree)
114 | {
115 | System.out.printf("numDims : %d%n", tree.getNumDims());
116 | try {
117 | printRTreeNode(tree.getRoot(), 0);
118 | }
119 | catch (Exception e) {
120 | throw Throwables.propagate(e);
121 | }
122 | }
123 |
124 | public static void print(ImmutableRTree tree)
125 | {
126 | System.out.printf("numDims : %d%n", tree.getNumDims());
127 | try {
128 | printNode(tree.getRoot(), 0);
129 | }
130 | catch (Exception e) {
131 | throw Throwables.propagate(e);
132 | }
133 | }
134 |
135 | public static void printRTreeNode(Node node, int level) throws Exception
136 | {
137 | System.out.printf(
138 | "%sminCoords: %s, maxCoords: %s, numChildren: %d, isLeaf:%s%n",
139 | makeDashes(level),
140 | jsonMapper.writeValueAsString(node.getMinCoordinates()),
141 | jsonMapper.writeValueAsString(
142 | node.getMaxCoordinates()
143 | ),
144 | node.getChildren().size(),
145 | node.isLeaf()
146 | );
147 | if (node.isLeaf()) {
148 | for (Node child : node.getChildren()) {
149 | Point point = (Point) (child);
150 | System.out
151 | .printf(
152 | "%scoords: %s, conciseSet: %s%n",
153 | makeDashes(level),
154 | jsonMapper.writeValueAsString(point.getCoords()),
155 | point.getBitmap()
156 | );
157 | }
158 | } else {
159 | level++;
160 | for (Node child : node.getChildren()) {
161 | printRTreeNode(child, level);
162 | }
163 | }
164 | }
165 |
166 | public static boolean verifyEnclose(Node node)
167 | {
168 | for (Node child : node.getChildren()) {
169 | for (int i = 0; i < node.getNumDims(); i++) {
170 | if (child.getMinCoordinates()[i] < node.getMinCoordinates()[i]
171 | || child.getMaxCoordinates()[i] > node.getMaxCoordinates()[i]) {
172 | return false;
173 | }
174 | }
175 | }
176 |
177 | if (!node.isLeaf()) {
178 | for (Node child : node.getChildren()) {
179 | if (!verifyEnclose(child)) {
180 | return false;
181 | }
182 | }
183 | }
184 |
185 | return true;
186 | }
187 |
188 | public static boolean verifyEnclose(ImmutableNode node)
189 | {
190 | for (ImmutableNode child : node.getChildren()) {
191 | for (int i = 0; i < node.getNumDims(); i++) {
192 | if (child.getMinCoordinates()[i] < node.getMinCoordinates()[i]
193 | || child.getMaxCoordinates()[i] > node.getMaxCoordinates()[i]) {
194 | return false;
195 | }
196 | }
197 | }
198 |
199 | if (!node.isLeaf()) {
200 | for (ImmutableNode child : node.getChildren()) {
201 | if (!verifyEnclose(child)) {
202 | return false;
203 | }
204 | }
205 | }
206 |
207 | return true;
208 | }
209 |
210 | private static void printNode(ImmutableNode node, int level) throws Exception
211 | {
212 | System.out.printf(
213 | "%sminCoords: %s, maxCoords: %s, numChildren: %d, isLeaf: %s%n",
214 | makeDashes(level),
215 | jsonMapper.writeValueAsString(node.getMinCoordinates()),
216 | jsonMapper.writeValueAsString(
217 | node.getMaxCoordinates()
218 | ),
219 | node.getNumChildren(),
220 | node.isLeaf()
221 | );
222 | if (node.isLeaf()) {
223 | for (ImmutableNode immutableNode : node.getChildren()) {
224 | ImmutablePoint point = new ImmutablePoint(immutableNode);
225 | System.out
226 | .printf(
227 | "%scoords: %s, conciseSet: %s%n",
228 | makeDashes(level),
229 | jsonMapper.writeValueAsString(point.getCoords()),
230 | point.getImmutableBitmap()
231 | );
232 | }
233 | } else {
234 | level++;
235 | for (ImmutableNode immutableNode : node.getChildren()) {
236 | printNode(immutableNode, level);
237 | }
238 | }
239 | }
240 |
241 | private static String makeDashes(int level)
242 | {
243 | String retVal = "";
244 | for (int i = 0; i < level; i++) {
245 | retVal += "-";
246 | }
247 | return retVal;
248 | }
249 | }
250 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/search/Bound.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial.search;
18 |
19 | import com.fasterxml.jackson.annotation.JsonSubTypes;
20 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
21 | import com.metamx.collections.spatial.ImmutableNode;
22 | import com.metamx.collections.spatial.ImmutablePoint;
23 |
24 | /**
25 | */
26 | @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, property="type")
27 | @JsonSubTypes(value={
28 | @JsonSubTypes.Type(name="rectangular", value=RectangularBound.class),
29 | @JsonSubTypes.Type(name="radius", value=RadiusBound.class),
30 | @JsonSubTypes.Type(name="polygon", value=PolygonBound.class)
31 | })
32 | public interface Bound
33 | {
34 | public int getLimit();
35 |
36 | public int getNumDims();
37 |
38 | public boolean overlaps(ImmutableNode node);
39 |
40 | public boolean contains(float[] coords);
41 |
42 | public Iterable filter(Iterable points);
43 |
44 | public byte[] getCacheKey();
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/search/GutmanSearchStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial.search;
18 |
19 | import com.google.common.base.Function;
20 | import com.google.common.base.Predicate;
21 | import com.google.common.collect.Iterables;
22 | import com.metamx.collections.bitmap.ImmutableBitmap;
23 | import com.metamx.collections.spatial.ImmutableNode;
24 | import com.metamx.collections.spatial.ImmutablePoint;
25 |
26 | /**
27 | */
28 | public class GutmanSearchStrategy implements SearchStrategy
29 | {
30 | @Override
31 | public Iterable search(ImmutableNode node, Bound bound)
32 | {
33 | if (bound.getLimit() > 0) {
34 | return Iterables.transform(
35 | breadthFirstSearch(node, bound),
36 | new Function()
37 | {
38 | @Override
39 | public ImmutableBitmap apply(ImmutableNode immutableNode)
40 | {
41 | return immutableNode.getImmutableBitmap();
42 | }
43 | }
44 | );
45 | }
46 |
47 | return Iterables.transform(
48 | depthFirstSearch(node, bound),
49 | new Function()
50 | {
51 | @Override
52 | public ImmutableBitmap apply(ImmutablePoint immutablePoint)
53 | {
54 | return immutablePoint.getImmutableBitmap();
55 | }
56 | }
57 | );
58 | }
59 |
60 | public Iterable depthFirstSearch(ImmutableNode node, final Bound bound)
61 | {
62 | if (node.isLeaf()) {
63 | return bound.filter(
64 | Iterables.transform(
65 | node.getChildren(),
66 | new Function()
67 | {
68 | @Override
69 | public ImmutablePoint apply(ImmutableNode tNode)
70 | {
71 | return new ImmutablePoint(tNode);
72 | }
73 | }
74 | )
75 | );
76 | } else {
77 | return Iterables.concat(
78 | Iterables.transform(
79 | Iterables.filter(
80 | node.getChildren(),
81 | new Predicate()
82 | {
83 | @Override
84 | public boolean apply(ImmutableNode child)
85 | {
86 | return bound.overlaps(child);
87 | }
88 | }
89 | ),
90 | new Function>()
91 | {
92 | @Override
93 | public Iterable apply(ImmutableNode child)
94 | {
95 | return depthFirstSearch(child, bound);
96 | }
97 | }
98 | )
99 | );
100 | }
101 | }
102 |
103 | public Iterable breadthFirstSearch(
104 | ImmutableNode node,
105 | final Bound bound
106 | )
107 | {
108 | if (node.isLeaf()) {
109 | return Iterables.filter(
110 | node.getChildren(),
111 | new Predicate()
112 | {
113 | @Override
114 | public boolean apply(ImmutableNode immutableNode)
115 | {
116 | return bound.contains(immutableNode.getMinCoordinates());
117 | }
118 | }
119 | );
120 | }
121 | return breadthFirstSearch(node.getChildren(), bound, 0);
122 | }
123 |
124 | public Iterable breadthFirstSearch(
125 | Iterable nodes,
126 | final Bound bound,
127 | int total
128 | )
129 | {
130 | Iterable points = Iterables.concat(
131 | Iterables.transform(
132 | Iterables.filter(
133 | nodes,
134 | new Predicate()
135 | {
136 | @Override
137 | public boolean apply(ImmutableNode immutableNode)
138 | {
139 | return immutableNode.isLeaf();
140 | }
141 | }
142 | ),
143 | new Function>()
144 | {
145 | @Override
146 | public Iterable apply(ImmutableNode immutableNode)
147 | {
148 | return Iterables.filter(
149 | immutableNode.getChildren(),
150 | new Predicate()
151 | {
152 | @Override
153 | public boolean apply(ImmutableNode immutableNode)
154 | {
155 | return bound.contains(immutableNode.getMinCoordinates());
156 | }
157 | }
158 | );
159 | }
160 | }
161 | )
162 | );
163 |
164 | Iterable overlappingNodes = Iterables.filter(
165 | nodes,
166 | new Predicate()
167 | {
168 | @Override
169 | public boolean apply(ImmutableNode immutableNode)
170 | {
171 | return !immutableNode.isLeaf() && bound.overlaps(immutableNode);
172 | }
173 | }
174 | );
175 |
176 | int totalPoints = Iterables.size(points);
177 | int totalOverlap = Iterables.size(overlappingNodes);
178 |
179 | if (totalOverlap == 0 || (totalPoints + totalOverlap + total) >= bound.getLimit()) {
180 | return Iterables.concat(
181 | points,
182 | overlappingNodes
183 | );
184 | } else {
185 | return Iterables.concat(
186 | points,
187 | breadthFirstSearch(
188 | Iterables.concat(
189 | Iterables.transform(
190 | overlappingNodes,
191 | new Function>()
192 | {
193 | @Override
194 | public Iterable apply(ImmutableNode immutableNode)
195 | {
196 | return immutableNode.getChildren();
197 | }
198 | }
199 | )
200 | ),
201 | bound,
202 | totalPoints
203 | )
204 | );
205 | }
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/search/PolygonBound.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial.search;
18 |
19 | import com.fasterxml.jackson.annotation.JsonCreator;
20 | import com.fasterxml.jackson.annotation.JsonProperty;
21 | import com.google.common.base.Preconditions;
22 | import com.google.common.base.Predicate;
23 | import com.google.common.collect.Iterables;
24 | import com.google.common.primitives.Floats;
25 | import com.google.common.primitives.Ints;
26 | import com.metamx.collections.spatial.ImmutableNode;
27 | import com.metamx.collections.spatial.ImmutablePoint;
28 |
29 | import java.nio.ByteBuffer;
30 | import java.util.List;
31 |
32 | /**
33 | */
34 | public class PolygonBound extends RectangularBound
35 | {
36 | private static final byte CACHE_TYPE_ID = 0x02;
37 |
38 | private final float[] abscissa;
39 | private final float[] ordinate;
40 |
41 | @JsonProperty
42 | public float[] getOrdinate()
43 | {
44 | return ordinate;
45 | }
46 |
47 | @JsonProperty
48 | public float[] getAbscissa()
49 | {
50 | return abscissa;
51 | }
52 |
53 | private static float[] getMinCoords(float[] abscissa, float[] ordinate)
54 | {
55 | float[] retVal = new float[2];
56 | retVal[0] = abscissa[0];
57 | retVal[1] = ordinate[0];
58 |
59 | for (int i = 1; i < abscissa.length; i++) {
60 | if (abscissa[i] < retVal[0])
61 | retVal[0] = abscissa[i];
62 | if (ordinate[i] < retVal[1])
63 | retVal[1] = ordinate[i];
64 | }
65 | return retVal;
66 | }
67 |
68 | private static float[] getMaxCoords(float[] abscissa, float[] ordinate)
69 | {
70 | float[] retVal = new float[2];
71 | retVal[0] = abscissa[0];
72 | retVal[1] = ordinate[0];
73 | for (int i = 1; i < abscissa.length; i++)
74 | {
75 | if (abscissa[i] > retVal[0])
76 | retVal[0] = abscissa[i];
77 | if (ordinate[i] > retVal[1])
78 | retVal[1] = ordinate[i];
79 | }
80 | return retVal;
81 | }
82 |
83 | /**
84 | * abscissa and ordinate contain the coordinates of polygon.
85 | * abscissa[i] is the horizontal coordinate for the i'th corner of the polygon,
86 | * and ordinate[i] is the vertical coordinate for the i'th corner.
87 | * The polygon must have more than 2 corners, so the length of abscissa or ordinate must be equal or greater than 3.
88 | *
89 | * if the polygon is a rectangular, which corners are {0.0, 0.0}, {0.0, 1.0}, {1.0, 1.0}, {1.0, 0.0},
90 | * the abscissa should be {0.0, 0.0, 1.0, 1.0} and ordinate should be {0.0, 1.0, 1.0, 0.0}
91 | */
92 | @JsonCreator
93 | public static PolygonBound from(
94 | @JsonProperty("abscissa") float[] abscissa,
95 | @JsonProperty("ordinate") float[] ordinate,
96 | @JsonProperty("limit") int limit
97 | )
98 | {
99 | Preconditions.checkArgument(abscissa.length == ordinate.length); //abscissa and ordinate should be the same length
100 | Preconditions.checkArgument(abscissa.length > 2); //a polygon should have more than 2 corners
101 | return new PolygonBound(abscissa, ordinate, limit);
102 | }
103 |
104 | public static PolygonBound from(float[] abscissa, float[] ordinate)
105 | {
106 | return PolygonBound.from(abscissa, ordinate, 0);
107 | }
108 |
109 | private PolygonBound (float[] abscissa, float[] ordinate, int limit)
110 | {
111 | super(getMinCoords(abscissa, ordinate), getMaxCoords(abscissa, ordinate), limit);
112 | this.abscissa = abscissa;
113 | this.ordinate = ordinate;
114 | }
115 |
116 | @Override
117 | public boolean contains(float[] coords)
118 | {
119 | int polyCorners = abscissa.length;
120 | int j = polyCorners - 1;
121 | boolean oddNodes = false;
122 | for (int i = 0; i < polyCorners; i++)
123 | {
124 | if ((ordinate[i] < coords[1] && ordinate[j] >= coords[1]
125 | || ordinate[j] < coords[1] && ordinate[i] >= coords[1])
126 | && (abscissa[i] <= coords[0] || abscissa[j] <= coords[0]))
127 | {
128 | if (abscissa[i] + (coords[1] - ordinate[i]) / (ordinate[j] - ordinate[i]) * (abscissa[j] - abscissa[i]) < coords[0])
129 | {
130 | oddNodes = !oddNodes;
131 | }
132 | }
133 | j = i;
134 | }
135 | return oddNodes;
136 | }
137 |
138 | @Override
139 | public Iterable filter(Iterable points)
140 | {
141 | return Iterables.filter(
142 | points,
143 | new Predicate()
144 | {
145 | @Override
146 | public boolean apply(ImmutablePoint immutablePoint)
147 | {
148 | return contains(immutablePoint.getCoords());
149 | }
150 | }
151 | );
152 | }
153 |
154 | @Override
155 | public byte[] getCacheKey()
156 | {
157 | ByteBuffer abscissaBuffer = ByteBuffer.allocate(abscissa.length * Floats.BYTES);
158 | abscissaBuffer.asFloatBuffer().put(abscissa);
159 | final byte[] abscissaCacheKey = abscissaBuffer.array();
160 |
161 | ByteBuffer ordinateBuffer = ByteBuffer.allocate(ordinate.length * Floats.BYTES);
162 | ordinateBuffer.asFloatBuffer().put(ordinate);
163 | final byte[] ordinateCacheKey = ordinateBuffer.array();
164 |
165 | final ByteBuffer cacheKey = ByteBuffer
166 | .allocate(1 + abscissaCacheKey.length + ordinateCacheKey.length + Ints.BYTES)
167 | .put(abscissaCacheKey)
168 | .put(ordinateCacheKey)
169 | .putInt(getLimit())
170 | .put(CACHE_TYPE_ID);
171 |
172 | return cacheKey.array();
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/search/RadiusBound.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial.search;
18 |
19 | import com.fasterxml.jackson.annotation.JsonCreator;
20 | import com.fasterxml.jackson.annotation.JsonProperty;
21 | import com.google.common.base.Predicate;
22 | import com.google.common.collect.Iterables;
23 | import com.google.common.primitives.Floats;
24 | import com.google.common.primitives.Ints;
25 | import com.metamx.collections.spatial.ImmutablePoint;
26 |
27 | import java.nio.ByteBuffer;
28 |
29 | /**
30 | */
31 | public class RadiusBound extends RectangularBound
32 | {
33 | private static final byte CACHE_TYPE_ID = 0x01;
34 |
35 | private static float[] getMinCoords(float[] coords, float radius)
36 | {
37 | float[] retVal = new float[coords.length];
38 | for (int i = 0; i < coords.length; i++) {
39 | retVal[i] = coords[i] - radius;
40 | }
41 | return retVal;
42 | }
43 |
44 | private static float[] getMaxCoords(float[] coords, float radius)
45 | {
46 | float[] retVal = new float[coords.length];
47 | for (int i = 0; i < coords.length; i++) {
48 | retVal[i] = coords[i] + radius;
49 | }
50 | return retVal;
51 | }
52 |
53 | private final float[] coords;
54 | private final float radius;
55 |
56 | @JsonCreator
57 | public RadiusBound(
58 | @JsonProperty("coords") float[] coords,
59 | @JsonProperty("radius") float radius,
60 | @JsonProperty("limit") int limit
61 | )
62 | {
63 | super(getMinCoords(coords, radius), getMaxCoords(coords, radius), limit);
64 |
65 | this.coords = coords;
66 | this.radius = radius;
67 | }
68 |
69 | public RadiusBound(
70 | float[] coords,
71 | float radius
72 | )
73 | {
74 | this(coords, radius, 0);
75 | }
76 |
77 | @JsonProperty
78 | public float[] getCoords()
79 | {
80 | return coords;
81 | }
82 |
83 | @JsonProperty
84 | public float getRadius()
85 | {
86 | return radius;
87 | }
88 |
89 | @Override
90 | public boolean contains(float[] otherCoords)
91 | {
92 | double total = 0.0;
93 | for (int i = 0; i < coords.length; i++) {
94 | total += Math.pow(otherCoords[i] - coords[i], 2);
95 | }
96 |
97 | return (total <= Math.pow(radius, 2));
98 | }
99 |
100 | @Override
101 | public Iterable filter(Iterable points)
102 | {
103 | return Iterables.filter(
104 | points,
105 | new Predicate()
106 | {
107 | @Override
108 | public boolean apply(ImmutablePoint point)
109 | {
110 | return contains(point.getCoords());
111 | }
112 | }
113 | );
114 | }
115 |
116 | @Override
117 | public byte[] getCacheKey()
118 | {
119 | final ByteBuffer minCoordsBuffer = ByteBuffer.allocate(coords.length * Floats.BYTES);
120 | minCoordsBuffer.asFloatBuffer().put(coords);
121 | final byte[] minCoordsCacheKey = minCoordsBuffer.array();
122 | final ByteBuffer cacheKey = ByteBuffer
123 | .allocate(1 + minCoordsCacheKey.length + Ints.BYTES + Floats.BYTES)
124 | .put(minCoordsCacheKey)
125 | .putFloat(radius)
126 | .putInt(getLimit())
127 | .put(CACHE_TYPE_ID);
128 | return cacheKey.array();
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/search/RectangularBound.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial.search;
18 |
19 | import com.fasterxml.jackson.annotation.JsonCreator;
20 | import com.fasterxml.jackson.annotation.JsonProperty;
21 | import com.google.common.base.Preconditions;
22 | import com.google.common.base.Predicate;
23 | import com.google.common.collect.Iterables;
24 | import com.google.common.primitives.Floats;
25 | import com.google.common.primitives.Ints;
26 | import com.metamx.collections.spatial.ImmutableNode;
27 | import com.metamx.collections.spatial.ImmutablePoint;
28 |
29 | import java.nio.ByteBuffer;
30 |
31 | /**
32 | */
33 | public class RectangularBound implements Bound
34 | {
35 | private static final byte CACHE_TYPE_ID = 0x0;
36 |
37 | private final float[] minCoords;
38 | private final float[] maxCoords;
39 | private final int limit;
40 | private final int numDims;
41 |
42 | @JsonCreator
43 | public RectangularBound(
44 | @JsonProperty("minCoords") float[] minCoords,
45 | @JsonProperty("maxCoords") float[] maxCoords,
46 | @JsonProperty("limit") int limit
47 | )
48 | {
49 | Preconditions.checkArgument(minCoords.length == maxCoords.length);
50 |
51 | this.numDims = minCoords.length;
52 |
53 | this.minCoords = minCoords;
54 | this.maxCoords = maxCoords;
55 | this.limit = limit;
56 | }
57 |
58 | public RectangularBound(
59 | float[] minCoords,
60 | float[] maxCoords
61 | )
62 | {
63 | this(minCoords, maxCoords, 0);
64 | }
65 |
66 | @JsonProperty
67 | public float[] getMinCoords()
68 | {
69 | return minCoords;
70 | }
71 |
72 | @JsonProperty
73 | public float[] getMaxCoords()
74 | {
75 | return maxCoords;
76 | }
77 |
78 | @JsonProperty
79 | public int getLimit()
80 | {
81 | return limit;
82 | }
83 |
84 | @Override
85 | public int getNumDims()
86 | {
87 | return numDims;
88 | }
89 |
90 | @Override
91 | public boolean overlaps(ImmutableNode node)
92 | {
93 | final float[] nodeMinCoords = node.getMinCoordinates();
94 | final float[] nodeMaxCoords = node.getMaxCoordinates();
95 |
96 | for (int i = 0; i < numDims; i++) {
97 | if (nodeMaxCoords[i] < minCoords[i] || nodeMinCoords[i] > maxCoords[i]) {
98 | return false;
99 | }
100 | }
101 |
102 | return true;
103 | }
104 |
105 | @Override
106 | public boolean contains(float[] coords)
107 | {
108 | for (int i = 0; i < numDims; i++) {
109 | if (coords[i] < minCoords[i] || coords[i] > maxCoords[i]) {
110 | return false;
111 | }
112 | }
113 |
114 | return true;
115 | }
116 |
117 | @Override
118 | public Iterable filter(Iterable points)
119 | {
120 | return Iterables.filter(
121 | points,
122 | new Predicate()
123 | {
124 | @Override
125 | public boolean apply(ImmutablePoint immutablePoint)
126 | {
127 | return contains(immutablePoint.getCoords());
128 | }
129 | }
130 | );
131 | }
132 |
133 | @Override
134 | public byte[] getCacheKey()
135 | {
136 | ByteBuffer minCoordsBuffer = ByteBuffer.allocate(minCoords.length * Floats.BYTES);
137 | minCoordsBuffer.asFloatBuffer().put(minCoords);
138 | final byte[] minCoordsCacheKey = minCoordsBuffer.array();
139 |
140 | ByteBuffer maxCoordsBuffer = ByteBuffer.allocate(maxCoords.length * Floats.BYTES);
141 | maxCoordsBuffer.asFloatBuffer().put(maxCoords);
142 | final byte[] maxCoordsCacheKey = maxCoordsBuffer.array();
143 |
144 | final ByteBuffer cacheKey = ByteBuffer
145 | .allocate(1 + minCoordsCacheKey.length + maxCoordsCacheKey.length + Ints.BYTES)
146 | .put(minCoordsCacheKey)
147 | .put(maxCoordsCacheKey)
148 | .putInt(limit)
149 | .put(CACHE_TYPE_ID);
150 | return cacheKey.array();
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/search/SearchStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial.search;
18 |
19 | import com.metamx.collections.bitmap.ImmutableBitmap;
20 | import com.metamx.collections.spatial.ImmutableNode;
21 | //import it.uniroma3.mat.extendedset.intset.ImmutableConciseSet;
22 |
23 |
24 | /**
25 | */
26 | public interface SearchStrategy
27 | {
28 | public Iterable search(ImmutableNode node, Bound bound);
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/split/GutmanSplitStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial.split;
18 |
19 | import com.google.common.collect.Lists;
20 | import com.metamx.collections.bitmap.BitmapFactory;
21 | import com.metamx.collections.spatial.Node;
22 | import com.metamx.collections.spatial.RTreeUtils;
23 |
24 | import java.util.Arrays;
25 | import java.util.List;
26 |
27 | /**
28 | */
29 | public abstract class GutmanSplitStrategy implements SplitStrategy
30 | {
31 | private final int minNumChildren;
32 | private final int maxNumChildren;
33 | private final BitmapFactory bf;
34 |
35 | protected GutmanSplitStrategy(int minNumChildren, int maxNumChildren, BitmapFactory b)
36 | {
37 | this.minNumChildren = minNumChildren;
38 | this.maxNumChildren = maxNumChildren;
39 | this.bf = b;
40 | }
41 |
42 | @Override
43 | public boolean needToSplit(Node node)
44 | {
45 | return (node.getChildren().size() > maxNumChildren);
46 | }
47 |
48 | /**
49 | * This algorithm is from the original paper.
50 | *
51 | * Algorithm Split. Divide a set of M+1 index entries into two groups.
52 | *
53 | * S1. [Pick first entry for each group]. Apply Algorithm {@link #pickSeeds(java.util.List)} to choose
54 | * two entries to be the first elements of the groups. Assign each to a group.
55 | *
56 | * S2. [Check if done]. If all entries have been assigned, stop. If one group has so few entries that all the rest
57 | * must be assigned to it in order for it to have the minimum number m, assign them and stop.
58 | *
59 | * S3. [Select entry to assign]. Invoke Algorithm {@link #pickNext(java.util.List, com.metamx.collections.spatial.Node[])}
60 | * to choose the next entry to assign. Add it to the group whose covering rectangle will have to be enlarged least to
61 | * accommodate it. Resolve ties by adding the entry to the group smaller area, then to the one with fewer entries, then
62 | * to either. Repeat from S2.
63 | */
64 | @Override
65 | public Node[] split(Node node)
66 | {
67 | List children = Lists.newArrayList(node.getChildren());
68 | Node[] seeds = pickSeeds(children);
69 |
70 | node.clear();
71 | node.addChild(seeds[0]);
72 | node.addToBitmapIndex(seeds[0]);
73 |
74 | Node group1 = new Node(
75 | Arrays.copyOf(seeds[1].getMinCoordinates(), seeds[1].getMinCoordinates().length),
76 | Arrays.copyOf(seeds[1].getMaxCoordinates(), seeds[1].getMaxCoordinates().length),
77 | Lists.newArrayList(seeds[1]),
78 | node.isLeaf(),
79 | node.getParent(),
80 | bf.makeEmptyMutableBitmap()
81 | );
82 | group1.addToBitmapIndex(seeds[1]);
83 | if (node.getParent() != null) {
84 | node.getParent().addChild(group1);
85 | }
86 | Node[] groups = new Node[]{
87 | node, group1
88 | };
89 |
90 | RTreeUtils.enclose(groups);
91 |
92 | while (!children.isEmpty()) {
93 | for (Node group : groups) {
94 | if (group.getChildren().size() + children.size() <= minNumChildren) {
95 | for (Node child : children) {
96 | group.addToBitmapIndex(child);
97 | group.addChild(child);
98 | }
99 | RTreeUtils.enclose(groups);
100 | return groups;
101 | }
102 | }
103 |
104 | Node nextToAssign = pickNext(children, groups);
105 | double group0ExpandedArea = RTreeUtils.getEnclosingArea(groups[0], nextToAssign);
106 | double group1ExpandedArea = RTreeUtils.getEnclosingArea(groups[1], nextToAssign);
107 |
108 | Node optimal;
109 | if (group0ExpandedArea < group1ExpandedArea) {
110 | optimal = groups[0];
111 | } else if (group0ExpandedArea == group1ExpandedArea) {
112 | if (groups[0].getArea() < groups[1].getArea()) {
113 | optimal = groups[0];
114 | } else {
115 | optimal = groups[1];
116 | }
117 | } else {
118 | optimal = groups[1];
119 | }
120 |
121 | optimal.addToBitmapIndex(nextToAssign);
122 | optimal.addChild(nextToAssign);
123 | optimal.enclose();
124 | }
125 |
126 | return groups;
127 | }
128 |
129 | public abstract Node[] pickSeeds(List nodes);
130 |
131 | public abstract Node pickNext(List nodes, Node[] groups);
132 | }
133 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/split/LinearGutmanSplitStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial.split;
18 |
19 | import com.metamx.collections.spatial.Node;
20 | import com.metamx.collections.bitmap.BitmapFactory;
21 |
22 | import java.util.List;
23 |
24 | /**
25 | */
26 | public class LinearGutmanSplitStrategy extends GutmanSplitStrategy
27 | {
28 | public LinearGutmanSplitStrategy(int minNumChildren, int maxNumChildren, BitmapFactory bf)
29 | {
30 | super(minNumChildren, maxNumChildren, bf);
31 | }
32 |
33 | /**
34 | * This algorithm is from the original paper.
35 | *
36 | * Algorithm LinearPickSeeds. Select two entries to be the first elements of the groups.
37 | *
38 | * LPS1. [Find extreme rectangles along all dimensions]. Along each dimension, find the entry whose rectangle has
39 | * the highest low side, and the one with the lowest high side. Record the separation.
40 | *
41 | * LPS2. [Adjust for shape of the rectangle cluster]. Normalize the separations by dividing by the width of the
42 | * entire set along the corresponding dimension.
43 | *
44 | * LPS3. [Select the most extreme pair]. Choose the pair with the greatest normalized separation along any dimension.
45 | *
46 | * @param nodes - nodes to choose from
47 | * @return - two groups representing the seeds
48 | */
49 | @Override
50 | public Node[] pickSeeds(List nodes)
51 | {
52 | int[] optimalIndices = new int[2];
53 | int numDims = nodes.get(0).getNumDims();
54 |
55 | double bestNormalized = 0.0;
56 | for (int i = 0; i < numDims; i++) {
57 | float minCoord = Float.MAX_VALUE;
58 | float maxCoord = -Float.MAX_VALUE;
59 | float highestLowSide = -Float.MAX_VALUE;
60 | float lowestHighside = Float.MAX_VALUE;
61 | int highestLowSideIndex = 0;
62 | int lowestHighSideIndex = 0;
63 |
64 | int counter = 0;
65 | for (Node node : nodes) {
66 | minCoord = Math.min(minCoord, node.getMinCoordinates()[i]);
67 | maxCoord = Math.max(maxCoord, node.getMaxCoordinates()[i]);
68 |
69 | if (node.getMinCoordinates()[i] > highestLowSide) {
70 | highestLowSide = node.getMinCoordinates()[i];
71 | highestLowSideIndex = counter;
72 | }
73 | if (node.getMaxCoordinates()[i] < lowestHighside) {
74 | lowestHighside = node.getMaxCoordinates()[i];
75 | lowestHighSideIndex = counter;
76 | }
77 |
78 | counter++;
79 | }
80 | double normalizedSeparation = (highestLowSideIndex == lowestHighSideIndex) ? -1.0 :
81 | Math.abs((highestLowSide - lowestHighside) / (maxCoord - minCoord));
82 | if (normalizedSeparation > bestNormalized) {
83 | optimalIndices[0] = highestLowSideIndex;
84 | optimalIndices[1] = lowestHighSideIndex;
85 | bestNormalized = normalizedSeparation;
86 | }
87 | }
88 |
89 | // Didn't actually find anything, just return first 2 children
90 | if (bestNormalized == 0) {
91 | optimalIndices[0] = 0;
92 | optimalIndices[1] = 1;
93 | }
94 |
95 | int indexToRemove1 = Math.min(optimalIndices[0], optimalIndices[1]);
96 | int indexToRemove2 = Math.max(optimalIndices[0], optimalIndices[1]);
97 | return new Node[]{nodes.remove(indexToRemove1), nodes.remove(indexToRemove2 - 1)};
98 | }
99 |
100 | /**
101 | * This algorithm is from the original paper.
102 | *
103 | * Algorithm LinearPickNext. PickNext simply choose any of the remaining entries.
104 | *
105 | * @param nodes - remaining nodes
106 | * @param groups - the left and right groups
107 | * @return - the optimal selected node
108 | */
109 | @Override
110 | public Node pickNext(List nodes, Node[] groups)
111 | {
112 | return nodes.remove(0);
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/split/QuadraticGutmanSplitStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial.split;
18 |
19 | import com.metamx.collections.spatial.Node;
20 | import com.metamx.collections.spatial.RTreeUtils;
21 | import com.metamx.collections.bitmap.BitmapFactory;
22 |
23 | import java.util.List;
24 |
25 | /**
26 | */
27 | public class QuadraticGutmanSplitStrategy extends GutmanSplitStrategy
28 | {
29 | public QuadraticGutmanSplitStrategy(int minNumChildren, int maxNumChildren, BitmapFactory bf)
30 | {
31 | super(minNumChildren, maxNumChildren, bf);
32 | }
33 |
34 | @Override
35 | public Node[] pickSeeds(List nodes)
36 | {
37 | double highestCost = Double.MIN_VALUE;
38 | int[] highestCostIndices = new int[2];
39 |
40 | for (int i = 0; i < nodes.size() - 1; i++) {
41 | for (int j = i + 1; j < nodes.size(); j++) {
42 | double cost = RTreeUtils.getEnclosingArea(nodes.get(i), nodes.get(j)) -
43 | nodes.get(i).getArea() - nodes.get(j).getArea();
44 | if (cost > highestCost) {
45 | highestCost = cost;
46 | highestCostIndices[0] = i;
47 | highestCostIndices[1] = j;
48 | }
49 | }
50 | }
51 |
52 | return new Node[]{nodes.remove(highestCostIndices[0]), nodes.remove(highestCostIndices[1] - 1)};
53 | }
54 |
55 | @Override
56 | public Node pickNext(List nodes, Node[] groups)
57 | {
58 | double highestCost = Double.MIN_VALUE;
59 | Node costlyNode = null;
60 | int counter = 0;
61 | int index = -1;
62 | for (Node node : nodes) {
63 | double group0Cost = RTreeUtils.getEnclosingArea(node, groups[0]);
64 | double group1Cost = RTreeUtils.getEnclosingArea(node, groups[1]);
65 | double cost = Math.abs(group0Cost - group1Cost);
66 | if (cost > highestCost) {
67 | highestCost = cost;
68 | costlyNode = node;
69 | index = counter;
70 | }
71 | counter++;
72 | }
73 |
74 | if (costlyNode != null) {
75 | nodes.remove(index);
76 | }
77 |
78 | return costlyNode;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/com/metamx/collections/spatial/split/SplitStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial.split;
18 |
19 | import com.metamx.collections.spatial.Node;
20 |
21 | /**
22 | */
23 | public interface SplitStrategy
24 | {
25 | public boolean needToSplit(Node node);
26 |
27 | public Node[] split(Node node);
28 | }
29 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/collections/IntSetTestUtility.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections;
18 |
19 | import com.google.common.collect.Lists;
20 | import com.google.common.collect.Sets;
21 | import com.metamx.collections.bitmap.ImmutableBitmap;
22 | import com.metamx.collections.bitmap.MutableBitmap;
23 | import org.roaringbitmap.IntIterator;
24 |
25 | import java.util.BitSet;
26 | import java.util.HashSet;
27 | import java.util.Iterator;
28 | import java.util.Set;
29 |
30 | /**
31 | *
32 | */
33 | public class IntSetTestUtility
34 | {
35 |
36 | private static Set setBits = Sets.newTreeSet(Lists.newArrayList(1, 2, 3, 5, 8, 13, 21));
37 | public static Set getSetBits(){
38 | return Sets.newTreeSet(setBits);
39 | }
40 | public static final BitSet createSimpleBitSet(Set setBits){
41 | BitSet retval = new BitSet();
42 | for(int i : setBits){
43 | retval.set(i);
44 | }
45 | return retval;
46 | }
47 |
48 | public static final void addAllToMutable(MutableBitmap mutableBitmap, Iterable intSet){
49 | for(Integer integer : intSet){
50 | mutableBitmap.add(integer);
51 | }
52 | }
53 |
54 | private static class IntIt implements Iterable
55 | {
56 | private final Iterator intIter;
57 | public IntIt(IntIterator intIt){
58 | this.intIter = new IntIter(intIt);
59 | }
60 |
61 | @Override
62 | public Iterator iterator()
63 | {
64 | return intIter;
65 | }
66 |
67 | private static class IntIter implements Iterator
68 | {
69 | private final IntIterator intIt;
70 |
71 | public IntIter(IntIterator intIt)
72 | {
73 | this.intIt = intIt;
74 | }
75 |
76 | @Override
77 | public boolean hasNext()
78 | {
79 | return intIt.hasNext();
80 | }
81 |
82 | @Override
83 | public Integer next()
84 | {
85 | return intIt.next();
86 | }
87 |
88 | @Override
89 | public void remove()
90 | {
91 | throw new UnsupportedOperationException("Cannot remove ints from int iterator");
92 | }
93 | }
94 | }
95 |
96 | public static Boolean equalSets(Set s1, ImmutableBitmap s2){
97 | Set s3 = new HashSet<>();
98 | for(Integer i : new IntIt(s2.iterator())){
99 | s3.add(i);
100 | }
101 | return Sets.difference(s1,s3).isEmpty();
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/collections/TestIntegerSet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections;
18 |
19 | import com.google.common.collect.Lists;
20 | import com.google.common.collect.Sets;
21 | import com.metamx.collections.bitmap.MutableBitmap;
22 | import com.metamx.collections.bitmap.WrappedBitSetBitmap;
23 | import com.metamx.collections.bitmap.WrappedConciseBitmap;
24 | import com.metamx.collections.bitmap.WrappedRoaringBitmap;
25 | import org.junit.Assert;
26 | import org.junit.Test;
27 |
28 | import java.util.Set;
29 |
30 | /**
31 | *
32 | */
33 | public class TestIntegerSet
34 | {
35 | @Test
36 | public void testSimpleSet(){
37 | WrappedBitSetBitmap wrappedBitSetBitmapBitSet = new WrappedBitSetBitmap();
38 | IntSetTestUtility.addAllToMutable(wrappedBitSetBitmapBitSet,IntSetTestUtility.getSetBits());
39 | IntegerSet integerSet = IntegerSet.wrap(wrappedBitSetBitmapBitSet);
40 |
41 | Assert.assertTrue(Sets.difference(integerSet, IntSetTestUtility.getSetBits()).isEmpty());
42 | }
43 |
44 | private static Iterable> clazzes = Lists.newArrayList(
45 | WrappedBitSetBitmap.class,
46 | WrappedConciseBitmap.class,
47 | WrappedRoaringBitmap.class
48 | );
49 |
50 | @Test
51 | public void testSimpleAdd() throws IllegalAccessException, InstantiationException
52 | {
53 | for(Class extends MutableBitmap> clazz : clazzes) {
54 | MutableBitmap wrappedBitmap = clazz.newInstance();
55 | IntSetTestUtility.addAllToMutable(wrappedBitmap, IntSetTestUtility.getSetBits());
56 | IntegerSet integerSet = IntegerSet.wrap(wrappedBitmap);
57 |
58 | Set set = IntSetTestUtility.getSetBits();
59 | set.add(999);
60 | integerSet.add(999);
61 |
62 | Assert.assertTrue(Sets.difference(integerSet, set).isEmpty());
63 |
64 | integerSet.add(58577);
65 | Assert.assertFalse(Sets.difference(integerSet, set).isEmpty());
66 | }
67 | }
68 |
69 | @Test
70 | public void testContainsAll() throws IllegalAccessException, InstantiationException
71 | {
72 | for(Class extends MutableBitmap> clazz : clazzes) {
73 | MutableBitmap wrappedBitmap = clazz.newInstance();
74 | IntSetTestUtility.addAllToMutable(wrappedBitmap, IntSetTestUtility.getSetBits());
75 | IntegerSet integerSet = IntegerSet.wrap(wrappedBitmap);
76 |
77 | Set set = IntSetTestUtility.getSetBits();
78 | Assert.assertTrue(integerSet.containsAll(set));
79 |
80 | set.add(999);
81 | Assert.assertFalse(integerSet.containsAll(set));
82 | }
83 | }
84 |
85 | @Test
86 | public void testRemoveEverything() throws IllegalAccessException, InstantiationException
87 | {
88 | for(Class extends MutableBitmap> clazz : clazzes) {
89 | MutableBitmap wrappedBitmap = clazz.newInstance();
90 | IntSetTestUtility.addAllToMutable(wrappedBitmap, IntSetTestUtility.getSetBits());
91 | IntegerSet integerSet = IntegerSet.wrap(wrappedBitmap);
92 |
93 | Set set = IntSetTestUtility.getSetBits();
94 |
95 | integerSet.removeAll(set);
96 | boolean isEmpty = integerSet.isEmpty();
97 | Assert.assertTrue(isEmpty);
98 | }
99 | }
100 |
101 | @Test
102 | public void testRemoveOneThing() throws IllegalAccessException, InstantiationException
103 | {
104 | for(Class extends MutableBitmap> clazz : clazzes) {
105 | MutableBitmap wrappedBitmap = clazz.newInstance();
106 | IntSetTestUtility.addAllToMutable(wrappedBitmap, IntSetTestUtility.getSetBits());
107 | IntegerSet integerSet = IntegerSet.wrap(wrappedBitmap);
108 |
109 | Set set = IntSetTestUtility.getSetBits();
110 |
111 | integerSet.remove(1);
112 | set.remove(1);
113 |
114 | Assert.assertTrue(Sets.difference(set, integerSet).isEmpty());
115 | }
116 | }
117 |
118 |
119 | @Test
120 | public void testIsEmpty() throws IllegalAccessException, InstantiationException
121 | {
122 | for(Class extends MutableBitmap> clazz : clazzes) {
123 | MutableBitmap wrappedBitmap = clazz.newInstance();
124 | IntSetTestUtility.addAllToMutable(wrappedBitmap, IntSetTestUtility.getSetBits());
125 | IntegerSet integerSet = IntegerSet.wrap(wrappedBitmap);
126 |
127 | Assert.assertFalse(integerSet.isEmpty());
128 |
129 | integerSet.clear();
130 |
131 | Assert.assertTrue(integerSet.isEmpty());
132 |
133 | integerSet.add(1);
134 | Assert.assertFalse(integerSet.isEmpty());
135 | }
136 | }
137 |
138 | @Test
139 | public void testSize() throws IllegalAccessException, InstantiationException
140 | {
141 | for(Class extends MutableBitmap> clazz : clazzes) {
142 | MutableBitmap wrappedBitmap = clazz.newInstance();
143 | IntSetTestUtility.addAllToMutable(wrappedBitmap, IntSetTestUtility.getSetBits());
144 | IntegerSet integerSet = IntegerSet.wrap(wrappedBitmap);
145 |
146 | Set set = IntSetTestUtility.getSetBits();
147 |
148 | Assert.assertEquals(set.size(), integerSet.size());
149 | }
150 | }
151 |
152 |
153 | @Test
154 | public void testRetainAll() throws IllegalAccessException, InstantiationException
155 | {
156 | for(Class extends MutableBitmap> clazz : clazzes) {
157 | MutableBitmap wrappedBitmap = clazz.newInstance();
158 | IntSetTestUtility.addAllToMutable(wrappedBitmap, IntSetTestUtility.getSetBits());
159 | IntegerSet integerSet = IntegerSet.wrap(wrappedBitmap);
160 |
161 | Set set = IntSetTestUtility.getSetBits();
162 |
163 | set.remove(1);
164 | set.add(9999);
165 |
166 | boolean threwError = false;
167 | try {
168 | integerSet.retainAll(set);
169 | }catch(UnsupportedOperationException ex){
170 | threwError = true;
171 | }
172 | Assert.assertTrue(threwError);
173 | }
174 | }
175 |
176 | @Test
177 | public void testIntOverflow() throws IllegalAccessException, InstantiationException
178 | {
179 | for(Class extends MutableBitmap> clazz : clazzes) {
180 | Exception e = null;
181 | try {
182 | MutableBitmap wrappedBitmap = clazz.newInstance();
183 | IntSetTestUtility.addAllToMutable(wrappedBitmap, IntSetTestUtility.getSetBits());
184 | IntegerSet integerSet = IntegerSet.wrap(wrappedBitmap);
185 | integerSet.add(Integer.MAX_VALUE + 1);
186 | }catch(java.lang.IllegalArgumentException ex){
187 | e = ex;
188 | }
189 | Assert.assertNotNull(e);
190 | }
191 | }
192 |
193 | @Test
194 | public void testToArray() throws IllegalAccessException, InstantiationException
195 | {
196 | for(Class extends MutableBitmap> clazz : clazzes) {
197 | Exception e = null;
198 | MutableBitmap wrappedBitmap = clazz.newInstance();
199 | IntSetTestUtility.addAllToMutable(wrappedBitmap, IntSetTestUtility.getSetBits());
200 | IntegerSet integerSet = IntegerSet.wrap(wrappedBitmap);
201 | Set set = Sets.newHashSet((Integer[]) integerSet.toArray());
202 | Assert.assertTrue(Sets.difference(integerSet, set).isEmpty());
203 | }
204 | }
205 |
206 |
207 | @Test
208 | public void testToSmallArray() throws IllegalAccessException, InstantiationException
209 | {
210 | for(Class extends MutableBitmap> clazz : clazzes) {
211 | Exception e = null;
212 | MutableBitmap wrappedBitmap = clazz.newInstance();
213 | IntSetTestUtility.addAllToMutable(wrappedBitmap, IntSetTestUtility.getSetBits());
214 | IntegerSet integerSet = IntegerSet.wrap(wrappedBitmap);
215 | Set set = Sets.newHashSet((Integer[]) integerSet.toArray(new Integer[0]));
216 | Assert.assertTrue(Sets.difference(integerSet, set).isEmpty());
217 | }
218 | }
219 |
220 |
221 | @Test
222 | public void testToBigArray() throws IllegalAccessException, InstantiationException
223 | {
224 | for(Class extends MutableBitmap> clazz : clazzes) {
225 | Exception e = null;
226 | MutableBitmap wrappedBitmap = clazz.newInstance();
227 | IntSetTestUtility.addAllToMutable(wrappedBitmap, IntSetTestUtility.getSetBits());
228 | IntegerSet integerSet = IntegerSet.wrap(wrappedBitmap);
229 |
230 | Integer[] bigArray = new Integer[1024];
231 | integerSet.toArray(bigArray);
232 | Set set = Sets.newHashSet(bigArray);
233 | Assert.assertTrue(Sets.difference(integerSet, set).isEmpty());
234 | }
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/collections/bitmap/BitmapBenchmark.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import com.carrotsearch.junitbenchmarks.BenchmarkOptions;
20 | import com.carrotsearch.junitbenchmarks.BenchmarkRule;
21 | import com.carrotsearch.junitbenchmarks.Clock;
22 | import com.google.common.collect.Lists;
23 | import it.uniroma3.mat.extendedset.intset.ImmutableConciseSet;
24 | import org.junit.Assert;
25 | import org.junit.Rule;
26 | import org.junit.Test;
27 | import org.junit.rules.TestRule;
28 | import org.roaringbitmap.buffer.BufferFastAggregation;
29 | import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
30 | import org.roaringbitmap.buffer.MutableRoaringBitmap;
31 |
32 | import java.io.ByteArrayOutputStream;
33 | import java.io.DataOutputStream;
34 | import java.io.IOException;
35 | import java.nio.ByteBuffer;
36 | import java.util.Random;
37 |
38 |
39 | @BenchmarkOptions(clock = Clock.NANO_TIME, benchmarkRounds = 50)
40 | public class BitmapBenchmark
41 | {
42 | public static final int LENGTH = 500_000;
43 | public static final int SIZE = 10_000;
44 |
45 | @Rule
46 | public TestRule benchmarkRun = new BenchmarkRule();
47 |
48 | final static ImmutableConciseSet concise[] = new ImmutableConciseSet[SIZE];
49 | final static ImmutableConciseSet offheapConcise[] = new ImmutableConciseSet[SIZE];
50 | final static ImmutableRoaringBitmap roaring[] = new ImmutableRoaringBitmap[SIZE];
51 | final static ImmutableRoaringBitmap immutableRoaring[] = new ImmutableRoaringBitmap[SIZE];
52 | final static ImmutableRoaringBitmap offheapRoaring[] = new ImmutableRoaringBitmap[SIZE];
53 | final static ImmutableBitmap genericConcise[] = new ImmutableBitmap[SIZE];
54 | final static ImmutableBitmap genericRoaring[] = new ImmutableBitmap[SIZE];
55 | final static ConciseBitmapFactory conciseFactory = new ConciseBitmapFactory();
56 | final static RoaringBitmapFactory roaringFactory = new RoaringBitmapFactory();
57 |
58 | static Random rand = new Random(0);
59 | static long totalConciseBytes = 0;
60 | static long totalRoaringBytes = 0;
61 | static long conciseCount = 0;
62 | static long roaringCount = 0;
63 | static long unionCount = 0;
64 | static long minIntersection = 0;
65 |
66 | protected static ImmutableConciseSet makeOffheapConcise(ImmutableConciseSet concise)
67 | {
68 | final byte[] bytes = concise.toBytes();
69 | totalConciseBytes += bytes.length;
70 | conciseCount++;
71 | final ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length).put(bytes);
72 | buf.rewind();
73 | return new ImmutableConciseSet(buf);
74 | }
75 |
76 | protected static ImmutableRoaringBitmap writeImmutable(MutableRoaringBitmap r, ByteBuffer buf) throws IOException
77 | {
78 | final ByteArrayOutputStream out = new ByteArrayOutputStream();
79 | r.serialize(new DataOutputStream(out));
80 | final byte[] bytes = out.toByteArray();
81 | Assert.assertEquals(buf.remaining(), bytes.length);
82 | buf.put(bytes);
83 | buf.rewind();
84 | return new ImmutableRoaringBitmap(buf.asReadOnlyBuffer());
85 | }
86 |
87 | protected static void reset()
88 | {
89 | conciseCount = 0;
90 | roaringCount = 0;
91 | totalConciseBytes = 0;
92 | totalRoaringBytes = 0;
93 | unionCount = 0;
94 | minIntersection = 0;
95 | rand = new Random(0);
96 | }
97 |
98 | protected static void printSizeStats(double density, String name)
99 | {
100 | System.out.println("");
101 | System.out.println("## " + name);
102 | System.out.println("");
103 | System.out.printf(" d = %06.5f | Concise | Roaring" + System.lineSeparator(), density);
104 | System.out.println("-------------|---------|---------");
105 | System.out.printf ("Count | %5d | %5d " + System.lineSeparator(), conciseCount, roaringCount);
106 | System.out.printf ("Average size | %5d | %5d " + System.lineSeparator(), totalConciseBytes / conciseCount, totalRoaringBytes / roaringCount);
107 | System.out.println("-------------|---------|---------");
108 | System.out.println("");
109 | System.out.flush();
110 | }
111 |
112 | protected static ImmutableRoaringBitmap makeOffheapRoaring(MutableRoaringBitmap r) throws IOException
113 | {
114 | final int size = r.serializedSizeInBytes();
115 | final ByteBuffer buf = ByteBuffer.allocateDirect(size);
116 | totalRoaringBytes += size;
117 | roaringCount++;
118 | return writeImmutable(r, buf);
119 | }
120 |
121 | protected static ImmutableRoaringBitmap makeImmutableRoaring(MutableRoaringBitmap r) throws IOException
122 | {
123 | final ByteBuffer buf = ByteBuffer.allocate(r.serializedSizeInBytes());
124 | return writeImmutable(r, buf);
125 | }
126 |
127 | @Test @BenchmarkOptions(warmupRounds = 1, benchmarkRounds = 2)
128 | public void timeConciseUnion() throws Exception
129 | {
130 | ImmutableConciseSet union = ImmutableConciseSet.union(concise);
131 | Assert.assertEquals(unionCount, union.size());
132 | }
133 |
134 | @Test @BenchmarkOptions(warmupRounds = 1, benchmarkRounds = 2)
135 | public void timeOffheapConciseUnion() throws Exception
136 | {
137 | ImmutableConciseSet union = ImmutableConciseSet.union(offheapConcise);
138 | Assert.assertEquals(unionCount, union.size());
139 | }
140 |
141 | @Test @BenchmarkOptions(warmupRounds = 1, benchmarkRounds = 2)
142 | public void timeGenericConciseUnion() throws Exception
143 | {
144 | ImmutableBitmap union = conciseFactory.union(Lists.newArrayList(genericConcise));
145 | Assert.assertEquals(unionCount, union.size());
146 | }
147 |
148 | @Test @BenchmarkOptions(warmupRounds = 1, benchmarkRounds = 5)
149 | public void timeGenericConciseIntersection() throws Exception
150 | {
151 | ImmutableBitmap intersection = conciseFactory.intersection(Lists.newArrayList(genericConcise));
152 | Assert.assertTrue(intersection.size() >= minIntersection);
153 | }
154 |
155 | @Test
156 | public void timeRoaringUnion() throws Exception
157 | {
158 | ImmutableRoaringBitmap union = BufferFastAggregation.horizontal_or(Lists.newArrayList(roaring).iterator());
159 | Assert.assertEquals(unionCount, union.getCardinality());
160 | }
161 |
162 | @Test
163 | public void timeImmutableRoaringUnion() throws Exception
164 | {
165 | ImmutableRoaringBitmap union = BufferFastAggregation.horizontal_or(Lists.newArrayList(immutableRoaring).iterator());
166 | Assert.assertEquals(unionCount, union.getCardinality());
167 | }
168 |
169 | @Test
170 | public void timeOffheapRoaringUnion() throws Exception
171 | {
172 | ImmutableRoaringBitmap union = BufferFastAggregation.horizontal_or(Lists.newArrayList(offheapRoaring).iterator());
173 | Assert.assertEquals(unionCount, union.getCardinality());
174 | }
175 |
176 | @Test
177 | public void timeGenericRoaringUnion() throws Exception
178 | {
179 | ImmutableBitmap union = roaringFactory.union(Lists.newArrayList(genericRoaring));
180 | Assert.assertEquals(unionCount, union.size());
181 | }
182 |
183 | @Test
184 | public void timeGenericRoaringIntersection() throws Exception
185 | {
186 | ImmutableBitmap intersection = roaringFactory.intersection(Lists.newArrayList(genericRoaring));
187 | Assert.assertTrue(intersection.size() >= minIntersection);
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/collections/bitmap/ConciseBitmapFactoryTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import com.google.common.base.Function;
20 | import com.google.common.collect.ImmutableSet;
21 | import com.google.common.collect.Iterables;
22 | import com.google.common.collect.Lists;
23 | import it.uniroma3.mat.extendedset.intset.ConciseSet;
24 | import it.uniroma3.mat.extendedset.intset.ImmutableConciseSet;
25 | import junit.framework.Assert;
26 | import org.junit.Test;
27 |
28 | import java.util.Arrays;
29 | import java.util.Set;
30 |
31 | public class ConciseBitmapFactoryTest
32 | {
33 | @Test
34 | public void testUnwrapWithNull() throws Exception
35 | {
36 | ConciseBitmapFactory factory = new ConciseBitmapFactory();
37 |
38 | ImmutableBitmap bitmap = factory.union(
39 | Iterables.transform(
40 | Lists.newArrayList(new WrappedConciseBitmap()),
41 | new Function()
42 | {
43 | @Override
44 | public ImmutableBitmap apply(WrappedConciseBitmap input)
45 | {
46 | return null;
47 | }
48 | }
49 | )
50 | );
51 |
52 | Assert.assertEquals(0, bitmap.size());
53 | }
54 |
55 | @Test
56 | public void testUnwrapMerge() throws Exception
57 | {
58 | ConciseBitmapFactory factory = new ConciseBitmapFactory();
59 |
60 | WrappedConciseBitmap set = new WrappedConciseBitmap();
61 | set.add(1);
62 | set.add(3);
63 | set.add(5);
64 |
65 | ImmutableBitmap bitmap = factory.union(
66 | Arrays.asList(
67 | factory.makeImmutableBitmap(set),
68 | null
69 | )
70 | );
71 |
72 | Assert.assertEquals(3, bitmap.size());
73 | }
74 |
75 | @Test
76 | public void testGetOutOfBounds()
77 | {
78 | final ConciseSet conciseSet = new ConciseSet();
79 | final Set ints = ImmutableSet.of(0, 4, 9);
80 | for (int i : ints) {
81 | conciseSet.add(i);
82 | }
83 | final ImmutableBitmap immutableBitmap = new WrappedImmutableConciseBitmap(
84 | ImmutableConciseSet.newImmutableFromMutable(conciseSet));
85 | final MutableBitmap mutableBitmap = new WrappedConciseBitmap(conciseSet);
86 | for (int i = 0; i < 10; ++i) {
87 | Assert.assertEquals(Integer.toString(i), ints.contains(i), mutableBitmap.get(i));
88 | Assert.assertEquals(Integer.toString(i), ints.contains(i), immutableBitmap.get(i));
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/collections/bitmap/RangeBitmapBenchmarkTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import com.carrotsearch.junitbenchmarks.annotation.BenchmarkHistoryChart;
20 | import com.carrotsearch.junitbenchmarks.annotation.LabelType;
21 | import com.metamx.test.annotation.Benchmark;
22 | import it.uniroma3.mat.extendedset.intset.ConciseSet;
23 | import it.uniroma3.mat.extendedset.intset.ImmutableConciseSet;
24 | import org.junit.BeforeClass;
25 | import org.junit.experimental.categories.Category;
26 | import org.roaringbitmap.buffer.MutableRoaringBitmap;
27 |
28 | import java.util.BitSet;
29 |
30 | @Category({Benchmark.class})
31 | @BenchmarkHistoryChart(labelWith = LabelType.CUSTOM_KEY, maxRuns = 20)
32 | public class RangeBitmapBenchmarkTest extends BitmapBenchmark
33 | {
34 |
35 | public static final double DENSITY = 0.001;
36 | public static final int MIN_INTERSECT = 50;
37 |
38 | @BeforeClass
39 | public static void prepareRandomRanges() throws Exception
40 | {
41 | System.setProperty("jub.customkey", String.format("%06.5f", DENSITY));
42 | reset();
43 |
44 | final BitSet expectedUnion = new BitSet();
45 | for (int i = 0; i < SIZE; ++i) {
46 | ConciseSet c = new ConciseSet();
47 | MutableRoaringBitmap r = new MutableRoaringBitmap();
48 | {
49 | int k = 0;
50 | boolean fill = true;
51 | while (k < LENGTH) {
52 | int runLength = (int) (LENGTH * DENSITY) + rand.nextInt((int) (LENGTH * DENSITY));
53 | for (int j = k; fill && j < LENGTH && j < k + runLength; ++j) {
54 | c.add(j);
55 | r.add(j);
56 | expectedUnion.set(j);
57 | }
58 | k += runLength;
59 | fill = !fill;
60 | }
61 | }
62 | minIntersection = MIN_INTERSECT;
63 | for (int k = LENGTH / 2; k < LENGTH / 2 + minIntersection; ++k) {
64 | c.add(k);
65 | r.add(k);
66 | expectedUnion.set(k);
67 | }
68 | concise[i] = ImmutableConciseSet.newImmutableFromMutable(c);
69 | offheapConcise[i] = makeOffheapConcise(concise[i]);
70 | roaring[i] = r;
71 | immutableRoaring[i] = makeImmutableRoaring(r);
72 | offheapRoaring[i] = makeOffheapRoaring(r);
73 | genericConcise[i] = new WrappedImmutableConciseBitmap(offheapConcise[i]);
74 | genericRoaring[i] = new WrappedImmutableRoaringBitmap(offheapRoaring[i]);
75 | }
76 | unionCount = expectedUnion.cardinality();
77 | printSizeStats(DENSITY, "Random Alternating Bitmap");
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/collections/bitmap/RoaringBitmapFactoryTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import com.google.common.base.Function;
20 | import com.google.common.collect.Iterables;
21 | import com.google.common.collect.Lists;
22 | import org.junit.Assert;
23 | import org.junit.Test;
24 | import org.roaringbitmap.IntIterator;
25 |
26 | import java.util.Arrays;
27 |
28 | public class RoaringBitmapFactoryTest
29 | {
30 |
31 | // testing https://github.com/metamx/bytebuffer-collections/issues/26
32 | @Test
33 | public void testIssue26() throws Exception
34 | {
35 | checkEmptyComplement(new ConciseBitmapFactory());
36 | checkEmptyComplement(new RoaringBitmapFactory());
37 | }
38 |
39 | // used by issue 26
40 | private void checkEmptyComplement(BitmapFactory bitmapFactory) throws Exception
41 | {
42 | int numRow = 5104234;
43 | ImmutableBitmap bitmap = bitmapFactory.complement(bitmapFactory.makeEmptyImmutableBitmap(), numRow);
44 | ImmutableBitmap notBitmap = bitmapFactory.complement(bitmap,numRow);
45 | Assert.assertTrue(notBitmap.size() == 0);
46 | Assert.assertTrue(notBitmap.isEmpty());
47 | IntIterator intIter = notBitmap.iterator();
48 | Assert.assertFalse(intIter.hasNext());
49 | }
50 |
51 | @Test
52 | public void testUnwrapWithNull() throws Exception
53 | {
54 | RoaringBitmapFactory factory = new RoaringBitmapFactory();
55 |
56 | ImmutableBitmap bitmap = factory.union(
57 | Iterables.transform(
58 | Lists.newArrayList(new WrappedRoaringBitmap()),
59 | new Function()
60 | {
61 | @Override
62 | public ImmutableBitmap apply(WrappedRoaringBitmap input)
63 | {
64 | return null;
65 | }
66 | }
67 | )
68 | );
69 |
70 | Assert.assertEquals(0, bitmap.size());
71 | }
72 |
73 | @Test
74 | public void testUnwrapMerge() throws Exception
75 | {
76 | RoaringBitmapFactory factory = new RoaringBitmapFactory();
77 |
78 | WrappedRoaringBitmap set = new WrappedRoaringBitmap();
79 | set.add(1);
80 | set.add(3);
81 | set.add(5);
82 |
83 | ImmutableBitmap bitmap = factory.union(
84 | Arrays.asList(
85 | factory.makeImmutableBitmap(set),
86 | null
87 | )
88 | );
89 |
90 | Assert.assertEquals(3, bitmap.size());
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/collections/bitmap/UniformBitmapBenchmarkTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import com.carrotsearch.junitbenchmarks.annotation.BenchmarkHistoryChart;
20 | import com.carrotsearch.junitbenchmarks.annotation.LabelType;
21 | import com.metamx.test.annotation.Benchmark;
22 | import it.uniroma3.mat.extendedset.intset.ConciseSet;
23 | import it.uniroma3.mat.extendedset.intset.ImmutableConciseSet;
24 | import org.junit.BeforeClass;
25 | import org.junit.experimental.categories.Category;
26 | import org.roaringbitmap.buffer.MutableRoaringBitmap;
27 |
28 | import java.util.BitSet;
29 |
30 | @Category({Benchmark.class})
31 | @BenchmarkHistoryChart(labelWith = LabelType.CUSTOM_KEY, maxRuns = 20)
32 | public class UniformBitmapBenchmarkTest extends BitmapBenchmark
33 | {
34 |
35 | public static final double DENSITY = 0.01;
36 | public static final int MIN_INTERSECT = 50;
37 |
38 | @BeforeClass
39 | public static void prepareMostlyUniform() throws Exception
40 | {
41 | System.setProperty("jub.customkey", String.format("%05.4f", DENSITY));
42 | reset();
43 |
44 | final BitSet expectedUnion = new BitSet();
45 | final int[] knownTrue = new int[MIN_INTERSECT];
46 | for (int i = 0; i < knownTrue.length; ++i) {
47 | knownTrue[i] = rand.nextInt(LENGTH);
48 | }
49 | for (int i = 0; i < SIZE; ++i) {
50 | ConciseSet c = new ConciseSet();
51 | MutableRoaringBitmap r = new MutableRoaringBitmap();
52 | for (int k = 0; k < LENGTH; ++k) {
53 | if (rand.nextDouble() < DENSITY) {
54 | c.add(k);
55 | r.add(k);
56 | expectedUnion.set(k);
57 | }
58 | }
59 | for (int k : knownTrue) {
60 | c.add(k);
61 | r.add(k);
62 | expectedUnion.set(k);
63 | }
64 | concise[i] = ImmutableConciseSet.newImmutableFromMutable(c);
65 | offheapConcise[i] = makeOffheapConcise(concise[i]);
66 | roaring[i] = r;
67 | immutableRoaring[i] = makeImmutableRoaring(r);
68 | offheapRoaring[i] = makeOffheapRoaring(r);
69 | genericConcise[i] = new WrappedImmutableConciseBitmap(offheapConcise[i]);
70 | genericRoaring[i] = new WrappedImmutableRoaringBitmap(offheapRoaring[i]);
71 | }
72 | unionCount = expectedUnion.cardinality();
73 | minIntersection = knownTrue.length;
74 | printSizeStats(DENSITY, "Uniform Bitmap");
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/collections/bitmap/WrappedBitSetBitmapBitSetTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import com.google.common.collect.Sets;
20 | import com.metamx.collections.IntSetTestUtility;
21 | import org.junit.Assert;
22 | import org.junit.Test;
23 | import org.roaringbitmap.IntIterator;
24 |
25 | import java.nio.ByteBuffer;
26 | import java.nio.ByteOrder;
27 | import java.util.BitSet;
28 | import java.util.Set;
29 |
30 | /**
31 | *
32 | */
33 | public class WrappedBitSetBitmapBitSetTest
34 | {
35 |
36 | private static final WrappedBitSetBitmap defaultBitSet(){
37 | return new WrappedBitSetBitmap(IntSetTestUtility.createSimpleBitSet(IntSetTestUtility.getSetBits()));
38 | }
39 | @Test
40 | public void testIterator(){
41 | WrappedBitSetBitmap bitSet = new WrappedBitSetBitmap();
42 | for(int i : IntSetTestUtility.getSetBits()){
43 | bitSet.add(i);
44 | }
45 | IntIterator intIt = bitSet.iterator();
46 | for(int i : IntSetTestUtility.getSetBits()){
47 | Assert.assertTrue(intIt.hasNext());
48 | Assert.assertEquals(i,intIt.next());
49 | }
50 | }
51 |
52 | @Test
53 | public void testSize(){
54 | BitSet bitSet = IntSetTestUtility.createSimpleBitSet(IntSetTestUtility.getSetBits());
55 | WrappedBitSetBitmap wrappedBitSetBitmapBitSet = new WrappedBitSetBitmap(bitSet);
56 | Assert.assertEquals(bitSet.cardinality(), wrappedBitSetBitmapBitSet.size());
57 | }
58 |
59 | @Test
60 | public void testOffHeap(){
61 | ByteBuffer buffer = ByteBuffer.allocateDirect(Long.SIZE * 100 / 8).order(ByteOrder.LITTLE_ENDIAN);
62 | BitSet testSet = BitSet.valueOf(buffer);
63 | testSet.set(1);
64 | WrappedImmutableBitSetBitmap bitMap = new WrappedImmutableBitSetBitmap(testSet);
65 | Assert.assertTrue(bitMap.get(1));
66 | testSet.set(2);
67 | Assert.assertTrue(bitMap.get(2));
68 | }
69 | @Test
70 | public void testSimpleBitSet(){
71 | WrappedBitSetBitmap bitSet = new WrappedBitSetBitmap(IntSetTestUtility.createSimpleBitSet(IntSetTestUtility.getSetBits()));
72 | Assert.assertTrue(IntSetTestUtility.equalSets(IntSetTestUtility.getSetBits(), bitSet));
73 | }
74 |
75 | @Test
76 | public void testUnion(){
77 | WrappedBitSetBitmap bitSet = new WrappedBitSetBitmap(IntSetTestUtility.createSimpleBitSet(IntSetTestUtility.getSetBits()));
78 |
79 | Set extraBits = Sets.newHashSet(6,9);
80 | WrappedBitSetBitmap bitExtraSet = new WrappedBitSetBitmap(IntSetTestUtility.createSimpleBitSet(extraBits));
81 |
82 | Set union = Sets.union(extraBits, IntSetTestUtility.getSetBits());
83 |
84 | Assert.assertTrue(IntSetTestUtility.equalSets(union, (WrappedBitSetBitmap) bitSet.union(bitExtraSet)));
85 | }
86 | @Test
87 | public void testIntersection(){
88 | WrappedBitSetBitmap bitSet = new WrappedBitSetBitmap(IntSetTestUtility.createSimpleBitSet(IntSetTestUtility.getSetBits()));
89 |
90 | Set extraBits = Sets.newHashSet(1,2,3,4,5,6,7,8);
91 | WrappedBitSetBitmap bitExtraSet = new WrappedBitSetBitmap(IntSetTestUtility.createSimpleBitSet(extraBits));
92 |
93 | Set intersection = Sets.intersection(extraBits, IntSetTestUtility.getSetBits());
94 |
95 | Assert.assertTrue(IntSetTestUtility.equalSets(intersection, (WrappedBitSetBitmap) bitSet.intersection(bitExtraSet)));
96 | }
97 |
98 | @Test
99 | public void testAnd(){
100 | WrappedBitSetBitmap bitSet = defaultBitSet();
101 | WrappedBitSetBitmap bitSet2 = defaultBitSet();
102 | Set defaultBitSet = IntSetTestUtility.getSetBits();
103 | bitSet.remove(1);
104 | bitSet2.remove(2);
105 |
106 | bitSet.and(bitSet2);
107 |
108 | defaultBitSet.remove(1);
109 | defaultBitSet.remove(2);
110 |
111 | Assert.assertTrue(IntSetTestUtility.equalSets(defaultBitSet,bitSet));
112 | }
113 |
114 |
115 | @Test
116 | public void testOr(){
117 | WrappedBitSetBitmap bitSet = defaultBitSet();
118 | WrappedBitSetBitmap bitSet2 = defaultBitSet();
119 | Set defaultBitSet = IntSetTestUtility.getSetBits();
120 | bitSet.remove(1);
121 | bitSet2.remove(2);
122 |
123 | bitSet.or(bitSet2);
124 |
125 | Assert.assertTrue(IntSetTestUtility.equalSets(defaultBitSet,bitSet));
126 | }
127 |
128 | @Test
129 | public void testAndNot(){
130 | WrappedBitSetBitmap bitSet = defaultBitSet();
131 | WrappedBitSetBitmap bitSet2 = defaultBitSet();
132 | Set defaultBitSet = Sets.newHashSet();
133 | bitSet.remove(1);
134 | bitSet2.remove(2);
135 |
136 | bitSet.andNot(bitSet2);
137 |
138 | defaultBitSet.add(2);
139 |
140 | Assert.assertTrue(IntSetTestUtility.equalSets(defaultBitSet,bitSet));
141 | }
142 |
143 |
144 | @Test
145 | public void testSerialize(){
146 | WrappedBitSetBitmap bitSet = defaultBitSet();
147 | Set defaultBitSet = IntSetTestUtility.getSetBits();
148 | byte[] buffer = new byte[bitSet.getSizeInBytes()];
149 | ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
150 | bitSet.serialize(byteBuffer);
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/collections/bitmap/WrappedRoaringBitmapTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.bitmap;
18 |
19 | import com.metamx.collections.IntSetTestUtility;
20 | import java.io.IOException;
21 | import java.nio.ByteBuffer;
22 | import java.util.Arrays;
23 | import java.util.BitSet;
24 | import java.util.List;
25 | import java.util.Set;
26 | import junit.framework.Assert;
27 | import org.junit.Test;
28 | import org.junit.runner.RunWith;
29 | import org.junit.runners.Parameterized;
30 |
31 | @RunWith(Parameterized.class)
32 | public class WrappedRoaringBitmapTest
33 | {
34 | @Parameterized.Parameters
35 | public static List factoryClasses()
36 | {
37 | return Arrays.asList(
38 | (RoaringBitmapFactory[]) Arrays.asList(
39 | new RoaringBitmapFactory(false)
40 | ).toArray(),
41 | (RoaringBitmapFactory[]) Arrays.asList(
42 | new RoaringBitmapFactory(true)
43 | ).toArray()
44 | );
45 | }
46 |
47 | private final RoaringBitmapFactory factory;
48 |
49 | public WrappedRoaringBitmapTest(RoaringBitmapFactory factory)
50 | {
51 | this.factory = factory;
52 | }
53 |
54 | private WrappedRoaringBitmap createWrappedRoaringBitmap()
55 | {
56 | WrappedRoaringBitmap set = (WrappedRoaringBitmap) factory.makeEmptyMutableBitmap();
57 | set.add(1);
58 | set.add(3);
59 | set.add(5);
60 | set.add(7);
61 | set.add(9);
62 | return set;
63 | }
64 |
65 | @Test
66 | public void testSerialize()
67 | {
68 | WrappedRoaringBitmap set = createWrappedRoaringBitmap();
69 |
70 | byte[] buffer = new byte[set.getSizeInBytes()];
71 | ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
72 | set.serialize(byteBuffer);
73 | byteBuffer.flip();
74 | ImmutableBitmap immutableBitmap = new RoaringBitmapFactory().mapImmutableBitmap(byteBuffer);
75 | Assert.assertEquals(5, immutableBitmap.size());
76 | }
77 |
78 | @Test
79 | public void testToByteArray()
80 | {
81 | WrappedRoaringBitmap set = createWrappedRoaringBitmap();
82 | ImmutableBitmap immutableBitmap = new RoaringBitmapFactory().mapImmutableBitmap(ByteBuffer.wrap(set.toBytes()));
83 | Assert.assertEquals(5, immutableBitmap.size());
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/collections/spatial/RTreeTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial;
18 |
19 | import com.metamx.collections.bitmap.BitmapFactory;
20 | import com.metamx.collections.bitmap.ConciseBitmapFactory;
21 | import com.metamx.collections.bitmap.RoaringBitmapFactory;
22 | import com.metamx.collections.spatial.split.LinearGutmanSplitStrategy;
23 |
24 | import junit.framework.Assert;
25 |
26 | import org.junit.Before;
27 | import org.junit.Test;
28 |
29 | import java.util.Arrays;
30 | import java.util.Random;
31 |
32 | /**
33 | */
34 | public class RTreeTest
35 | {
36 | private RTree tree;
37 | private RTree roaringtree;
38 |
39 | @Before
40 | public void setUp() throws Exception
41 | {
42 | BitmapFactory bf = new ConciseBitmapFactory();
43 | tree = new RTree(2, new LinearGutmanSplitStrategy(0, 50, bf), bf );
44 | BitmapFactory rbf = new RoaringBitmapFactory();
45 | roaringtree = new RTree(2, new LinearGutmanSplitStrategy(0, 50, rbf), rbf );
46 |
47 | }
48 |
49 | @Test
50 | public void testInsertNoSplit()
51 | {
52 | float[] elem = new float[]{5, 5};
53 | tree.insert(elem, 1);
54 | Assert.assertTrue(Arrays.equals(elem, tree.getRoot().getMinCoordinates()));
55 | Assert.assertTrue(Arrays.equals(elem, tree.getRoot().getMaxCoordinates()));
56 |
57 | tree.insert(new float[]{6, 7}, 2);
58 | tree.insert(new float[]{1, 3}, 3);
59 | tree.insert(new float[]{10, 4}, 4);
60 | tree.insert(new float[]{8, 2}, 5);
61 |
62 | Assert.assertEquals(tree.getRoot().getChildren().size(), 5);
63 |
64 | float[] expectedMin = new float[]{1, 2};
65 | float[] expectedMax = new float[]{10, 7};
66 |
67 | Assert.assertTrue(Arrays.equals(expectedMin, tree.getRoot().getMinCoordinates()));
68 | Assert.assertTrue(Arrays.equals(expectedMax, tree.getRoot().getMaxCoordinates()));
69 | Assert.assertEquals(tree.getRoot().getArea(), 45.0d);
70 | }
71 |
72 | @Test
73 | public void testInsertDuplicatesNoSplit()
74 | {
75 | tree.insert(new float[]{1, 1}, 1);
76 | tree.insert(new float[]{1, 1}, 1);
77 | tree.insert(new float[]{1, 1}, 1);
78 |
79 | Assert.assertEquals(tree.getRoot().getChildren().size(), 3);
80 | }
81 |
82 | @Test
83 | public void testInsertDuplicatesNoSplitRoaring()
84 | {
85 | roaringtree.insert(new float[]{1, 1}, 1);
86 | roaringtree.insert(new float[]{1, 1}, 1);
87 | roaringtree.insert(new float[]{1, 1}, 1);
88 |
89 | Assert.assertEquals(roaringtree.getRoot().getChildren().size(), 3);
90 | }
91 |
92 |
93 | @Test
94 | public void testSplitOccurs()
95 | {
96 | Random rand = new Random();
97 | for (int i = 0; i < 100; i++) {
98 | tree.insert(new float[]{rand.nextFloat(), rand.nextFloat()}, i);
99 | }
100 |
101 | Assert.assertTrue(tree.getRoot().getChildren().size() > 1);
102 | }
103 |
104 | @Test
105 | public void testSplitOccursRoaring()
106 | {
107 | Random rand = new Random();
108 | for (int i = 0; i < 100; i++) {
109 | roaringtree.insert(new float[]{rand.nextFloat(), rand.nextFloat()}, i);
110 | }
111 |
112 | Assert.assertTrue(roaringtree.getRoot().getChildren().size() > 1);
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/collections/spatial/search/PolygonBoundTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.metamx.collections.spatial.search;
17 |
18 | import org.junit.Assert;
19 | import org.junit.Test;
20 |
21 | import java.util.Arrays;
22 |
23 | public class PolygonBoundTest
24 | {
25 | @Test
26 | public void testCacheKey()
27 | {
28 | Assert.assertArrayEquals(
29 | PolygonBound.from(new float[]{1F, 2F, 3F}, new float[]{0F, 2F, 0F}, 1).getCacheKey(),
30 | PolygonBound.from(new float[]{1F, 2F, 3F}, new float[]{0F, 2F, 0F}, 1).getCacheKey()
31 | );
32 | Assert.assertFalse(Arrays.equals(
33 | PolygonBound.from(new float[]{1F, 2F, 3F}, new float[]{0F, 2F, 0F}, 1).getCacheKey(),
34 | PolygonBound.from(new float[]{1F, 2F, 3F}, new float[]{0F, 2F, 1F}, 1).getCacheKey()
35 | ));
36 | Assert.assertFalse(Arrays.equals(
37 | PolygonBound.from(new float[]{1F, 2F, 3F}, new float[]{0F, 2F, 0F}, 1).getCacheKey(),
38 | PolygonBound.from(new float[]{1F, 2F, 2F}, new float[]{0F, 2F, 0F}, 1).getCacheKey()
39 | ));
40 | Assert.assertFalse(Arrays.equals(
41 | PolygonBound.from(new float[]{1F, 2F, 3F}, new float[]{0F, 2F, 0F}, 1).getCacheKey(),
42 | PolygonBound.from(new float[]{1F, 2F, 3F}, new float[]{0F, 2F, 0F}, 2).getCacheKey()
43 | ));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/collections/spatial/search/RadiusBoundTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.metamx.collections.spatial.search;
17 |
18 | import org.junit.Assert;
19 | import org.junit.Test;
20 |
21 | import java.util.Arrays;
22 |
23 | public class RadiusBoundTest
24 | {
25 | @Test
26 | public void testCacheKey()
27 | {
28 | final float[] coords0 = new float[]{1.0F, 2.0F};
29 | final float[] coords1 = new float[]{1.1F, 2.1F};
30 | Assert.assertArrayEquals(
31 | new RadiusBound(coords0, 3.0F, 10).getCacheKey(),
32 | new RadiusBound(coords0, 3.0F, 10).getCacheKey()
33 | );
34 | Assert.assertFalse(Arrays.equals(
35 | new RadiusBound(coords0, 3.0F, 10).getCacheKey(),
36 | new RadiusBound(coords1, 3.0F, 10).getCacheKey()
37 | ));
38 | Assert.assertFalse(Arrays.equals(
39 | new RadiusBound(coords0, 3.0F, 10).getCacheKey(),
40 | new RadiusBound(coords0, 3.1F, 10).getCacheKey()
41 | ));
42 | Assert.assertFalse(Arrays.equals(
43 | new RadiusBound(coords0, 3.0F, 10).getCacheKey(),
44 | new RadiusBound(coords0, 3.0F, 9).getCacheKey()
45 | ));
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/collections/spatial/search/RectangularBoundTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | package com.metamx.collections.spatial.search;
17 |
18 | import org.junit.Assert;
19 | import org.junit.Test;
20 |
21 | import java.util.Arrays;
22 |
23 | public class RectangularBoundTest
24 | {
25 | @Test
26 | public void testCacheKey()
27 | {
28 | Assert.assertArrayEquals(
29 | new RectangularBound(new float[]{1F, 1F}, new float[]{2F, 2F}, 1).getCacheKey(),
30 | new RectangularBound(new float[]{1F, 1F}, new float[]{2F, 2F}, 1).getCacheKey()
31 | );
32 | Assert.assertFalse(Arrays.equals(
33 | new RectangularBound(new float[]{1F, 1F}, new float[]{2F, 2F}, 1).getCacheKey(),
34 | new RectangularBound(new float[]{1F, 1F}, new float[]{2F, 3F}, 1).getCacheKey()
35 | ));
36 | Assert.assertFalse(Arrays.equals(
37 | new RectangularBound(new float[]{1F, 1F}, new float[]{2F, 2F}, 1).getCacheKey(),
38 | new RectangularBound(new float[]{1F, 0F}, new float[]{2F, 2F}, 1).getCacheKey()
39 | ));
40 | Assert.assertFalse(Arrays.equals(
41 | new RectangularBound(new float[]{1F, 1F}, new float[]{2F, 2F}, 1).getCacheKey(),
42 | new RectangularBound(new float[]{1F, 1F}, new float[]{2F, 2F}, 2).getCacheKey()
43 | ));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/collections/spatial/split/LinearGutmanSplitStrategyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.collections.spatial.split;
18 |
19 | import com.metamx.collections.spatial.Node;
20 | import com.metamx.collections.spatial.Point;
21 | import com.metamx.collections.spatial.RTree;
22 | import com.metamx.collections.bitmap.BitmapFactory;
23 | import com.metamx.collections.bitmap.ConciseBitmapFactory;
24 | import com.metamx.collections.bitmap.RoaringBitmapFactory;
25 |
26 | import junit.framework.Assert;
27 |
28 | import org.junit.Test;
29 |
30 | import java.util.Random;
31 |
32 | /**
33 | */
34 | public class LinearGutmanSplitStrategyTest
35 | {
36 | @Test
37 | public void testPickSeeds() throws Exception
38 | {
39 | BitmapFactory bf = new ConciseBitmapFactory();
40 | LinearGutmanSplitStrategy strategy = new LinearGutmanSplitStrategy(0, 50, bf);
41 | Node node = new Node(new float[2], new float[2], true, bf);
42 |
43 | node.addChild(new Point(new float[]{3, 7}, 1, bf));
44 | node.addChild(new Point(new float[]{1, 6}, 1, bf));
45 | node.addChild(new Point(new float[]{9, 8}, 1, bf));
46 | node.addChild(new Point(new float[]{2, 5}, 1, bf));
47 | node.addChild(new Point(new float[]{4, 4}, 1, bf));
48 | node.enclose();
49 |
50 | Node[] groups = strategy.split(node);
51 | Assert.assertEquals(groups[0].getMinCoordinates()[0], 1.0f);
52 | Assert.assertEquals(groups[0].getMinCoordinates()[1], 4.0f);
53 | Assert.assertEquals(groups[1].getMinCoordinates()[0], 9.0f);
54 | Assert.assertEquals(groups[1].getMinCoordinates()[1], 8.0f);
55 | }
56 |
57 | @Test
58 | public void testPickSeedsRoaring() throws Exception
59 | {
60 | BitmapFactory bf = new RoaringBitmapFactory();
61 | LinearGutmanSplitStrategy strategy = new LinearGutmanSplitStrategy(0, 50, bf);
62 | Node node = new Node(new float[2], new float[2], true, bf);
63 |
64 | node.addChild(new Point(new float[]{3, 7}, 1, bf));
65 | node.addChild(new Point(new float[]{1, 6}, 1, bf));
66 | node.addChild(new Point(new float[]{9, 8}, 1, bf));
67 | node.addChild(new Point(new float[]{2, 5}, 1, bf));
68 | node.addChild(new Point(new float[]{4, 4}, 1, bf));
69 | node.enclose();
70 |
71 | Node[] groups = strategy.split(node);
72 | Assert.assertEquals(groups[0].getMinCoordinates()[0], 1.0f);
73 | Assert.assertEquals(groups[0].getMinCoordinates()[1], 4.0f);
74 | Assert.assertEquals(groups[1].getMinCoordinates()[0], 9.0f);
75 | Assert.assertEquals(groups[1].getMinCoordinates()[1], 8.0f);
76 | }
77 |
78 |
79 | @Test
80 | public void testNumChildrenSize()
81 | {
82 | BitmapFactory bf = new ConciseBitmapFactory();
83 | RTree tree = new RTree(2, new LinearGutmanSplitStrategy(0, 50, bf), bf);
84 | Random rand = new Random();
85 | for (int i = 0; i < 100; i++) {
86 | tree.insert(new float[]{rand.nextFloat(), rand.nextFloat()}, i);
87 | }
88 |
89 | Assert.assertTrue(getNumPoints(tree.getRoot()) >= tree.getSize());
90 | }
91 |
92 | @Test
93 | public void testNumChildrenSizeRoaring()
94 | {
95 | BitmapFactory bf = new RoaringBitmapFactory();
96 | RTree tree = new RTree(2, new LinearGutmanSplitStrategy(0, 50, bf), bf);
97 | Random rand = new Random();
98 | for (int i = 0; i < 100; i++) {
99 | tree.insert(new float[]{rand.nextFloat(), rand.nextFloat()}, i);
100 | }
101 |
102 | Assert.assertTrue(getNumPoints(tree.getRoot()) >= tree.getSize());
103 | }
104 |
105 | private int getNumPoints(Node node)
106 | {
107 | int total = 0;
108 | if (node.isLeaf()) {
109 | total += node.getChildren().size();
110 | } else {
111 | for (Node child : node.getChildren()) {
112 | total += getNumPoints(child);
113 | }
114 | }
115 | return total;
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/test/annotation/Benchmark.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.test.annotation;
18 |
19 | public interface Benchmark
20 | {
21 | }
22 |
--------------------------------------------------------------------------------
/src/test/java/com/metamx/test/annotation/Dummy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 - 2015 Metamarkets Group Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.metamx.test.annotation;
18 |
19 | public interface Dummy
20 | {
21 | }
22 |
--------------------------------------------------------------------------------