sn-markov: Implement counting of comparators.
[sort-networks.git] / src / histogram.c
1 /**
2  * libsortnetwork - src/histrogram.c
3  * Copyright (C) 2011  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Florian octo Forster <ff at octo.it>
20  **/
21
22 #ifndef _ISOC99_SOURCE
23 # define _ISOC99_SOURCE
24 #endif
25 #ifndef _POSIX_C_SOURCE
26 # define _POSIX_C_SOURCE 200809L
27 #endif
28 #ifndef _XOPEN_SOURCE
29 # define _XOPEN_SOURCE 700
30 #endif
31
32 #include <stdlib.h>
33 #include <stdint.h>
34 #include <inttypes.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <assert.h>
38 #include <errno.h>
39
40 #include "histogram.h"
41
42 #define BAR_WIDTH 64
43
44 struct histogram_s
45 {
46   uint64_t *data;
47   int index_min;
48   int index_max;
49 };
50
51 static int hist_resize (histogram_t *h, int rating) /* {{{ */
52 {
53   int min_new;
54   int max_new;
55   size_t nelem_new;
56   size_t nelem_old;
57   uint64_t *tmp;
58
59   if ((h->index_min == 0) && (h->index_max == 0))
60   {
61     min_new = rating;
62     max_new = rating;
63   }
64   else
65   {
66     min_new = ((h->index_min < rating) ? h->index_min : rating);
67     max_new = ((h->index_max > rating) ? h->index_max : rating);
68   }
69
70   nelem_new = (size_t) ((max_new - min_new) + 1);
71   nelem_old = (size_t) ((h->index_max - h->index_min) + 1);
72
73   assert (nelem_new >= nelem_old);
74
75   tmp = realloc (h->data, nelem_new * sizeof (*h->data));
76   if (tmp == NULL)
77     return (ENOMEM);
78   h->data = tmp;
79
80   if ((h->index_min == 0) && (h->index_max == 0))
81   {
82     h->index_min = min_new;
83     h->index_max = max_new;
84     h->data[0] = 0;
85     return (0);
86   }
87
88   if (min_new < h->index_min)
89   {
90     size_t diff = (size_t) (h->index_min - min_new);
91
92     memmove (h->data + diff, h->data, nelem_old * sizeof (*h->data));
93     memset (h->data, 0, diff * sizeof (*h->data));
94
95     h->index_min = min_new;
96   }
97   else if (max_new > h->index_max)
98   {
99     size_t diff = (size_t) (max_new - h->index_max);
100     memset (h->data + nelem_old, 0, diff * sizeof (*h->data));
101
102     h->index_max = max_new;
103   }
104
105   return (0);
106 } /* }}} int hist_resize */
107
108 histogram_t *hist_create (void) /* {{{ */
109 {
110   histogram_t *h = malloc (sizeof (*h));
111   if (h == NULL)
112     return (NULL);
113   memset (h, 0, sizeof (*h));
114   h->data = NULL;
115
116   return (h);
117 } /* }}} hist_create */
118
119 void hist_destroy (histogram_t *h) /* {{{ */
120 {
121   if (h != NULL)
122     free (h->data);
123   free (h);
124 } /* }}} hist_destroy */
125
126 int hist_account (histogram_t *h, int rating) /* {{{ */
127 {
128   if ((h == NULL) || (rating < 0))
129     return (EINVAL);
130
131   if ((rating < h->index_min) || (rating > h->index_max))
132     hist_resize (h, rating);
133
134   h->data[rating - h->index_min]++;
135
136   return (0);
137 } /* }}} int hist_account */
138
139 int hist_print (histogram_t *h) /* {{{ */
140 {
141   char bar[BAR_WIDTH + 1];
142   uint64_t max;
143   int i;
144
145   if (h == NULL)
146     return (EINVAL);
147
148   max = 1;
149   for (i = h->index_min; i <= h->index_max; i++)
150     if (max < h->data[i - h->index_min])
151       max = h->data[i - h->index_min];
152
153   for (i = h->index_min; i <= h->index_max; i++)
154   {
155     uint64_t num = h->data[i - h->index_min];
156     uint64_t points = (BAR_WIDTH * num) / max;
157     uint64_t j;
158
159     for (j = 0; j < (BAR_WIDTH + 1); j++)
160       bar[j] = (j < points) ? '#' : 0;
161
162     printf ("%4i: %8"PRIu64" %s\n", i, num, bar);
163   }
164
165   return (0);
166 } /* }}} int hist_print */
167
168 /* vim: set shiftwidth=2 softtabstop=2 fdm=marker : */