blob: e958df04fc69304f463a31f11233bbb7d0c7f357 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include <errno.h>
#include <string.h>
#include "avro/data.h"
#include "avro/allocation.h"
#include "avro/errors.h"
#include "avro_private.h"
#include "st.h"
typedef struct avro_memoize_key {
void *key1;
void *key2;
} avro_memoize_key_t;
static int
avro_memoize_key_cmp(avro_memoize_key_t *a, avro_memoize_key_t *b)
{
/*
* This isn't a proper cmp operation, since it always returns 1
* if the keys are different. But that's okay for the hash
* table implementation we're using.
*/
return (a->key1 != b->key1) || (a->key2 != b->key2);
}
static int
avro_memoize_key_hash(avro_memoize_key_t *a)
{
return ((uintptr_t) a->key1) ^ ((uintptr_t) a->key2);
}
static struct st_hash_type avro_memoize_hash_type = {
HASH_FUNCTION_CAST avro_memoize_key_cmp,
HASH_FUNCTION_CAST avro_memoize_key_hash
};
void
avro_memoize_init(avro_memoize_t *mem)
{
memset(mem, 0, sizeof(avro_memoize_t));
mem->cache = st_init_table(&avro_memoize_hash_type);
}
static int
avro_memoize_free_key(avro_memoize_key_t *key, void *result, void *dummy)
{
AVRO_UNUSED(result);
AVRO_UNUSED(dummy);
avro_freet(avro_memoize_key_t, key);
return ST_CONTINUE;
}
void
avro_memoize_done(avro_memoize_t *mem)
{
st_foreach((st_table *) mem->cache, HASH_FUNCTION_CAST avro_memoize_free_key, 0);
st_free_table((st_table *) mem->cache);
memset(mem, 0, sizeof(avro_memoize_t));
}
int
avro_memoize_get(avro_memoize_t *mem,
void *key1, void *key2,
void **result)
{
avro_memoize_key_t key;
key.key1 = key1;
key.key2 = key2;
union {
st_data_t data;
void *value;
} val;
if (st_lookup((st_table *) mem->cache, (st_data_t) &key, &val.data)) {
if (result) {
*result = val.value;
}
return 1;
} else {
return 0;
}
}
void
avro_memoize_set(avro_memoize_t *mem,
void *key1, void *key2,
void *result)
{
/*
* First see if there's already a cached value for this key. If
* so, we don't want to allocate a new avro_memoize_key_t
* instance.
*/
avro_memoize_key_t key;
key.key1 = key1;
key.key2 = key2;
union {
st_data_t data;
void *value;
} val;
if (st_lookup((st_table *) mem->cache, (st_data_t) &key, &val.data)) {
st_insert((st_table *) mem->cache, (st_data_t) &key, (st_data_t) result);
return;
}
/*
* If it's a new key pair, then we do need to allocate.
*/
avro_memoize_key_t *real_key = (avro_memoize_key_t *) avro_new(avro_memoize_key_t);
real_key->key1 = key1;
real_key->key2 = key2;
st_insert((st_table *) mem->cache, (st_data_t) real_key, (st_data_t) result);
}
void
avro_memoize_delete(avro_memoize_t *mem, void *key1, void *key2)
{
avro_memoize_key_t key;
key.key1 = key1;
key.key2 = key2;
union {
st_data_t data;
avro_memoize_key_t *key;
} real_key;
real_key.key = &key;
if (st_delete((st_table *) mem->cache, &real_key.data, NULL)) {
avro_freet(avro_memoize_key_t, real_key.key);
}
}