##! Functions to probabilistically determine top-k elements.

%%{
#include "zeek/probabilistic/Topk.h"
%%}

## Creates a top-k data structure which tracks *size* elements.
##
## size: number of elements to track.
##
## Returns: Opaque pointer to the data structure.
##
## .. zeek:see:: topk_add topk_get_top topk_count topk_epsilon
##    topk_size topk_sum topk_merge topk_merge_prune
function topk_init%(size: count%): opaque of topk
	%{
	auto v = zeek::make_intrusive<zeek::probabilistic::detail::TopkVal>(size);
	return v;
	%}

## Add a new observed object to the data structure.
##
## .. note:: The first added object sets the type of data tracked by
##    the top-k data structure. All following values have to be of the same
##    type.
##
## handle: the TopK handle.
##
## value: observed value.
##
## .. zeek:see:: topk_init topk_get_top topk_count topk_epsilon
##    topk_size topk_sum topk_merge topk_merge_prune
function topk_add%(handle: opaque of topk, value: any%): any
	%{
	assert(handle);
	auto* h = (zeek::probabilistic::detail::TopkVal*) handle;
	h->Encountered({zeek::NewRef{}, value});

	return nullptr;
	%}

## Get the first *k* elements of the top-k data structure.
##
## handle: the TopK handle.
##
## k: number of elements to return.
##
## Returns: vector of the first k elements.
##
## .. zeek:see:: topk_init topk_add topk_count topk_epsilon
##    topk_size topk_sum topk_merge topk_merge_prune
function topk_get_top%(handle: opaque of topk, k: count%): any_vec
	%{
	assert(handle);
	auto* h = (zeek::probabilistic::detail::TopkVal*) handle;
	return h->GetTopK(k);
	%}

## Get an overestimated count of how often a value has been encountered.
##
## .. note:: The value has to be part of the currently tracked elements,
##    otherwise 0 will be returned and an error message will be added to
##    reporter.
##
## handle: the TopK handle.
##
## value: Value to look up count for.
##
## Returns: Overestimated number for how often the element has been encountered.
##
## .. zeek:see:: topk_init topk_add topk_get_top topk_epsilon
##    topk_size topk_sum topk_merge topk_merge_prune
function topk_count%(handle: opaque of topk, value: any%): count
	%{
	assert(handle);
	auto* h = (zeek::probabilistic::detail::TopkVal*) handle;
	return zeek::val_mgr->Count(h->GetCount(value));
	%}

## Get the maximal overestimation for count.
##
## .. note:: Same restrictions as for :zeek:id:`topk_count` apply.
##
## handle: the TopK handle.
##
## value: Value to look up epsilon for.
##
## Returns: Number which represents the maximal overestimation for the count of
##          this element.
##
## .. zeek:see:: topk_init topk_add topk_get_top topk_count
##    topk_size topk_sum topk_merge topk_merge_prune
function topk_epsilon%(handle: opaque of topk, value: any%): count
	%{
	assert(handle);
	auto* h = (zeek::probabilistic::detail::TopkVal*) handle;
	return zeek::val_mgr->Count(h->GetEpsilon(value));
	%}

## Get the number of elements this data structure is supposed to track (given
## on init).
##
## .. note:: Note that the actual number of elements in the data structure can
##    be lower or higher (due to non-pruned merges) than this.
##
## handle: the TopK handle.
##
## Returns: size given during initialization.
##
## .. zeek:see:: topk_init topk_add topk_get_top topk_count topk_epsilon
##    topk_sum topk_merge topk_merge_prune
function topk_size%(handle: opaque of topk%): count
	%{
	assert(handle);
	auto* h = (zeek::probabilistic::detail::TopkVal*) handle;
	return zeek::val_mgr->Count(h->GetSize());
	%}

## Get the sum of all counts of all elements in the data structure.
##
## .. note:: This is equal to the number of all inserted objects if the data
##    structure never has been pruned. Do not use after
##    calling :zeek:id:`topk_merge_prune` (will throw a warning message if used
##    afterwards).
##
## handle: the TopK handle.
##
## Returns: sum of all counts.
##
## .. zeek:see:: topk_init topk_add topk_get_top topk_count topk_epsilon
##    topk_size topk_merge topk_merge_prune
function topk_sum%(handle: opaque of topk%): count
	%{
	assert(handle);
	auto* h = (zeek::probabilistic::detail::TopkVal*) handle;
	return zeek::val_mgr->Count(h->GetSum());
	%}

## Merge the second top-k data structure into the first.
##
## handle1: the first TopK handle.
##
## handle2: the second TopK handle.
##
## .. note:: This does not remove any elements, the resulting data structure
##    can be bigger than the maximum size given on initialization.
##
## .. zeek:see:: topk_init topk_add topk_get_top topk_count topk_epsilon
##    topk_size topk_sum topk_merge_prune
function topk_merge%(handle1: opaque of topk, handle2: opaque of topk%): any
	%{
	assert(handle1);
	assert(handle2);

	auto* h1 = (zeek::probabilistic::detail::TopkVal*) handle1;
	auto* h2 = (zeek::probabilistic::detail::TopkVal*) handle2;

	h1->Merge(h2);

	return nullptr;
	%}

## Merge the second top-k data structure into the first and prunes the final
## data structure back to the size given on initialization.
##
## .. note:: Use with care and only when being aware of the restrictions this
##    entails. Do not call :zeek:id:`topk_size` or :zeek:id:`topk_add` afterwards,
##    results will probably not be what you expect.
##
## handle1: the TopK handle in which the second TopK structure is merged.
##
## handle2: the TopK handle in which is merged into the first TopK structure.
##
## .. zeek:see:: topk_init topk_add topk_get_top topk_count topk_epsilon
##    topk_size topk_sum topk_merge
function topk_merge_prune%(handle1: opaque of topk, handle2: opaque of topk%): any
	%{
	assert(handle1);
	assert(handle2);

	auto* h1 = (zeek::probabilistic::detail::TopkVal*) handle1;
	auto* h2 = (zeek::probabilistic::detail::TopkVal*) handle2;

	h1->Merge(h2, true);

	return nullptr;
	%}
