After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 789170 - GFormatSizeFlags should have a value for bits
GFormatSizeFlags should have a value for bits
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: general
unspecified
Other All
: Normal enhancement
: ---
Assigned To: Benoît Dejean
gtkdev
Depends on:
Blocks:
 
 
Reported: 2017-10-18 18:52 UTC by Benoît Dejean
Modified: 2017-11-02 13:40 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
G_FORMAT_SIZE_BITS (5.57 KB, patch)
2017-10-19 19:18 UTC, Benoît Dejean
none Details | Review
refactor g_format_size_full (4.75 KB, patch)
2017-10-20 16:40 UTC, Benoît Dejean
none Details | Review
0001-utils-refactor-g_format_size_full.patch (5.31 KB, patch)
2017-10-25 12:18 UTC, Benoît Dejean
none Details | Review
0001-utils-refactor-g_format_size_full.patch (5.18 KB, patch)
2017-10-25 14:53 UTC, Benoît Dejean
none Details | Review
0001-utils-refactor-g_format_size_full.patch (4.85 KB, patch)
2017-10-26 11:06 UTC, Benoît Dejean
none Details | Review
0001-utils-refactor-g_format_size_full.patch (4.85 KB, patch)
2017-10-26 11:11 UTC, Benoît Dejean
none Details | Review
0001-utils-refactor-g_format_size_full (4.85 KB, patch)
2017-10-26 18:37 UTC, Benoît Dejean
committed Details | Review
0001-utils-new-G_FORMAT_SIZE_BITS-flag-to-g_format_size_f (8.24 KB, patch)
2017-11-02 13:29 UTC, Benoît Dejean
committed Details | Review

Description Benoît Dejean 2017-10-18 18:52:05 UTC
Hello,

would it be possible to add a GFormatSizeFlags G_FORMAT_SIZE_BITS for g_format_size_full that would format the size in bits, instead of bytes ? (still wrt G_FORMAT_SIZE_LONG_FORMAT, but exclusive with G_FORMAT_SIZE_IEC_UNITS).
Comment 1 Philip Withnall 2017-10-18 23:01:16 UTC
What’s the use case?
Comment 2 Robert Roth 2017-10-19 04:19:19 UTC
(In reply to Philip Withnall from comment #1)
> What’s the use case?

Formatting transfer (network/disk) speed for use in System Monitor and Gnome Usage.
Comment 3 Philip Withnall 2017-10-19 07:55:54 UTC
So you’d typically expect it to return formatted results in Mb and Gb, rather than just bits?
Comment 4 Philip Withnall 2017-10-19 07:56:16 UTC
If so, seems reasonable. Patch welcome. :-)
Comment 5 Benoît Dejean 2017-10-19 13:08:34 UTC
Hello, in fact, to cover our usage, we will also need an additional feature. In the graph UI, we display a scale, and for consistency, it's important to use the same unit for every graduation. So our version has a third argument (a maximum value) that is used to find the unit to format the value.

Would it be possible to emulate this with additional flags like FORCE_KILO, FORCE_MEGA, etc ?
Comment 6 Philip Withnall 2017-10-19 13:23:06 UTC
(In reply to Benoît Dejean from comment #5)
> Would it be possible to emulate this with additional flags like FORCE_KILO,
> FORCE_MEGA, etc ?

I’m not so happy about that, since that’s a lot less general purpose. It’s starting to sound like you should implement your own version of g_format_size_full() with the functionality you need. It’s not a complex function, and you can copy the implementation from GLib if the license of GNOME Usage is compatible.
Comment 7 Benoît Dejean 2017-10-19 13:33:57 UTC
We had one long before you :-)
OK, let's stick to the bits flag only.
I'll make the patch.
Comment 8 Benoît Dejean 2017-10-19 19:18:52 UTC
Created attachment 361901 [details] [review]
G_FORMAT_SIZE_BITS

Not sure how you want to name it. It passes basic tests.
I don't know what's the policy about errors: it makes no sense to ask for bits & IEC, so I've added a simple assert.
Comment 9 Philip Withnall 2017-10-19 23:40:50 UTC
Review of attachment 361901 [details] [review]:

::: glib/gutils.c
@@ +2172,3 @@
  *     a strong "power of 2" basis, like RAM sizes or RAID stripe sizes.
  *     Network and storage sizes should be reported in the normal SI units.
+ * @G_FORMAT_SIZE_BITS: use bits units. Cannot be used with

I’d rephrase this as:

@G_FORMAT_SIZE_BITS: Treat the size as a quantity in bits, rather than bytes, and return units in bits. For example, ‘Mb’ rather than ‘MB’.

@@ +2202,3 @@
   GString *string;
 
+  g_assert(!(flags & (G_FORMAT_SIZE_IEC_UNITS | G_FORMAT_SIZE_BITS)));

Why does it have to be mutually exclusive with G_FORMAT_SIZE_IEC_UNITS?

Mib should be just as valid a unit as MiB, Mb or MB.

Aside: This should be g_return_val_if_fail() rather than g_assert(), as it bails out gracefully.

::: glib/gutils.h
@@ +183,3 @@
   G_FORMAT_SIZE_LONG_FORMAT = 1 << 0,
+  G_FORMAT_SIZE_IEC_UNITS   = 1 << 1,
+  G_FORMAT_SIZE_BITS        = 2 << 1

Please add a trailing comma to the new line to prevent diff noise in future if another element is added after it.
Comment 10 Emmanuele Bassi (:ebassi) 2017-10-20 10:20:45 UTC
(In reply to Philip Withnall from comment #9)

> ::: glib/gutils.h
> @@ +183,3 @@
>    G_FORMAT_SIZE_LONG_FORMAT = 1 << 0,
> +  G_FORMAT_SIZE_IEC_UNITS   = 1 << 1,
> +  G_FORMAT_SIZE_BITS        = 2 << 1
> 
> Please add a trailing comma to the new line to prevent diff noise in future
> if another element is added after it.

No, don't do this, otherwise C++ developers will be very angry at us, and file bugs to remove the trailing comma.

The support for trailing commas in enumerations was added in C99, but C++03 was forked off from C89, and no new C++ standard decided to fix this.
Comment 11 Benoît Dejean 2017-10-20 12:39:19 UTC
Ok for the rephrasing.

(In reply to Philip Withnall from comment #9)
> Review of attachment 361901 [details] [review] [review]:
> 
> ::: glib/gutils.c
> @@ +2172,3 @@
>   *     a strong "power of 2" basis, like RAM sizes or RAID stripe sizes.
>   *     Network and storage sizes should be reported in the normal SI units.
> + * @G_FORMAT_SIZE_BITS: use bits units. Cannot be used with
> 
> I’d rephrase this as:
> 
> @G_FORMAT_SIZE_BITS: Treat the size as a quantity in bits, rather than
> bytes, and return units in bits. For example, ‘Mb’ rather than ‘MB’.

OK


> @@ +2202,3 @@
>    GString *string;
>  
> +  g_assert(!(flags & (G_FORMAT_SIZE_IEC_UNITS | G_FORMAT_SIZE_BITS)));
> 
> Why does it have to be mutually exclusive with G_FORMAT_SIZE_IEC_UNITS?
> 
> Mib should be just as valid a unit as MiB, Mb or MB.

I've never heard anyone using mebibits, but I'll add it.


> Aside: This should be g_return_val_if_fail() rather than g_assert(), as it
> bails out gracefully.
> 
> ::: glib/gutils.h
> @@ +183,3 @@
>    G_FORMAT_SIZE_LONG_FORMAT = 1 << 0,
> +  G_FORMAT_SIZE_IEC_UNITS   = 1 << 1,
> +  G_FORMAT_SIZE_BITS        = 2 << 1
> 
> Please add a trailing comma to the new line to prevent diff noise in future
> if another element is added after it.

That's actually "1 << 2" and I agree with Emmanuele that we should not have a trailing comma.
Comment 12 Benoît Dejean 2017-10-20 16:40:59 UTC
Created attachment 361966 [details] [review]
refactor g_format_size_full

Before submitting the patch to add kb and Kib, would you accept this refactoring that would make the addition of 2 new units easier (a lot less of copy/paste code).

   text    data     bss     dec     hex filename
   8622       0     168    8790    2256 ./glib/.libs/libglib_2_0_la-gutils.o
   8304       0     168    8472    2118 ./glib/.libs/libglib_2_0_la-gutils.o (patched)
Comment 13 Philip Withnall 2017-10-23 11:18:53 UTC
Review of attachment 361966 [details] [review]:

This looks like a good cleanup, thanks. I have a few nitpicks, but other than these it looks good.

::: glib/gutils.c
@@ +2243,2 @@
+  GString *string;
+  int index = -1;

Add a typedef to the enum above and declare this to be of that type.

@@ +2261,3 @@
+      const struct FormatPlural * const f = &format_plurals[index];
+      g_string_printf (string,
+                       g_dngettext(GETTEXT_PACKAGE,

Nitpick: Missing space before `(`

@@ +2270,3 @@
+  else
+    {
+      const size_t n = G_N_ELEMENTS(formats[index]);

Nitpick: Missing space before `(`

@@ +2281,1 @@
+      for (size_t i = 1; i < G_N_ELEMENTS(formats[index]); i++)

Can’t use inline declarations.

Missing a space before the `(` in `G_N_ELEMENTS`.
Comment 14 Benoît Dejean 2017-10-23 18:34:58 UTC
Noted.

But what version of  C standard does glib stick to ?
It doesn't compile at all with c89, and with gnu89 it actually fails in g_format_size_full:

in gutils.c:2337:43: error: ISO C ne supporte pas le fanion « ' » de printf [-Werror=format=]
       formatted_number = g_strdup_printf ("%'"G_GUINT64_FORMAT, size);

I would assume not C99 because you told me not to mixed code and declarations.
Or is it only a matter of style ?
Comment 15 Philip Withnall 2017-10-23 21:10:19 UTC
There’s a handy wiki page for it, which I was reminded of today:

https://wiki.gnome.org/Projects/GLib/CompilerRequirements
Comment 16 Benoît Dejean 2017-10-25 12:18:54 UTC
Created attachment 362256 [details] [review]
0001-utils-refactor-g_format_size_full.patch
Comment 17 Philip Withnall 2017-10-25 13:08:30 UTC
Review of attachment 362256 [details] [review]:

::: glib/gutils.c
@@ +2212,1 @@
+  enum FormatIndex

Nitpick: Use

typedef enum
{

} FormatIndex;

since we don’t use the ‘enum’ prefix in GLib.

@@ +2244,2 @@
+  GString *string;
+  enum FormatIndex index = FORMAT_UNDEFINED;

No need for `FORMAT_UNDEFINED`, since this is unconditionally initialised just below. In fact, it’s less safe to unconditionally initialise this, as it means the compiler (or analysis tools) won’t give you a used-before-initialised warning if the code below changes, and we don’t ever want to dereference things with FORMAT_UNDEFINED.

@@ +2272,3 @@
+    {
+      const size_t n = G_N_ELEMENTS (formats[index]);
+      size_t i;

Nitpick: For consistency within GLib, please use gsize instead of size_t (they’re equivalent).

@@ +2278,3 @@
+        and then then scan all formats, starting with the 2nd one
+        because the 1st is already managed by with the plural form
+      */

Nitpick: Please prefix each line in a multi-line comment with asterisks.

/*
 * i.e. Write it
 * like this.
 */

@@ +2293,3 @@
     }
 
+

Spurious additional new line.
Comment 18 Benoît Dejean 2017-10-25 14:53:56 UTC
Created attachment 362274 [details] [review]
0001-utils-refactor-g_format_size_full.patch
Comment 19 Philip Withnall 2017-10-25 15:09:30 UTC
Review of attachment 362274 [details] [review]:

Great, thanks.
Comment 20 Piotr Drąg 2017-10-25 16:18:12 UTC
51f9c95cf240b7de4c1db8e4dcb7e18d72ba0d3c made this appear in .po files:

#: ../glib/gutils.c:2220 ../glib/gutils.c:2221
#, c-format
msgid "%u bytes"
msgstr ""

…which is very wrong for i18n.

https://wiki.gnome.org/TranslationProject/DevGuidelines/Plurals
Comment 21 Benoît Dejean 2017-10-25 16:34:10 UTC
I understand but in the end, it gets called with g_dngettext.
Maybe we should a comment for translators before lines 2220 and 2221 ?

(I'm actually more concerned about the string butchering happening starting at https://git.gnome.org/browse/glib/tree/glib/gutils.c#n2328 to make the long format output)
Comment 22 Piotr Drąg 2017-10-25 16:37:36 UTC
(In reply to Benoît Dejean from comment #21)
> I understand but in the end, it gets called with g_dngettext.
> Maybe we should a comment for translators before lines 2220 and 2221 ?
> 

I don’t understand why you are asking translators to translate a string that won’t be used, and also can’t be translated correctly in most languages.
Comment 23 Benoît Dejean 2017-10-25 17:39:20 UTC
Those strings are defined there:

  struct FormatPlural format_plurals[2] =
    {
      { N_("%u byte"), N_("%u bytes") },
      { N_("%u byte"), N_("%u bytes") }
    };

and later they are really used:

      g_string_printf (string,
                       g_dngettext (GETTEXT_PACKAGE,
                                    _(f->singular),
                                    _(f->plural),
                                    (guint) size),
                       (guint) size);
Comment 24 Piotr Drąg 2017-10-25 17:47:33 UTC
#: ../glib/gutils.c:2220 ../glib/gutils.c:2221 ../glib/gutils.c:2377
#, c-format
msgid "%u byte"
msgid_plural "%u bytes"
msgstr[0] ""
msgstr[1] ""

#: ../glib/gutils.c:2220 ../glib/gutils.c:2221
#, c-format
msgid "%u bytes"
msgstr ""


This looks all kinds of wrong. :(
Comment 25 Philip Withnall 2017-10-25 23:02:25 UTC
I’ve reverted the patch until a fix is found, so we don’t end up with unnecessary translation churn. (Revert is commit f43babfea.)
Comment 26 Philip Withnall 2017-10-25 23:07:10 UTC
(In reply to Benoît Dejean from comment #23)
> Those strings are defined there:
> 
>   struct FormatPlural format_plurals[2] =
>     {
>       { N_("%u byte"), N_("%u bytes") },
>       { N_("%u byte"), N_("%u bytes") }
>     };
> 
> and later they are really used:
> 
>       g_string_printf (string,
>                        g_dngettext (GETTEXT_PACKAGE,
>                                     _(f->singular),
>                                     _(f->plural),
>                                     (guint) size),
>                        (guint) size);

Given that the FORMAT_BYTES and FORMAT_BYTES_IEC entries in format_plurals are identical, could we not drop the format_plurals array and put the strings directly into the g_dngettext() call? I suspect that should fix the string extraction and POT file generation.
Comment 27 Daniel Boles 2017-10-25 23:09:36 UTC
(In reply to Emmanuele Bassi (:ebassi) from comment #10)
> (In reply to Philip Withnall from comment #9)
> > Please add a trailing comma to the new line to prevent diff noise in future
> > if another element is added after it.
> 
> No, don't do this, otherwise C++ developers will be very angry at us, and
> file bugs to remove the trailing comma.
> 
> The support for trailing commas in enumerations was added in C99, but C++03
> was forked off from C89, and no new C++ standard decided to fix this.

C++11 did: https://stackoverflow.com/questions/6372650/trailing-commas-and-c
Comment 28 Benoît Dejean 2017-10-26 08:22:20 UTC
(In reply to Philip Withnall from comment #26)
> Given that the FORMAT_BYTES and FORMAT_BYTES_IEC entries in format_plurals
> are identical, could we not drop the format_plurals array and put the
> strings directly into the g_dngettext() call? I suspect that should fix the
> string extraction and POT file generation.

That table will be extended for bits.
But if you want, we can replace it with a if/else that will only duplicate one call.
Comment 29 Philip Withnall 2017-10-26 08:46:39 UTC
(In reply to Benoît Dejean from comment #28)
> (In reply to Philip Withnall from comment #26)
> > Given that the FORMAT_BYTES and FORMAT_BYTES_IEC entries in format_plurals
> > are identical, could we not drop the format_plurals array and put the
> > strings directly into the g_dngettext() call? I suspect that should fix the
> > string extraction and POT file generation.
> 
> That table will be extended for bits.
> But if you want, we can replace it with a if/else that will only duplicate
> one call.

Unless you’ve got any better suggestions, that would be the approach I’d try. I suspect the problem is that xgettext looks for g_dngettext() calls and extracts plural strings from them; and doesn’t know how to extract plural strings from anything else (specifically, not N_() macros).
Comment 30 Benoît Dejean 2017-10-26 11:06:05 UTC
Created attachment 362332 [details] [review]
0001-utils-refactor-g_format_size_full.patch

Here's a version that keeps the plain call to g_dngettext.
I've checked the statistics for fr.po before and after this patch and they are the same.
Comment 31 Benoît Dejean 2017-10-26 11:11:22 UTC
Created attachment 362333 [details] [review]
0001-utils-refactor-g_format_size_full.patch

And there was an off-by-one error as "%.1f KiB" requires 9 bytes of storage.
Comment 32 Benoît Dejean 2017-10-26 18:37:12 UTC
Created attachment 362364 [details] [review]
0001-utils-refactor-g_format_size_full

More const.
Comment 33 Philip Withnall 2017-10-27 11:18:08 UTC
Review of attachment 362364 [details] [review]:

++
Comment 34 Robert Roth 2017-11-02 12:45:48 UTC
Is there anything else to fix here, I see that the fix is already on master since a couple of days. Can this be marked as fixed?
Comment 35 Benoît Dejean 2017-11-02 13:29:20 UTC
Created attachment 362811 [details] [review]
0001-utils-new-G_FORMAT_SIZE_BITS-flag-to-g_format_size_f
Comment 36 Philip Withnall 2017-11-02 13:37:59 UTC
Review of attachment 362811 [details] [review]:

A couple of nitpicks, but this looks good. I’ll fix the nitpicks when I push. Thanks.

::: glib/gutils.c
@@ +2275,3 @@
+      break;
+    case (G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS):
+      index= FORMAT_BITS_IEC;

Nitpick: Missing a space before `=`.

@@ +2278,3 @@
+      break;
+    default:
+      g_assert_not_reached();

Nitpick: Please add a space before the `(`.
Comment 37 Philip Withnall 2017-11-02 13:40:38 UTC
I also tweaked the commit message to be the right length before I pushed.