summaryrefslogtreecommitdiffstats
path: root/web/api/queries/countif/countif.h
blob: 896b9d873ae449d47d7af91938a1b10e6242a55f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef NETDATA_API_QUERY_COUNTIF_H
#define NETDATA_API_QUERY_COUNTIF_H

#include "../query.h"
#include "../rrdr.h"

enum tg_countif_cmp {
    TG_COUNTIF_EQUAL,
    TG_COUNTIF_NOTEQUAL,
    TG_COUNTIF_LESS,
    TG_COUNTIF_LESSEQUAL,
    TG_COUNTIF_GREATER,
    TG_COUNTIF_GREATEREQUAL,
};

struct tg_countif {
    enum tg_countif_cmp comparison;
    NETDATA_DOUBLE target;
    size_t count;
    size_t matched;
};

static inline void tg_countif_create(RRDR *r, const char *options __maybe_unused) {
    struct tg_countif *g = onewayalloc_callocz(r->internal.owa, 1, sizeof(struct tg_countif));
    r->time_grouping.data = g;

    if(options && *options) {
        // skip any leading spaces
        while(isspace(*options)) options++;

        // find the comparison function
        switch(*options) {
            case '!':
                options++;
                if(*options != '=' && *options != ':')
                    options--;
                g->comparison = TG_COUNTIF_NOTEQUAL;
                break;

            case '>':
                options++;
                if(*options == '=' || *options == ':') {
                    g->comparison = TG_COUNTIF_GREATEREQUAL;
                }
                else {
                    options--;
                    g->comparison = TG_COUNTIF_GREATER;
                }
                break;

            case '<':
                options++;
                if(*options == '>') {
                    g->comparison = TG_COUNTIF_NOTEQUAL;
                }
                else if(*options == '=' || *options == ':') {
                    g->comparison = TG_COUNTIF_LESSEQUAL;
                }
                else {
                    options--;
                    g->comparison = TG_COUNTIF_LESS;
                }
                break;

            default:
            case '=':
            case ':':
                g->comparison = TG_COUNTIF_EQUAL;
                break;
        }
        if(*options) options++;

        // skip everything up to the first digit
        while(isspace(*options)) options++;

        g->target = str2ndd(options, NULL);
    }
    else {
        g->target = 0.0;
        g->comparison = TG_COUNTIF_EQUAL;
    }
}

// resets when switches dimensions
// so, clear everything to restart
static inline void tg_countif_reset(RRDR *r) {
    struct tg_countif *g = (struct tg_countif *)r->time_grouping.data;
    g->matched = 0;
    g->count = 0;
}

static inline void tg_countif_free(RRDR *r) {
    onewayalloc_freez(r->internal.owa, r->time_grouping.data);
    r->time_grouping.data = NULL;
}

static inline void tg_countif_add(RRDR *r, NETDATA_DOUBLE value) {
    struct tg_countif *g = (struct tg_countif *)r->time_grouping.data;
    switch(g->comparison) {
        case TG_COUNTIF_GREATER:
            if(value > g->target) g->matched++;
            break;

        case TG_COUNTIF_GREATEREQUAL:
            if(value >= g->target) g->matched++;
            break;

        case TG_COUNTIF_LESS:
            if(value < g->target) g->matched++;
            break;

        case TG_COUNTIF_LESSEQUAL:
            if(value <= g->target) g->matched++;
            break;

        case TG_COUNTIF_EQUAL:
            if(value == g->target) g->matched++;
            break;

        case TG_COUNTIF_NOTEQUAL:
            if(value != g->target) g->matched++;
            break;
    }
    g->count++;
}

static inline NETDATA_DOUBLE tg_countif_flush(RRDR *r, RRDR_VALUE_FLAGS *rrdr_value_options_ptr) {
    struct tg_countif *g = (struct tg_countif *)r->time_grouping.data;

    NETDATA_DOUBLE value;

    if(unlikely(!g->count)) {
        value = 0.0;
        *rrdr_value_options_ptr |= RRDR_VALUE_EMPTY;
    }
    else {
        value = (NETDATA_DOUBLE)g->matched * 100 / (NETDATA_DOUBLE)g->count;
    }

    g->matched = 0;
    g->count = 0;

    return value;
}

#endif //NETDATA_API_QUERY_COUNTIF_H