miller/c/mapping/stats1_accumulators.c
2016-02-25 09:12:59 -05:00

587 lines
23 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/mlrutil.h"
#include "lib/mlr_globals.h"
#include "lib/mlrstat.h"
#include "containers/slls.h"
#include "containers/lhmslv.h"
#include "containers/lhmsv.h"
#include "containers/lhmss.h"
#include "containers/lhmsi.h"
#include "containers/percentile_keeper.h"
#include "containers/mlrval.h"
#include "mapping/stats1_accumulators.h"
// ----------------------------------------------------------------
static int is_percentile_acc_name(char* stats1_acc_name) {
double percentile;
// sscanf(stats1_acc_name, "p%lf", &percentile) allows "p74x" et al. which isn't ok.
if (stats1_acc_name[0] != 'p')
return FALSE;
if (!mlr_try_float_from_string(&stats1_acc_name[1], &percentile))
return FALSE;
if (percentile < 0.0 || percentile > 100.0) {
fprintf(stderr, "%s stats1: percentile \"%s\" outside range [0,100].\n",
MLR_GLOBALS.argv0, stats1_acc_name);
exit(1);
}
return TRUE;
}
// ----------------------------------------------------------------
void make_stats1_accs(
char* value_field_name, // input
slls_t* paccumulator_names, // input
int allow_int_float, // input
lhmsv_t* acc_field_to_acc_state) // output
{
stats1_acc_t* ppercentile_acc = NULL;
for (sllse_t* pc = paccumulator_names->phead; pc != NULL; pc = pc->pnext) {
// for "sum", "count"
char* stats1_acc_name = pc->value;
if (is_percentile_acc_name(stats1_acc_name)) {
if (ppercentile_acc == NULL) {
ppercentile_acc = stats1_percentile_alloc(value_field_name, stats1_acc_name, allow_int_float);
} else {
stats1_percentile_reuse(ppercentile_acc);
}
lhmsv_put(acc_field_to_acc_state, stats1_acc_name, ppercentile_acc, NO_FREE);
} else {
stats1_acc_t* pstats1_acc = make_stats1_acc(value_field_name, stats1_acc_name, allow_int_float);
if (pstats1_acc == NULL) {
fprintf(stderr, "%s stats1: accumulator \"%s\" not found.\n",
MLR_GLOBALS.argv0, stats1_acc_name);
exit(1);
}
lhmsv_put(acc_field_to_acc_state, stats1_acc_name, pstats1_acc, NO_FREE);
}
}
}
stats1_acc_t* make_stats1_acc(char* value_field_name, char* stats1_acc_name, int allow_int_float) {
for (int i = 0; i < stats1_acc_lookup_table_length; i++)
if (streq(stats1_acc_name, stats1_acc_lookup_table[i].name))
return stats1_acc_lookup_table[i].palloc_func(value_field_name, stats1_acc_name, allow_int_float);
return NULL;
}
// ----------------------------------------------------------------
typedef struct _stats1_count_state_t {
mv_t counter;
mv_t one;
char* output_field_name;
} stats1_count_state_t;
static void stats1_count_singest(void* pvstate, char* val) {
stats1_count_state_t* pstate = pvstate;
pstate->counter = x_xx_plus_func(&pstate->counter, &pstate->one);
}
static void stats1_count_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) {
stats1_count_state_t* pstate = pvstate;
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), mv_alloc_format_val(&pstate->counter),
FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
else
lrec_put(poutrec, pstate->output_field_name, mv_alloc_format_val(&pstate->counter),
FREE_ENTRY_VALUE);
}
static void stats1_count_free(stats1_acc_t* pstats1_acc) {
stats1_count_state_t* pstate = pstats1_acc->pvstate;
free(pstate->output_field_name);
free(pstate);
free(pstats1_acc);
}
stats1_acc_t* stats1_count_alloc(char* value_field_name, char* stats1_acc_name, int allow_int_float) {
stats1_acc_t* pstats1_acc = mlr_malloc_or_die(sizeof(stats1_acc_t));
stats1_count_state_t* pstate = mlr_malloc_or_die(sizeof(stats1_count_state_t));
pstate->counter = allow_int_float ? mv_from_int(0LL) : mv_from_float(0.0);
pstate->one = allow_int_float ? mv_from_int(1LL) : mv_from_float(1.0);
pstate->output_field_name = mlr_paste_3_strings(value_field_name, "_", stats1_acc_name);
pstats1_acc->pvstate = (void*)pstate;
pstats1_acc->pdingest_func = NULL;
pstats1_acc->pningest_func = NULL;
pstats1_acc->psingest_func = stats1_count_singest;
pstats1_acc->pemit_func = stats1_count_emit;
pstats1_acc->pfree_func = stats1_count_free;
return pstats1_acc;
}
// ----------------------------------------------------------------
typedef struct _stats1_mode_state_t {
lhmsi_t* pcounts_for_value;
char* output_field_name;
} stats1_mode_state_t;
// mode on strings: "1" and "1.0" and "1.0000" are distinct text.
static void stats1_mode_singest(void* pvstate, char* val) {
stats1_mode_state_t* pstate = pvstate;
lhmsie_t* pe = lhmsi_get_entry(pstate->pcounts_for_value, val);
if (pe == NULL) {
// lhmsi does a strdup so we needn't.
lhmsi_put(pstate->pcounts_for_value, mlr_strdup_or_die(val), 1, FREE_ENTRY_KEY);
} else {
pe->value++;
}
}
static void stats1_mode_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) {
stats1_mode_state_t* pstate = pvstate;
int max_count = 0;
char* max_key = "";
for (lhmsie_t* pe = pstate->pcounts_for_value->phead; pe != NULL; pe = pe->pnext) {
int count = pe->value;
if (count > max_count) {
max_key = pe->key;
max_count = count;
}
}
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), mlr_strdup_or_die(max_key), FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
else
lrec_put(poutrec, pstate->output_field_name, max_key, NO_FREE);
}
static void stats1_mode_free(stats1_acc_t* pstats1_acc) {
stats1_mode_state_t* pstate = pstats1_acc->pvstate;
lhmsi_free(pstate->pcounts_for_value);
free(pstate->output_field_name);
free(pstate);
free(pstats1_acc);
}
stats1_acc_t* stats1_mode_alloc(char* value_field_name, char* stats1_acc_name, int allow_int_float) {
stats1_acc_t* pstats1_acc = mlr_malloc_or_die(sizeof(stats1_acc_t));
stats1_mode_state_t* pstate = mlr_malloc_or_die(sizeof(stats1_mode_state_t));
pstate->pcounts_for_value = lhmsi_alloc();
pstate->output_field_name = mlr_paste_3_strings(value_field_name, "_", stats1_acc_name);
pstats1_acc->pvstate = (void*)pstate;
pstats1_acc->pdingest_func = NULL;
pstats1_acc->pningest_func = NULL;
pstats1_acc->psingest_func = stats1_mode_singest;
pstats1_acc->pemit_func = stats1_mode_emit;
pstats1_acc->pfree_func = stats1_mode_free;
return pstats1_acc;
}
// ----------------------------------------------------------------
typedef struct _stats1_sum_state_t {
mv_t sum;
char* output_field_name;
int allow_int_float;
} stats1_sum_state_t;
static void stats1_sum_ningest(void* pvstate, mv_t* pval) {
stats1_sum_state_t* pstate = pvstate;
pstate->sum = x_xx_plus_func(&pstate->sum, pval);
}
static void stats1_sum_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) {
stats1_sum_state_t* pstate = pvstate;
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), mv_alloc_format_val(&pstate->sum),
FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
else
lrec_put(poutrec, pstate->output_field_name, mv_alloc_format_val(&pstate->sum),
FREE_ENTRY_VALUE);
}
static void stats1_sum_free(stats1_acc_t* pstats1_acc) {
stats1_sum_state_t* pstate = pstats1_acc->pvstate;
free(pstate->output_field_name);
free(pstate);
free(pstats1_acc);
}
stats1_acc_t* stats1_sum_alloc(char* value_field_name, char* stats1_acc_name, int allow_int_float) {
stats1_acc_t* pstats1_acc = mlr_malloc_or_die(sizeof(stats1_acc_t));
stats1_sum_state_t* pstate = mlr_malloc_or_die(sizeof(stats1_sum_state_t));
pstate->allow_int_float = allow_int_float;
pstate->sum = pstate->allow_int_float ? mv_from_int(0LL) : mv_from_float(0.0);
pstate->output_field_name = mlr_paste_3_strings(value_field_name, "_", stats1_acc_name);
pstats1_acc->pvstate = (void*)pstate;
pstats1_acc->pdingest_func = NULL;
pstats1_acc->pningest_func = stats1_sum_ningest;
pstats1_acc->psingest_func = NULL;
pstats1_acc->pemit_func = stats1_sum_emit;
pstats1_acc->pfree_func = stats1_sum_free;
return pstats1_acc;
}
// ----------------------------------------------------------------
typedef struct _stats1_mean_state_t {
double sum;
unsigned long long count;
char* output_field_name;
} stats1_mean_state_t;
static void stats1_mean_dingest(void* pvstate, double val) {
stats1_mean_state_t* pstate = pvstate;
pstate->sum += val;
pstate->count++;
}
static void stats1_mean_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) {
stats1_mean_state_t* pstate = pvstate;
if (pstate->count == 0LL) {
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), "", FREE_ENTRY_KEY);
else
lrec_put(poutrec, pstate->output_field_name, "", NO_FREE);
} else {
double quot = pstate->sum / pstate->count;
char* val = mlr_alloc_string_from_double(quot, MLR_GLOBALS.ofmt);
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), val, FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
else
lrec_put(poutrec, pstate->output_field_name, val, FREE_ENTRY_VALUE);
}
}
static void stats1_mean_free(stats1_acc_t* pstats1_acc) {
stats1_mean_state_t* pstate = pstats1_acc->pvstate;
free(pstate->output_field_name);
free(pstate);
free(pstats1_acc);
}
stats1_acc_t* stats1_mean_alloc(char* value_field_name, char* stats1_acc_name, int allow_int_float) {
stats1_acc_t* pstats1_acc = mlr_malloc_or_die(sizeof(stats1_acc_t));
stats1_mean_state_t* pstate = mlr_malloc_or_die(sizeof(stats1_mean_state_t));
pstate->sum = 0.0;
pstate->count = 0LL;
pstate->output_field_name = mlr_paste_3_strings(value_field_name, "_", stats1_acc_name);
pstats1_acc->pvstate = (void*)pstate;
pstats1_acc->pdingest_func = stats1_mean_dingest;
pstats1_acc->pningest_func = NULL;
pstats1_acc->psingest_func = NULL;
pstats1_acc->pemit_func = stats1_mean_emit;
pstats1_acc->pfree_func = stats1_mean_free;
return pstats1_acc;
}
// ----------------------------------------------------------------
typedef struct _stats1_stddev_var_meaneb_state_t {
unsigned long long count;
double sumx;
double sumx2;
cumulant2o_t do_which;
char* output_field_name;
} stats1_stddev_var_meaneb_state_t;
static void stats1_stddev_var_meaneb_dingest(void* pvstate, double val) {
stats1_stddev_var_meaneb_state_t* pstate = pvstate;
pstate->count++;
pstate->sumx += val;
pstate->sumx2 += val*val;
}
static void stats1_stddev_var_meaneb_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) {
stats1_stddev_var_meaneb_state_t* pstate = pvstate;
if (pstate->count < 2LL) {
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), "", FREE_ENTRY_KEY);
else
lrec_put(poutrec, pstate->output_field_name, "", NO_FREE);
} else {
double output = mlr_get_var(pstate->count, pstate->sumx, pstate->sumx2);
if (pstate->do_which == DO_STDDEV)
output = sqrt(output);
else if (pstate->do_which == DO_MEANEB)
output = sqrt(output / pstate->count);
char* val = mlr_alloc_string_from_double(output, MLR_GLOBALS.ofmt);
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), val, FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
else
lrec_put(poutrec, pstate->output_field_name, val, FREE_ENTRY_VALUE);
}
}
static void stats1_stddev_var_meaneb_free(stats1_acc_t* pstats1_acc) {
stats1_stddev_var_meaneb_state_t* pstate = pstats1_acc->pvstate;
free(pstate->output_field_name);
free(pstate);
free(pstats1_acc);
}
stats1_acc_t* stats1_stddev_var_meaneb_alloc(char* value_field_name, char* stats1_acc_name, cumulant2o_t do_which) {
stats1_acc_t* pstats1_acc = mlr_malloc_or_die(sizeof(stats1_acc_t));
stats1_stddev_var_meaneb_state_t* pstate = mlr_malloc_or_die(sizeof(stats1_stddev_var_meaneb_state_t));
pstate->count = 0LL;
pstate->sumx = 0.0;
pstate->sumx2 = 0.0;
pstate->do_which = do_which;
pstate->output_field_name = mlr_paste_3_strings(value_field_name, "_", stats1_acc_name);
pstats1_acc->pvstate = (void*)pstate;
pstats1_acc->pdingest_func = stats1_stddev_var_meaneb_dingest;
pstats1_acc->pningest_func = NULL;
pstats1_acc->psingest_func = NULL;
pstats1_acc->pemit_func = stats1_stddev_var_meaneb_emit;
pstats1_acc->pfree_func = stats1_stddev_var_meaneb_free;
return pstats1_acc;
}
stats1_acc_t* stats1_stddev_alloc(char* value_field_name, char* stats1_acc_name, int allow_int_float) {
return stats1_stddev_var_meaneb_alloc(value_field_name, stats1_acc_name, DO_STDDEV);
}
stats1_acc_t* stats1_var_alloc(char* value_field_name, char* stats1_acc_name, int allow_int_float) {
return stats1_stddev_var_meaneb_alloc(value_field_name, stats1_acc_name, DO_VAR);
}
stats1_acc_t* stats1_meaneb_alloc(char* value_field_name, char* stats1_acc_name, int allow_int_float) {
return stats1_stddev_var_meaneb_alloc(value_field_name, stats1_acc_name, DO_MEANEB);
}
// ----------------------------------------------------------------
typedef struct _stats1_skewness_state_t {
unsigned long long count;
double sumx;
double sumx2;
double sumx3;
char* output_field_name;
} stats1_skewness_state_t;
static void stats1_skewness_dingest(void* pvstate, double val) {
stats1_skewness_state_t* pstate = pvstate;
pstate->count++;
pstate->sumx += val;
pstate->sumx2 += val*val;
pstate->sumx3 += val*val*val;
}
static void stats1_skewness_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) {
stats1_skewness_state_t* pstate = pvstate;
if (pstate->count < 2LL) {
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), "", FREE_ENTRY_KEY);
else
lrec_put(poutrec, pstate->output_field_name, "", NO_FREE);
} else {
double output = mlr_get_skewness(pstate->count, pstate->sumx, pstate->sumx2, pstate->sumx3);
char* val = mlr_alloc_string_from_double(output, MLR_GLOBALS.ofmt);
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), val, FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
else
lrec_put(poutrec, pstate->output_field_name, val, FREE_ENTRY_VALUE);
}
}
static void stats1_skewness_free(stats1_acc_t* pstats1_acc) {
stats1_skewness_state_t* pstate = pstats1_acc->pvstate;
free(pstate->output_field_name);
free(pstate);
free(pstats1_acc);
}
stats1_acc_t* stats1_skewness_alloc(char* value_field_name, char* stats1_acc_name, int allow_int_float) {
stats1_acc_t* pstats1_acc = mlr_malloc_or_die(sizeof(stats1_acc_t));
stats1_skewness_state_t* pstate = mlr_malloc_or_die(sizeof(stats1_skewness_state_t));
pstate->count = 0LL;
pstate->sumx = 0.0;
pstate->sumx2 = 0.0;
pstate->sumx3 = 0.0;
pstate->output_field_name = mlr_paste_3_strings(value_field_name, "_", stats1_acc_name);
pstats1_acc->pvstate = (void*)pstate;
pstats1_acc->pdingest_func = stats1_skewness_dingest;
pstats1_acc->pningest_func = NULL;
pstats1_acc->psingest_func = NULL;
pstats1_acc->pemit_func = stats1_skewness_emit;
pstats1_acc->pfree_func = stats1_skewness_free;
return pstats1_acc;
}
// ----------------------------------------------------------------
typedef struct _stats1_kurtosis_state_t {
unsigned long long count;
double sumx;
double sumx2;
double sumx3;
double sumx4;
char* output_field_name;
} stats1_kurtosis_state_t;
static void stats1_kurtosis_dingest(void* pvstate, double val) {
stats1_kurtosis_state_t* pstate = pvstate;
pstate->count++;
pstate->sumx += val;
pstate->sumx2 += val*val;
pstate->sumx3 += val*val*val;
pstate->sumx4 += val*val*val*val;
}
static void stats1_kurtosis_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) {
stats1_kurtosis_state_t* pstate = pvstate;
if (pstate->count < 2LL) {
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), "", FREE_ENTRY_KEY);
else
lrec_put(poutrec, pstate->output_field_name, "", NO_FREE);
} else {
double output = mlr_get_kurtosis(pstate->count, pstate->sumx, pstate->sumx2, pstate->sumx3, pstate->sumx4);
char* val = mlr_alloc_string_from_double(output, MLR_GLOBALS.ofmt);
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), val, FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
else
lrec_put(poutrec, pstate->output_field_name, val, FREE_ENTRY_VALUE);
}
}
static void stats1_kurtosis_free(stats1_acc_t* pstats1_acc) {
stats1_kurtosis_state_t* pstate = pstats1_acc->pvstate;
free(pstate->output_field_name);
free(pstate);
free(pstats1_acc);
}
stats1_acc_t* stats1_kurtosis_alloc(char* value_field_name, char* stats1_acc_name, int allow_int_float) {
stats1_acc_t* pstats1_acc = mlr_malloc_or_die(sizeof(stats1_acc_t));
stats1_kurtosis_state_t* pstate = mlr_malloc_or_die(sizeof(stats1_kurtosis_state_t));
pstate->count = 0LL;
pstate->sumx = 0.0;
pstate->sumx2 = 0.0;
pstate->sumx3 = 0.0;
pstate->output_field_name = mlr_paste_3_strings(value_field_name, "_", stats1_acc_name);
pstats1_acc->pvstate = (void*)pstate;
pstats1_acc->pdingest_func = stats1_kurtosis_dingest;
pstats1_acc->pningest_func = NULL;
pstats1_acc->psingest_func = NULL;
pstats1_acc->pemit_func = stats1_kurtosis_emit;
pstats1_acc->pfree_func = stats1_kurtosis_free;
return pstats1_acc;
}
// ----------------------------------------------------------------
typedef struct _stats1_min_state_t {
mv_t min;
char* output_field_name;
} stats1_min_state_t;
static void stats1_min_ningest(void* pvstate, mv_t* pval) {
stats1_min_state_t* pstate = pvstate;
pstate->min = x_xx_min_func(&pstate->min, pval);
}
static void stats1_min_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) {
stats1_min_state_t* pstate = pvstate;
if (mv_is_null(&pstate->min)) {
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), "", FREE_ENTRY_KEY);
else
lrec_put(poutrec, pstate->output_field_name, "", NO_FREE);
} else {
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), mv_alloc_format_val(&pstate->min),
FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
else
lrec_put(poutrec, pstate->output_field_name, mv_alloc_format_val(&pstate->min),
FREE_ENTRY_VALUE);
}
}
static void stats1_min_free(stats1_acc_t* pstats1_acc) {
stats1_min_state_t* pstate = pstats1_acc->pvstate;
free(pstate->output_field_name);
free(pstate);
free(pstats1_acc);
}
stats1_acc_t* stats1_min_alloc(char* value_field_name, char* stats1_acc_name, int allow_int_float) {
stats1_acc_t* pstats1_acc = mlr_malloc_or_die(sizeof(stats1_acc_t));
stats1_min_state_t* pstate = mlr_malloc_or_die(sizeof(stats1_min_state_t));
pstate->min = mv_absent();
pstate->output_field_name = mlr_paste_3_strings(value_field_name, "_", stats1_acc_name);
pstats1_acc->pvstate = (void*)pstate;
pstats1_acc->pdingest_func = NULL;
pstats1_acc->pningest_func = stats1_min_ningest;
pstats1_acc->psingest_func = NULL;
pstats1_acc->pemit_func = stats1_min_emit;
pstats1_acc->pfree_func = stats1_min_free;
return pstats1_acc;
}
// ----------------------------------------------------------------
typedef struct _stats1_max_state_t {
mv_t max;
char* output_field_name;
} stats1_max_state_t;
static void stats1_max_ningest(void* pvstate, mv_t* pval) {
stats1_max_state_t* pstate = pvstate;
pstate->max = x_xx_max_func(&pstate->max, pval);
}
static void stats1_max_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) {
stats1_max_state_t* pstate = pvstate;
if (mv_is_null(&pstate->max)) {
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), "", FREE_ENTRY_KEY);
else
lrec_put(poutrec, pstate->output_field_name, "", NO_FREE);
} else {
if (copy_data)
lrec_put(poutrec, mlr_strdup_or_die(pstate->output_field_name), mv_alloc_format_val(&pstate->max),
FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
else
lrec_put(poutrec, pstate->output_field_name, mv_alloc_format_val(&pstate->max),
FREE_ENTRY_VALUE);
}
}
static void stats1_max_free(stats1_acc_t* pstats1_acc) {
stats1_max_state_t* pstate = pstats1_acc->pvstate;
free(pstate->output_field_name);
free(pstate);
free(pstats1_acc);
}
stats1_acc_t* stats1_max_alloc(char* value_field_name, char* stats1_acc_name, int allow_int_float) {
stats1_acc_t* pstats1_acc = mlr_malloc_or_die(sizeof(stats1_acc_t));
stats1_max_state_t* pstate = mlr_malloc_or_die(sizeof(stats1_max_state_t));
pstate->max = mv_absent();
pstate->output_field_name = mlr_paste_3_strings(value_field_name, "_", stats1_acc_name);
pstats1_acc->pvstate = (void*)pstate;
pstats1_acc->pdingest_func = NULL;
pstats1_acc->pningest_func = stats1_max_ningest;
pstats1_acc->psingest_func = NULL;
pstats1_acc->pemit_func = stats1_max_emit;
pstats1_acc->pfree_func = stats1_max_free;
return pstats1_acc;
}
// ----------------------------------------------------------------
typedef struct _stats1_percentile_state_t {
percentile_keeper_t* ppercentile_keeper;
lhmss_t* poutput_field_names;
int reference_count;
} stats1_percentile_state_t;
static void stats1_percentile_ningest(void* pvstate, mv_t* pval) {
stats1_percentile_state_t* pstate = pvstate;
percentile_keeper_ingest(pstate->ppercentile_keeper, *pval);
}
static void stats1_percentile_emit(void* pvstate, char* value_field_name, char* stats1_acc_name, int copy_data, lrec_t* poutrec) {
stats1_percentile_state_t* pstate = pvstate;
double p;
(void)sscanf(stats1_acc_name, "p%lf", &p); // Assuming this was range-checked earlier on to be in [0,100].
mv_t v = percentile_keeper_emit(pstate->ppercentile_keeper, p);
char* s = mv_alloc_format_val(&v);
// For this type, one accumulator tracks many stats1_names, but a single value_field_name.
char* output_field_name = lhmss_get(pstate->poutput_field_names, stats1_acc_name);
if (output_field_name == NULL) {
output_field_name = mlr_paste_3_strings(value_field_name, "_", stats1_acc_name);
lhmss_put(pstate->poutput_field_names, mlr_strdup_or_die(stats1_acc_name),
output_field_name, FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
}
lrec_put(poutrec, mlr_strdup_or_die(output_field_name), s, FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
}
static void stats1_percentile_free(stats1_acc_t* pstats1_acc) {
stats1_percentile_state_t* pstate = pstats1_acc->pvstate;
pstate->reference_count--;
if (pstate->reference_count == 0) {
percentile_keeper_free(pstate->ppercentile_keeper);
lhmss_free(pstate->poutput_field_names);
free(pstate);
free(pstats1_acc);
}
}
stats1_acc_t* stats1_percentile_alloc(char* value_field_name, char* stats1_acc_name, int allow_int_float) {
stats1_acc_t* pstats1_acc = mlr_malloc_or_die(sizeof(stats1_acc_t));
stats1_percentile_state_t* pstate = mlr_malloc_or_die(sizeof(stats1_percentile_state_t));
pstate->ppercentile_keeper = percentile_keeper_alloc();
pstate->poutput_field_names = lhmss_alloc();
pstate->reference_count = 1;
pstats1_acc->pvstate = (void*)pstate;
pstats1_acc->pdingest_func = NULL;
pstats1_acc->pningest_func = stats1_percentile_ningest;
pstats1_acc->psingest_func = NULL;
pstats1_acc->pemit_func = stats1_percentile_emit;
pstats1_acc->pfree_func = stats1_percentile_free;
return pstats1_acc;
}
void stats1_percentile_reuse(stats1_acc_t* pstats1_acc) {
stats1_percentile_state_t* pstate = pstats1_acc->pvstate;
pstate->reference_count++;
}