/* * Copyright (C) 2013 Omry Yadan <omry@yadan.net> * All rights reserved. * * See https://github.com/omry/banana/blob/master/BSD-LICENSE for licensing information */ package net.yadan.banana.map; import net.yadan.banana.DebugLevel; import net.yadan.banana.Formatter; import net.yadan.banana.ICollection; import net.yadan.banana.memory.Buffer; import net.yadan.banana.memory.IBuffer; import net.yadan.banana.memory.IPrimitiveAccess; /** * Created by : omry Date: 6/29/13 */ public class FormattingMapElements { /** * This usage example demonstrates using a map where the value is a variable * length structure. In addition, it demonstrates how to use a Formatter to * make debugging the map easier. All Banana data structures that implements * {@link ICollection} supports formatting using a Formatter, so you can reuse * your formatters. * * Lets say we want the following C like struct as the value of our map. Note * that this is variable length struct. * * <pre> * struct person { * int age * struct name { * int size * char chars[] * } * } * * * * Since banana storage is always ints, a record for 13 year old Romeo would look like * * ┌──0──╦──1──┬──2──┬──3──┬──4──┐ * │ ║ NAME STRING │ * │ AGE ╬─────╦─────────────────┤ * │ ║SIZE ║ CHARS │ * ├─────╬─────╬─────┬─────┬─────┤ * │ 13 ║ 5 ║ R|o │ m|e │ o| │ * └─────╩─────╩─────┴─────┴─────┘ * * Note that each int contains two chars (Java chars are 16 bit values). * </pre> */ // Offset constants final static int AGE_OFFSET = 0; final static int NAME_SIZE_OFFSET = 1; final static int NAME_CHARS_OFFSET = 2; public static void main(String[] args) { // initial number of blocks in the block allocator int maxBlocks = 100; // minimal size of data we will want to put into the map (in ints) int blockSize = 5; // how full should the map be before incresing size and rehashing? double loadFactor = 0.75; // if we run out of blocks in the underlying block allocator, grow it by // what factor? double growthFactor = 2.0; IHashMap map = new HashMap(maxBlocks, blockSize, growthFactor, loadFactor); // activate map debug level map.setDebug(DebugLevel.DEBUG_CONTENT); // you can use a formatter to make the map easier to debug by using your own // logic to convert records to strings map.setFormatter(new PersonFormatter()); long key = 1000; char name1[] = "Romeo".toCharArray(); IBuffer romeo = new Buffer(10); romeo.setInt(AGE_OFFSET, 13); romeo.setInt(NAME_SIZE_OFFSET, name1.length); romeo.setChars(NAME_CHARS_OFFSET, name1, 0, name1.length); map.createRecord(key, romeo); long key2 = 1002; char name2[] = "Juliet".toCharArray(); // this will be enough to hold the data int size = NAME_CHARS_OFFSET + name2.length / 2 + 1; // create empty record for size ints and get handle back int r = map.createRecord(key2, size); map.setInt(r, AGE_OFFSET, 13); map.setInt(r, NAME_SIZE_OFFSET, name2.length); map.setChars(r, NAME_CHARS_OFFSET, name2, 0, name2.length); System.out.println(map); /** * Outputs : * * <pre> * Map : net.yadan.banana.map.HashMap 2 / 100 * 1000=Romeo, age 13 (underage!) * 1002=Juliet, age 13 (underage!) * </pre> */ } private static final class PersonFormatter implements Formatter { @Override public String format(IPrimitiveAccess parent, int pointer) { int age = parent.getInt(pointer, AGE_OFFSET); int num = parent.getInt(pointer, NAME_SIZE_OFFSET); char chars[] = new char[num]; parent.getChars(pointer, NAME_CHARS_OFFSET, chars, 0, num); return String.format("%s, age %d%s", new String(chars), age, age < 18 ? " (underage!)" : ""); } } }