001/*
002 * Copyright 2013 Alex Kasko (alexkasko.com)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.alexkasko.unsafe.offheapstruct;
018
019import com.alexkasko.unsafe.bytearray.ByteArrayTool;
020
021import java.util.Comparator;
022
023/**
024 * Internal wrapper for user-provided comparator.
025 * NOT thread-safe.
026 *
027 * @author alexkasko
028 *         Date: 9/13/13
029 */
030class OffHeapStructComparator {
031    private final OffHeapStructIndexAccessor ia1;
032    private final OffHeapStructIndexAccessor ia2;
033    private final OffHeapStructByteArrayAccessor baa1;
034    private final OffHeapStructByteArrayAccessor baa2;
035    private final Comparator<OffHeapStructAccessor> comp;
036
037    /**
038     * Constructor
039     *
040     * @param col collection for index access
041     * @param comp comparator
042     */
043    OffHeapStructComparator(OffHeapStructCollection col, Comparator<OffHeapStructAccessor> comp) {
044        ByteArrayTool bt = ByteArrayTool.get();
045        this.ia1 = new OffHeapStructIndexAccessor(col);
046        this.ia2 = new OffHeapStructIndexAccessor(col);
047        this.baa1 = new OffHeapStructByteArrayAccessor(bt);
048        this.baa2 = new OffHeapStructByteArrayAccessor(bt);
049        this.comp = comp;
050    }
051
052    /**
053     * Greater-then operation
054     *
055     * @param index1 collection index
056     * @param index2 collection index
057     * @return 'gt' operation result
058     */
059    boolean gt(long index1, long index2) {
060        ia1.setIndex(index1);
061        ia2.setIndex(index2);
062        return comp.compare(ia1, ia2) > 0;
063    }
064
065    /**
066     * Greater-then operation
067     *
068     * @param index1 collection index
069     * @param struct2 structure
070     * @return 'gt' operation result
071     */
072    boolean gt(long index1, byte[] struct2) {
073        ia1.setIndex(index1);
074        baa2.setStruct(struct2);
075        return comp.compare(ia1, baa2) > 0;
076    }
077
078    /**
079     * Lesser-then operation
080     *
081     * @param index1 collection index
082     * @param struct2 structure
083     * @return 'lt' operation result
084     */
085    boolean lt(long index1, byte[] struct2) {
086        ia1.setIndex(index1);
087        baa2.setStruct(struct2);
088        return comp.compare(ia1, baa2) < 0;
089    }
090
091    /**
092     * Lesser-then operation
093     *
094     * @param struct1 structure
095     * @param index2 collection index
096     * @return 'lt' operation result
097     */
098    boolean lt(byte[] struct1, long index2) {
099        baa1.setStruct(struct1);
100        ia2.setIndex(index2);
101        return comp.compare(baa1, ia2) < 0;
102    }
103
104    /**
105     * Equals operation
106     *
107     * @param index1 collection index
108     * @param struct2 structure
109     * @return 'eq' operation result
110     */
111    boolean eq(long index1, byte[] struct2) {
112        ia1.setIndex(index1);
113        baa2.setStruct(struct2);
114        return 0 == comp.compare(ia1, baa2);
115    }
116
117    /**
118     * Equals operation
119     *
120     * @param struct1 structure
121     * @param struct2 structure
122     * @return 'eq' operation result
123     */
124    boolean eq(byte[] struct1, byte[] struct2) {
125        baa1.setStruct(struct1);
126        baa2.setStruct(struct2);
127        return 0 == comp.compare(baa1, baa2);
128    }
129
130    /**
131     * Calls {@code compare} on comparator and return it results
132     *
133     * @param index1 collection index
134     * @param struct2 structure
135     * @return compare result from comparator
136     */
137    int compare(long index1, byte[] struct2) {
138        ia1.setIndex(index1);
139        baa2.setStruct(struct2);
140        return comp.compare(ia1, baa2);
141    }
142
143    /**
144     * {@inheritDoc}
145     */
146    @Override
147    public String toString() {
148        final StringBuilder sb = new StringBuilder();
149        sb.append("OffHeapStructComparator");
150        sb.append("{comp=").append(comp);
151        sb.append('}');
152        return sb.toString();
153    }
154
155    /**
156     * Struct's accessor implementation for byte array structs
157     *
158     * @author alexkasko
159     * Date: 9/13/13
160     */
161    private static class OffHeapStructByteArrayAccessor implements OffHeapStructAccessor {
162        private final ByteArrayTool bt;
163        private byte[] struct;
164
165        /**
166         * Constructor
167         *
168         * @param bt byte array tool to operate over held byte array
169         */
170        private OffHeapStructByteArrayAccessor(ByteArrayTool bt) {
171            this.bt = bt;
172        }
173
174        /**
175         * Constructor
176         *
177         * @param bt byte array tool to operate over held byte array
178         * @param struct byte array to hold
179         */
180        private OffHeapStructByteArrayAccessor(ByteArrayTool bt, byte[] struct) {
181            this.bt = bt;
182            this.struct = struct;
183        }
184
185        /**
186         * {@inheritDoc}
187         */
188        @Override
189        public int structLength() {
190            return struct.length;
191        }
192
193        /**
194         * {@inheritDoc}
195         */
196        @Override
197        public void get(byte[] buffer) {
198            bt.copy(struct, 0, buffer, 0, struct.length);
199        }
200
201        /**
202         * {@inheritDoc}
203         */
204        @Override
205        public void get(int srcPos, byte[] dest, int destPos, int length) {
206            bt.copy(struct, srcPos, dest, destPos, length);
207        }
208
209        /**
210         * Copies specified buffer data into internal buffer
211         *
212         * @param buffer data to copy
213         */
214        public void set(byte[] buffer) {
215            bt.copy(buffer, 0, struct, 0, struct.length);
216        }
217
218        /**
219         * {@inheritDoc}
220         */
221        @Override
222        public byte getByte(int offset) {
223            return bt.getByte(struct, offset);
224        }
225
226        /**
227         * {@inheritDoc}
228         */
229        @Override
230        public short getUnsignedByte(int offset) {
231            return bt.getUnsignedByte(struct, offset);
232        }
233
234        /**
235         * {@inheritDoc}
236         */
237        @Override
238        public short getShort(int offset) {
239            return bt.getShort(struct, offset);
240        }
241
242        /**
243         * {@inheritDoc}
244         */
245        @Override
246        public int getUnsignedShort(int offset) {
247            return bt.getUnsignedShort(struct, offset);
248        }
249
250        /**
251         * {@inheritDoc}
252         */
253        @Override
254        public int getInt(int offset) {
255            return bt.getInt(struct, offset);
256        }
257
258        /**
259         * {@inheritDoc}
260         */
261        @Override
262        public long getUnsignedInt(int offset) {
263            return bt.getUnsignedInt(struct, offset);
264        }
265
266        /**
267         * {@inheritDoc}
268         */
269        @Override
270        public long getLong(int offset) {
271            return bt.getLong(struct, offset);
272        }
273
274        /**
275         * Returns previously setted struct
276         *
277         * @return struct
278         */
279        private byte[] getStruct() {
280            return struct;
281        }
282
283        /**
284         * Sets struct to access it
285         *
286         * @param struct struct
287         */
288        private void setStruct(byte[] struct) {
289            this.struct = struct;
290        }
291
292        /**
293         * {@inheritDoc}
294         *
295         * @return
296         */
297        @Override
298        public String toString() {
299            final StringBuilder sb = new StringBuilder();
300            sb.append("OffHeapStructByteArrayAccessor");
301            sb.append("{bt=").append(bt);
302            sb.append('}');
303            return sb.toString();
304        }
305    }
306
307    /**
308     * Struct's accessor implementation for off-heap stored structs
309     *
310     * @author alexkasko
311     * Date: 9/13/13
312     */
313    private static class OffHeapStructIndexAccessor implements OffHeapStructAccessor {
314        private final OffHeapStructCollection col;
315        private long index = -1;
316
317        /**
318         * Constructor
319         *
320         * @param col collection to access structs from
321         */
322        private OffHeapStructIndexAccessor(OffHeapStructCollection col) {
323            this.col = col;
324        }
325
326        /**
327         * {@inheritDoc}
328         */
329        @Override
330        public int structLength() {
331            return col.structLength();
332        }
333
334        /**
335         * {@inheritDoc}
336         */
337        @Override
338        public void get(byte[] buffer) {
339            col.get(index, buffer);
340        }
341
342        /**
343         * {@inheritDoc}
344         */
345        @Override
346        public void get(int srcPos, byte[] dest, int destPos, int length) {
347            col.get(index, srcPos, dest, destPos, length);
348        }
349
350        /**
351         * {@inheritDoc}
352         */
353        @Override
354        public byte getByte(int offset) {
355            return col.getByte(index, offset);
356        }
357
358        /**
359         * {@inheritDoc}
360         */
361        @Override
362        public short getUnsignedByte(int offset) {
363            return col.getUnsignedByte(index, offset);
364        }
365
366        /**
367         * {@inheritDoc}
368         */
369        @Override
370        public short getShort(int offset) {
371            return col.getShort(index, offset);
372        }
373
374        /**
375         * {@inheritDoc}
376         */
377        @Override
378        public int getUnsignedShort(int offset) {
379            return col.getUnsignedShort(index, offset);
380        }
381
382        /**
383         * {@inheritDoc}
384         */
385        @Override
386        public int getInt(int offset) {
387            return col.getInt(index, offset);
388        }
389
390        /**
391         * {@inheritDoc}
392         */
393        @Override
394        public long getUnsignedInt(int offset) {
395            return col.getUnsignedInt(index, offset);
396        }
397
398        /**
399         * {@inheritDoc}
400         */
401        @Override
402        public long getLong(int offset) {
403            return col.getLong(index, offset);
404        }
405
406        /**
407         * Sets index value
408         *
409         * @param index index value
410         */
411        private void setIndex(long index) {
412            this.index = index;
413        }
414
415        /**
416         * {@inheritDoc}
417         */
418        @Override
419        public String toString() {
420            final StringBuilder sb = new StringBuilder();
421            sb.append("OffHeapStructIndexAccessor");
422            sb.append("{col=").append(col);
423            sb.append(", index=").append(index);
424            sb.append('}');
425            return sb.toString();
426        }
427    }
428}