{"thread":{"id":"15513","subject":"[RFC Redux] strbuf: Add method to convert byte-size to human readable form","startedAt":"2008-09-13T04:26:37Z","lastAt":"2008-09-19T22:37:26Z","messageCount":6,"participants":["Marcus Griep","Junio C Hamano","Daniel Barkalow"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"90622","messageId":"1221279997-9336-1-git-send-email-marcus@griep.us","threadId":"15513","inReplyTo":null,"subject":"[RFC Redux] strbuf: Add method to convert byte-size to human readable form","fromName":"Marcus Griep","fromEmail":"marcus@griep.us","sentAt":"2008-09-13T04:26:37Z","receivedAt":"2008-09-13T04:26:37Z","isPatch":false,"sender":{"key":"marcus@griep.us","avatar":"https://gravatar.com/avatar/0a841f2aad3f9a38c9bcf87a567c2a1751cb08924bae1bc46ee171395bcf9794?d=mp&s=160"},"body":"Takes a strbuf as its first argument and appends the human-readable\nform of 'value', the second argument, to that buffer.\n\ne.g. strbuf_append_human_readable(sb, 1012, 0, 0, HR_SPACE)\nproduces \"0.9 Ki\".\n\nDocumented in strbuf.h; units can be directly appended to the strbuf\nto produce \"0.9 KiB/s\", \"0.9 KiB\".\n\nSupports SI magnitude prefixes as well as padding and spacing of\nthe units portion of the output.\n\nAlso, add in test cases to ensure it produces the expected output\nand to demonstrate what different arguments do.\n\nSigned-off-by: Marcus Griep <marcus@griep.us>\n---\n\n This is a redux of a prior patch as part of a series on count-objects\n but is now split off and submitted on its own as an RFC for a library\n function to be added to strbuf.  If accepted, I'd like to standardize\n upon this method for user visible byte-sizes, thoroughput, large object\n counts, etc.\n\n Provides similar functionality similar to the '-h' size output of du\n in the default case.\n\n Based on master, but also applies cleanly to next.\n\n .gitignore                |    1 +\n Makefile                  |    2 +-\n strbuf.c                  |   92 +++++++++++++++++++++++++++++++++++++++++++++\n strbuf.h                  |   30 +++++++++++++++\n t/t0031-human-readable.sh |   49 ++++++++++++++++++++++++\n test-human-read.c         |   23 +++++++++++\n 6 files changed, 196 insertions(+), 1 deletions(-)\n create mode 100755 t/t0031-human-readable.sh\n create mode 100644 test-human-read.c\n\ndiff --git a/.gitignore b/.gitignore\nindex bbaf9de..251537b 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -147,6 +147,7 @@ test-date\n test-delta\n test-dump-cache-tree\n test-genrandom\n+test-human-read\n test-match-trees\n test-parse-options\n test-path-utils\ndiff --git a/Makefile b/Makefile\nindex 247cd2d..cd97468 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1322,7 +1322,7 @@ endif\n \n ### Testing rules\n \n-TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-parse-options$X test-path-utils$X\n+TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-parse-options$X test-path-utils$X test-human-read$X\n \n all:: $(TEST_PROGRAMS)\n \ndiff --git a/strbuf.c b/strbuf.c\nindex 720737d..d9888fb 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -308,3 +308,95 @@ int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)\n \n \treturn len;\n }\n+\n+int strbuf_append_human_readable(struct strbuf *sb,\n+\t\t\t\tdouble val,\n+\t\t\t\tint maxlen, int scale,\n+\t\t\t\tint flags)\n+{\n+\tconst int maxscale = 7;\n+\n+\tchar *hr_prefixes[] = {\n+\t\t\"\", \"Ki\", \"Mi\", \"Gi\", \"Ti\", \"Pi\", \"Ei\", \"Zi\", \"Yi\", NULL\n+\t};\n+\tchar *hr_si_prefixes[] = {\n+\t\t\"\", \"k\", \"M\", \"G\", \"T\", \"P\", \"E\", \"Z\", \"Y\", NULL\n+\t};\n+\tchar **prefix = &hr_prefixes[0];\n+\tint period = 1024;\n+\tint sign = val < 0 ? -1 : 1;\n+\tint retval = 0;\n+\n+\tval *= sign;\n+\n+\tif (flags & HR_PAD_UNIT) {\n+\t\thr_prefixes[0] = \"  \";\n+\t\thr_si_prefixes[0] = \" \";\n+\t}\n+\n+\tif (flags & HR_USE_SI) {\n+\t\tperiod = 1000;\n+\t\tprefix = &hr_si_prefixes[0];\n+\t}\n+\n+\tif (scale == 0) {\n+\t\tif (maxlen == 0) {\n+\t\t\tscale = 1000;\n+\t\t\tmaxlen = 3;\n+\t\t}\n+\t\telse {\n+\t\t\tint space = maxlen;\n+\t\t\tscale = 10;\n+\t\t\twhile (--space > 0) {\n+\t\t\t\tscale *= 10;\n+\t\t\t}\n+\t\t}\n+\t}\n+\telse {\n+\t\tint space = 1;\n+\t\tint check = 10;\n+\t\tint setscale = scale;\n+\t\twhile (check < scale) {\n+\t\t\tcheck *= 10;\n+\t\t\t++space;\n+\t\t\tif (maxlen - space == 0)\n+\t\t\t\tsetscale = check;\n+\t\t}\n+\t\tif (!maxlen)\n+\t\t\tmaxlen = space;\n+\t\tscale = setscale;\n+\t}\n+\n+\twhile (val >= scale && *prefix++)\n+\t\tval /= period;\n+\n+\tif (val >= scale) {\n+\t\tint needed = 0;\n+\t\twhile (val >= scale) {\n+\t\t\tval /= period;\n+\t\t\t--needed;\n+\t\t}\n+\t\tif (needed < retval)\n+\t\t\tretval = needed;\n+\t}\n+\n+\tstrbuf_addf(sb, \"%f\", sign * val);\n+\n+\tif (maxlen) {\n+\t\tint signlen = sign == -1 ? 1 : 0;\n+\t\tmaxlen -= (sb->buf[maxlen-1+signlen] == '.' ? 1 : 0);\n+\t\tif (maxlen <= 0) {\n+\t\t\tstrbuf_setlen(sb, 0);\n+\t\t\tretval = maxlen - 1;\n+\t\t} else {\n+\t\t\tstrbuf_setlen(sb, maxlen + signlen);\n+\t\t}\n+\t}\n+\n+\tstrbuf_addf(sb, \"%s%s\",\n+\t\tflags & HR_SPACE ? \" \" : \"\",\n+\t\t*prefix\n+\t\t);\n+\n+\treturn retval;\n+}\ndiff --git a/strbuf.h b/strbuf.h\nindex eba7ba4..305ef55 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -125,4 +125,34 @@ extern int strbuf_getline(struct strbuf *, FILE *, int);\n extern void stripspace(struct strbuf *buf, int skip_comments);\n extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);\n \n+/*\n+ * strbuf_append_human_readable\n+ *\n+ * 'val': value to be metrically-reduced to a human-readable number\n+ * 'maxlen': maximum number of characters to be taken up by the reduced 'val'\n+ *           not including the sign or magnitude (i.e. 'Ki') characters;\n+ *           when 'maxlen' is 0 length is controled by 'scale'\n+ * 'scale': when 'val' is greater than 'scale', 'val' is reduced by the\n+ *          period (default 1024, see 'flags') until it is less than 'scale';\n+ *          when 'scale' is 0, 'val' is reduced until it fits in 'maxlen';\n+ *          when 'scale' and 'maxlen' are both zero, 'scale' defaults to 1000\n+ * 'flags': HR_USE_SI: uses a period of 1000 and uses SI magnitude prefixes\n+ *          HR_SPACE: inserts a space between the reduced 'val' and the units\n+ *          HR_PAD_UNIT: instead of an empty string for singles, pads with\n+ *                       spaces to the length of the magnitude prefixes\n+ *\n+ * Returns 0 if 'val' is successfully reduced and fits in 'maxlen', otherwise\n+ * returns -n where n is the number of additional characters necessary to\n+ * fully fit the reduced value.\n+ */\n+\n+#define HR_USE_SI 0x01\n+#define HR_SPACE 0x02\n+#define HR_PAD_UNIT 0x04\n+\n+extern int strbuf_append_human_readable(struct strbuf *,\n+\t\t\t\t\tdouble val,\n+\t\t\t\t\tint maxlen, int scale,\n+\t\t\t\t\tint flags);\n+\n #endif /* STRBUF_H */\ndiff --git a/t/t0031-human-readable.sh b/t/t0031-human-readable.sh\nnew file mode 100755\nindex 0000000..d4266f2\n--- /dev/null\n+++ b/t/t0031-human-readable.sh\n@@ -0,0 +1,49 @@\n+#!/bin/sh\n+\n+test_description=\"Test human-readable formatting\"\n+\n+. ./test-lib.sh\n+\n+HR_NONE=0\n+HR_USE_SI=1\n+HR_SPACE=2\n+HR_PAD_UNIT=4\n+\n+test_hr () {\n+\ttest_expect_success \"'$5' ($6)\" \"\n+\t\ttest-human-read $1 $2 $3 $4 $5\n+\t\t[[ $? -eq $6 ]]\n+\t\"\n+}\n+\n+test_hr 1012 0 0 $HR_SPACE \"0.9 Ki\" 0\n+test_hr 1012 0 0 $(($HR_SPACE+$HR_USE_SI)) \"1.0 k\" 0\n+test_hr -1012 0 0 $(($HR_SPACE+$HR_USE_SI)) \"-1.0 k\" 0\n+test_hr 1012 5 0 $(($HR_SPACE+$HR_PAD_UNIT)) \"1012   \" 0\n+test_hr 1012 5 0 $HR_SPACE \"1012 \" 0\n+test_hr 1012 5 0 $(($HR_USE_SI+$HR_SPACE+$HR_PAD_UNIT)) \"1012  \" 0\n+test_hr 1012 5 0 $(($HR_USE_SI+$HR_SPACE)) \"1012 \" 0\n+test_hr 1012 4 0 $HR_NONE \"1012\" 0\n+test_hr 1012 3 0 $HR_NONE \"0.9Ki\" 0\n+test_hr 1012 2 0 $HR_NONE \"0Ki\" 0\n+test_hr 1012 1 0 $HR_NONE \"0Ki\" 0\n+test_hr 1012 0 0 $HR_NONE \"0.9Ki\" 0\n+test_hr -1012 3 0 $HR_NONE \"-0.9Ki\" 0\n+test_hr -1012 2 0 $HR_NONE \"-0Ki\" 0\n+test_hr -1012 1 0 $HR_NONE \"-0Ki\" 0\n+test_hr -1012 0 0 $HR_NONE \"-0.9Ki\" 0\n+test_hr 2024 4 0 $HR_NONE \"2024\" 0\n+test_hr 20240 4 0 $HR_NONE \"19.7Ki\" 0\n+test_hr 1012 0 1000 $HR_NONE \"0.9Ki\" 0\n+test_hr $((506*1024*1024)) 0 1000000 $HR_NONE \"518144Ki\" 0\n+test_hr $((506*1024*1024)) 7 1000000 $HR_NONE \"518144Ki\" 0\n+test_hr $((506*1024*1024)) 6 1000000 $HR_NONE \"518144Ki\" 0\n+test_hr $((506*1024*1024)) 5 1000000 $HR_NONE \"506.0Mi\" 0\n+test_hr $((506*1024*1024)) 4 1000000 $HR_NONE \"506Mi\" 0\n+test_hr $((506*1024*1024)) 3 1000000 $HR_NONE \"506Mi\" 0\n+test_hr $((506*1024*1024)) 2 1000000 $HR_NONE \"0Gi\" 0\n+test_hr $((506*1024*1024*1024)) 0 1000000 $HR_NONE \"518144Mi\" 0\n+test_hr $((506*1024*1024*1024)) 0 1000000 $HR_USE_SI \"543313Mi\" 0\n+test_hr 0 0 0 $HR_NONE \"0\" 0\n+\n+test_done\ndiff --git a/test-human-read.c b/test-human-read.c\nnew file mode 100644\nindex 0000000..7890922\n--- /dev/null\n+++ b/test-human-read.c\n@@ -0,0 +1,23 @@\n+#include \"builtin.h\"\n+#include \"strbuf.h\"\n+\n+int main(int argc, char **argv) {\n+\tif (argc != 6) {\n+\t\texit(-1);\n+\t}\n+\n+\tstruct strbuf sb;\n+\tstrbuf_init(&sb, 0);\n+\n+\tint retval = strbuf_append_human_readable(&sb,\n+\t\tatof(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4]));\n+\n+\tint failed = strcmp(sb.buf, argv[5]);\n+\n+\tfprintf( stderr, failed ? \"Failure\" : \"Success\" );\n+\tfprintf( stderr, \": Act '%s'; Exp '%s'\\n\", sb.buf, argv[5] );\n+\tfprintf( stderr, \"Return Value: %d\\n\", retval );\n+\n+\tif(failed) return -1;\n+\treturn retval;\n+}\n-- \n1.6.0.1.451.gc8d31\n"},{"id":"91127","messageId":"48D3CBBA.8060507@griep.us","threadId":"15513","inReplyTo":"1221279997-9336-1-git-send-email-marcus@griep.us","subject":"Re: [RFC Redux] strbuf: Add method to convert byte-size to human readable form","fromName":"Marcus Griep","fromEmail":"marcus@griep.us","sentAt":"2008-09-19T15:56:42Z","receivedAt":"2008-09-19T15:56:42Z","isPatch":false,"sender":{"key":"marcus@griep.us","avatar":"https://gravatar.com/avatar/0a841f2aad3f9a38c9bcf87a567c2a1751cb08924bae1bc46ee171395bcf9794?d=mp&s=160"},"body":"If there is no comment on this, Junio, would you be ok accepting this as a patch,\neven as a feature-branch on pu or next?\n\nMarcus Griep wrote:\n> Takes a strbuf as its first argument and appends the human-readable\n> form of 'value', the second argument, to that buffer.\n> \n> e.g. strbuf_append_human_readable(sb, 1012, 0, 0, HR_SPACE)\n> produces \"0.9 Ki\".\n> \n> Documented in strbuf.h; units can be directly appended to the strbuf\n> to produce \"0.9 KiB/s\", \"0.9 KiB\".\n> \n> Supports SI magnitude prefixes as well as padding and spacing of\n> the units portion of the output.\n> \n> Also, add in test cases to ensure it produces the expected output\n> and to demonstrate what different arguments do.\n> \n> Signed-off-by: Marcus Griep <marcus@griep.us>\n> ---\n> \n>  This is a redux of a prior patch as part of a series on count-objects\n>  but is now split off and submitted on its own as an RFC for a library\n>  function to be added to strbuf.  If accepted, I'd like to standardize\n>  upon this method for user visible byte-sizes, thoroughput, large object\n>  counts, etc.\n> \n>  Provides similar functionality similar to the '-h' size output of du\n>  in the default case.\n> \n>  Based on master, but also applies cleanly to next.\n> \n>  .gitignore                |    1 +\n>  Makefile                  |    2 +-\n>  strbuf.c                  |   92 +++++++++++++++++++++++++++++++++++++++++++++\n>  strbuf.h                  |   30 +++++++++++++++\n>  t/t0031-human-readable.sh |   49 ++++++++++++++++++++++++\n>  test-human-read.c         |   23 +++++++++++\n>  6 files changed, 196 insertions(+), 1 deletions(-)\n>  create mode 100755 t/t0031-human-readable.sh\n>  create mode 100644 test-human-read.c\n\n-- \nMarcus Griep\nGPG Key ID: 0x5E968152\n——\nhttp://www.boohaunt.net\nאת.ψο´\n\n"},{"id":"91144","messageId":"7vzlm3ri50.fsf@gitster.siamese.dyndns.org","threadId":"15513","inReplyTo":"48D3CBBA.8060507@griep.us","subject":"Re: [RFC Redux] strbuf: Add method to convert byte-size to human readable form","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-19T20:32:43Z","receivedAt":"2008-09-19T20:32:43Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Marcus Griep <marcus@griep.us> writes:\n\n> If there is no comment on this, Junio, would you be ok accepting this as\n> a patch, even as a feature-branch on pu or next?\n\nWe (collectively as the development community) should be doing better than\nthat.  \"No comment\" should not mean \"no objection with huge silent\nsupport\".  \"No comment\" simply means \"no support\".\n\nIf I recall correctly (I did read the patch myself when it was posted), I\ndid not spot anything glaringly wrong in it, but I have to go back to make\nsure if we are going to queue this in 'next'.\n\nI have deliberately been trying to keep myself from commenting on series\nthat I have read.  The thing is, it seems to me that that seeing my\ncomments on the list somehow discourages others from reviewing and\ncommenting, and I would really like to see people on the list to review\nand help improve more patches from others.\n"},{"id":"91146","messageId":"alpine.LNX.1.00.0809191656220.19665@iabervon.org","threadId":"15513","inReplyTo":"7vzlm3ri50.fsf@gitster.siamese.dyndns.org","subject":"Re: [RFC Redux] strbuf: Add method to convert byte-size to human readable form","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2008-09-19T20:59:38Z","receivedAt":"2008-09-19T20:59:38Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Fri, 19 Sep 2008, Junio C Hamano wrote:\n\n> Marcus Griep <marcus@griep.us> writes:\n> \n> > If there is no comment on this, Junio, would you be ok accepting this as\n> > a patch, even as a feature-branch on pu or next?\n> \n> We (collectively as the development community) should be doing better than\n> that.  \"No comment\" should not mean \"no objection with huge silent\n> support\".  \"No comment\" simply means \"no support\".\n\nIIRC people commentted positively on the feature, but there were \nimplementation issues, which got resolved, and then nothing.\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"91148","messageId":"7v1vzfrebs.fsf@gitster.siamese.dyndns.org","threadId":"15513","inReplyTo":"1221279997-9336-1-git-send-email-marcus@griep.us","subject":"Re: [RFC Redux] strbuf: Add method to convert byte-size to human readable form","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-19T21:55:03Z","receivedAt":"2008-09-19T21:55:03Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Marcus Griep <marcus@griep.us> writes:\n\n>  This is a redux of a prior patch as part of a series on count-objects\n>  but is now split off and submitted on its own as an RFC for a library\n>  function to be added to strbuf.\n\nOk, so I looked at the patch again.\n\n> diff --git a/.gitignore b/.gitignore\n> index bbaf9de..251537b 100644\n> --- a/.gitignore\n> +++ b/.gitignore\n> @@ -147,6 +147,7 @@ test-date\n>  test-delta\n>  test-dump-cache-tree\n>  test-genrandom\n> +test-human-read\n>  test-match-trees\n>  test-parse-options\n>  test-path-utils\n\nIs it just me or should the test called \"test-human-readable\"?\n\n> diff --git a/strbuf.c b/strbuf.c\n> index 720737d..d9888fb 100644\n> --- a/strbuf.c\n> +++ b/strbuf.c\n> @@ -308,3 +308,95 @@ int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)\n> ...\n> +{\n> +\tconst int maxscale = 7;\n\nThis is unused as far as I can tell.\n\n> +\tstrbuf_addf(sb, \"%f\", sign * val);\n> +\n> +\tif (maxlen) {\n> +\t\tint signlen = sign == -1 ? 1 : 0;\n> +\t\tmaxlen -= (sb->buf[maxlen-1+signlen] == '.' ? 1 : 0);\n> +\t\tif (maxlen <= 0) {\n> +\t\t\tstrbuf_setlen(sb, 0);\n> +\t\t\tretval = maxlen - 1;\n> +\t\t} else {\n> +\t\t\tstrbuf_setlen(sb, maxlen + signlen);\n> +\t\t}\n> +\t}\n\nThis means you print to the buffer and then _truncate_ down to precision,\ndoesn't it?  Shouldn't you be rounding (possibly up if it is above the\nmidway point)?\n\nFor example, if I hand 1638 to you, you would give 1.599Ki back to me, but\nif I give you only 4 digits to work with, you do not want to say 1.59Ki;\ninstead you would rather say 1.60Ki, right?\n\nYou would need to compute the number of digits you would want to see\nupfront and format the value using \"%.*f\" with appropriate precision.\n\n> diff --git a/test-human-read.c b/test-human-read.c\n> new file mode 100644\n> index 0000000..7890922\n> --- /dev/null\n> +++ b/test-human-read.c\n> @@ -0,0 +1,23 @@\n> +#include \"builtin.h\"\n> +#include \"strbuf.h\"\n> +\n> +int main(int argc, char **argv) {\n> +\tif (argc != 6) {\n> +\t\texit(-1);\n> +\t}\n> +\n> +\tstruct strbuf sb;\n\nDecl after statement.\n\n> +\tstrbuf_init(&sb, 0);\n> +\n> +\tint retval = strbuf_append_human_readable(&sb,\n> +\t\tatof(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4]));\n> +\n> +\tint failed = strcmp(sb.buf, argv[5]);\n> +\n> +\tfprintf( stderr, failed ? \"Failure\" : \"Success\" );\n> +\tfprintf( stderr, \": Act '%s'; Exp '%s'\\n\", sb.buf, argv[5] );\n> +\tfprintf( stderr, \"Return Value: %d\\n\", retval );\n\nStyle.\n\n> +\n> +\tif(failed) return -1;\n\nStyle.\n\n> +\treturn retval;\n> +}\n> -- \n> 1.6.0.1.451.gc8d31\n"},{"id":"91151","messageId":"7vod2jpxsp.fsf@gitster.siamese.dyndns.org","threadId":"15513","inReplyTo":"7v1vzfrebs.fsf@gitster.siamese.dyndns.org","subject":"Re: [RFC Redux] strbuf: Add method to convert byte-size to human readable form","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-09-19T22:37:26Z","receivedAt":"2008-09-19T22:37:26Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Marcus Griep <marcus@griep.us> writes:\n>\n>>  This is a redux of a prior patch as part of a series on count-objects\n>>  but is now split off and submitted on its own as an RFC for a library\n>>  function to be added to strbuf.\n>\n> Ok, so I looked at the patch again.\n>...\n> For example, if I hand 1638 to you, you would give 1.599Ki back to me, but\n> if I give you only 4 digits to work with, you do not want to say 1.59Ki;\n> instead you would rather say 1.60Ki, right?\n\nThis also takes me back to this part...\n\n>/*\n> * strbuf_append_human_readable\n> *\n> * 'val': value to be metrically-reduced to a human-readable number\n> * 'maxlen': maximum number of characters to be taken up by the reduced 'val'\n> *           not including the sign or magnitude (i.e. 'Ki') characters;\n> *           when 'maxlen' is 0 length is controled by 'scale'\n> * 'scale': when 'val' is greater than 'scale', 'val' is reduced by the\n> *          period (default 1024, see 'flags') until it is less than 'scale';\n> *          when 'scale' is 0, 'val' is reduced until it fits in 'maxlen';\n> *          when 'scale' and 'maxlen' are both zero, 'scale' defaults to 1000\n> * 'flags': HR_USE_SI: uses a period of 1000 and uses SI magnitude prefixes\n> *          HR_SPACE: inserts a space between the reduced 'val' and the units\n> *          HR_PAD_UNIT: instead of an empty string for singles, pads with\n> *                       spaces to the length of the magnitude prefixes\n> *\n> * Returns 0 if 'val' is successfully reduced and fits in 'maxlen', otherwise\n> * returns -n where n is the number of additional characters necessary to\n> * fully fit the reduced value.\n> */\n\nThe lines are overlong but that is not my main complaint.\n\nI do not see how the above definition of \"scale\" can be useful.\n\nFirst, for the case of scale=0, if I tell you to format 1638 into 7 spaces\n(without HR_PAD_UNIT), you could give me one of:\n\n           1638\n        1.560Ki\n        0.002Mi\n        0.000Gi\n        ...\n\nIt is clear that 1638 is better than 1.560Ki which in turn is better than\n0.002Mi, because the earlier ones give the information in better precision\nwith a shorter string than the later ones.  Typically the smaller unit\nwould give you the better answer but does that match \"reduced repeatedly\nuntil it fits in 'maxlen'\" rule?  I do not think so (\"1638  \" is more\nprecise than \"1.56Ki\", even with HR_PAD_UNIT on).\n\nSecond, why is the default of \"scale\" independent from \"period\"?  Scale\nthat defaults to 1000 in binary system would mean that you would give\n\n        ...\n   998  998.0000\n   999  999.0000\n  1000  0.976562Ki\n  1001  0.977539Ki\n        ...\n\nI have this feeling that the \"scale\" knob does not match well with human\nexpectations.  Admittedly, \"most precision within the allocated space\"\nrule may not match human expectation either (e.g. when you have a\nsequence of three numbers \"520\", \"1048\", \"9999\" and you are expecting to\nsee approximation in binary system, you would probably expect to see\n0.51k, 1.02k, and 9.76k, instead of the original integers), but I think it\nat least matches human expectations better than the \"scale\" system.\n\nBy the way, about the internal math you do for \"repeatedly reduce\", I do\nnot think repeatedly dividing with \"period\" is kosher.  I'd very much\nprefer seeing something like:\n\n\tdouble magnitude = fabs(value);\n        double scaler;\n\n        for (unit = 0, scaler = 1.0;\n             scaler < magnitude && unit < max_units;\n             unit++)\n             scaler *= period;\n\n\tprintf(\"%f%s\", value / scaler, unit_names[unit]);\n\nmodulo the terminating condition --- it may make more sense to stop one\nstep before \"scaler < magnitude\" happens so that we won't see \"0.9765Ki\"\nbut instead see \"1000\".\n\nAfter thinking about this longer, I unfortunately have to say that the\nonly thing I like about the current iteration of the patch is the name of\nthe function \"strbuf_append_human_readable\" and what goal (at the abstract\nlevel) it wants to achieve.\n"}]}