view gcc/d/dmd/root/stringtable.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents
children
line wrap: on
line source


/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
 * http://www.digitalmars.com
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
 * https://github.com/D-Programming-Language/dmd/blob/master/src/root/stringtable.c
 */

#include "dsystem.h"                    // uint{8|16|32}_t, memcpy()
#include "root.h"
#include "rmem.h"                       // mem
#include "stringtable.h"
#include "hash.h"

#define POOL_BITS 12
#define POOL_SIZE (1U << POOL_BITS)

struct StringEntry
{
    uint32_t hash;
    uint32_t vptr;
};

uint32_t StringTable::allocValue(const char *s, size_t length, void *ptrvalue)
{
    const size_t nbytes = sizeof(StringValue) + length + 1;

    if (!npools || nfill + nbytes > POOL_SIZE)
    {
        pools = (uint8_t **)mem.xrealloc(pools, ++npools * sizeof(pools[0]));
        pools[npools - 1] = (uint8_t *)mem.xmalloc(nbytes > POOL_SIZE ? nbytes : POOL_SIZE);
        nfill = 0;
    }

    StringValue *sv = (StringValue *)&pools[npools - 1][nfill];
    sv->ptrvalue = ptrvalue;
    sv->length = length;
    ::memcpy(sv->lstring(), s, length);
    sv->lstring()[length] = 0;

    const uint32_t vptr = (uint32_t)(npools << POOL_BITS | nfill);
    nfill += nbytes + (-nbytes & 7); // align to 8 bytes
    return vptr;
}

StringValue *StringTable::getValue(uint32_t vptr)
{
    if (!vptr) return NULL;

    const size_t idx = (vptr >> POOL_BITS) - 1;
    const size_t off = vptr & (POOL_SIZE - 1);
    return (StringValue *)&pools[idx][off];
}

static size_t nextpow2(size_t val)
{
    size_t res = 1;
    while (res < val)
        res <<= 1;
    return res;
}

static const double loadFactor = 0.8;

void StringTable::_init(size_t size)
{
    size = nextpow2((size_t)(size / loadFactor));
    if (size < 32) size = 32;
    table = (StringEntry *)mem.xcalloc(size, sizeof(table[0]));
    tabledim = size;
    pools = NULL;
    npools = nfill = 0;
    count = 0;
}

void StringTable::reset(size_t size)
{
    for (size_t i = 0; i < npools; ++i)
        mem.xfree(pools[i]);

    mem.xfree(table);
    mem.xfree(pools);
    table = NULL;
    pools = NULL;
    _init(size);
}

StringTable::~StringTable()
{
    for (size_t i = 0; i < npools; ++i)
        mem.xfree(pools[i]);

    mem.xfree(table);
    mem.xfree(pools);
    table = NULL;
    pools = NULL;
}

size_t StringTable::findSlot(hash_t hash, const char *s, size_t length)
{
    // quadratic probing using triangular numbers
    // http://stackoverflow.com/questions/2348187/moving-from-linear-probing-to-quadratic-probing-hash-collisons/2349774#2349774
    for (size_t i = hash & (tabledim - 1), j = 1; ;++j)
    {
        StringValue *sv;
        if (!table[i].vptr ||
            (table[i].hash == hash &&
             (sv = getValue(table[i].vptr))->length == length &&
             ::memcmp(s, sv->lstring(), length) == 0))
            return i;
        i = (i + j) & (tabledim - 1);
    }
}

StringValue *StringTable::lookup(const char *s, size_t length)
{
    const hash_t hash = calcHash(s, length);
    const size_t i = findSlot(hash, s, length);
    // printf("lookup %.*s %p\n", (int)length, s, table[i].value ?: NULL);
    return getValue(table[i].vptr);
}

StringValue *StringTable::update(const char *s, size_t length)
{
    const hash_t hash = calcHash(s, length);
    size_t i = findSlot(hash, s, length);
    if (!table[i].vptr)
    {
        if (++count > tabledim * loadFactor)
        {
            grow();
            i = findSlot(hash, s, length);
        }
        table[i].hash = hash;
        table[i].vptr = allocValue(s, length, NULL);
    }
    // printf("update %.*s %p\n", (int)length, s, table[i].value ?: NULL);
    return getValue(table[i].vptr);
}

StringValue *StringTable::insert(const char *s, size_t length, void *ptrvalue)
{
    const hash_t hash = calcHash(s, length);
    size_t i = findSlot(hash, s, length);
    if (table[i].vptr)
        return NULL; // already in table
    if (++count > tabledim * loadFactor)
    {
        grow();
        i = findSlot(hash, s, length);
    }
    table[i].hash = hash;
    table[i].vptr = allocValue(s, length, ptrvalue);
    // printf("insert %.*s %p\n", (int)length, s, table[i].value ?: NULL);
    return getValue(table[i].vptr);
}

void StringTable::grow()
{
    const size_t odim = tabledim;
    StringEntry *otab = table;
    tabledim *= 2;
    table = (StringEntry *)mem.xcalloc(tabledim, sizeof(table[0]));

    for (size_t i = 0; i < odim; ++i)
    {
        StringEntry *se = &otab[i];
        if (!se->vptr) continue;
        StringValue *sv = getValue(se->vptr);
        table[findSlot(se->hash, sv->lstring(), sv->length)] = *se;
    }
    mem.xfree(otab);
}

/********************************
 * Walk the contents of the string table,
 * calling fp for each entry.
 * Params:
 *      fp = function to call. Returns !=0 to stop
 * Returns:
 *      last return value of fp call
 */
int StringTable::apply(int (*fp)(StringValue *))
{
    for (size_t i = 0; i < tabledim; ++i)
    {
        StringEntry *se = &table[i];
        if (!se->vptr) continue;
        StringValue *sv = getValue(se->vptr);
        int result = (*fp)(sv);
        if (result)
            return result;
    }
    return 0;
}