/*-------------------------------------------------------------------------
 *
 * Pseudo-Random Number Generator
 *
 * Copyright (c) 2021-2024, PostgreSQL Global Development Group
 *
 * src/include/common/pg_prng.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef PG_PRNG_H
#define PG_PRNG_H

/*
 * State vector for PRNG generation.  Callers should treat this as an
 * opaque typedef, but we expose its definition to allow it to be
 * embedded in other structs.
 */
typedef struct pg_prng_state
{
	uint64		s0,
				s1;
} pg_prng_state;

/*
 * Callers not needing local PRNG series may use this global state vector,
 * after initializing it with one of the pg_prng_...seed functions.
 */
extern PGDLLIMPORT pg_prng_state pg_global_prng_state;

extern void pg_prng_seed(pg_prng_state *state, uint64 seed);
extern void pg_prng_fseed(pg_prng_state *state, double fseed);
extern bool pg_prng_seed_check(pg_prng_state *state);

/*
 * Initialize the PRNG state from the pg_strong_random source,
 * taking care that we don't produce all-zeroes.  If this returns false,
 * caller should initialize the PRNG state from some other random seed,
 * using pg_prng_[f]seed.
 *
 * We implement this as a macro, so that the pg_strong_random() call is
 * in the caller.  If it were in pg_prng.c, programs using pg_prng.c
 * but not needing strong seeding would nonetheless be forced to pull in
 * pg_strong_random.c and thence OpenSSL.
 */
#define pg_prng_strong_seed(state) \
	(pg_strong_random((void *) (state), sizeof(pg_prng_state)) ? \
	 pg_prng_seed_check(state) : false)

extern uint64 pg_prng_uint64(pg_prng_state *state);
extern uint64 pg_prng_uint64_range(pg_prng_state *state, uint64 rmin, uint64 rmax);
extern int64 pg_prng_int64(pg_prng_state *state);
extern int64 pg_prng_int64p(pg_prng_state *state);
extern int64 pg_prng_int64_range(pg_prng_state *state, int64 rmin, int64 rmax);
extern uint32 pg_prng_uint32(pg_prng_state *state);
extern int32 pg_prng_int32(pg_prng_state *state);
extern int32 pg_prng_int32p(pg_prng_state *state);
extern double pg_prng_double(pg_prng_state *state);
extern double pg_prng_double_normal(pg_prng_state *state);
extern bool pg_prng_bool(pg_prng_state *state);

#endif							/* PG_PRNG_H */
