/* * 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 * * https://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 #include #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); } }