1 /* 2 * This file is part of ELKI: 3 * Environment for Developing KDD-Applications Supported by Index-Structures 4 * 5 * Copyright (C) 2018 6 * ELKI Development Team 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Affero General Public License for more details. 17 * 18 * You should have received a copy of the GNU Affero General Public License 19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 package de.lmu.ifi.dbs.elki.database.ids.integer; 22 23 import java.io.IOException; 24 import java.nio.ByteBuffer; 25 26 import de.lmu.ifi.dbs.elki.database.ids.ArrayDBIDs; 27 import de.lmu.ifi.dbs.elki.database.ids.DBID; 28 import de.lmu.ifi.dbs.elki.database.ids.DBIDArrayIter; 29 import de.lmu.ifi.dbs.elki.database.ids.DBIDRef; 30 import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil; 31 import de.lmu.ifi.dbs.elki.database.ids.DBIDVar; 32 import de.lmu.ifi.dbs.elki.logging.LoggingUtil; 33 import de.lmu.ifi.dbs.elki.utilities.io.ByteArrayUtil; 34 import de.lmu.ifi.dbs.elki.utilities.io.ByteBufferSerializer; 35 import de.lmu.ifi.dbs.elki.utilities.io.FixedSizeByteBufferSerializer; 36 37 /** 38 * Database ID object. 39 * 40 * While this currently is just an Integer, it should be avoided to store the 41 * object IDs in regular integers to reduce problems if this API ever changes 42 * (for example if someone needs to support {@code long}, it should not require 43 * changes in too many places!) 44 * 45 * In particular, a developer should not make any assumption of these IDs being 46 * consistent across multiple results/databases. 47 * 48 * @author Erich Schubert 49 * @since 0.4.0 50 * 51 * @composed - - - DynamicSerializer 52 * @composed - - - StaticSerializer 53 */ 54 final class IntegerDBID implements DBID, IntegerDBIDRef { 55 /** 56 * The actual object ID. 57 */ 58 protected final int id; 59 60 /** 61 * Constructor from integer id. 62 * 63 * @param id integer id. 64 */ IntegerDBID(int id)65 protected IntegerDBID(int id) { 66 super(); 67 this.id = id; 68 } 69 70 /** 71 * Constructor from integer id. 72 * 73 * @param id integer id. 74 */ IntegerDBID(Integer id)75 protected IntegerDBID(Integer id) { 76 super(); 77 this.id = id.intValue(); 78 } 79 80 /** 81 * Return the integer value of the object ID. 82 * 83 * @return integer id 84 */ 85 @Override internalGetIndex()86 public int internalGetIndex() { 87 return this.id; 88 } 89 90 @Override size()91 public int size() { 92 return 1; 93 } 94 95 @Override isEmpty()96 public boolean isEmpty() { 97 return false; 98 } 99 100 @Override toString()101 public String toString() { 102 return (id != Integer.MIN_VALUE) ? Integer.toString(id) : "null"; 103 } 104 105 @Override hashCode()106 public int hashCode() { 107 return id; 108 } 109 110 @Override 111 @Deprecated equals(Object obj)112 public boolean equals(Object obj) { 113 if(this == obj) { 114 return true; 115 } 116 if(!(obj instanceof IntegerDBID)) { 117 if(obj instanceof DBIDRef) { 118 LoggingUtil.warning("Programming error: DBID.equals(DBIDRef) is not well-defined. Use DBIDUtil.equal() instead!", new Throwable()); 119 } 120 return false; 121 } 122 IntegerDBID other = (IntegerDBID) obj; 123 return this.id == other.id; 124 } 125 126 @Override compareTo(DBIDRef o)127 public int compareTo(DBIDRef o) { 128 final int anotherVal = o.internalGetIndex(); 129 return (this.id < anotherVal ? -1 : (this.id == anotherVal ? 0 : 1)); 130 } 131 132 @Override iter()133 public Itr iter() { 134 return new Itr(); 135 } 136 137 @Override get(int i)138 public DBID get(int i) { 139 if(i != 0) { 140 throw new ArrayIndexOutOfBoundsException(); 141 } 142 return this; 143 } 144 145 @Override assignVar(int index, DBIDVar var)146 public DBIDVar assignVar(int index, DBIDVar var) { 147 if(index != 0) { 148 throw new ArrayIndexOutOfBoundsException(); 149 } 150 var.set(this); 151 return var; 152 } 153 154 @Override contains(DBIDRef o)155 public boolean contains(DBIDRef o) { 156 return o.internalGetIndex() == id; 157 } 158 159 @Override binarySearch(DBIDRef key)160 public int binarySearch(DBIDRef key) { 161 final int other = key.internalGetIndex(); 162 return (other == id) ? 0 : (other < id) ? -1 : -2; 163 } 164 165 @Override slice(int begin, int end)166 public ArrayDBIDs slice(int begin, int end) { 167 if(begin == 0 && end == 1) { 168 return this; 169 } 170 else { 171 return DBIDUtil.EMPTYDBIDS; 172 } 173 } 174 175 /** 176 * Pseudo iterator for DBIDs interface. 177 * 178 * @author Erich Schubert 179 */ 180 protected class Itr implements DBIDArrayIter, IntegerDBIDRef { 181 /** 182 * Iterator position: We use an integer so we can support retract(). 183 */ 184 int pos = 0; 185 186 @Override advance()187 public Itr advance() { 188 pos++; 189 return this; 190 } 191 192 @Override advance(int count)193 public Itr advance(int count) { 194 pos += count; 195 return this; 196 } 197 198 @Override retract()199 public Itr retract() { 200 pos--; 201 return this; 202 } 203 204 @Override seek(int off)205 public Itr seek(int off) { 206 pos = off; 207 return this; 208 } 209 210 @Override getOffset()211 public int getOffset() { 212 return pos; 213 } 214 215 @Override internalGetIndex()216 public int internalGetIndex() { 217 return IntegerDBID.this.id; 218 } 219 220 @Override valid()221 public boolean valid() { 222 return (pos == 0); 223 } 224 225 @Override hashCode()226 public int hashCode() { 227 // Override, because we also are overriding equals. 228 return super.hashCode(); 229 } 230 231 @Override equals(Object other)232 public boolean equals(Object other) { 233 if(other instanceof DBID) { 234 LoggingUtil.warning("Programming error detected: DBIDItr.equals(DBID). Use sameDBID()!", new Throwable()); 235 } 236 return super.equals(other); 237 } 238 239 @Override toString()240 public String toString() { 241 return Integer.toString(internalGetIndex()); 242 } 243 } 244 245 /** 246 * Dynamic sized serializer, using varint. 247 * 248 * @author Erich Schubert 249 */ 250 public static class DynamicSerializer implements ByteBufferSerializer<DBID> { 251 /** 252 * Constructor. Protected: use static instance! 253 */ DynamicSerializer()254 public DynamicSerializer() { 255 super(); 256 } 257 258 @Override fromByteBuffer(ByteBuffer buffer)259 public DBID fromByteBuffer(ByteBuffer buffer) throws IOException { 260 return new IntegerDBID(ByteArrayUtil.readSignedVarint(buffer)); 261 } 262 263 @Override toByteBuffer(ByteBuffer buffer, DBID object)264 public void toByteBuffer(ByteBuffer buffer, DBID object) throws IOException { 265 ByteArrayUtil.writeSignedVarint(buffer, ((IntegerDBID) object).id); 266 } 267 268 @Override getByteSize(DBID object)269 public int getByteSize(DBID object) throws IOException { 270 return ByteArrayUtil.getSignedVarintSize(((IntegerDBID) object).id); 271 } 272 } 273 274 /** 275 * Static sized serializer, using regular integers. 276 * 277 * @author Erich Schubert 278 */ 279 public static class StaticSerializer implements FixedSizeByteBufferSerializer<DBID> { 280 /** 281 * Constructor. Protected: use static instance! 282 */ StaticSerializer()283 public StaticSerializer() { 284 super(); 285 } 286 287 @Override fromByteBuffer(ByteBuffer buffer)288 public DBID fromByteBuffer(ByteBuffer buffer) throws IOException { 289 return new IntegerDBID(buffer.getInt()); 290 } 291 292 @Override toByteBuffer(ByteBuffer buffer, DBID object)293 public void toByteBuffer(ByteBuffer buffer, DBID object) throws IOException { 294 buffer.putInt(((IntegerDBID) object).id); 295 } 296 297 @Override getByteSize(DBID object)298 public int getByteSize(DBID object) throws IOException { 299 return getFixedByteSize(); 300 } 301 302 @Override getFixedByteSize()303 public int getFixedByteSize() { 304 return ByteArrayUtil.SIZE_INT; 305 } 306 } 307 308 /** 309 * The public instance to use for dynamic serialization. 310 */ 311 public static final ByteBufferSerializer<DBID> DYNAMIC_SERIALIZER = new DynamicSerializer(); 312 313 /** 314 * The public instance to use for static serialization. 315 */ 316 public static final FixedSizeByteBufferSerializer<DBID> STATIC_SERIALIZER = new StaticSerializer(); 317 } 318