00001 /* Part of the culibs project, <http://www.eideticdew.org/culibs/>. 00002 * Copyright (C) 2009 Petter Urkedal <urkedal@nbi.dk> 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation, either version 3 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00018 #ifndef CUOO_HCTEM_H 00019 #define CUOO_HCTEM_H 00020 00021 #include <cuoo/halloc.h> 00022 00023 CU_BEGIN_DECLARATIONS 00024 /** \defgroup cuoo_hctem_h cuoo/hctem.h: Boilerplates for Hash-Consing 00025 ** @{ \ingroup cuoo_mod 00026 ** 00027 ** These macros simplifies the allocation of hash-consed objects. They are 00028 ** documented individually below, but how they work together is maybe best 00029 ** understood by a simple example, here the creation of a dynamically typed 00030 ** and hash-consed pair: 00031 ** 00032 ** \code 00033 ** struct pair { 00034 ** CUOO_HCOBJ 00035 ** cuex_t left; 00036 ** cuex_t right; 00037 ** }; 00038 ** 00039 ** cuoo_type_t pair_type(); 00040 ** 00041 ** struct pair *pair_new(cuex_t left, cuex_t right) 00042 ** { 00043 ** cuoo_hctem_decl(pair, key); 00044 ** cuoo_hctem_init(pair, key); 00045 ** cuoo_hctem_get(pair, key)->left = left; 00046 ** cuoo_hctem_get(pair, key)->right = right; 00047 ** return cuoo_hctem_new(pair, key); 00048 ** } 00049 ** \endcode 00050 ** 00051 ** The <tt>cuoo_hctem_*</tt> macros only work when following the above naming 00052 ** conventions for the struct and dynamic-type functions. Otherwise, use the 00053 ** generic functions from \ref cuoo_halloc_h "cuoo/halloc.h". 00054 **/ 00055 00056 /** Assuming a declaration of <tt>struct <em>prefix</em></tt> which starts 00057 ** with a \ref CUOO_HCOBJ statement, this macro returns the key-size to use 00058 ** for hash-consing object of the struct. */ 00059 #define cuoo_hctem_key_size(prefix) (sizeof(struct prefix) - CUOO_HCOBJ_SHIFT) 00060 00061 /** This macro emits a declaration of a key-template used for hash-consed 00062 ** allocation. \a key must be initialised with \ref cuoo_hctem_init and 00063 ** assigned through the pointer returned by \a cuoo_hctem_get. */ 00064 #ifdef CUOO_HCTEM_EXCLUDE_HCOBJ_SHIFT 00065 # define cuoo_hctem_decl(prefix, key) char key[cuoo_hctem_key_size(prefix)] 00066 #else 00067 # define cuoo_hctem_decl(prefix, tem) struct prefix tem 00068 #endif 00069 00070 /** This macro initialises the template \a key, which must be declared with 00071 ** \ref cuoo_hctem_decl. This macro should be invoked before assigning to the 00072 ** struct fields to ensure a predictable hash-key. In particular, calling 00073 ** \ref cuoo_hctem_init zeros any padding at the end of the struct or holes 00074 ** within the struct due to alignment constraints, so that they do not contain 00075 ** arbitrary data which would affect the hash key. 00076 ** 00077 ** Inspection of generated code generated by GCC at <tt>-O2</tt> suggests that 00078 ** it's able to optimise the cuoo_hctem_init invokation against subsequent 00079 ** unconditional \ref cuoo_hctem_get invocations. */ 00080 #define cuoo_hctem_init(prefix, key) \ 00081 (memset(cuoo_hctem_key(prefix, key), 0, cuoo_hctem_key_size(prefix))) 00082 00083 /** Given a prefix and a template variable \a key, returns a pointer to the 00084 ** template struct, which has type <tt><em>prefix</em>_s *</tt>. */ 00085 #ifdef CUOO_HCTEM_EXCLUDE_HCOBJ_SHIFT 00086 # define cuoo_hctem_get(prefix, key) \ 00087 ((struct prefix *)((char *)(key) - CUOO_HCOBJ_SHIFT)) 00088 #else 00089 # define cuoo_hctem_get(prefix, key) (&(key)) 00090 #endif 00091 00092 /** The address of the key of a template, in case you need to use \ref 00093 ** cuoo_halloc or \ref cuoo_hxalloc_init instead of cuoo_hctem_new. */ 00094 #ifdef CUOO_HCTEM_EXCLUDE_HCOBJ_SHIFT 00095 # define cuoo_hctem_key(prefix, key) (&(key)) 00096 #else 00097 # define cuoo_hctem_key(prefix, tem) cu_ptr_add(&(tem), CUOO_HCOBJ_SHIFT) 00098 #endif 00099 00100 /** Given previous definition of a <tt>struct <em>prefix</em>_s</tt> and a 00101 ** function <tt><em>prefix</em>_type()</tt> returning the corresponding 00102 ** dynamic type, this macro returns a hash-consed object from the 00103 ** pre-initialised template \a key. This macro is used in conjunction with 00104 ** \ref cuoo_hctem_decl, \ref cuoo_hctem_init, \ref cuoo_hctem_get. */ 00105 #define cuoo_hctem_new(prefix, key) \ 00106 ((struct prefix *) \ 00107 cuoo_halloc(prefix##_type(), cuoo_hctem_key_size(prefix), \ 00108 cuoo_hctem_key(prefix, key))) 00109 00110 #define cuoo_hctem_new_of_type(prefix, key, type) \ 00111 ((struct prefix *) \ 00112 cuoo_halloc(type, cuoo_hctem_key_size(prefix), \ 00113 cuoo_hctem_key(prefix, key))) 00114 00115 00116 /** @} */ 00117 CU_END_DECLARATIONS 00118 00119 #endif