public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug libstdc++/98978] New: Consider packing _M_Engaged in the tail padding of T in optional<>
@ 2021-02-05 17:14 andysem at mail dot ru
  2021-02-05 17:58 ` [Bug libstdc++/98978] " redi at gcc dot gnu.org
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: andysem at mail dot ru @ 2021-02-05 17:14 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98978

            Bug ID: 98978
           Summary: Consider packing _M_Engaged in the tail padding of T
                    in optional<>
           Product: gcc
           Version: 11.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: andysem at mail dot ru
  Target Milestone: ---

Using std::optional with some types may considerably increase object sizes
since it adds alignof(T) bytes worth of overhead. Sometimes it is possible to
avoid this overhead if the flag indicating presence of the stored value
(_M_Engaged in libstdc++ sources) is placed in the tail padding of the T
object. This can be done if std::optional constructs an object of a type that
derives from T, which has an additional bool data member that is initialized to
true upon construction. The below code roughly illustrates the idea:

template< typename T >
struct _Optional_payload_base
{
  struct _PresentT : T
  {
    const bool _M_Engaged = true;

    // Forwarding ctors and other members
  };

  static constexpr size_t engaged_offset = offsetof(_PresentT, _M_Engaged);

  struct _AbsentT
  {
    unsigned char _M_Offset[engaged_offset];
    const bool _M_Engaged = false;
  };

  union _Storage
  {
    _AbsentT _M_Empty;
    _PresentT _M_Value;

    _Storage() : _M_Empty() {}

    // Forwarding ctors and other members
  };

  _Storage _M_payload

  bool is_engaged() const noexcept
  {
    return *reinterpret_cast< const bool* >(reinterpret_cast< const unsigned
char* >(&_M_payload) + engaged_offset);
  }
};

The above relies on some implementation details, such as:

- offsetof works for the type T. It does for many types in gcc, beyond what is
required by the C++ standard. Maybe there is a way to avoid offsetof, I just
didn't immediately see it.
- The location of _M_Engaged in both _PresentT and _AbsentT is the same. This
is a property of the target ABI, and AFAICS it should be true at least on x86
psABI and I think Microsoft ABI.

The above will only work for non-final class types, for other types, and where
the above requirements don't hold true, the current code with a separate
_M_Engaged flag would work.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2022-09-18 12:28 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-05 17:14 [Bug libstdc++/98978] New: Consider packing _M_Engaged in the tail padding of T in optional<> andysem at mail dot ru
2021-02-05 17:58 ` [Bug libstdc++/98978] " redi at gcc dot gnu.org
2021-02-05 18:00 ` redi at gcc dot gnu.org
2021-02-05 20:44 ` andysem at mail dot ru
2021-02-06 17:26 ` redi at gcc dot gnu.org
2021-08-31 16:24 ` redi at gcc dot gnu.org
2022-09-07 12:30 ` redi at gcc dot gnu.org
2022-09-18 12:27 ` andysem at mail dot ru

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).