forked from microsoft/react-native-macos
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Replace CompactValue with StyleValueHandle and StyleValuePool (facebo…
…ok#42131) Summary: X-link: facebook/yoga#1534 Now that the storage method is a hidden implementation detail, this changes the underlying data structure used to store styles, from `CompactValue` (a customized 32-bit float with tag bits), to `StyleValuePool`. This new structure operates on 16-bit handles, and a shared small buffer. The vast majority of real-world values can be stored directly in the handle, but we allow arbitrary 32 bit (and soon 64-bit) values to be stored, where the handle then becomes an index into the styles buffer. This results in a real-world memory usage win, while also letting us store the 64-bit values we are wanting to use for math function support (compared to doubling the storage requirements). | | Before | After | Δ | | `sizeof(yoga::Style)` | 208B | 144B | -64B/-31% | | `sizeof(yoga::Node)` | 640B | 576B | -64B/-10% | | `sizeof(YogaLayoutableShadowNode) ` | 920B | 856B | -64B/-7% | | `sizeof(YogaLayoutableShadowNode) + sizeof(YogaStylableProps)` | 1296B | 1168B | -128B/-10% | | `sizeof(ViewShadowNode)` | 920B | 856B | -64B/-7% | | `sizeof(ViewShadowNode) + sizeof(ViewShadowNodeProps)` | 2000B | 1872B | -128B/-6% | Differential Revision: D52223122
- Loading branch information
1 parent
73d02fa
commit 677f31b
Showing
7 changed files
with
454 additions
and
244 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
177 changes: 0 additions & 177 deletions
177
packages/react-native/ReactCommon/yoga/yoga/style/CompactValue.h
This file was deleted.
Oops, something went wrong.
129 changes: 129 additions & 0 deletions
129
packages/react-native/ReactCommon/yoga/yoga/style/SmallValueBuffer.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <array> | ||
#include <bitset> | ||
#include <cstdint> | ||
#include <memory> | ||
#include <vector> | ||
|
||
namespace facebook::yoga { | ||
|
||
// Container which allows storing 32 or 64 bit integer values, whose index may | ||
// never change. Values are first stored in a fixed buffer of `BufferSize` | ||
// 32-bit chunks, before falling back to heap allocation. | ||
template <size_t BufferSize> | ||
class SmallValueBuffer { | ||
public: | ||
SmallValueBuffer() = default; | ||
SmallValueBuffer(const SmallValueBuffer& other) { | ||
*this = other; | ||
} | ||
SmallValueBuffer(SmallValueBuffer&& other) = default; | ||
|
||
// Add a new element to the buffer, returning the index of the element | ||
uint16_t push(uint32_t value) { | ||
const auto index = count_++; | ||
if (index < buffer_.size()) { | ||
buffer_[index] = value; | ||
return index; | ||
} | ||
|
||
if (overflow_ == nullptr) { | ||
overflow_ = std::make_unique<SmallValueBuffer::Overflow>(); | ||
} | ||
|
||
overflow_->buffer_.push_back(value); | ||
overflow_->wideElements_.push_back(false); | ||
return index; | ||
} | ||
|
||
uint16_t push(uint64_t value) { | ||
const auto lsb = static_cast<uint32_t>(value & 0xFFFFFFFF); | ||
const auto msb = static_cast<uint32_t>(value >> 32); | ||
|
||
const auto lsbIndex = push(lsb); | ||
push(msb); | ||
|
||
if (lsbIndex < buffer_.size()) { | ||
wideElements_[lsbIndex] = true; | ||
} else { | ||
overflow_->wideElements_[lsbIndex - buffer_.size()] = true; | ||
} | ||
return lsbIndex; | ||
} | ||
|
||
// Replace an existing element in the buffer with a new value. A new index | ||
// may be returned, e.g. if a new value is wider than the previous. | ||
[[nodiscard]] uint16_t replace(uint16_t index, uint32_t value) { | ||
if (index < buffer_.size()) { | ||
buffer_[index] = value; | ||
} else { | ||
overflow_->buffer_.at(index - buffer_.size()) = value; | ||
} | ||
|
||
return index; | ||
} | ||
|
||
[[nodiscard]] uint16_t replace(uint16_t index, uint64_t value) { | ||
const bool isWide = index < wideElements_.size() | ||
? wideElements_[index] | ||
: overflow_->wideElements_.at(index - buffer_.size()); | ||
|
||
if (isWide) { | ||
const auto lsb = static_cast<uint32_t>(value & 0xFFFFFFFF); | ||
const auto msb = static_cast<uint32_t>(value >> 32); | ||
|
||
[[maybe_unused]] auto lsbIndex = replace(index, lsb); | ||
[[maybe_unused]] auto msbIndex = replace(index + 1, msb); | ||
return index; | ||
} else { | ||
return push(value); | ||
} | ||
} | ||
|
||
// Get a value of a given width | ||
uint32_t get32(uint16_t index) const { | ||
if (index < buffer_.size()) { | ||
return buffer_[index]; | ||
} else { | ||
return overflow_->buffer_.at(index - buffer_.size()); | ||
} | ||
} | ||
|
||
uint64_t get64(uint16_t index) const { | ||
const auto lsb = get32(index); | ||
const auto msb = get32(index + 1); | ||
return (static_cast<uint64_t>(msb) << 32) | lsb; | ||
} | ||
|
||
SmallValueBuffer& operator=(const SmallValueBuffer& other) { | ||
count_ = other.count_; | ||
buffer_ = other.buffer_; | ||
wideElements_ = other.wideElements_; | ||
overflow_ = other.overflow_ ? std::make_unique<Overflow>(*other.overflow_) | ||
: nullptr; | ||
return *this; | ||
} | ||
|
||
SmallValueBuffer& operator=(SmallValueBuffer&& other) = default; | ||
|
||
private: | ||
struct Overflow { | ||
std::vector<uint32_t> buffer_; | ||
std::vector<bool> wideElements_; | ||
}; | ||
|
||
uint16_t count_{0}; | ||
std::array<uint32_t, BufferSize> buffer_; | ||
std::bitset<BufferSize> wideElements_; | ||
std::unique_ptr<Overflow> overflow_; | ||
}; | ||
|
||
} // namespace facebook::yoga |
Oops, something went wrong.