All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.robovm.compiler.hash.HashTableGenerator Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2012 RoboVM AB
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.robovm.compiler.hash;

import java.util.LinkedList;
import java.util.List;

import org.robovm.compiler.llvm.Constant;
import org.robovm.compiler.llvm.IntegerConstant;
import org.robovm.compiler.llvm.IntegerType;
import org.robovm.compiler.llvm.StructureConstant;
import org.robovm.compiler.llvm.StructureConstantBuilder;
import org.robovm.compiler.llvm.Type;

/**
 * Generates static hash tables in the form of a {@link StructureConstant} using
 * a {@link HashFunction}.
 */
public class HashTableGenerator {
    private static final IntegerType INDEX_TYPE = Type.I32;

    private final HashFunction function;
    private List>[] table;
    private int tableSize;
    private int count = 0;
    private double loadFactor;
    
    public HashTableGenerator(HashFunction function) {
        this(function, 4, 0.75);
    }
    
    public HashTableGenerator(HashFunction function, int tableSize) {
        this(function, tableSize, 0.75);
    }
    
    public HashTableGenerator(HashFunction function, int tableSize, double loadFactor) {
        this.function = function;
        this.tableSize = tableSize;
        this.loadFactor = loadFactor;
        allocateTable();
    }
    
    @SuppressWarnings("unchecked")
    private void allocateTable() {
        this.table = new List[1 << tableSize];
    }
    
    public void put(K k, V v) {
        int h = function.hash(k);
        putNoRehash(new Entry(h, k, v));
        if (count > loadFactor * table.length) {
            rehash();
        }
    }
    
    private void rehash() {
        List>[] oldTable = table;
        tableSize++;
        count = 0;
        allocateTable();
        for (int i = 0; i < oldTable.length; i++) {
            if (oldTable[i] != null) {
                for (Entry entry : oldTable[i]) {
                    putNoRehash(entry);
                }
            }
        }
    }
    
    private void putNoRehash(Entry entry) {
        int idx = entry.h & ((1 << tableSize) - 1);
        if (table[idx] == null) {
            table[idx] = new LinkedList>();
        }
        for (Entry e : table[idx]) {
            if (e.h == entry.h && (e.k.equals(entry.k))) {
                e.v = entry.v;
                return;
            }
        }
        table[idx].add(entry);
        count++;
    }
    
    public StructureConstant generate() {
        StructureConstantBuilder builder = new StructureConstantBuilder();
        int start = 0;
        builder.add(new IntegerConstant(count));
        builder.add(new IntegerConstant(table.length, INDEX_TYPE));
        builder.add(new IntegerConstant(start, INDEX_TYPE));
        for (int i = 1; i <= table.length; i++) {
            if (table[i - 1] == null) {
                builder.add(new IntegerConstant(start, INDEX_TYPE));                
            } else {
                start += table[i - 1].size();
                builder.add(new IntegerConstant(start, INDEX_TYPE));
            }
        }
        for (int i = 0; i < table.length; i++) {
            if (table[i] != null) {
                for (Entry entry : table[i]) {
                    builder.add(entry.v);
                }
            }
        }
        return builder.build();
    }
    
    private static class Entry {
        int h;
        K k;
        V v;
        Entry(int h, K k, V v) {
            this.h = h;
            this.k = k;
            this.v = v;
        }
        @Override
        public int hashCode() {
            return h;
        }
        @SuppressWarnings("unchecked")
        @Override
        public boolean equals(Object obj) {
            Entry e = (Entry) obj;
            return this.h == e.h 
                    && (this.k == e.k || this.k.equals(e.k))
                    && (this.v == e.v || this.v.equals(e.v));
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy