| /* |
| * 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); |
| } |
| } |