/*-
 * Copyright (c) 2020 UPLEX Nils Goroll Systemoptimierung
 * All rights reserved
 *
 * Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/* Interface for perfect hashing */

#include <stdint.h>
#include <limits.h>
#include <unistd.h>

/*
 * A perfect hash comprises a struct ph and a table of strings, both of
 * which are owned by a VMOD object. Successful lookups return the index
 * of a string in the table.
 */
struct ph;

struct ph_stats {
	unsigned	magic;
#define PH_STATS_MAGIC 0x68b803bb
	uint64_t	buckets;
	uint64_t	collisions;
	uint64_t	klen;
	uint64_t	minlen;
	uint64_t	maxlen;
	uint64_t	h2buckets_min;
	uint64_t	h2buckets_max;
	double		h2buckets_avg;
	uint64_t	h2strings_min;
	uint64_t	h2strings_max;
	double		h2strings_avg;
	size_t		h2klen_min;
	size_t		h2klen_max;
	double		h2klen_avg;
};

/*
 * Initialize perfect hashing. Supplies a seed for random number
 * generation, which should be obtained from an entropy source.  Only
 * needs to be called once.
 */
void PH_Init(const uint32_t seed[4]);

/*
 * Generate a perfect hash from a table of strings with n elements.
 * strings MAY NOT be NULL, and SHALL NOT contain duplicates. n MUST be >
 * 0 and <= 2^31.
 *
 * Returns non-NULL on success, NULL on error, except that PH_Generate()
 * will probably not terminate if strings contains duplicates.
 *
 * On error, errno is set. errno == ERANGE if n is out of range, or may
 * set for other errors (probably ENOMEM for malloc failures).
 */
struct ph * PH_Generate(char * const * const strings, unsigned n);

/*
 * Return the index of subject in the table strings, with which ph was
 * generated.
 *
 * ph MUST be generated for strings previously by PH_Generate() (or NULL).
 * strings and subject MAY NOT be NULL.
 *
 * Returns the index of subject in strings, or UINT_MAX if subject is not
 * in strings or if ph is NULL.
 */
unsigned PH_Lookup(const struct ph * const restrict ph,
		   char * const restrict * const restrict strings,
		   const char * const restrict subject);

void PH_Stats(const struct ph * const restrict ph,
	      char * const restrict * const restrict strings,
	      struct ph_stats * const restrict stats);

/*
 * Return a string dump of ph as generated for strings.
 *
 * Returns a empty buffer if ph is NULL. If ph is non-NULL, strings MAY
 * NOT be NULL.
 */
struct vsb * PH_Dump(const struct ph *ph, const char * const * const strings);

/*
 * Free ph. Silently does nothing if ph is NULL.
 */
void PH_Free(struct ph *ph);
