Check-in [dfd4a3dfd0]

Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
SHA1 Hash:dfd4a3dfd063c17ad760c77c2320bad69ccfac59
Date: 2008-11-21 16:25:00
User: stephan
Comment:added whst
Tags And Properties
Changes
hide diffs unified diffs patch

Changes to Makefile

Old (6c7cd75103ca0205) New (e136c51f53d75cda)
1 #!/usr/bin/make -f 1 #!/usr/bin/make -f
2 # Requires GNU Make 3.80+! 2 # Requires GNU Make 3.80+!
3 default: all 3 default: all
4 4
5 ifeq (1,$(TCC)) 5 ifeq (1,$(TCC))
34 hidden lines
40 libwhhash.LIB.OBJECTS = $(HASH_OBJ) 40 libwhhash.LIB.OBJECTS = $(HASH_OBJ)
41 $(call ShakeNMake.CALL.RULES.LIBS,libwhhash) 41 $(call ShakeNMake.CALL.RULES.LIBS,libwhhash)
42 42
43 ######################################################################## 43 ########################################################################
44 # GC lib: 44 # GC lib:
45 WHGC_OBJ := whgc.o whrc.o | 45 WHGC_OBJ := whgc.o whrc.o whst.o
46 libwhgc.LIB.OBJECTS = $(WHGC_OBJ) $(HASH_OBJ) 46 libwhgc.LIB.OBJECTS = $(WHGC_OBJ) $(HASH_OBJ)
47 $(call ShakeNMake.CALL.RULES.LIBS,libwhgc) 47 $(call ShakeNMake.CALL.RULES.LIBS,libwhgc)
48 $(libwhgc.LIB): $(libwhhash.LIB) 48 $(libwhgc.LIB): $(libwhhash.LIB)
49 libs: $(libwhgc.LIB) 49 libs: $(libwhgc.LIB)
50 50
6 hidden lines
57 CLEAN_FILES += *~ *.valgrind *.a 57 CLEAN_FILES += *~ *.valgrind *.a
58 58
59 PACKAGE.DIST_FILES += $(wildcard *.c *.h) 59 PACKAGE.DIST_FILES += $(wildcard *.c *.h)
60 60
61 all: libs bins 61 all: libs bins

Changes to test.c

Old (c4bd24e3ba1c76f7) New (65c58898d96b6066)
1 #include <stdio.h> 1 #include <stdio.h>
2 #include <stdlib.h> 2 #include <stdlib.h>
3 #include <string.h> 3 #include <string.h>
4 #include <ctype.h> 4 #include <ctype.h>
5 #include "whrc.h" 5 #include "whrc.h"
> 6 #include "whst.h"
6 7
7 #if 1 8 #if 1
8 #include <stdio.h> // only for debuggering 9 #include <stdio.h> // only for debuggering
9 #define MARKER if(1) printf("MARKER: %s:%d:%s():\n",__FILE__,__LINE__,__func__); if(1) printf 10 #define MARKER if(1) printf("MARKER: %s:%d:%s():\n",__FILE__,__LINE__,__func__); if(1) printf
10 #else 11 #else
17 hidden lines
28 MARKER("refcount=%u\n",rc); 29 MARKER("refcount=%u\n",rc);
29 rc = whrc_rmref(cx,str); // rc == 1 30 rc = whrc_rmref(cx,str); // rc == 1
30 MARKER("refcount=%u\n",rc); 31 MARKER("refcount=%u\n",rc);
31 rc = whrc_rmref(cx,str); // rc == 0, free(str) is called 32 rc = whrc_rmref(cx,str); // rc == 0, free(str) is called
32 MARKER("refcount=%u\n",rc); 33 MARKER("refcount=%u\n",rc);
33 rc = whrc_rmref(cx,str); // rc == 0, free(str) is called | 34 rc = whrc_rmref(cx,str); // rc == whrc_ref_err_val
34 MARKER("refcount=%u\n",rc); 35 MARKER("refcount=%u\n",rc);
35 //whrc_destroy_context(cx,true); | 36 whrc_destroy_context(cx,true);
36 MARKER("ending test\n"); 37 MARKER("ending test\n");
> 38 return 0;
> 39 }
> 40
> 41 int test_whst()
> 42 {
> 43 MARKER("starting\n");
> 44
> 45 whst_context * cx = 0;
> 46 cx = whst_create_context();
> 47 #if 1
> 48 char const * str = "this is the string";
> 49 char const * str2 = "this is the other string";
> 50 size_t i = 0;
> 51 const size_t max = 20;
> 52 char const * strR;
> 53 char const * strR2;
> 54 for( ; i < max; ++i )
> 55 {
> 56 strR = whst_addref( cx, str );
> 57 strR2 = whst_addref( cx, str2 );
> 58 }
> 59 MARKER("refcounts=%u %u\n",whst_refcount(cx,strR), whst_refcount(cx,strR2));
> 60 for( i = 0; i < max; ++i )
> 61 {
> 62 whst_rmref( cx, strR );
> 63 if( 0 == (i%3) ) whst_rmref( cx, strR2 );
> 64 }
> 65 MARKER("refcounts=%u %u\n",whst_refcount(cx,strR), whst_refcount(cx,strR2));
> 66 MARKER("addresses=[%p==%p] [%p==%p]\n",str,strR,str2,strR2);
> 67 #endif
> 68 whst_destroy_context(cx);
> 69 MARKER("ending\n");
37 return 0; 70 return 0;
38 } 71 }
39 72
40 int main( int argc, char ** argv ) 73 int main( int argc, char ** argv )
41 { 74 {
42 int rc = 0; 75 int rc = 0;
43 rc = test_one(); | 76 //if(!rc) rc = test_one();
| 77 if(!rc) rc = test_whst();
44 printf("Done rc=%d=[%s].\n",rc, 78 printf("Done rc=%d=[%s].\n",rc,
45 (0==rc) 79 (0==rc)
46 ? "You win :)" 80 ? "You win :)"
47 : "You lose :("); 81 : "You lose :(");
48 return rc; 82 return rc;
49 } 83 }

Added whst.c

Old () New (46b70e6683b88cff)
> 1 #include <stdlib.h> /* malloc/free */
> 2 #include <assert.h>
> 3 #include <string.h>
> 4
> 5 #include "whst.h"
> 6 #include "whhash.h"
> 7 #ifdef __cplusplus
> 8 extern "C" {
> 9 #endif
> 10
> 11 #if 1
> 12 #include <stdio.h> // only for debuggering
> 13 #define MARKER if(1) printf("MARKER: %s:%d:%s():\n",__FILE__,__LINE__,__func__); if(1) printf
> 14 #else
> 15 static void bogo_printf(char const * fmt, ...) {}
> 16 #define MARKER if(0) bogo_printf
> 17 #endif
> 18
> 19 const size_t whst_ref_err_val = ((size_t)-1);
> 20 struct whst_context
> 21 {
> 22 whhash_table * ht;
> 23 };
> 24
> 25 static const whst_context whst_context_init =
> 26 {
> 27 0 /* ht */
> 28 };
> 29
> 30 struct whst_entry
> 31 {
> 32 char * string;
> 33 size_t refcount;
> 34 };
> 35 typedef struct whst_entry whst_entry;
> 36 static const whst_entry whst_entry_init = {0,0};
> 37
> 38
> 39 static void whst_entry_destroy( whst_entry * e)
> 40 {
> 41 if( e )
> 42 {
> 43 free(e->string);
> 44 free(e);
> 45 }
> 46 }
> 47 /**
> 48 For use as a whhash_table entry dtor.
> 49 */
> 50 static void whst_entry_dtor( void * x)
> 51 {
> 52 whst_entry_destroy( (whst_entry*)x );
> 53 }
> 54
> 55
> 56 whst_context * whst_create_context()
> 57 {
> 58 whst_context * c = (whst_context *)malloc(sizeof(whst_context));
> 59 if( ! c ) return 0;
> 60 *c = whst_context_init;
> 61 if( (c->ht = whhash_create( 10, whhash_hash_cstring_djb2m, whhash_cmp_cstring ) ) )
> 62 {
> 63 whhash_set_dtors( c->ht, 0, whst_entry_dtor );
> 64 }
> 65 else
> 66 {
> 67 free(c);
> 68 c = 0;
> 69 }
> 70 return c;
> 71 }
> 72
> 73 void whst_clear_context( whst_context * cx )
> 74 {
> 75 whhash_clear(cx->ht);
> 76 /* TODO: also recreate the hashtable, since that's the only way
> 77 to shrink it.
> 78 */
> 79 }
> 80
> 81 void whst_destroy_context( whst_context * cx )
> 82 {
> 83 if( cx )
> 84 {
> 85 whst_clear_context(cx);
> 86 whhash_destroy( cx->ht );
> 87 *cx = whst_context_init;
> 88 free(cx);
> 89 }
> 90 }
> 91
> 92 static whst_entry * whst_search_entry( whst_context * cx, char const * item )
> 93 {
> 94 return (cx && item)
> 95 ? (whst_entry *) whhash_search(cx->ht, item)
> 96 : 0;
> 97 }
> 98
> 99 size_t whst_refcount( whst_context * cx, char const * item )
> 100 {
> 101 whst_entry const * e = whst_search_entry(cx, item);
> 102 return e ? e->refcount : 0;
> 103 }
> 104
> 105
> 106
> 107 static whst_entry * whst_take_entry( whst_context * cx, char const * item )
> 108 {
> 109 return cx
> 110 ? (whst_entry *) whhash_take(cx->ht, item)
> 111 : 0;
> 112 }
> 113
> 114 char * whst_copy_string( char const * str, size_t len )
> 115 {
> 116 char * rc = 0;
> 117 if( str && !len ) len = (str ? strlen(str) : 0);
> 118 if( !len ) return 0;
> 119 rc = (char * )malloc(len+1);
> 120 if( rc )
> 121 {
> 122 size_t i = 0;
> 123 for( ; (i < len) && str[i]; ++i ) rc[i] = str[i];
> 124 for( ; i < len; ++i ) rc[i] = 0;
> 125 }
> 126 return rc;
> 127 }
> 128
> 129 char const * whst_addref( whst_context * cx, char const * item )
> 130 {
> 131 if( ! cx || !item ) return 0;
> 132 whst_entry * e = whst_search_entry(cx,item);
> 133 if( e )
> 134 {
> 135 ++e->refcount;
> 136 return e->string;
> 137 }
> 138 e = (whst_entry*)malloc(sizeof(whst_entry));
> 139 if( ! e ) return 0;
> 140 *e = whst_entry_init;
> 141 e->refcount = 1;
> 142 e->string = whst_copy_string( item, 0 );
> 143 if( ! whhash_insert( cx->ht, e->string, e ) )
> 144 {
> 145 whst_entry_destroy( e );
> 146 e = 0;
> 147 }
> 148 return e ? e->string : 0;
> 149 }
> 150
> 151 size_t whst_rmref( whst_context * cx, char const * item )
> 152 {
> 153 whst_entry * e = whst_search_entry(cx,item);
> 154 //MARKER("e=@%p, rc=%u\n",e,e?e->refcount:whst_ref_err_val);
> 155 if( ! e ) return 0;
> 156 size_t rc = --e->refcount;
> 157 if( 0 == rc )
> 158 {
> 159 whst_entry * check = whst_take_entry(cx, item);
> 160 assert( (check == e) && "Internal state error - maybe another thread has trashed our hashtable?");
> 161 whst_entry_destroy( check );
> 162 }
> 163 return rc;
> 164 }
> 165
> 166 #ifdef __cplusplus
> 167 } /* extern "C" */
> 168 #endif

Added whst.h

Old () New (115900f7df5f45ce)
> 1 #ifndef WANDERINGHORSE_NET_WHST_H_INCLUDED
> 2 #define WANDERINGHORSE_NET_WHST_H_INCLUDED 1
> 3 /** @page whst_page_main whst: reference counting string pool for C
> 4
> 5 whst (the WanderingHorse.net String Table) is a small C library for
> 6 adding reference counts to strings. It is intended for applications where
> 7 many strings may need to be copied, but for which many duplicates
> 8 are expected. By adding the string to the pool, we can often void
> 9 another string allocation. This is only useful for avoiding mallocs
> 10 when many dupes are expected, as the reference counting takes
> 11 requires approximately 3 internal allocs for hashtable entries.
> 12
> 13 It internally uses a hashtable which uses a hash code based on the
> 14 string value of an item. In theory the hashtable can average 0(1)
> 15 speeds, so there is very little performance hit. That said, the hash
> 16 routine is O(N), where N is the length of the string.
> 17
> 18 Example:
> 19 @code
> 20 whst_context * cx = whst_create_context();
> 21 char const * str = "hi, world";
> 22 whst_addref( cx, str );
> 23 size_t rc = whst_refcount(cx,str); // rc == 1
> 24 rc = whst_addref(cx,str); //rc == 2
> 25 rc = whst_rmref(cx,str); // rc == 1
> 26 rc = whst_rmref(cx,str); // rc == 0, string is internally cleaned up
> 27 whst_destroy_context(cx,true);
> 28 @endcode
> 29
> 30 When adding a new string it must make a copy of that string.
> 31
> 32 That demonstrates the majority of the API. There are only a handful of
> 33 functions to learn.
> 34
> 35 @section whst_sec_threadsafety Thread safety
> 36
> 37 By default it is never legal to use the same @ref whst_context from
> 38 multiple threads at the same time. That said, the client may use
> 39 their own locking to serialize access. All API functions which
> 40 take a (@ref whst_context const *) argument require only a read lock,
> 41 whereas those taking a (@ref whst_context *) argument require a
> 42 exclusive (read/write) access. whst_create_context() is reentrant
> 43 and does not need to be locked.
> 44 */
> 45
> 46 #include <stddef.h> /* size_t */
> 47
> 48 #ifdef __cplusplus
> 49 extern "C" {
> 50 #endif
> 51
> 52 #ifndef __cplusplus
> 53 # ifndef WHGC_HAVE_STDBOOL
> 54 # define WHGC_HAVE_STDBOOL 0
> 55 # endif
> 56 # if defined(WHST_HAVE_STDBOOL) && !(WHST_HAVE_STDBOOL)
> 57 # if !defined(bool)
> 58 # define bool char
> 59 # endif
> 60 # if !defined(true)
> 61 # define true 1
> 62 # endif
> 63 # if !defined(false)
> 64 # define false 0
> 65 # endif
> 66 # else /* aha! stdbool.h! C99. */
> 67 # include <stdbool.h>
> 68 # endif /* WHST_HAVE_STDBOOL */
> 69 #endif /* __cplusplus */
> 70
> 71 /**
> 72 Defined to ((size_t)-1), and returned from some functions
> 73 which need to report an error.
> 74 */
> 75 extern const size_t whst_ref_err_val;
> 76
> 77 /**@typedef struct whst_context whst_context
> 78
> 79 Opaque handle type for reference count operations.
> 80 */
> 81 struct whst_context;
> 82 typedef struct whst_context whst_context;
> 83
> 84 /**
> 85 Creates a new whst_context object and transfers ownership to the
> 86 caller. The caller must free it with whst_destroy_context().
> 87 */
> 88 whst_context * whst_create_context();
> 89
> 90 /**
> 91 Clears all items in a context, unconditionally passing them to
> 92 their registered destructors.
> 93 */
> 94 void whst_clear_context( whst_context * );
> 95
> 96 /**
> 97 Like whst_clear_context() , but also frees cx.
> 98 */
> 99 void whst_destroy_context( whst_context * cx );
> 100
> 101 /**
> 102 Adds one to the reference count of the given string. If the string
> 103 has not yet been registered then a new copy is created and its
> 104 reference count is set to 1. The internal copy of the string is
> 105 returned. It is owned by cx and will be cleaned up when the
> 106 refcount goes to 0 or cx is destroy.
> 107
> 108 Returns 0 on an allocation error or if !cx or !item.
> 109 */
> 110 char const * whst_addref( whst_context * cx, char const * item );
> 111
> 112 /**
> 113 Subtracts one to the reference count of item and returns the new
> 114 reference count. It returns 0 if (!cx) or (!item), or if no entry
> 115 is found, but this is indistinguishable from a refcount which just
> 116 dropped to 0.
> 117
> 118 If the refcount is reduced to 0 then the internal string copy is
> 119 cleaned up.
> 120 */
> 121 size_t whst_rmref( whst_context * cx, char const * item );
> 122
> 123 /**
> 124 Returns the current refcount for the given string, or
> 125 0 if no such item is found or if cx or item are 0.
> 126 */
> 127 size_t whst_refcount( whst_context * cx, char const * item );
> 128
> 129
> 130 #ifdef __cplusplus
> 131 } /* extern "C" */
> 132 #endif
> 133
> 134
> 135 #endif /* WANDERINGHORSE_NET_WHST_H_INCLUDED */