source: mainline/uspace/lib/c/generic/capa.c@ cf9a1e2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since cf9a1e2 was c24b0dcb, checked in by Jakub Jermar <jakub@…>, 6 years ago

Rename capacity-related 'cap' to 'capa'

This allows to use 'cap' for capabilities.

  • Property mode set to 100644
File size: 6.3 KB
RevLine 
[9854a8f]1/*
2 * Copyright (c) 2015 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[6c4eedf]29/** @addtogroup libc
[9854a8f]30 * @{
31 */
32/**
[6c4eedf]33 * @file Storage capacity specification.
[9854a8f]34 */
35
[c24b0dcb]36#include <capa.h>
[9854a8f]37#include <errno.h>
38#include <imath.h>
39#include <stdio.h>
40#include <str.h>
41
42/** Simplified capacity parameters */
43enum {
44 /** Simplified capacity maximum integer digits */
[c24b0dcb]45 scapa_max_idig = 3,
[9854a8f]46 /** Simplified capacity maximum significant digits */
[c24b0dcb]47 scapa_max_sdig = 4
[9854a8f]48};
49
50static const char *cu_str[] = {
51 [cu_byte] = "B",
52 [cu_kbyte] = "kB",
53 [cu_mbyte] = "MB",
54 [cu_gbyte] = "GB",
55 [cu_tbyte] = "TB",
56 [cu_pbyte] = "PB",
57 [cu_ebyte] = "EB",
58 [cu_zbyte] = "ZB",
59 [cu_ybyte] = "YB"
60};
61
[c24b0dcb]62void capa_from_blocks(uint64_t nblocks, size_t block_size, capa_spec_t *capa)
[9854a8f]63{
64 uint64_t tsize;
65
66 tsize = nblocks * block_size;
[c24b0dcb]67 capa->m = tsize;
68 capa->dp = 0;
69 capa->cunit = cu_byte;
[9854a8f]70}
71
72/** Convert capacity to blocks.
73 *
74 * If the value of bytes is not integer, it is properly rounded. If the number
75 * of bytes is not divisible by the number of blocks, it is rounded
76 * up to an integer number of blocks.
[03661d19]77 *
78 * A capacity value entails precision, i.e. it corresponds to a range
[6c4eedf]79 * of values. @a cvsel selects the value to return. @c cv_nom gives
80 * the nominal (middle) value, @c cv_min gives the minimum value
81 * and @c cv_max gives the maximum value.
[9854a8f]82 */
[c24b0dcb]83errno_t capa_to_blocks(capa_spec_t *capa, capa_vsel_t cvsel, size_t block_size,
[6c4eedf]84 uint64_t *rblocks)
[9854a8f]85{
86 int exp;
87 uint64_t bytes;
88 uint64_t f;
[03661d19]89 uint64_t adj;
90 uint64_t blocks;
91 uint64_t rem;
[b7fd2a0]92 errno_t rc;
[9854a8f]93
[c24b0dcb]94 exp = capa->cunit * 3 - capa->dp;
[9854a8f]95 if (exp < 0) {
96 rc = ipow10_u64(-exp, &f);
97 if (rc != EOK)
98 return ERANGE;
[c24b0dcb]99 bytes = (capa->m + (f / 2)) / f;
100 if (bytes * f - (f / 2) != capa->m)
[03661d19]101 return ERANGE;
[9854a8f]102 } else {
103 rc = ipow10_u64(exp, &f);
104 if (rc != EOK)
105 return ERANGE;
[03661d19]106
107 adj = 0;
108 switch (cvsel) {
[6c4eedf]109 case cv_nom:
[03661d19]110 adj = 0;
111 break;
[6c4eedf]112 case cv_min:
[03661d19]113 adj = -(f / 2);
114 break;
[6c4eedf]115 case cv_max:
[03661d19]116 adj = f / 2 - 1;
117 break;
118 }
119
[c24b0dcb]120 bytes = capa->m * f + adj;
121 if ((bytes - adj) / f != capa->m)
[03661d19]122 return ERANGE;
[9854a8f]123 }
124
[03661d19]125 rem = bytes % block_size;
126 if ((bytes + rem) < bytes)
127 return ERANGE;
128
129 blocks = (bytes + rem) / block_size;
130
131 *rblocks = blocks;
[9854a8f]132 return EOK;
133}
134
135/** Simplify and round capacity to a human-friendly form.
136 *
137 * Change unit and round the number so that we have at most three integer
138 * digits and at most two fractional digits, e.g abc.xy <unit>.
139 */
[c24b0dcb]140void capa_simplify(capa_spec_t *capa)
[9854a8f]141{
142 uint64_t div;
143 uint64_t maxv;
144 unsigned sdig;
145 unsigned rdig;
[b7fd2a0]146 errno_t rc;
[9854a8f]147
[c24b0dcb]148 /* Change units so that we have at most @c scapa_max_idig integer digits */
149 rc = ipow10_u64(scapa_max_idig, &maxv);
[9854a8f]150 assert(rc == EOK);
151
[c24b0dcb]152 rc = ipow10_u64(capa->dp, &div);
[9854a8f]153 assert(rc == EOK);
154
[c24b0dcb]155 while (capa->m / div >= maxv) {
156 ++capa->cunit;
157 capa->dp += 3;
[9854a8f]158 div = div * 1000;
159 }
160
[c24b0dcb]161 /* Round the number so that we have at most @c scapa_max_sdig significant digits */
162 sdig = 1 + ilog10_u64(capa->m); /* number of significant digits */
163 if (sdig > scapa_max_sdig) {
[9854a8f]164 /* Number of digits to remove */
[c24b0dcb]165 rdig = sdig - scapa_max_sdig;
166 if (rdig > capa->dp)
167 rdig = capa->dp;
[9854a8f]168
169 rc = ipow10_u64(rdig, &div);
170 assert(rc == EOK);
171
[c24b0dcb]172 capa->m = (capa->m + (div / 2)) / div;
173 capa->dp -= rdig;
[9854a8f]174 }
175}
176
[c24b0dcb]177errno_t capa_format(capa_spec_t *capa, char **rstr)
[9854a8f]178{
[b7fd2a0]179 errno_t rc;
[d5c1051]180 int ret;
[9854a8f]181 const char *sunit;
182 uint64_t ipart;
183 uint64_t fpart;
184 uint64_t div;
185
186 sunit = NULL;
187
[c24b0dcb]188 assert(capa->cunit < CU_LIMIT);
[9854a8f]189
[c24b0dcb]190 rc = ipow10_u64(capa->dp, &div);
[9854a8f]191 if (rc != EOK)
192 return rc;
193
[c24b0dcb]194 ipart = capa->m / div;
195 fpart = capa->m % div;
[9854a8f]196
[c24b0dcb]197 sunit = cu_str[capa->cunit];
198 if (capa->dp > 0) {
[d5c1051]199 ret = asprintf(rstr, "%" PRIu64 ".%0*" PRIu64 " %s", ipart,
[c24b0dcb]200 (int)capa->dp, fpart, sunit);
[9854a8f]201 } else {
[d5c1051]202 ret = asprintf(rstr, "%" PRIu64 " %s", ipart, sunit);
[9854a8f]203 }
[d5c1051]204 if (ret < 0)
[9854a8f]205 return ENOMEM;
206
207 return EOK;
208}
209
[c24b0dcb]210static errno_t capa_digit_val(char c, int *val)
[03661d19]211{
212 switch (c) {
[1433ecda]213 case '0':
214 *val = 0;
215 break;
216 case '1':
217 *val = 1;
218 break;
219 case '2':
220 *val = 2;
221 break;
222 case '3':
223 *val = 3;
224 break;
225 case '4':
226 *val = 4;
227 break;
228 case '5':
229 *val = 5;
230 break;
231 case '6':
232 *val = 6;
233 break;
234 case '7':
235 *val = 7;
236 break;
237 case '8':
238 *val = 8;
239 break;
240 case '9':
241 *val = 9;
242 break;
[03661d19]243 default:
244 return EINVAL;
245 }
246
247 return EOK;
248}
249
[c24b0dcb]250errno_t capa_parse(const char *str, capa_spec_t *capa)
[9854a8f]251{
[03661d19]252 const char *eptr;
253 const char *p;
254 int d;
255 int dp;
256 unsigned long m;
[9854a8f]257 int i;
258
[03661d19]259 m = 0;
260
261 eptr = str;
[c24b0dcb]262 while (capa_digit_val(*eptr, &d) == EOK) {
[03661d19]263 m = m * 10 + d;
264 ++eptr;
265 }
266
267 if (*eptr == '.') {
268 ++eptr;
269 dp = 0;
[c24b0dcb]270 while (capa_digit_val(*eptr, &d) == EOK) {
[03661d19]271 m = m * 10 + d;
272 ++dp;
273 ++eptr;
274 }
275 } else {
[2dab624]276 dp = 0;
[03661d19]277 }
[9854a8f]278
279 while (*eptr == ' ')
280 ++eptr;
281
282 if (*eptr == '\0') {
[c24b0dcb]283 capa->cunit = cu_byte;
[9854a8f]284 } else {
285 for (i = 0; i < CU_LIMIT; i++) {
286 if (str_lcasecmp(eptr, cu_str[i],
287 str_length(cu_str[i])) == 0) {
288 p = eptr + str_size(cu_str[i]);
289 while (*p == ' ')
290 ++p;
291 if (*p == '\0')
292 goto found;
293 }
294 }
295
296 return EINVAL;
[1433ecda]297 found:
[c24b0dcb]298 capa->cunit = i;
[9854a8f]299 }
300
[c24b0dcb]301 capa->m = m;
302 capa->dp = dp;
[9854a8f]303 return EOK;
304}
305
306/** @}
307 */
Note: See TracBrowser for help on using the repository browser.