Воспроизведение оптимизации Libc ++, которая использует хвостовую прокладку для хранения участников поля без дополнительC++

Программы на C++. Форум разработчиков
Ответить Пред. темаСлед. тема
Anonymous
 Воспроизведение оптимизации Libc ++, которая использует хвостовую прокладку для хранения участников поля без дополнитель

Сообщение Anonymous »

Я читал реализацию std :: weder в Libc ++, и она описывает интересную оптимизацию, в которой он хранит Bool дискриминатор в хвостовой накладке типов значения/ошибок, когда это возможно, используя c ++ 20 [[no_unique_address]] attribute.

Код: Выделить всё

// This class implements the storage used by `std::expected`. We have a few
// goals for this storage:
// 1. Whenever the underlying {_Tp | _Unex} combination has free bytes in its
//    tail padding, we should reuse it to store the bool discriminator of the
//    expected, so as to save space.
// 2. Whenever the `expected` as a whole has free bytes in its tail
//    padding, we should allow an object following the expected to be stored in
//    its tail padding.
// 3. However, we never want a user object (say `X`) that would follow an
//    `expected` to be stored in the padding bytes of the
//    underlying {_Tp | _Unex} union, if any. That is because we use
//    `construct_at` on that union, which would end up overwriting the `X`
//    member if it is stored in the tail padding of the union.
//
// To achieve this, `__expected_base`'s logic is implemented in an inner
// `__repr` class. `__expected_base` holds one `__repr` member which is
// conditionally `[[no_unique_address]]`. The `__repr` class holds the
// underlying {_Tp | _Unex} union and a boolean "has value" flag.
//
// Which one of the `__repr_`/`__union_` members is `[[no_unique_address]]`
// depends on whether the "has value" boolean fits into the tail padding of
// the underlying {_Tp | _Unex} union:
//
// - In case the "has value" bool fits into the tail padding of the union, the
//   whole `__repr_` member is _not_ `[[no_unique_address]]` as it needs to be
//   transparently replaced on `emplace()`/`swap()` etc.
// - In case the "has value" bool does not fit into the tail padding of the
//   union, only the union member must be transparently replaced (therefore is
//   _not_ `[[no_unique_address]]`) and the "has value" flag must be adjusted
//   manually.
//
// This way, the member that is transparently replaced on mutating operations
// is never `[[no_unique_address]]`, satisfying the requirements from
// "[basic.life]" in the standard.
//
// Stripped away of all superfluous elements, the layout of `__expected_base`
// then looks like this:
//
//     template 
//     class expected_base {
//       union union_t {
//         [[no_unique_address]] Tp val;
//         [[no_unique_address]] Err unex;
//       };
//
//       static constexpr bool put_flag_in_tail                    = fits_in_tail_padding;
//       static constexpr bool allow_reusing_expected_tail_padding = !put_flag_in_tail;
//
//       struct repr {
//       private:
//         // If "has value" fits into the tail, this should be
//         // `[[no_unique_address]]`, otherwise not.
//         [[no_unique_address]] conditional_no_unique_address<
//             put_flag_in_tail,
//             union_t>::type union_;
//         [[no_unique_address]] bool has_val_;
//       };
//
//     protected:
//       // If "has value" fits into the tail, this must _not_ be
//       // `[[no_unique_address]]` so that we fill out the
//       // complete `expected` object.
//       [[no_unique_address]] conditional_no_unique_address<
//           allow_reusing_expected_tail_padding,
//           repr>::type repr_;
//     };
//
< /code>
Я выкопал историю коммит и обзор кода и нашел ссылку «Годбалт», которая демонстрирует поведение при использовании пустых структур: < /p>
struct T{};
struct E{};

struct s{
[[no_unique_address]] union{
[[no_unique_address]]  T t;
[[no_unique_address]]  E e;
} u;
bool b;
};

int main(){
return sizeof(s);
}
В качестве образования я хочу воспроизвести это поведение для своих собственных типов, но я изо всех сил пытаюсь сделать это для чего угодно , но пустой случай структуры. Я предполагаю, что концепция «повторного использования хвостовой накладки» применяется в целом, потому что использование двух пустых контактов в Std :: ожидается , похоже на превышение редкого/исключительного края для оптимизации, и комментарий в коде подразумевает его более общий. PrettyPrint-Override ">

Код: Выделить всё

struct T {
int foo;
char bar;
// 3 bytes of tail padding
};

struct E {
char e;
};

union U {
[[no_unique_address]]  T t;
[[no_unique_address]]  E e;
// When engaged as E, there are 7 bytes of
// trailing padding to hit the 8-byte
// size of T, the largest member of U.
};

template 
inline constexpr bool FitsInTailPadding = []() {
struct repr {
[[no_unique_address]] A a;
[[no_unique_address]] B b;
};
return sizeof(repr) == sizeof(A);
}();

int main(){
return FitsInTailPadding;
}
Шаблон FitsIntailPadding - это прямой перевод эквивалентного шаблона, используемого в реализации LIBC ++. Что я здесь недоразумю?


Подробнее здесь: https://stackoverflow.com/questions/796 ... ld-members
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C++»