Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
ZHASHX(3)			  CZMQ Manual			     ZHASHX(3)

NAME
       zhashx -	Class for extended generic hash	container

SYNOPSIS
       //  This	is a stable class, and may not change except for emergencies. It
       //  is provided in stable builds.
       //  This	class has draft	methods, which may change over time. They are not
       //  in stable releases, by default. Use --enable-drafts to enable.
       // Destroy an item
       typedef void (zhashx_destructor_fn) (
	   void	**item);

       // Duplicate an item
       typedef void * (zhashx_duplicator_fn) (
	   const void *item);

       // Compare two items, for sorting
       typedef int (zhashx_comparator_fn) (
	   const void *item1, const void *item2);

       // Destroy an item.
       typedef void (zhashx_free_fn) (
	   void	*data);

       // Hash function	for keys.
       typedef size_t (zhashx_hash_fn) (
	   const void *key);

       // Serializes an	item to	a longstr.
       // The caller takes ownership of	the newly created object.
       typedef char * (zhashx_serializer_fn) (
	   const void *item);

       // Deserializes a longstr into an item.
       // The caller takes ownership of	the newly created object.
       typedef void * (zhashx_deserializer_fn) (
	   const char *item_str);

       //  Create a new, empty hash container
       CZMQ_EXPORT zhashx_t *
	   zhashx_new (void);

       //  Unpack binary frame into a new hash table. Packed data must follow format
       //  defined by zhashx_pack. Hash	table is set to	autofree. An empty frame
       //  unpacks to an empty hash table.
       CZMQ_EXPORT zhashx_t *
	   zhashx_unpack (zframe_t *frame);

       //  Destroy a hash container and	all items in it
       CZMQ_EXPORT void
	   zhashx_destroy (zhashx_t **self_p);

       //  Insert item into hash table with specified key and item.
       //  If key is already present returns -1	and leaves existing item unchanged
       //  Returns 0 on	success.
       CZMQ_EXPORT int
	   zhashx_insert (zhashx_t *self, const	void *key, void	*item);

       //  Update or insert item into hash table with specified	key and	item. If the
       //  key is already present, destroys old	item and inserts new one. If you set
       //  a container item destructor,	this is	called on the old value. If the	key
       //  was not already present, inserts a new item.	Sets the hash cursor to	the
       //  new item.
       CZMQ_EXPORT void
	   zhashx_update (zhashx_t *self, const	void *key, void	*item);

       //  Remove an item specified by key from	the hash table.	If there was no	such
       //  item, this function does nothing.
       CZMQ_EXPORT void
	   zhashx_delete (zhashx_t *self, const	void *key);

       //  Delete all items from the hash table. If the	key destructor is
       //  set,	calls it on every key. If the item destructor is set, calls
       //  it on every item.
       CZMQ_EXPORT void
	   zhashx_purge	(zhashx_t *self);

       //  Return the item at the specified key, or null
       CZMQ_EXPORT void	*
	   zhashx_lookup (zhashx_t *self, const	void *key);

       //  Reindexes an	item from an old key to	a new key. If there was	no such
       //  item, does nothing. Returns 0 if successful,	else -1.
       CZMQ_EXPORT int
	   zhashx_rename (zhashx_t *self, const	void *old_key, const void *new_key);

       //  Set a free function for the specified hash table item. When the item	is
       //  destroyed, the free function, if any, is called on that item.
       //  Use this when hash items are	dynamically allocated, to ensure that
       //  you don't have memory leaks.	You can	pass 'free' or NULL as a free_fn.
       //  Returns the item, or	NULL if	there is no such item.
       CZMQ_EXPORT void	*
	   zhashx_freefn (zhashx_t *self, const	void *key, zhashx_free_fn free_fn);

       //  Return the number of	keys/items in the hash table
       CZMQ_EXPORT size_t
	   zhashx_size (zhashx_t *self);

       //  Return a zlistx_t containing	the keys for the items in the
       //  table. Uses the key_duplicator to duplicate all keys	and sets the
       //  key_destructor as destructor	for the	list.
       //  Caller owns return value and	must destroy it	when done.
       CZMQ_EXPORT zlistx_t *
	   zhashx_keys (zhashx_t *self);

       //  Return a zlistx_t containing	the values for the items in the
       //  table. Uses the duplicator to duplicate all items and sets the
       //  destructor as destructor for	the list.
       //  Caller owns return value and	must destroy it	when done.
       CZMQ_EXPORT zlistx_t *
	   zhashx_values (zhashx_t *self);

       //  Simple iterator; returns first item in hash table, in no given order,
       //  or NULL if the table	is empty. This method is simpler to use	than the
       //  foreach() method, which is deprecated. To access the	key for	this item
       //  use zhashx_cursor().	NOTE: do NOT modify the	table while iterating.
       CZMQ_EXPORT void	*
	   zhashx_first	(zhashx_t *self);

       //  Simple iterator; returns next item in hash table, in	no given order,
       //  or NULL if the last item was	already	returned. Use this together with
       //  zhashx_first() to process all items in a hash table.	If you need the
       //  items in sorted order, use zhashx_keys() and	then zlistx_sort(). To
       //  access the key for this item	use zhashx_cursor(). NOTE: do NOT modify
       //  the table while iterating.
       CZMQ_EXPORT void	*
	   zhashx_next (zhashx_t *self);

       //  After a successful first/next method, returns the key for the item that
       //  was returned. This is a constant string that	you may	not modify or
       //  deallocate, and which lasts as long as the item in the hash.	After an
       //  unsuccessful	first/next, returns NULL.
       CZMQ_EXPORT const void *
	   zhashx_cursor (zhashx_t *self);

       //  Add a comment to hash table before saving to	disk. You can add as many
       //  comment lines as you	like. These comment lines are discarded	when loading
       //  the file. If	you use	a null format, all comments are	deleted.
       CZMQ_EXPORT void
	   zhashx_comment (zhashx_t *self, const char *format, ...) CHECK_PRINTF (2);

       //  Save	hash table to a	text file in name=value	format.	Hash values must be
       //  printable strings; keys may not contain '=' character. Returns 0 if OK,
       //  else	-1 if a	file error occurred.
       CZMQ_EXPORT int
	   zhashx_save (zhashx_t *self,	const char *filename);

       //  Load	hash table from	a text file in name=value format; hash table must
       //  already exist. Hash values must printable strings; keys may not contain
       //  '=' character. Returns 0 if OK, else	-1 if a	file was not readable.
       CZMQ_EXPORT int
	   zhashx_load (zhashx_t *self,	const char *filename);

       //  When	a hash table was loaded	from a file by zhashx_load, this method	will
       //  reload the file if it has been modified since, and is "stable", i.e.	not
       //  still changing. Returns 0 if	OK, -1 if there	was an error reloading the
       //  file.
       CZMQ_EXPORT int
	   zhashx_refresh (zhashx_t *self);

       //  Serialize hash table	to a binary frame that can be sent in a	message.
       //  The packed format is	compatible with	the 'dictionary' type defined in
       //  http://rfc.zeromq.org/spec:35/FILEMQ, and implemented by zproto:
       //
       //     ;	A list of name/value pairs
       //     dictionary      =	dict-count *( dict-name	dict-value )
       //     dict-count      =	number-4
       //     dict-value      =	longstr
       //     dict-name	      =	string
       //
       //     ;	Strings	are always length + text contents
       //     longstr	      =	number-4 *VCHAR
       //     string	      =	number-1 *VCHAR
       //
       //     ;	Numbers	are unsigned integers in network byte order
       //     number-1	      =	1OCTET
       //     number-4	      =	4OCTET
       //
       //  Comments are	not included in	the packed data. Item values MUST be
       //  strings.
       //  Caller owns return value and	must destroy it	when done.
       CZMQ_EXPORT zframe_t *
	   zhashx_pack (zhashx_t *self);

       //  Make	a copy of the list; items are duplicated if you	set a duplicator
       //  for the list, otherwise not.	Copying	a null reference returns a null
       //  reference. Note that	this method's behavior changed slightly	for CZMQ
       //  v3.x, as it does not	set nor	respect	autofree. It does however let you
       //  duplicate any hash table safely. The	old behavior is	in zhashx_dup_v2.
       //  Caller owns return value and	must destroy it	when done.
       CZMQ_EXPORT zhashx_t *
	   zhashx_dup (zhashx_t	*self);

       //  Set a user-defined deallocator for hash items; by default items are not
       //  freed when the hash is destroyed.
       CZMQ_EXPORT void
	   zhashx_set_destructor (zhashx_t *self, zhashx_destructor_fn destructor);

       //  Set a user-defined duplicator for hash items; by default items are not
       //  copied when the hash	is duplicated.
       CZMQ_EXPORT void
	   zhashx_set_duplicator (zhashx_t *self, zhashx_duplicator_fn duplicator);

       //  Set a user-defined deallocator for keys; by default keys are	freed
       //  when	the hash is destroyed using free().
       CZMQ_EXPORT void
	   zhashx_set_key_destructor (zhashx_t *self, zhashx_destructor_fn destructor);

       //  Set a user-defined duplicator for keys; by default keys are duplicated
       //  using strdup.
       CZMQ_EXPORT void
	   zhashx_set_key_duplicator (zhashx_t *self, zhashx_duplicator_fn duplicator);

       //  Set a user-defined comparator for keys; by default keys are
       //  compared using strcmp.
       //  The callback	function should	return zero (0)	on matching
       //  items.
       CZMQ_EXPORT void
	   zhashx_set_key_comparator (zhashx_t *self, zhashx_comparator_fn comparator);

       //  Set a user-defined hash function for	keys; by default keys are
       //  hashed by a modified	Bernstein hashing function.
       CZMQ_EXPORT void
	   zhashx_set_key_hasher (zhashx_t *self, zhashx_hash_fn hasher);

       //  Make	copy of	hash table; if supplied	table is null, returns null.
       //  Does	not copy items themselves. Rebuilds new	table so may be	slow on
       //  very	large tables. NOTE: only works with item values	that are strings
       //  since there's no other way to know how to duplicate the item	value.
       CZMQ_EXPORT zhashx_t *
	   zhashx_dup_v2 (zhashx_t *self);

       //  Self	test of	this class.
       CZMQ_EXPORT void
	   zhashx_test (bool verbose);

       #ifdef CZMQ_BUILD_DRAFT_API
       //  *** Draft method, for development use, may change without warning ***
       //  Same	as unpack but uses a user-defined deserializer function	to convert
       //  a longstr back into item format.
       CZMQ_EXPORT zhashx_t *
	   zhashx_unpack_own (zframe_t *frame, zhashx_deserializer_fn deserializer);

       //  *** Draft method, for development use, may change without warning ***
       //  Same	as pack	but uses a user-defined	serializer function to convert items
       //  into	longstr.
       //  Caller owns return value and	must destroy it	when done.
       CZMQ_EXPORT zframe_t *
	   zhashx_pack_own (zhashx_t *self, zhashx_serializer_fn serializer);

       #endif // CZMQ_BUILD_DRAFT_API
       Please add '@interface' section in './../src/zhashx.c'.

DESCRIPTION
       zhashx is an extended hash table	container with more functionality than
       zhash, its simpler cousin.

       The hash	table always has a size	that is	prime and roughly doubles its
       size when 75% full. In case of hash collisions items are	chained	in a
       linked list. The	hash table size	is increased slightly (up to 5 times
       before roughly doubling the size) when an overly	long chain (between 1
       and 63 items depending on table size) is	detected.

EXAMPLE
       From zhashx_test	method.

	   zhashx_t *hash = zhashx_new ();
	   assert (hash);
	   assert (zhashx_size (hash) == 0);
	   assert (zhashx_first	(hash) == NULL);
	   assert (zhashx_cursor (hash)	== NULL);

	   //  Insert some items
	   int rc;
	   rc =	zhashx_insert (hash, "DEADBEEF", "dead beef");
	   char	*item =	(char *) zhashx_first (hash);
	   assert (streq ((char	*) zhashx_cursor (hash), "DEADBEEF"));
	   assert (streq (item,	"dead beef"));
	   assert (rc == 0);
	   rc =	zhashx_insert (hash, "ABADCAFE", "a bad	cafe");
	   assert (rc == 0);
	   rc =	zhashx_insert (hash, "C0DEDBAD", "coded	bad");
	   assert (rc == 0);
	   rc =	zhashx_insert (hash, "DEADF00D", "dead food");
	   assert (rc == 0);
	   assert (zhashx_size (hash) == 4);

	   //  Look for	existing items
	   item	= (char	*) zhashx_lookup (hash,	"DEADBEEF");
	   assert (streq (item,	"dead beef"));
	   item	= (char	*) zhashx_lookup (hash,	"ABADCAFE");
	   assert (streq (item,	"a bad cafe"));
	   item	= (char	*) zhashx_lookup (hash,	"C0DEDBAD");
	   assert (streq (item,	"coded bad"));
	   item	= (char	*) zhashx_lookup (hash,	"DEADF00D");
	   assert (streq (item,	"dead food"));

	   //  Look for	non-existent items
	   item	= (char	*) zhashx_lookup (hash,	"foo");
	   assert (item	== NULL);

	   //  Try to insert duplicate items
	   rc =	zhashx_insert (hash, "DEADBEEF", "foo");
	   assert (rc == -1);
	   item	= (char	*) zhashx_lookup (hash,	"DEADBEEF");
	   assert (streq (item,	"dead beef"));

	   //  Some rename tests

	   //  Valid rename, key is now	LIVEBEEF
	   rc =	zhashx_rename (hash, "DEADBEEF", "LIVEBEEF");
	   assert (rc == 0);
	   item	= (char	*) zhashx_lookup (hash,	"LIVEBEEF");
	   assert (streq (item,	"dead beef"));

	   //  Trying to rename	an unknown item	to a non-existent key
	   rc =	zhashx_rename (hash, "WHATBEEF", "NONESUCH");
	   assert (rc == -1);

	   //  Trying to rename	an unknown item	to an existing key
	   rc =	zhashx_rename (hash, "WHATBEEF", "LIVEBEEF");
	   assert (rc == -1);
	   item	= (char	*) zhashx_lookup (hash,	"LIVEBEEF");
	   assert (streq (item,	"dead beef"));

	   //  Trying to rename	an existing item to another existing item
	   rc =	zhashx_rename (hash, "LIVEBEEF", "ABADCAFE");
	   assert (rc == -1);
	   item	= (char	*) zhashx_lookup (hash,	"LIVEBEEF");
	   assert (streq (item,	"dead beef"));
	   item	= (char	*) zhashx_lookup (hash,	"ABADCAFE");
	   assert (streq (item,	"a bad cafe"));

	   //  Test keys method
	   zlistx_t *keys = zhashx_keys	(hash);
	   assert (zlistx_size (keys) == 4);
	   zlistx_destroy (&keys);

	   zlistx_t *values = zhashx_values (hash);
	   assert (zlistx_size (values)	== 4);
	   zlistx_destroy (&values);

	   //  Test dup	method
	   zhashx_t *copy = zhashx_dup (hash);
	   assert (zhashx_size (copy) == 4);
	   item	= (char	*) zhashx_lookup (copy,	"LIVEBEEF");
	   assert (item);
	   assert (streq (item,	"dead beef"));
	   zhashx_destroy (&copy);

	   //  Test pack/unpack	methods
	   zframe_t *frame = zhashx_pack (hash);
	   copy	= zhashx_unpack	(frame);
	   zframe_destroy (&frame);
	   assert (zhashx_size (copy) == 4);
	   item	= (char	*) zhashx_lookup (copy,	"LIVEBEEF");
	   assert (item);
	   assert (streq (item,	"dead beef"));
	   zhashx_destroy (&copy);

	   #ifdef CZMQ_BUILD_DRAFT_API
	   //  Test own	pack/unpack methods
	   zhashx_t *own_hash =	zhashx_new ();
	   zhashx_set_destructor (own_hash, s_test_destroy_int);
	   assert (own_hash);
	   int *val1 = (int *) zmalloc (sizeof (int));
	   int *val2 = (int *) zmalloc (sizeof (int));
	   *val1 = 25;
	   *val2 = 100;
	   zhashx_insert (own_hash, "val1", val1);
	   zhashx_insert (own_hash, "val2", val2);
	   frame = zhashx_pack_own (own_hash, s_test_serialize_int);
	   copy	= zhashx_unpack_own (frame, s_test_deserialze_int);
	   zhashx_set_destructor (copy,	s_test_destroy_int);
	   zframe_destroy (&frame);
	   assert (zhashx_size (copy) == 2);
	   assert (*((int *) zhashx_lookup (copy, "val1")) == 25);
	   assert (*((int *) zhashx_lookup (copy, "val2")) == 100);
	   zhashx_destroy (&copy);
	   zhashx_destroy (&own_hash);
	   #endif // CZMQ_BUILD_DRAFT_API

	   //  Test save and load
	   zhashx_comment (hash, "This is a test file");
	   zhashx_comment (hash, "Created by %s", "czmq_selftest");
	   zhashx_save (hash, ".cache");
	   copy	= zhashx_new ();
	   assert (copy);
	   zhashx_load (copy, ".cache");
	   item	= (char	*) zhashx_lookup (copy,	"LIVEBEEF");
	   assert (item);
	   assert (streq (item,	"dead beef"));
	   zhashx_destroy (&copy);
	   zsys_file_delete (".cache");

	   //  Delete a	item
	   zhashx_delete (hash,	"LIVEBEEF");
	   item	= (char	*) zhashx_lookup (hash,	"LIVEBEEF");
	   assert (item	== NULL);
	   assert (zhashx_size (hash) == 3);

	   //  Check that the queue is robust against random usage
	   struct {
	       char name [100];
	       bool exists;
	   } testset [200];
	   memset (testset, 0, sizeof (testset));
	   int testmax = 200, testnbr, iteration;

	   srandom ((unsigned) time (NULL));
	   for (iteration = 0; iteration < 25000; iteration++) {
	       testnbr = randof	(testmax);
	       assert (testnbr != testmax);
	       assert (testnbr < testmax);
	       if (testset [testnbr].exists) {
		   item	= (char	*) zhashx_lookup (hash,	testset	[testnbr].name);
		   assert (item);
		   zhashx_delete (hash,	testset	[testnbr].name);
		   testset [testnbr].exists = false;
	       }
	       else {
		   sprintf (testset [testnbr].name, "%x-%x", rand (), rand ());
		   if (zhashx_insert (hash, testset [testnbr].name, "")	== 0)
		       testset [testnbr].exists	= true;
	       }
	   }
	   //  Test 10K	lookups
	   for (iteration = 0; iteration < 10000; iteration++)
	       item = (char *) zhashx_lookup (hash, "DEADBEEFABADCAFE");

	   //  Destructor should be safe to call twice
	   zhashx_destroy (&hash);
	   zhashx_destroy (&hash);
	   assert (hash	== NULL);

	   //  Test randof() limits - should be	within (0..testmax)
	   //  and randomness distribution - should not	have (many) zero-counts
	   //  If there	are - maybe the	ZSYS_RANDOF_MAX	is too big for this platform
	   //  Note: This test can take	a while	on systems with	weak floating point HW
	   testmax = 999;
	   size_t rndcnt[999];
	   assert ((sizeof (rndcnt)/sizeof(rndcnt[0])) == testmax);
	   memset (rndcnt, 0, sizeof (rndcnt));
	   for (iteration = 0; iteration < 10000000; iteration++) {
	       testnbr = randof	(testmax);
	       assert (testnbr != testmax);
	       assert (testnbr < testmax);
	       assert (testnbr >= 0);
	       rndcnt[testnbr]++;
	   }
	   int rndmisses = 0;
	   for (iteration = 0; iteration < testmax; iteration++) {
	       if (rndcnt[iteration] ==	0) {
		   zsys_warning("zhashx_test() : random	distribution fault : got 0 hits	for %d/%d",
		       iteration, testmax);
		   rndmisses++;
	       }
	   }
	   //  Too many	misses are suspicious... we can	lose half the entries
	   //  for each	bit not	used in	the assumed ZSYS_RANDOF_MAX...
	   assert ( (rndmisses < (testmax / 3 )) );

	   //  Test destructor;	automatically copies and frees string values
	   hash	= zhashx_new ();
	   assert (hash);
	   zhashx_set_destructor (hash,	(zhashx_destructor_fn *) zstr_free);
	   zhashx_set_duplicator (hash,	(zhashx_duplicator_fn *) strdup);
	   char	value [255];
	   strcpy (value, "This	is a string");
	   rc =	zhashx_insert (hash, "key1", value);
	   assert (rc == 0);
	   strcpy (value, "Ring	a ding ding");
	   rc =	zhashx_insert (hash, "key2", value);
	   assert (rc == 0);
	   assert (streq ((char	*) zhashx_lookup (hash,	"key1"), "This is a string"));
	   assert (streq ((char	*) zhashx_lookup (hash,	"key2"), "Ring a ding ding"));
	   zhashx_destroy (&hash);

	   //  Test purger and shrinker: no data should	end up unreferenced in valgrind
	   hash	= zhashx_new ();
	   assert (hash);
	   zhashx_set_destructor (hash,	(zhashx_destructor_fn *) zstr_free);
	   zhashx_set_duplicator (hash,	(zhashx_duplicator_fn *) strdup);
	   char	valuep [255];
	   strcpy (valuep, "This is a string");
	   rc =	zhashx_insert (hash, "key1", valuep);
	   assert (rc == 0);
	   strcpy (valuep, "Ring a ding	ding");
	   rc =	zhashx_insert (hash, "key2", valuep);
	   assert (rc == 0);
	   strcpy (valuep, "Cartahena delenda est");
	   rc =	zhashx_insert (hash, "key3", valuep);
	   assert (rc == 0);
	   strcpy (valuep, "So say we all!");
	   rc =	zhashx_insert (hash, "key4", valuep);
	   assert (rc == 0);
	   assert (streq ((char	*) zhashx_lookup (hash,	"key1"), "This is a string"));
	   assert (streq ((char	*) zhashx_lookup (hash,	"key2"), "Ring a ding ding"));
	   assert (streq ((char	*) zhashx_lookup (hash,	"key3"), "Cartahena delenda est"));
	   assert (streq ((char	*) zhashx_lookup (hash,	"key4"), "So say we all!"));
	   zhashx_purge	(hash);
	   zhashx_destroy (&hash);

	   #if defined (__WINDOWS__)
	   zsys_shutdown();
	   #endif

AUTHORS
       The czmq	manual was written by the authors in the AUTHORS file.

RESOURCES
       Main web	site:

       Report bugs to the email	<zeromq-dev@lists.zeromq.org[1]>

COPYRIGHT
       Copyright (c) the Contributors as noted in the AUTHORS file. This file
       is part of CZMQ,	the high-level C binding for 0MQ:
       http://czmq.zeromq.org. This Source Code	Form is	subject	to the terms
       of the Mozilla Public License, v. 2.0. If a copy	of the MPL was not
       distributed with	this file, You can obtain one at
       http://mozilla.org/MPL/2.0/. LICENSE included with the czmq
       distribution.

NOTES
	1. zeromq-dev@lists.zeromq.org
	   mailto:zeromq-dev@lists.zeromq.org

CZMQ 4.2.1			  11/01/2025			     ZHASHX(3)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=zhashx&sektion=3&manpath=FreeBSD+Ports+15.0>

home | help