Update thirdparty libs

fmt: 9.0.0 --> 9.1.0
    llhttp: 6.0.7 --> 6.0.9
    astc-encoder: 4.0.0 --> 4.1.0
    webp: 1.2.2 --> 1.2.4
    flatbuffers: 2.0.0 --> 2.0.8
This commit is contained in:
halx99 2022-09-15 20:15:28 +08:00
parent 0bd73df1dc
commit fad9afbc9a
95 changed files with 14618 additions and 11197 deletions

View File

@ -19,10 +19,10 @@ jobs:
- uses: actions/checkout@v2
- name: Run clang-format lint
uses: DoozyX/clang-format-lint-action@v0.13
uses: DoozyX/clang-format-lint-action@v0.14
with:
source: './core ./extensions ./tests ./templates'
exclude: './thidrparty ./extensions/fairygui ./extensions/scripting/lua-bindings/auto ./extensions/spine ./tests/fairygui-tests'
exclude: './thidrparty ./extensions/fairygui ./extensions/scripting/lua-bindings/auto ./extensions/spine ./tests/fairygui-tests' ./extensions/**/*_generated.h
extensions: 'h,cpp,c,mm'
clangFormatVersion: 13
inplace: True

View File

@ -19,7 +19,7 @@
#include <vector>
#include <deque>
#include "astc/astcenc.h"
#include "astc/astcenc_internal.h"
#include "astc/astcenc_internal_entry.h"
#include "yasio/detail/utils.hpp"
#define ASTCDEC_NO_CONTEXT 1

View File

@ -1,151 +1,171 @@
// automatically generated by the FlatBuffers compiler, do not modify
#ifndef FLATBUFFERS_GENERATED_CSLANGUAGEDATABINARY_FLATBUFFERS_H_
#define FLATBUFFERS_GENERATED_CSLANGUAGEDATABINARY_FLATBUFFERS_H_
#include "flatbuffers/flatbuffers.h"
namespace flatbuffers
{
// Ensure the included flatbuffers.h is the same version as when this file was
// generated, otherwise it may not be compatible.
static_assert(FLATBUFFERS_VERSION_MAJOR == 2 &&
FLATBUFFERS_VERSION_MINOR == 0 &&
FLATBUFFERS_VERSION_REVISION == 8,
"Non-compatible flatbuffers version included");
namespace flatbuffers {
struct LanguageItem;
struct LanguageItemBuilder;
struct LanguageSet;
struct LanguageSetBuilder;
struct LanguageItem FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
{
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
{
VT_KEY = 4,
VT_VALUE = 6
};
const flatbuffers::String* key() const { return GetPointer<const flatbuffers::String*>(VT_KEY); }
const flatbuffers::String* value() const { return GetPointer<const flatbuffers::String*>(VT_VALUE); }
bool Verify(flatbuffers::Verifier& verifier) const
{
return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_KEY) && verifier.VerifyString(key()) &&
VerifyOffset(verifier, VT_VALUE) && verifier.VerifyString(value()) && verifier.EndTable();
}
struct LanguageItem FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef LanguageItemBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_KEY = 4,
VT_VALUE = 6
};
const flatbuffers::String *key() const {
return GetPointer<const flatbuffers::String *>(VT_KEY);
}
const flatbuffers::String *value() const {
return GetPointer<const flatbuffers::String *>(VT_VALUE);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_KEY) &&
verifier.VerifyString(key()) &&
VerifyOffset(verifier, VT_VALUE) &&
verifier.VerifyString(value()) &&
verifier.EndTable();
}
};
struct LanguageItemBuilder
{
flatbuffers::FlatBufferBuilder& fbb_;
flatbuffers::uoffset_t start_;
void add_key(flatbuffers::Offset<flatbuffers::String> key) { fbb_.AddOffset(LanguageItem::VT_KEY, key); }
void add_value(flatbuffers::Offset<flatbuffers::String> value) { fbb_.AddOffset(LanguageItem::VT_VALUE, value); }
explicit LanguageItemBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
LanguageItemBuilder& operator=(const LanguageItemBuilder&);
flatbuffers::Offset<LanguageItem> Finish()
{
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<LanguageItem>(end);
return o;
}
struct LanguageItemBuilder {
typedef LanguageItem Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_key(flatbuffers::Offset<flatbuffers::String> key) {
fbb_.AddOffset(LanguageItem::VT_KEY, key);
}
void add_value(flatbuffers::Offset<flatbuffers::String> value) {
fbb_.AddOffset(LanguageItem::VT_VALUE, value);
}
explicit LanguageItemBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<LanguageItem> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<LanguageItem>(end);
return o;
}
};
inline flatbuffers::Offset<LanguageItem> CreateLanguageItem(flatbuffers::FlatBufferBuilder& _fbb,
flatbuffers::Offset<flatbuffers::String> key = 0,
flatbuffers::Offset<flatbuffers::String> value = 0)
{
LanguageItemBuilder builder_(_fbb);
builder_.add_value(value);
builder_.add_key(key);
return builder_.Finish();
inline flatbuffers::Offset<LanguageItem> CreateLanguageItem(
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::String> key = 0,
flatbuffers::Offset<flatbuffers::String> value = 0) {
LanguageItemBuilder builder_(_fbb);
builder_.add_value(value);
builder_.add_key(key);
return builder_.Finish();
}
inline flatbuffers::Offset<LanguageItem> CreateLanguageItemDirect(flatbuffers::FlatBufferBuilder& _fbb,
const char* key = nullptr,
const char* value = nullptr)
{
auto key__ = key ? _fbb.CreateString(key) : 0;
auto value__ = value ? _fbb.CreateString(value) : 0;
return flatbuffers::CreateLanguageItem(_fbb, key__, value__);
inline flatbuffers::Offset<LanguageItem> CreateLanguageItemDirect(
flatbuffers::FlatBufferBuilder &_fbb,
const char *key = nullptr,
const char *value = nullptr) {
auto key__ = key ? _fbb.CreateString(key) : 0;
auto value__ = value ? _fbb.CreateString(value) : 0;
return flatbuffers::CreateLanguageItem(
_fbb,
key__,
value__);
}
struct LanguageSet FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
{
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
{
VT_LANGUAGEITEMS = 4
};
const flatbuffers::Vector<flatbuffers::Offset<LanguageItem>>* languageItems() const
{
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<LanguageItem>>*>(VT_LANGUAGEITEMS);
}
bool Verify(flatbuffers::Verifier& verifier) const
{
return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_LANGUAGEITEMS) &&
verifier.VerifyVector(languageItems()) && verifier.VerifyVectorOfTables(languageItems()) &&
verifier.EndTable();
}
struct LanguageSet FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef LanguageSetBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_LANGUAGEITEMS = 4
};
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::LanguageItem>> *languageItems() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::LanguageItem>> *>(VT_LANGUAGEITEMS);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_LANGUAGEITEMS) &&
verifier.VerifyVector(languageItems()) &&
verifier.VerifyVectorOfTables(languageItems()) &&
verifier.EndTable();
}
};
struct LanguageSetBuilder
{
flatbuffers::FlatBufferBuilder& fbb_;
flatbuffers::uoffset_t start_;
void add_languageItems(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<LanguageItem>>> languageItems)
{
fbb_.AddOffset(LanguageSet::VT_LANGUAGEITEMS, languageItems);
}
explicit LanguageSetBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
LanguageSetBuilder& operator=(const LanguageSetBuilder&);
flatbuffers::Offset<LanguageSet> Finish()
{
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<LanguageSet>(end);
return o;
}
struct LanguageSetBuilder {
typedef LanguageSet Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_languageItems(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::LanguageItem>>> languageItems) {
fbb_.AddOffset(LanguageSet::VT_LANGUAGEITEMS, languageItems);
}
explicit LanguageSetBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<LanguageSet> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<LanguageSet>(end);
return o;
}
};
inline flatbuffers::Offset<LanguageSet> CreateLanguageSet(
flatbuffers::FlatBufferBuilder& _fbb,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<LanguageItem>>> languageItems = 0)
{
LanguageSetBuilder builder_(_fbb);
builder_.add_languageItems(languageItems);
return builder_.Finish();
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::LanguageItem>>> languageItems = 0) {
LanguageSetBuilder builder_(_fbb);
builder_.add_languageItems(languageItems);
return builder_.Finish();
}
inline flatbuffers::Offset<LanguageSet> CreateLanguageSetDirect(
flatbuffers::FlatBufferBuilder& _fbb,
const std::vector<flatbuffers::Offset<LanguageItem>>* languageItems = nullptr)
{
auto languageItems__ = languageItems ? _fbb.CreateVector<flatbuffers::Offset<LanguageItem>>(*languageItems) : 0;
return flatbuffers::CreateLanguageSet(_fbb, languageItems__);
flatbuffers::FlatBufferBuilder &_fbb,
const std::vector<flatbuffers::Offset<flatbuffers::LanguageItem>> *languageItems = nullptr) {
auto languageItems__ = languageItems ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::LanguageItem>>(*languageItems) : 0;
return flatbuffers::CreateLanguageSet(
_fbb,
languageItems__);
}
inline const flatbuffers::LanguageSet* GetLanguageSet(const void* buf)
{
return flatbuffers::GetRoot<flatbuffers::LanguageSet>(buf);
inline const flatbuffers::LanguageSet *GetLanguageSet(const void *buf) {
return flatbuffers::GetRoot<flatbuffers::LanguageSet>(buf);
}
inline const flatbuffers::LanguageSet* GetSizePrefixedLanguageSet(const void* buf)
{
return flatbuffers::GetSizePrefixedRoot<flatbuffers::LanguageSet>(buf);
inline const flatbuffers::LanguageSet *GetSizePrefixedLanguageSet(const void *buf) {
return flatbuffers::GetSizePrefixedRoot<flatbuffers::LanguageSet>(buf);
}
inline bool VerifyLanguageSetBuffer(flatbuffers::Verifier& verifier)
{
return verifier.VerifyBuffer<flatbuffers::LanguageSet>(nullptr);
inline bool VerifyLanguageSetBuffer(
flatbuffers::Verifier &verifier) {
return verifier.VerifyBuffer<flatbuffers::LanguageSet>(nullptr);
}
inline bool VerifySizePrefixedLanguageSetBuffer(flatbuffers::Verifier& verifier)
{
return verifier.VerifySizePrefixedBuffer<flatbuffers::LanguageSet>(nullptr);
inline bool VerifySizePrefixedLanguageSetBuffer(
flatbuffers::Verifier &verifier) {
return verifier.VerifySizePrefixedBuffer<flatbuffers::LanguageSet>(nullptr);
}
inline void FinishLanguageSetBuffer(flatbuffers::FlatBufferBuilder& fbb,
flatbuffers::Offset<flatbuffers::LanguageSet> root)
{
fbb.Finish(root);
inline void FinishLanguageSetBuffer(
flatbuffers::FlatBufferBuilder &fbb,
flatbuffers::Offset<flatbuffers::LanguageSet> root) {
fbb.Finish(root);
}
inline void FinishSizePrefixedLanguageSetBuffer(flatbuffers::FlatBufferBuilder& fbb,
flatbuffers::Offset<flatbuffers::LanguageSet> root)
{
fbb.FinishSizePrefixed(root);
inline void FinishSizePrefixedLanguageSetBuffer(
flatbuffers::FlatBufferBuilder &fbb,
flatbuffers::Offset<flatbuffers::LanguageSet> root) {
fbb.FinishSizePrefixed(root);
}
} // namespace flatbuffers

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,225 +1,258 @@
// automatically generated by the FlatBuffers compiler, do not modify
#ifndef FLATBUFFERS_GENERATED_CSARMATURENODE_FLATBUFFERS_H_
#define FLATBUFFERS_GENERATED_CSARMATURENODE_FLATBUFFERS_H_
#include "flatbuffers/flatbuffers.h"
// Ensure the included flatbuffers.h is the same version as when this file was
// generated, otherwise it may not be compatible.
static_assert(FLATBUFFERS_VERSION_MAJOR == 2 &&
FLATBUFFERS_VERSION_MINOR == 0 &&
FLATBUFFERS_VERSION_REVISION == 8,
"Non-compatible flatbuffers version included");
#include "CSParseBinary_generated.h"
namespace flatbuffers
{
namespace flatbuffers {
struct CSArmatureNodeOption;
struct CSArmatureNodeOptionBuilder;
struct ResourceItemData;
struct ResourceItemDataBuilder;
struct CSArmatureNodeOption FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
{
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
{
VT_NODEOPTIONS = 4,
VT_FILEDATA = 6,
VT_ISLOOP = 8,
VT_ISAUTOPLAY = 10,
VT_CURRENTANIMATIONNAME = 12,
VT_CURRENTARMATURENAME = 14,
VT_TIMESCALE = 16,
VT_ARMATURESCALE = 18
};
const WidgetOptions* nodeOptions() const { return GetPointer<const WidgetOptions*>(VT_NODEOPTIONS); }
const ResourceItemData* fileData() const { return GetPointer<const ResourceItemData*>(VT_FILEDATA); }
bool isLoop() const { return GetField<uint8_t>(VT_ISLOOP, 1) != 0; }
bool isAutoPlay() const { return GetField<uint8_t>(VT_ISAUTOPLAY, 1) != 0; }
const flatbuffers::String* currentAnimationName() const
{
return GetPointer<const flatbuffers::String*>(VT_CURRENTANIMATIONNAME);
}
const flatbuffers::String* currentArmatureName() const
{
return GetPointer<const flatbuffers::String*>(VT_CURRENTARMATURENAME);
}
float timeScale() const { return GetField<float>(VT_TIMESCALE, 0.0f); }
float armatureScale() const { return GetField<float>(VT_ARMATURESCALE, 0.0f); }
bool Verify(flatbuffers::Verifier& verifier) const
{
return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NODEOPTIONS) &&
verifier.VerifyTable(nodeOptions()) && VerifyOffset(verifier, VT_FILEDATA) &&
verifier.VerifyTable(fileData()) && VerifyField<uint8_t>(verifier, VT_ISLOOP) &&
VerifyField<uint8_t>(verifier, VT_ISAUTOPLAY) && VerifyOffset(verifier, VT_CURRENTANIMATIONNAME) &&
verifier.VerifyString(currentAnimationName()) && VerifyOffset(verifier, VT_CURRENTARMATURENAME) &&
verifier.VerifyString(currentArmatureName()) && VerifyField<float>(verifier, VT_TIMESCALE) &&
VerifyField<float>(verifier, VT_ARMATURESCALE) && verifier.EndTable();
}
struct CSArmatureNodeOption FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef CSArmatureNodeOptionBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_NODEOPTIONS = 4,
VT_FILEDATA = 6,
VT_ISLOOP = 8,
VT_ISAUTOPLAY = 10,
VT_CURRENTANIMATIONNAME = 12,
VT_CURRENTARMATURENAME = 14,
VT_TIMESCALE = 16,
VT_ARMATURESCALE = 18
};
const flatbuffers::WidgetOptions *nodeOptions() const {
return GetPointer<const flatbuffers::WidgetOptions *>(VT_NODEOPTIONS);
}
const flatbuffers::ResourceItemData *fileData() const {
return GetPointer<const flatbuffers::ResourceItemData *>(VT_FILEDATA);
}
bool isLoop() const {
return GetField<uint8_t>(VT_ISLOOP, 1) != 0;
}
bool isAutoPlay() const {
return GetField<uint8_t>(VT_ISAUTOPLAY, 1) != 0;
}
const flatbuffers::String *currentAnimationName() const {
return GetPointer<const flatbuffers::String *>(VT_CURRENTANIMATIONNAME);
}
const flatbuffers::String *currentArmatureName() const {
return GetPointer<const flatbuffers::String *>(VT_CURRENTARMATURENAME);
}
float timeScale() const {
return GetField<float>(VT_TIMESCALE, 0.0f);
}
float armatureScale() const {
return GetField<float>(VT_ARMATURESCALE, 0.0f);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_NODEOPTIONS) &&
verifier.VerifyTable(nodeOptions()) &&
VerifyOffset(verifier, VT_FILEDATA) &&
verifier.VerifyTable(fileData()) &&
VerifyField<uint8_t>(verifier, VT_ISLOOP, 1) &&
VerifyField<uint8_t>(verifier, VT_ISAUTOPLAY, 1) &&
VerifyOffset(verifier, VT_CURRENTANIMATIONNAME) &&
verifier.VerifyString(currentAnimationName()) &&
VerifyOffset(verifier, VT_CURRENTARMATURENAME) &&
verifier.VerifyString(currentArmatureName()) &&
VerifyField<float>(verifier, VT_TIMESCALE, 4) &&
VerifyField<float>(verifier, VT_ARMATURESCALE, 4) &&
verifier.EndTable();
}
};
struct CSArmatureNodeOptionBuilder
{
flatbuffers::FlatBufferBuilder& fbb_;
flatbuffers::uoffset_t start_;
void add_nodeOptions(flatbuffers::Offset<WidgetOptions> nodeOptions)
{
fbb_.AddOffset(CSArmatureNodeOption::VT_NODEOPTIONS, nodeOptions);
}
void add_fileData(flatbuffers::Offset<ResourceItemData> fileData)
{
fbb_.AddOffset(CSArmatureNodeOption::VT_FILEDATA, fileData);
}
void add_isLoop(bool isLoop)
{
fbb_.AddElement<uint8_t>(CSArmatureNodeOption::VT_ISLOOP, static_cast<uint8_t>(isLoop), 1);
}
void add_isAutoPlay(bool isAutoPlay)
{
fbb_.AddElement<uint8_t>(CSArmatureNodeOption::VT_ISAUTOPLAY, static_cast<uint8_t>(isAutoPlay), 1);
}
void add_currentAnimationName(flatbuffers::Offset<flatbuffers::String> currentAnimationName)
{
fbb_.AddOffset(CSArmatureNodeOption::VT_CURRENTANIMATIONNAME, currentAnimationName);
}
void add_currentArmatureName(flatbuffers::Offset<flatbuffers::String> currentArmatureName)
{
fbb_.AddOffset(CSArmatureNodeOption::VT_CURRENTARMATURENAME, currentArmatureName);
}
void add_timeScale(float timeScale) { fbb_.AddElement<float>(CSArmatureNodeOption::VT_TIMESCALE, timeScale, 0.0f); }
void add_armatureScale(float armatureScale)
{
fbb_.AddElement<float>(CSArmatureNodeOption::VT_ARMATURESCALE, armatureScale, 0.0f);
}
explicit CSArmatureNodeOptionBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb)
{
start_ = fbb_.StartTable();
}
CSArmatureNodeOptionBuilder& operator=(const CSArmatureNodeOptionBuilder&);
flatbuffers::Offset<CSArmatureNodeOption> Finish()
{
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<CSArmatureNodeOption>(end);
return o;
}
struct CSArmatureNodeOptionBuilder {
typedef CSArmatureNodeOption Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_nodeOptions(flatbuffers::Offset<flatbuffers::WidgetOptions> nodeOptions) {
fbb_.AddOffset(CSArmatureNodeOption::VT_NODEOPTIONS, nodeOptions);
}
void add_fileData(flatbuffers::Offset<flatbuffers::ResourceItemData> fileData) {
fbb_.AddOffset(CSArmatureNodeOption::VT_FILEDATA, fileData);
}
void add_isLoop(bool isLoop) {
fbb_.AddElement<uint8_t>(CSArmatureNodeOption::VT_ISLOOP, static_cast<uint8_t>(isLoop), 1);
}
void add_isAutoPlay(bool isAutoPlay) {
fbb_.AddElement<uint8_t>(CSArmatureNodeOption::VT_ISAUTOPLAY, static_cast<uint8_t>(isAutoPlay), 1);
}
void add_currentAnimationName(flatbuffers::Offset<flatbuffers::String> currentAnimationName) {
fbb_.AddOffset(CSArmatureNodeOption::VT_CURRENTANIMATIONNAME, currentAnimationName);
}
void add_currentArmatureName(flatbuffers::Offset<flatbuffers::String> currentArmatureName) {
fbb_.AddOffset(CSArmatureNodeOption::VT_CURRENTARMATURENAME, currentArmatureName);
}
void add_timeScale(float timeScale) {
fbb_.AddElement<float>(CSArmatureNodeOption::VT_TIMESCALE, timeScale, 0.0f);
}
void add_armatureScale(float armatureScale) {
fbb_.AddElement<float>(CSArmatureNodeOption::VT_ARMATURESCALE, armatureScale, 0.0f);
}
explicit CSArmatureNodeOptionBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<CSArmatureNodeOption> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<CSArmatureNodeOption>(end);
return o;
}
};
inline flatbuffers::Offset<CSArmatureNodeOption> CreateCSArmatureNodeOption(
flatbuffers::FlatBufferBuilder& _fbb,
flatbuffers::Offset<WidgetOptions> nodeOptions = 0,
flatbuffers::Offset<ResourceItemData> fileData = 0,
bool isLoop = true,
bool isAutoPlay = true,
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::WidgetOptions> nodeOptions = 0,
flatbuffers::Offset<flatbuffers::ResourceItemData> fileData = 0,
bool isLoop = true,
bool isAutoPlay = true,
flatbuffers::Offset<flatbuffers::String> currentAnimationName = 0,
flatbuffers::Offset<flatbuffers::String> currentArmatureName = 0,
float timeScale = 0.0f,
float armatureScale = 0.0f)
{
CSArmatureNodeOptionBuilder builder_(_fbb);
builder_.add_armatureScale(armatureScale);
builder_.add_timeScale(timeScale);
builder_.add_currentArmatureName(currentArmatureName);
builder_.add_currentAnimationName(currentAnimationName);
builder_.add_fileData(fileData);
builder_.add_nodeOptions(nodeOptions);
builder_.add_isAutoPlay(isAutoPlay);
builder_.add_isLoop(isLoop);
return builder_.Finish();
flatbuffers::Offset<flatbuffers::String> currentArmatureName = 0,
float timeScale = 0.0f,
float armatureScale = 0.0f) {
CSArmatureNodeOptionBuilder builder_(_fbb);
builder_.add_armatureScale(armatureScale);
builder_.add_timeScale(timeScale);
builder_.add_currentArmatureName(currentArmatureName);
builder_.add_currentAnimationName(currentAnimationName);
builder_.add_fileData(fileData);
builder_.add_nodeOptions(nodeOptions);
builder_.add_isAutoPlay(isAutoPlay);
builder_.add_isLoop(isLoop);
return builder_.Finish();
}
inline flatbuffers::Offset<CSArmatureNodeOption> CreateCSArmatureNodeOptionDirect(
flatbuffers::FlatBufferBuilder& _fbb,
flatbuffers::Offset<WidgetOptions> nodeOptions = 0,
flatbuffers::Offset<ResourceItemData> fileData = 0,
bool isLoop = true,
bool isAutoPlay = true,
const char* currentAnimationName = nullptr,
const char* currentArmatureName = nullptr,
float timeScale = 0.0f,
float armatureScale = 0.0f)
{
auto currentAnimationName__ = currentAnimationName ? _fbb.CreateString(currentAnimationName) : 0;
auto currentArmatureName__ = currentArmatureName ? _fbb.CreateString(currentArmatureName) : 0;
return flatbuffers::CreateCSArmatureNodeOption(_fbb, nodeOptions, fileData, isLoop, isAutoPlay,
currentAnimationName__, currentArmatureName__, timeScale,
armatureScale);
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::WidgetOptions> nodeOptions = 0,
flatbuffers::Offset<flatbuffers::ResourceItemData> fileData = 0,
bool isLoop = true,
bool isAutoPlay = true,
const char *currentAnimationName = nullptr,
const char *currentArmatureName = nullptr,
float timeScale = 0.0f,
float armatureScale = 0.0f) {
auto currentAnimationName__ = currentAnimationName ? _fbb.CreateString(currentAnimationName) : 0;
auto currentArmatureName__ = currentArmatureName ? _fbb.CreateString(currentArmatureName) : 0;
return flatbuffers::CreateCSArmatureNodeOption(
_fbb,
nodeOptions,
fileData,
isLoop,
isAutoPlay,
currentAnimationName__,
currentArmatureName__,
timeScale,
armatureScale);
}
struct ResourceItemData FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
{
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
{
VT_TYPE = 4,
VT_PATH = 6
};
int32_t type() const { return GetField<int32_t>(VT_TYPE, 0); }
const flatbuffers::String* path() const { return GetPointer<const flatbuffers::String*>(VT_PATH); }
bool Verify(flatbuffers::Verifier& verifier) const
{
return VerifyTableStart(verifier) && VerifyField<int32_t>(verifier, VT_TYPE) &&
VerifyOffset(verifier, VT_PATH) && verifier.VerifyString(path()) && verifier.EndTable();
}
struct ResourceItemData FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef ResourceItemDataBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_TYPE = 4,
VT_PATH = 6
};
int32_t type() const {
return GetField<int32_t>(VT_TYPE, 0);
}
const flatbuffers::String *path() const {
return GetPointer<const flatbuffers::String *>(VT_PATH);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<int32_t>(verifier, VT_TYPE, 4) &&
VerifyOffset(verifier, VT_PATH) &&
verifier.VerifyString(path()) &&
verifier.EndTable();
}
};
struct ResourceItemDataBuilder
{
flatbuffers::FlatBufferBuilder& fbb_;
flatbuffers::uoffset_t start_;
void add_type(int32_t type) { fbb_.AddElement<int32_t>(ResourceItemData::VT_TYPE, type, 0); }
void add_path(flatbuffers::Offset<flatbuffers::String> path) { fbb_.AddOffset(ResourceItemData::VT_PATH, path); }
explicit ResourceItemDataBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
ResourceItemDataBuilder& operator=(const ResourceItemDataBuilder&);
flatbuffers::Offset<ResourceItemData> Finish()
{
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<ResourceItemData>(end);
return o;
}
struct ResourceItemDataBuilder {
typedef ResourceItemData Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_type(int32_t type) {
fbb_.AddElement<int32_t>(ResourceItemData::VT_TYPE, type, 0);
}
void add_path(flatbuffers::Offset<flatbuffers::String> path) {
fbb_.AddOffset(ResourceItemData::VT_PATH, path);
}
explicit ResourceItemDataBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<ResourceItemData> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<ResourceItemData>(end);
return o;
}
};
inline flatbuffers::Offset<ResourceItemData> CreateResourceItemData(flatbuffers::FlatBufferBuilder& _fbb,
int32_t type = 0,
flatbuffers::Offset<flatbuffers::String> path = 0)
{
ResourceItemDataBuilder builder_(_fbb);
builder_.add_path(path);
builder_.add_type(type);
return builder_.Finish();
inline flatbuffers::Offset<ResourceItemData> CreateResourceItemData(
flatbuffers::FlatBufferBuilder &_fbb,
int32_t type = 0,
flatbuffers::Offset<flatbuffers::String> path = 0) {
ResourceItemDataBuilder builder_(_fbb);
builder_.add_path(path);
builder_.add_type(type);
return builder_.Finish();
}
inline flatbuffers::Offset<ResourceItemData> CreateResourceItemDataDirect(flatbuffers::FlatBufferBuilder& _fbb,
int32_t type = 0,
const char* path = nullptr)
{
auto path__ = path ? _fbb.CreateString(path) : 0;
return flatbuffers::CreateResourceItemData(_fbb, type, path__);
inline flatbuffers::Offset<ResourceItemData> CreateResourceItemDataDirect(
flatbuffers::FlatBufferBuilder &_fbb,
int32_t type = 0,
const char *path = nullptr) {
auto path__ = path ? _fbb.CreateString(path) : 0;
return flatbuffers::CreateResourceItemData(
_fbb,
type,
path__);
}
inline const flatbuffers::CSArmatureNodeOption* GetCSArmatureNodeOption(const void* buf)
{
return flatbuffers::GetRoot<flatbuffers::CSArmatureNodeOption>(buf);
inline const flatbuffers::CSArmatureNodeOption *GetCSArmatureNodeOption(const void *buf) {
return flatbuffers::GetRoot<flatbuffers::CSArmatureNodeOption>(buf);
}
inline const flatbuffers::CSArmatureNodeOption* GetSizePrefixedCSArmatureNodeOption(const void* buf)
{
return flatbuffers::GetSizePrefixedRoot<flatbuffers::CSArmatureNodeOption>(buf);
inline const flatbuffers::CSArmatureNodeOption *GetSizePrefixedCSArmatureNodeOption(const void *buf) {
return flatbuffers::GetSizePrefixedRoot<flatbuffers::CSArmatureNodeOption>(buf);
}
inline bool VerifyCSArmatureNodeOptionBuffer(flatbuffers::Verifier& verifier)
{
return verifier.VerifyBuffer<flatbuffers::CSArmatureNodeOption>(nullptr);
inline bool VerifyCSArmatureNodeOptionBuffer(
flatbuffers::Verifier &verifier) {
return verifier.VerifyBuffer<flatbuffers::CSArmatureNodeOption>(nullptr);
}
inline bool VerifySizePrefixedCSArmatureNodeOptionBuffer(flatbuffers::Verifier& verifier)
{
return verifier.VerifySizePrefixedBuffer<flatbuffers::CSArmatureNodeOption>(nullptr);
inline bool VerifySizePrefixedCSArmatureNodeOptionBuffer(
flatbuffers::Verifier &verifier) {
return verifier.VerifySizePrefixedBuffer<flatbuffers::CSArmatureNodeOption>(nullptr);
}
inline void FinishCSArmatureNodeOptionBuffer(flatbuffers::FlatBufferBuilder& fbb,
flatbuffers::Offset<flatbuffers::CSArmatureNodeOption> root)
{
fbb.Finish(root);
inline void FinishCSArmatureNodeOptionBuffer(
flatbuffers::FlatBufferBuilder &fbb,
flatbuffers::Offset<flatbuffers::CSArmatureNodeOption> root) {
fbb.Finish(root);
}
inline void FinishSizePrefixedCSArmatureNodeOptionBuffer(flatbuffers::FlatBufferBuilder& fbb,
flatbuffers::Offset<flatbuffers::CSArmatureNodeOption> root)
{
fbb.FinishSizePrefixed(root);
inline void FinishSizePrefixedCSArmatureNodeOptionBuffer(
flatbuffers::FlatBufferBuilder &fbb,
flatbuffers::Offset<flatbuffers::CSArmatureNodeOption> root) {
fbb.FinishSizePrefixed(root);
}
} // namespace flatbuffers

View File

@ -1,88 +1,115 @@
// automatically generated by the FlatBuffers compiler, do not modify
#ifndef FLATBUFFERS_GENERATED_CSBONEBINARY_FLATBUFFERS_H_
#define FLATBUFFERS_GENERATED_CSBONEBINARY_FLATBUFFERS_H_
#include "flatbuffers/flatbuffers.h"
// Ensure the included flatbuffers.h is the same version as when this file was
// generated, otherwise it may not be compatible.
static_assert(FLATBUFFERS_VERSION_MAJOR == 2 &&
FLATBUFFERS_VERSION_MINOR == 0 &&
FLATBUFFERS_VERSION_REVISION == 8,
"Non-compatible flatbuffers version included");
#include "CSParseBinary_generated.h"
namespace flatbuffers
{
namespace flatbuffers {
struct BoneOptions;
struct BoneOptionsBuilder;
struct BoneOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
{
enum
{
VT_NODEOPTIONS = 4,
VT_LENGTH = 6,
VT_BLENDFUNC = 8
};
const flatbuffers::WidgetOptions* nodeOptions() const
{
return GetPointer<const flatbuffers::WidgetOptions*>(VT_NODEOPTIONS);
}
float length() const { return GetField<float>(VT_LENGTH, 0.0f); }
const flatbuffers::BlendFunc* blendFunc() const { return GetStruct<const flatbuffers::BlendFunc*>(VT_BLENDFUNC); }
bool Verify(flatbuffers::Verifier& verifier) const
{
return VerifyTableStart(verifier) && VerifyField<flatbuffers::uoffset_t>(verifier, VT_NODEOPTIONS) &&
verifier.VerifyTable(nodeOptions()) && VerifyField<float>(verifier, VT_LENGTH) &&
VerifyField<flatbuffers::BlendFunc>(verifier, VT_BLENDFUNC) && verifier.EndTable();
}
struct BoneOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef BoneOptionsBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_NODEOPTIONS = 4,
VT_LENGTH = 6,
VT_BLENDFUNC = 8
};
const flatbuffers::WidgetOptions *nodeOptions() const {
return GetPointer<const flatbuffers::WidgetOptions *>(VT_NODEOPTIONS);
}
float length() const {
return GetField<float>(VT_LENGTH, 0.0f);
}
const flatbuffers::BlendFunc *blendFunc() const {
return GetStruct<const flatbuffers::BlendFunc *>(VT_BLENDFUNC);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_NODEOPTIONS) &&
verifier.VerifyTable(nodeOptions()) &&
VerifyField<float>(verifier, VT_LENGTH, 4) &&
VerifyField<flatbuffers::BlendFunc>(verifier, VT_BLENDFUNC, 4) &&
verifier.EndTable();
}
};
struct BoneOptionsBuilder
{
flatbuffers::FlatBufferBuilder& fbb_;
flatbuffers::uoffset_t start_;
void add_nodeOptions(flatbuffers::Offset<flatbuffers::WidgetOptions> nodeOptions)
{
fbb_.AddOffset(BoneOptions::VT_NODEOPTIONS, nodeOptions);
}
void add_length(float length) { fbb_.AddElement<float>(BoneOptions::VT_LENGTH, length, 0.0f); }
void add_blendFunc(const flatbuffers::BlendFunc* blendFunc)
{
fbb_.AddStruct(BoneOptions::VT_BLENDFUNC, blendFunc);
}
BoneOptionsBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
BoneOptionsBuilder& operator=(const BoneOptionsBuilder&);
flatbuffers::Offset<BoneOptions> Finish()
{
auto o = flatbuffers::Offset<BoneOptions>(fbb_.EndTable(start_, 3));
return o;
}
struct BoneOptionsBuilder {
typedef BoneOptions Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_nodeOptions(flatbuffers::Offset<flatbuffers::WidgetOptions> nodeOptions) {
fbb_.AddOffset(BoneOptions::VT_NODEOPTIONS, nodeOptions);
}
void add_length(float length) {
fbb_.AddElement<float>(BoneOptions::VT_LENGTH, length, 0.0f);
}
void add_blendFunc(const flatbuffers::BlendFunc *blendFunc) {
fbb_.AddStruct(BoneOptions::VT_BLENDFUNC, blendFunc);
}
explicit BoneOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<BoneOptions> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<BoneOptions>(end);
return o;
}
};
inline flatbuffers::Offset<BoneOptions> CreateBoneOptions(
flatbuffers::FlatBufferBuilder& _fbb,
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::WidgetOptions> nodeOptions = 0,
float length = 0.0f,
const flatbuffers::BlendFunc* blendFunc = 0)
{
BoneOptionsBuilder builder_(_fbb);
builder_.add_blendFunc(blendFunc);
builder_.add_length(length);
builder_.add_nodeOptions(nodeOptions);
return builder_.Finish();
float length = 0.0f,
const flatbuffers::BlendFunc *blendFunc = nullptr) {
BoneOptionsBuilder builder_(_fbb);
builder_.add_blendFunc(blendFunc);
builder_.add_length(length);
builder_.add_nodeOptions(nodeOptions);
return builder_.Finish();
}
inline const flatbuffers::BoneOptions* GetBoneOptions(const void* buf)
{
return flatbuffers::GetRoot<flatbuffers::BoneOptions>(buf);
inline const flatbuffers::BoneOptions *GetBoneOptions(const void *buf) {
return flatbuffers::GetRoot<flatbuffers::BoneOptions>(buf);
}
inline bool VerifyBoneOptionsBuffer(flatbuffers::Verifier& verifier)
{
return verifier.VerifyBuffer<flatbuffers::BoneOptions>(nullptr);
inline const flatbuffers::BoneOptions *GetSizePrefixedBoneOptions(const void *buf) {
return flatbuffers::GetSizePrefixedRoot<flatbuffers::BoneOptions>(buf);
}
inline void FinishBoneOptionsBuffer(flatbuffers::FlatBufferBuilder& fbb,
flatbuffers::Offset<flatbuffers::BoneOptions> root)
{
fbb.Finish(root);
inline bool VerifyBoneOptionsBuffer(
flatbuffers::Verifier &verifier) {
return verifier.VerifyBuffer<flatbuffers::BoneOptions>(nullptr);
}
inline bool VerifySizePrefixedBoneOptionsBuffer(
flatbuffers::Verifier &verifier) {
return verifier.VerifySizePrefixedBuffer<flatbuffers::BoneOptions>(nullptr);
}
inline void FinishBoneOptionsBuffer(
flatbuffers::FlatBufferBuilder &fbb,
flatbuffers::Offset<flatbuffers::BoneOptions> root) {
fbb.Finish(root);
}
inline void FinishSizePrefixedBoneOptionsBuffer(
flatbuffers::FlatBufferBuilder &fbb,
flatbuffers::Offset<flatbuffers::BoneOptions> root) {
fbb.FinishSizePrefixed(root);
}
} // namespace flatbuffers

View File

@ -1,351 +1,415 @@
// automatically generated by the FlatBuffers compiler, do not modify
#ifndef FLATBUFFERS_GENERATED_CSTABCONTROL_FLATBUFFERS_H_
#define FLATBUFFERS_GENERATED_CSTABCONTROL_FLATBUFFERS_H_
#include "flatbuffers/flatbuffers.h"
// Ensure the included flatbuffers.h is the same version as when this file was
// generated, otherwise it may not be compatible.
static_assert(FLATBUFFERS_VERSION_MAJOR == 2 &&
FLATBUFFERS_VERSION_MINOR == 0 &&
FLATBUFFERS_VERSION_REVISION == 8,
"Non-compatible flatbuffers version included");
#include "CSParseBinary_generated.h"
namespace flatbuffers
{
namespace flatbuffers {
struct TabControlOption;
struct TabControlOptionBuilder;
struct TabHeaderOption;
struct TabHeaderOptionBuilder;
struct TabItemOption;
struct TabItemOptionBuilder;
struct TabControlOption FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
{
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
{
VT_NODEOPTIONS = 4,
VT_HEADERPLACE = 6,
VT_HEADERWIDTH = 8,
VT_HEADERHEIGHT = 10,
VT_SELECTEDTABZOOM = 12,
VT_SELECTEDTABINDEX = 14,
VT_IGNOREHEADERTEXTURESIZE = 16,
VT_TABITEMS = 18
};
const WidgetOptions* nodeOptions() const { return GetPointer<const WidgetOptions*>(VT_NODEOPTIONS); }
int32_t headerPlace() const { return GetField<int32_t>(VT_HEADERPLACE, 0); }
int32_t headerWidth() const { return GetField<int32_t>(VT_HEADERWIDTH, 0); }
int32_t headerHeight() const { return GetField<int32_t>(VT_HEADERHEIGHT, 0); }
float selectedTabZoom() const { return GetField<float>(VT_SELECTEDTABZOOM, 0.0f); }
int32_t selectedTabIndex() const { return GetField<int32_t>(VT_SELECTEDTABINDEX, 0); }
uint8_t ignoreHeaderTextureSize() const { return GetField<uint8_t>(VT_IGNOREHEADERTEXTURESIZE, 0); }
const flatbuffers::Vector<flatbuffers::Offset<TabItemOption>>* tabItems() const
{
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<TabItemOption>>*>(VT_TABITEMS);
}
bool Verify(flatbuffers::Verifier& verifier) const
{
return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NODEOPTIONS) &&
verifier.VerifyTable(nodeOptions()) && VerifyField<int32_t>(verifier, VT_HEADERPLACE) &&
VerifyField<int32_t>(verifier, VT_HEADERWIDTH) && VerifyField<int32_t>(verifier, VT_HEADERHEIGHT) &&
VerifyField<float>(verifier, VT_SELECTEDTABZOOM) &&
VerifyField<int32_t>(verifier, VT_SELECTEDTABINDEX) &&
VerifyField<uint8_t>(verifier, VT_IGNOREHEADERTEXTURESIZE) && VerifyOffset(verifier, VT_TABITEMS) &&
verifier.VerifyVector(tabItems()) && verifier.VerifyVectorOfTables(tabItems()) && verifier.EndTable();
}
struct TabControlOption FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef TabControlOptionBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_NODEOPTIONS = 4,
VT_HEADERPLACE = 6,
VT_HEADERWIDTH = 8,
VT_HEADERHEIGHT = 10,
VT_SELECTEDTABZOOM = 12,
VT_SELECTEDTABINDEX = 14,
VT_IGNOREHEADERTEXTURESIZE = 16,
VT_TABITEMS = 18
};
const flatbuffers::WidgetOptions *nodeOptions() const {
return GetPointer<const flatbuffers::WidgetOptions *>(VT_NODEOPTIONS);
}
int32_t headerPlace() const {
return GetField<int32_t>(VT_HEADERPLACE, 0);
}
int32_t headerWidth() const {
return GetField<int32_t>(VT_HEADERWIDTH, 0);
}
int32_t headerHeight() const {
return GetField<int32_t>(VT_HEADERHEIGHT, 0);
}
float selectedTabZoom() const {
return GetField<float>(VT_SELECTEDTABZOOM, 0.0f);
}
int32_t selectedTabIndex() const {
return GetField<int32_t>(VT_SELECTEDTABINDEX, 0);
}
uint8_t ignoreHeaderTextureSize() const {
return GetField<uint8_t>(VT_IGNOREHEADERTEXTURESIZE, 0);
}
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::TabItemOption>> *tabItems() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::TabItemOption>> *>(VT_TABITEMS);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_NODEOPTIONS) &&
verifier.VerifyTable(nodeOptions()) &&
VerifyField<int32_t>(verifier, VT_HEADERPLACE, 4) &&
VerifyField<int32_t>(verifier, VT_HEADERWIDTH, 4) &&
VerifyField<int32_t>(verifier, VT_HEADERHEIGHT, 4) &&
VerifyField<float>(verifier, VT_SELECTEDTABZOOM, 4) &&
VerifyField<int32_t>(verifier, VT_SELECTEDTABINDEX, 4) &&
VerifyField<uint8_t>(verifier, VT_IGNOREHEADERTEXTURESIZE, 1) &&
VerifyOffset(verifier, VT_TABITEMS) &&
verifier.VerifyVector(tabItems()) &&
verifier.VerifyVectorOfTables(tabItems()) &&
verifier.EndTable();
}
};
struct TabControlOptionBuilder
{
flatbuffers::FlatBufferBuilder& fbb_;
flatbuffers::uoffset_t start_;
void add_nodeOptions(flatbuffers::Offset<WidgetOptions> nodeOptions)
{
fbb_.AddOffset(TabControlOption::VT_NODEOPTIONS, nodeOptions);
}
void add_headerPlace(int32_t headerPlace)
{
fbb_.AddElement<int32_t>(TabControlOption::VT_HEADERPLACE, headerPlace, 0);
}
void add_headerWidth(int32_t headerWidth)
{
fbb_.AddElement<int32_t>(TabControlOption::VT_HEADERWIDTH, headerWidth, 0);
}
void add_headerHeight(int32_t headerHeight)
{
fbb_.AddElement<int32_t>(TabControlOption::VT_HEADERHEIGHT, headerHeight, 0);
}
void add_selectedTabZoom(float selectedTabZoom)
{
fbb_.AddElement<float>(TabControlOption::VT_SELECTEDTABZOOM, selectedTabZoom, 0.0f);
}
void add_selectedTabIndex(int32_t selectedTabIndex)
{
fbb_.AddElement<int32_t>(TabControlOption::VT_SELECTEDTABINDEX, selectedTabIndex, 0);
}
void add_ignoreHeaderTextureSize(uint8_t ignoreHeaderTextureSize)
{
fbb_.AddElement<uint8_t>(TabControlOption::VT_IGNOREHEADERTEXTURESIZE, ignoreHeaderTextureSize, 0);
}
void add_tabItems(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<TabItemOption>>> tabItems)
{
fbb_.AddOffset(TabControlOption::VT_TABITEMS, tabItems);
}
explicit TabControlOptionBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
TabControlOptionBuilder& operator=(const TabControlOptionBuilder&);
flatbuffers::Offset<TabControlOption> Finish()
{
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<TabControlOption>(end);
return o;
}
struct TabControlOptionBuilder {
typedef TabControlOption Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_nodeOptions(flatbuffers::Offset<flatbuffers::WidgetOptions> nodeOptions) {
fbb_.AddOffset(TabControlOption::VT_NODEOPTIONS, nodeOptions);
}
void add_headerPlace(int32_t headerPlace) {
fbb_.AddElement<int32_t>(TabControlOption::VT_HEADERPLACE, headerPlace, 0);
}
void add_headerWidth(int32_t headerWidth) {
fbb_.AddElement<int32_t>(TabControlOption::VT_HEADERWIDTH, headerWidth, 0);
}
void add_headerHeight(int32_t headerHeight) {
fbb_.AddElement<int32_t>(TabControlOption::VT_HEADERHEIGHT, headerHeight, 0);
}
void add_selectedTabZoom(float selectedTabZoom) {
fbb_.AddElement<float>(TabControlOption::VT_SELECTEDTABZOOM, selectedTabZoom, 0.0f);
}
void add_selectedTabIndex(int32_t selectedTabIndex) {
fbb_.AddElement<int32_t>(TabControlOption::VT_SELECTEDTABINDEX, selectedTabIndex, 0);
}
void add_ignoreHeaderTextureSize(uint8_t ignoreHeaderTextureSize) {
fbb_.AddElement<uint8_t>(TabControlOption::VT_IGNOREHEADERTEXTURESIZE, ignoreHeaderTextureSize, 0);
}
void add_tabItems(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::TabItemOption>>> tabItems) {
fbb_.AddOffset(TabControlOption::VT_TABITEMS, tabItems);
}
explicit TabControlOptionBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<TabControlOption> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<TabControlOption>(end);
return o;
}
};
inline flatbuffers::Offset<TabControlOption> CreateTabControlOption(
flatbuffers::FlatBufferBuilder& _fbb,
flatbuffers::Offset<WidgetOptions> nodeOptions = 0,
int32_t headerPlace = 0,
int32_t headerWidth = 0,
int32_t headerHeight = 0,
float selectedTabZoom = 0.0f,
int32_t selectedTabIndex = 0,
uint8_t ignoreHeaderTextureSize = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<TabItemOption>>> tabItems = 0)
{
TabControlOptionBuilder builder_(_fbb);
builder_.add_tabItems(tabItems);
builder_.add_selectedTabIndex(selectedTabIndex);
builder_.add_selectedTabZoom(selectedTabZoom);
builder_.add_headerHeight(headerHeight);
builder_.add_headerWidth(headerWidth);
builder_.add_headerPlace(headerPlace);
builder_.add_nodeOptions(nodeOptions);
builder_.add_ignoreHeaderTextureSize(ignoreHeaderTextureSize);
return builder_.Finish();
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::WidgetOptions> nodeOptions = 0,
int32_t headerPlace = 0,
int32_t headerWidth = 0,
int32_t headerHeight = 0,
float selectedTabZoom = 0.0f,
int32_t selectedTabIndex = 0,
uint8_t ignoreHeaderTextureSize = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::TabItemOption>>> tabItems = 0) {
TabControlOptionBuilder builder_(_fbb);
builder_.add_tabItems(tabItems);
builder_.add_selectedTabIndex(selectedTabIndex);
builder_.add_selectedTabZoom(selectedTabZoom);
builder_.add_headerHeight(headerHeight);
builder_.add_headerWidth(headerWidth);
builder_.add_headerPlace(headerPlace);
builder_.add_nodeOptions(nodeOptions);
builder_.add_ignoreHeaderTextureSize(ignoreHeaderTextureSize);
return builder_.Finish();
}
inline flatbuffers::Offset<TabControlOption> CreateTabControlOptionDirect(
flatbuffers::FlatBufferBuilder& _fbb,
flatbuffers::Offset<WidgetOptions> nodeOptions = 0,
int32_t headerPlace = 0,
int32_t headerWidth = 0,
int32_t headerHeight = 0,
float selectedTabZoom = 0.0f,
int32_t selectedTabIndex = 0,
uint8_t ignoreHeaderTextureSize = 0,
const std::vector<flatbuffers::Offset<TabItemOption>>* tabItems = nullptr)
{
auto tabItems__ = tabItems ? _fbb.CreateVector<flatbuffers::Offset<TabItemOption>>(*tabItems) : 0;
return flatbuffers::CreateTabControlOption(_fbb, nodeOptions, headerPlace, headerWidth, headerHeight,
selectedTabZoom, selectedTabIndex, ignoreHeaderTextureSize, tabItems__);
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::WidgetOptions> nodeOptions = 0,
int32_t headerPlace = 0,
int32_t headerWidth = 0,
int32_t headerHeight = 0,
float selectedTabZoom = 0.0f,
int32_t selectedTabIndex = 0,
uint8_t ignoreHeaderTextureSize = 0,
const std::vector<flatbuffers::Offset<flatbuffers::TabItemOption>> *tabItems = nullptr) {
auto tabItems__ = tabItems ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::TabItemOption>>(*tabItems) : 0;
return flatbuffers::CreateTabControlOption(
_fbb,
nodeOptions,
headerPlace,
headerWidth,
headerHeight,
selectedTabZoom,
selectedTabIndex,
ignoreHeaderTextureSize,
tabItems__);
}
struct TabHeaderOption FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
{
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
{
VT_NODEOPTIONS = 4,
VT_FONTRES = 6,
VT_FONTSIZE = 8,
VT_TITLETEXT = 10,
VT_TEXTCOLOR = 12,
VT_NORMALBACKFILE = 14,
VT_PRESSBACKFILE = 16,
VT_DISABLEBACKFILE = 18,
VT_CROSSNORMALFILE = 20,
VT_CROSSDISABLEFILE = 22
};
const WidgetOptions* nodeOptions() const { return GetPointer<const WidgetOptions*>(VT_NODEOPTIONS); }
const ResourceData* fontRes() const { return GetPointer<const ResourceData*>(VT_FONTRES); }
int32_t fontSize() const { return GetField<int32_t>(VT_FONTSIZE, 0); }
const flatbuffers::String* titleText() const { return GetPointer<const flatbuffers::String*>(VT_TITLETEXT); }
const Color* textColor() const { return GetStruct<const Color*>(VT_TEXTCOLOR); }
const ResourceData* normalBackFile() const { return GetPointer<const ResourceData*>(VT_NORMALBACKFILE); }
const ResourceData* pressBackFile() const { return GetPointer<const ResourceData*>(VT_PRESSBACKFILE); }
const ResourceData* disableBackFile() const { return GetPointer<const ResourceData*>(VT_DISABLEBACKFILE); }
const ResourceData* crossNormalFile() const { return GetPointer<const ResourceData*>(VT_CROSSNORMALFILE); }
const ResourceData* crossDisableFile() const { return GetPointer<const ResourceData*>(VT_CROSSDISABLEFILE); }
bool Verify(flatbuffers::Verifier& verifier) const
{
return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NODEOPTIONS) &&
verifier.VerifyTable(nodeOptions()) && VerifyOffset(verifier, VT_FONTRES) &&
verifier.VerifyTable(fontRes()) && VerifyField<int32_t>(verifier, VT_FONTSIZE) &&
VerifyOffset(verifier, VT_TITLETEXT) && verifier.VerifyString(titleText()) &&
VerifyField<Color>(verifier, VT_TEXTCOLOR) && VerifyOffset(verifier, VT_NORMALBACKFILE) &&
verifier.VerifyTable(normalBackFile()) && VerifyOffset(verifier, VT_PRESSBACKFILE) &&
verifier.VerifyTable(pressBackFile()) && VerifyOffset(verifier, VT_DISABLEBACKFILE) &&
verifier.VerifyTable(disableBackFile()) && VerifyOffset(verifier, VT_CROSSNORMALFILE) &&
verifier.VerifyTable(crossNormalFile()) && VerifyOffset(verifier, VT_CROSSDISABLEFILE) &&
verifier.VerifyTable(crossDisableFile()) && verifier.EndTable();
}
struct TabHeaderOption FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef TabHeaderOptionBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_NODEOPTIONS = 4,
VT_FONTRES = 6,
VT_FONTSIZE = 8,
VT_TITLETEXT = 10,
VT_TEXTCOLOR = 12,
VT_NORMALBACKFILE = 14,
VT_PRESSBACKFILE = 16,
VT_DISABLEBACKFILE = 18,
VT_CROSSNORMALFILE = 20,
VT_CROSSDISABLEFILE = 22
};
const flatbuffers::WidgetOptions *nodeOptions() const {
return GetPointer<const flatbuffers::WidgetOptions *>(VT_NODEOPTIONS);
}
const flatbuffers::ResourceData *fontRes() const {
return GetPointer<const flatbuffers::ResourceData *>(VT_FONTRES);
}
int32_t fontSize() const {
return GetField<int32_t>(VT_FONTSIZE, 0);
}
const flatbuffers::String *titleText() const {
return GetPointer<const flatbuffers::String *>(VT_TITLETEXT);
}
const flatbuffers::Color *textColor() const {
return GetStruct<const flatbuffers::Color *>(VT_TEXTCOLOR);
}
const flatbuffers::ResourceData *normalBackFile() const {
return GetPointer<const flatbuffers::ResourceData *>(VT_NORMALBACKFILE);
}
const flatbuffers::ResourceData *pressBackFile() const {
return GetPointer<const flatbuffers::ResourceData *>(VT_PRESSBACKFILE);
}
const flatbuffers::ResourceData *disableBackFile() const {
return GetPointer<const flatbuffers::ResourceData *>(VT_DISABLEBACKFILE);
}
const flatbuffers::ResourceData *crossNormalFile() const {
return GetPointer<const flatbuffers::ResourceData *>(VT_CROSSNORMALFILE);
}
const flatbuffers::ResourceData *crossDisableFile() const {
return GetPointer<const flatbuffers::ResourceData *>(VT_CROSSDISABLEFILE);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_NODEOPTIONS) &&
verifier.VerifyTable(nodeOptions()) &&
VerifyOffset(verifier, VT_FONTRES) &&
verifier.VerifyTable(fontRes()) &&
VerifyField<int32_t>(verifier, VT_FONTSIZE, 4) &&
VerifyOffset(verifier, VT_TITLETEXT) &&
verifier.VerifyString(titleText()) &&
VerifyField<flatbuffers::Color>(verifier, VT_TEXTCOLOR, 1) &&
VerifyOffset(verifier, VT_NORMALBACKFILE) &&
verifier.VerifyTable(normalBackFile()) &&
VerifyOffset(verifier, VT_PRESSBACKFILE) &&
verifier.VerifyTable(pressBackFile()) &&
VerifyOffset(verifier, VT_DISABLEBACKFILE) &&
verifier.VerifyTable(disableBackFile()) &&
VerifyOffset(verifier, VT_CROSSNORMALFILE) &&
verifier.VerifyTable(crossNormalFile()) &&
VerifyOffset(verifier, VT_CROSSDISABLEFILE) &&
verifier.VerifyTable(crossDisableFile()) &&
verifier.EndTable();
}
};
struct TabHeaderOptionBuilder
{
flatbuffers::FlatBufferBuilder& fbb_;
flatbuffers::uoffset_t start_;
void add_nodeOptions(flatbuffers::Offset<WidgetOptions> nodeOptions)
{
fbb_.AddOffset(TabHeaderOption::VT_NODEOPTIONS, nodeOptions);
}
void add_fontRes(flatbuffers::Offset<ResourceData> fontRes)
{
fbb_.AddOffset(TabHeaderOption::VT_FONTRES, fontRes);
}
void add_fontSize(int32_t fontSize) { fbb_.AddElement<int32_t>(TabHeaderOption::VT_FONTSIZE, fontSize, 0); }
void add_titleText(flatbuffers::Offset<flatbuffers::String> titleText)
{
fbb_.AddOffset(TabHeaderOption::VT_TITLETEXT, titleText);
}
void add_textColor(const Color* textColor) { fbb_.AddStruct(TabHeaderOption::VT_TEXTCOLOR, textColor); }
void add_normalBackFile(flatbuffers::Offset<ResourceData> normalBackFile)
{
fbb_.AddOffset(TabHeaderOption::VT_NORMALBACKFILE, normalBackFile);
}
void add_pressBackFile(flatbuffers::Offset<ResourceData> pressBackFile)
{
fbb_.AddOffset(TabHeaderOption::VT_PRESSBACKFILE, pressBackFile);
}
void add_disableBackFile(flatbuffers::Offset<ResourceData> disableBackFile)
{
fbb_.AddOffset(TabHeaderOption::VT_DISABLEBACKFILE, disableBackFile);
}
void add_crossNormalFile(flatbuffers::Offset<ResourceData> crossNormalFile)
{
fbb_.AddOffset(TabHeaderOption::VT_CROSSNORMALFILE, crossNormalFile);
}
void add_crossDisableFile(flatbuffers::Offset<ResourceData> crossDisableFile)
{
fbb_.AddOffset(TabHeaderOption::VT_CROSSDISABLEFILE, crossDisableFile);
}
explicit TabHeaderOptionBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
TabHeaderOptionBuilder& operator=(const TabHeaderOptionBuilder&);
flatbuffers::Offset<TabHeaderOption> Finish()
{
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<TabHeaderOption>(end);
return o;
}
struct TabHeaderOptionBuilder {
typedef TabHeaderOption Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_nodeOptions(flatbuffers::Offset<flatbuffers::WidgetOptions> nodeOptions) {
fbb_.AddOffset(TabHeaderOption::VT_NODEOPTIONS, nodeOptions);
}
void add_fontRes(flatbuffers::Offset<flatbuffers::ResourceData> fontRes) {
fbb_.AddOffset(TabHeaderOption::VT_FONTRES, fontRes);
}
void add_fontSize(int32_t fontSize) {
fbb_.AddElement<int32_t>(TabHeaderOption::VT_FONTSIZE, fontSize, 0);
}
void add_titleText(flatbuffers::Offset<flatbuffers::String> titleText) {
fbb_.AddOffset(TabHeaderOption::VT_TITLETEXT, titleText);
}
void add_textColor(const flatbuffers::Color *textColor) {
fbb_.AddStruct(TabHeaderOption::VT_TEXTCOLOR, textColor);
}
void add_normalBackFile(flatbuffers::Offset<flatbuffers::ResourceData> normalBackFile) {
fbb_.AddOffset(TabHeaderOption::VT_NORMALBACKFILE, normalBackFile);
}
void add_pressBackFile(flatbuffers::Offset<flatbuffers::ResourceData> pressBackFile) {
fbb_.AddOffset(TabHeaderOption::VT_PRESSBACKFILE, pressBackFile);
}
void add_disableBackFile(flatbuffers::Offset<flatbuffers::ResourceData> disableBackFile) {
fbb_.AddOffset(TabHeaderOption::VT_DISABLEBACKFILE, disableBackFile);
}
void add_crossNormalFile(flatbuffers::Offset<flatbuffers::ResourceData> crossNormalFile) {
fbb_.AddOffset(TabHeaderOption::VT_CROSSNORMALFILE, crossNormalFile);
}
void add_crossDisableFile(flatbuffers::Offset<flatbuffers::ResourceData> crossDisableFile) {
fbb_.AddOffset(TabHeaderOption::VT_CROSSDISABLEFILE, crossDisableFile);
}
explicit TabHeaderOptionBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<TabHeaderOption> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<TabHeaderOption>(end);
return o;
}
};
inline flatbuffers::Offset<TabHeaderOption> CreateTabHeaderOption(
flatbuffers::FlatBufferBuilder& _fbb,
flatbuffers::Offset<WidgetOptions> nodeOptions = 0,
flatbuffers::Offset<ResourceData> fontRes = 0,
int32_t fontSize = 0,
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::WidgetOptions> nodeOptions = 0,
flatbuffers::Offset<flatbuffers::ResourceData> fontRes = 0,
int32_t fontSize = 0,
flatbuffers::Offset<flatbuffers::String> titleText = 0,
const Color* textColor = 0,
flatbuffers::Offset<ResourceData> normalBackFile = 0,
flatbuffers::Offset<ResourceData> pressBackFile = 0,
flatbuffers::Offset<ResourceData> disableBackFile = 0,
flatbuffers::Offset<ResourceData> crossNormalFile = 0,
flatbuffers::Offset<ResourceData> crossDisableFile = 0)
{
TabHeaderOptionBuilder builder_(_fbb);
builder_.add_crossDisableFile(crossDisableFile);
builder_.add_crossNormalFile(crossNormalFile);
builder_.add_disableBackFile(disableBackFile);
builder_.add_pressBackFile(pressBackFile);
builder_.add_normalBackFile(normalBackFile);
builder_.add_textColor(textColor);
builder_.add_titleText(titleText);
builder_.add_fontSize(fontSize);
builder_.add_fontRes(fontRes);
builder_.add_nodeOptions(nodeOptions);
return builder_.Finish();
const flatbuffers::Color *textColor = nullptr,
flatbuffers::Offset<flatbuffers::ResourceData> normalBackFile = 0,
flatbuffers::Offset<flatbuffers::ResourceData> pressBackFile = 0,
flatbuffers::Offset<flatbuffers::ResourceData> disableBackFile = 0,
flatbuffers::Offset<flatbuffers::ResourceData> crossNormalFile = 0,
flatbuffers::Offset<flatbuffers::ResourceData> crossDisableFile = 0) {
TabHeaderOptionBuilder builder_(_fbb);
builder_.add_crossDisableFile(crossDisableFile);
builder_.add_crossNormalFile(crossNormalFile);
builder_.add_disableBackFile(disableBackFile);
builder_.add_pressBackFile(pressBackFile);
builder_.add_normalBackFile(normalBackFile);
builder_.add_textColor(textColor);
builder_.add_titleText(titleText);
builder_.add_fontSize(fontSize);
builder_.add_fontRes(fontRes);
builder_.add_nodeOptions(nodeOptions);
return builder_.Finish();
}
inline flatbuffers::Offset<TabHeaderOption> CreateTabHeaderOptionDirect(
flatbuffers::FlatBufferBuilder& _fbb,
flatbuffers::Offset<WidgetOptions> nodeOptions = 0,
flatbuffers::Offset<ResourceData> fontRes = 0,
int32_t fontSize = 0,
const char* titleText = nullptr,
const Color* textColor = 0,
flatbuffers::Offset<ResourceData> normalBackFile = 0,
flatbuffers::Offset<ResourceData> pressBackFile = 0,
flatbuffers::Offset<ResourceData> disableBackFile = 0,
flatbuffers::Offset<ResourceData> crossNormalFile = 0,
flatbuffers::Offset<ResourceData> crossDisableFile = 0)
{
auto titleText__ = titleText ? _fbb.CreateString(titleText) : 0;
return flatbuffers::CreateTabHeaderOption(_fbb, nodeOptions, fontRes, fontSize, titleText__, textColor,
normalBackFile, pressBackFile, disableBackFile, crossNormalFile,
crossDisableFile);
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::WidgetOptions> nodeOptions = 0,
flatbuffers::Offset<flatbuffers::ResourceData> fontRes = 0,
int32_t fontSize = 0,
const char *titleText = nullptr,
const flatbuffers::Color *textColor = nullptr,
flatbuffers::Offset<flatbuffers::ResourceData> normalBackFile = 0,
flatbuffers::Offset<flatbuffers::ResourceData> pressBackFile = 0,
flatbuffers::Offset<flatbuffers::ResourceData> disableBackFile = 0,
flatbuffers::Offset<flatbuffers::ResourceData> crossNormalFile = 0,
flatbuffers::Offset<flatbuffers::ResourceData> crossDisableFile = 0) {
auto titleText__ = titleText ? _fbb.CreateString(titleText) : 0;
return flatbuffers::CreateTabHeaderOption(
_fbb,
nodeOptions,
fontRes,
fontSize,
titleText__,
textColor,
normalBackFile,
pressBackFile,
disableBackFile,
crossNormalFile,
crossDisableFile);
}
struct TabItemOption FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table
{
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE
{
VT_HEADER = 4,
VT_CONTAINER = 6
};
const TabHeaderOption* header() const { return GetPointer<const TabHeaderOption*>(VT_HEADER); }
const NodeTree* container() const { return GetPointer<const NodeTree*>(VT_CONTAINER); }
bool Verify(flatbuffers::Verifier& verifier) const
{
return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_HEADER) && verifier.VerifyTable(header()) &&
VerifyOffset(verifier, VT_CONTAINER) && verifier.VerifyTable(container()) && verifier.EndTable();
}
struct TabItemOption FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef TabItemOptionBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_HEADER = 4,
VT_CONTAINER = 6
};
const flatbuffers::TabHeaderOption *header() const {
return GetPointer<const flatbuffers::TabHeaderOption *>(VT_HEADER);
}
const flatbuffers::NodeTree *container() const {
return GetPointer<const flatbuffers::NodeTree *>(VT_CONTAINER);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_HEADER) &&
verifier.VerifyTable(header()) &&
VerifyOffset(verifier, VT_CONTAINER) &&
verifier.VerifyTable(container()) &&
verifier.EndTable();
}
};
struct TabItemOptionBuilder
{
flatbuffers::FlatBufferBuilder& fbb_;
flatbuffers::uoffset_t start_;
void add_header(flatbuffers::Offset<TabHeaderOption> header) { fbb_.AddOffset(TabItemOption::VT_HEADER, header); }
void add_container(flatbuffers::Offset<NodeTree> container)
{
fbb_.AddOffset(TabItemOption::VT_CONTAINER, container);
}
explicit TabItemOptionBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
TabItemOptionBuilder& operator=(const TabItemOptionBuilder&);
flatbuffers::Offset<TabItemOption> Finish()
{
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<TabItemOption>(end);
return o;
}
struct TabItemOptionBuilder {
typedef TabItemOption Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_header(flatbuffers::Offset<flatbuffers::TabHeaderOption> header) {
fbb_.AddOffset(TabItemOption::VT_HEADER, header);
}
void add_container(flatbuffers::Offset<flatbuffers::NodeTree> container) {
fbb_.AddOffset(TabItemOption::VT_CONTAINER, container);
}
explicit TabItemOptionBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<TabItemOption> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<TabItemOption>(end);
return o;
}
};
inline flatbuffers::Offset<TabItemOption> CreateTabItemOption(flatbuffers::FlatBufferBuilder& _fbb,
flatbuffers::Offset<TabHeaderOption> header = 0,
flatbuffers::Offset<NodeTree> container = 0)
{
TabItemOptionBuilder builder_(_fbb);
builder_.add_container(container);
builder_.add_header(header);
return builder_.Finish();
inline flatbuffers::Offset<TabItemOption> CreateTabItemOption(
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::TabHeaderOption> header = 0,
flatbuffers::Offset<flatbuffers::NodeTree> container = 0) {
TabItemOptionBuilder builder_(_fbb);
builder_.add_container(container);
builder_.add_header(header);
return builder_.Finish();
}
inline const flatbuffers::TabControlOption* GetTabControlOption(const void* buf)
{
return flatbuffers::GetRoot<flatbuffers::TabControlOption>(buf);
inline const flatbuffers::TabControlOption *GetTabControlOption(const void *buf) {
return flatbuffers::GetRoot<flatbuffers::TabControlOption>(buf);
}
inline const flatbuffers::TabControlOption* GetSizePrefixedTabControlOption(const void* buf)
{
return flatbuffers::GetSizePrefixedRoot<flatbuffers::TabControlOption>(buf);
inline const flatbuffers::TabControlOption *GetSizePrefixedTabControlOption(const void *buf) {
return flatbuffers::GetSizePrefixedRoot<flatbuffers::TabControlOption>(buf);
}
inline bool VerifyTabControlOptionBuffer(flatbuffers::Verifier& verifier)
{
return verifier.VerifyBuffer<flatbuffers::TabControlOption>(nullptr);
inline bool VerifyTabControlOptionBuffer(
flatbuffers::Verifier &verifier) {
return verifier.VerifyBuffer<flatbuffers::TabControlOption>(nullptr);
}
inline bool VerifySizePrefixedTabControlOptionBuffer(flatbuffers::Verifier& verifier)
{
return verifier.VerifySizePrefixedBuffer<flatbuffers::TabControlOption>(nullptr);
inline bool VerifySizePrefixedTabControlOptionBuffer(
flatbuffers::Verifier &verifier) {
return verifier.VerifySizePrefixedBuffer<flatbuffers::TabControlOption>(nullptr);
}
inline void FinishTabControlOptionBuffer(flatbuffers::FlatBufferBuilder& fbb,
flatbuffers::Offset<flatbuffers::TabControlOption> root)
{
fbb.Finish(root);
inline void FinishTabControlOptionBuffer(
flatbuffers::FlatBufferBuilder &fbb,
flatbuffers::Offset<flatbuffers::TabControlOption> root) {
fbb.Finish(root);
}
inline void FinishSizePrefixedTabControlOptionBuffer(flatbuffers::FlatBufferBuilder& fbb,
flatbuffers::Offset<flatbuffers::TabControlOption> root)
{
fbb.FinishSizePrefixed(root);
inline void FinishSizePrefixedTabControlOptionBuffer(
flatbuffers::FlatBufferBuilder &fbb,
flatbuffers::Offset<flatbuffers::TabControlOption> root) {
fbb.FinishSizePrefixed(root);
}
} // namespace flatbuffers

10
thirdparty/README.md vendored
View File

@ -6,7 +6,7 @@
## astc
- [![Upstream](https://img.shields.io/github/v/release/ARM-software/astc-encoder?label=Upstream)](https://github.com/ARM-software/astc-encoder)
- Version: 4.0.0
- Version: 4.1.0
- License: Apache-2.0
## Box2D
@ -52,12 +52,12 @@
## flatbuffers
- [![Upstream](https://img.shields.io/github/v/release/google/flatbuffers?label=Upstream)](https://github.com/google/flatbuffers)
- Version: 2.0.0
- Version: 2.0.8
- License: Apache-2.0
## {fmt}
- [![Upstream](https://img.shields.io/github/v/release/fmtlib/fmt?label=Upstream)](https://github.com/fmtlib/fmt)
- Version: 9.0.0
- Version: 9.1.0
- License: MIT
## FreeType
@ -102,7 +102,7 @@
## llhttp
- [![Upstream](https://img.shields.io/github/v/release/nodejs/llhttp?label=Upstream)](https://github.com/nodejs/llhttp)
- Version: 6.0.7
- Version: 6.0.9
- License: MIT
## lua
@ -216,7 +216,7 @@
## webp
- [![Upstream](https://img.shields.io/github/v/tag/webmproject/libwebp?label=Upstream)](https://github.com/webmproject/libwebp)
- Version: 1.2.2
- Version: 1.2.4
- License: Google Inc
## xsbase

View File

@ -1171,7 +1171,7 @@ static float prepare_block_statistics(
/* See header for documentation. */
void compress_block(
const astcenc_context& ctx,
const astcenc_contexti& ctx,
const image_block& blk,
physical_compressed_block& pcb,
compression_working_buffers& tmpbuf)

View File

@ -99,17 +99,9 @@ static void brent_kung_prefix_sum(
} while (lc_stride > 2);
}
/**
* @brief Compute averages for a pixel region.
*
* The routine computes both in a single pass, using a summed-area table to decouple the running
* time from the averaging/variance kernel size.
*
* @param[out] ctx The compressor context storing the output data.
* @param arg The input parameter structure.
*/
static void compute_pixel_region_variance(
astcenc_context& ctx,
/* See header for documentation. */
void compute_pixel_region_variance(
astcenc_contexti& ctx,
const pixel_region_args& arg
) {
// Unpack the memory structure into local variables
@ -427,57 +419,6 @@ static void compute_pixel_region_variance(
}
}
void compute_averages(
astcenc_context& ctx,
const avg_args &ag
) {
pixel_region_args arg = ag.arg;
arg.work_memory = new vfloat4[ag.work_memory_size];
int size_x = ag.img_size_x;
int size_y = ag.img_size_y;
int size_z = ag.img_size_z;
int step_xy = ag.blk_size_xy;
int step_z = ag.blk_size_z;
int y_tasks = (size_y + step_xy - 1) / step_xy;
// All threads run this processing loop until there is no work remaining
while (true)
{
unsigned int count;
unsigned int base = ctx.manage_avg.get_task_assignment(16, count);
if (!count)
{
break;
}
for (unsigned int i = base; i < base + count; i++)
{
int z = (i / (y_tasks)) * step_z;
int y = (i - (z * y_tasks)) * step_xy;
arg.size_z = astc::min(step_z, size_z - z);
arg.offset_z = z;
arg.size_y = astc::min(step_xy, size_y - y);
arg.offset_y = y;
for (int x = 0; x < size_x; x += step_xy)
{
arg.size_x = astc::min(step_xy, size_x - x);
arg.offset_x = x;
compute_pixel_region_variance(ctx, arg);
}
}
ctx.manage_avg.complete_task_assignment(count);
}
delete[] arg.work_memory;
}
/* See header for documentation. */
unsigned int init_compute_averages(
const astcenc_image& img,

View File

@ -24,7 +24,7 @@
#include <new>
#include "astcenc.h"
#include "astcenc_internal.h"
#include "astcenc_internal_entry.h"
#include "astcenc_diagnostic_trace.h"
/**
@ -701,7 +701,8 @@ astcenc_error astcenc_context_alloc(
}
#endif
astcenc_context* ctx = new astcenc_context;
astcenc_context* ctxo = new astcenc_context;
astcenc_contexti* ctx = &ctxo->context;
ctx->thread_count = thread_count;
ctx->config = config;
ctx->working_buffers = nullptr;
@ -746,7 +747,7 @@ astcenc_error astcenc_context_alloc(
if (!ctx->working_buffers)
{
aligned_free<block_size_descriptor>(ctx->bsd);
delete ctx;
delete ctxo;
*context = nullptr;
return ASTCENC_ERR_OUT_OF_MEM;
}
@ -765,7 +766,7 @@ astcenc_error astcenc_context_alloc(
trace_add_data("block_z", config.block_z);
#endif
*context = ctx;
*context = ctxo;
#if !defined(ASTCENC_DECOMPRESS_ONLY)
prepare_angular_tables();
@ -776,16 +777,17 @@ astcenc_error astcenc_context_alloc(
/* See header dor documentation. */
void astcenc_context_free(
astcenc_context* ctx
astcenc_context* ctxo
) {
if (ctx)
if (ctxo)
{
astcenc_contexti* ctx = &ctxo->context;
aligned_free<compression_working_buffers>(ctx->working_buffers);
aligned_free<block_size_descriptor>(ctx->bsd);
#if defined(ASTCENC_DIAGNOSTICS)
delete ctx->trace_log;
#endif
delete ctx;
delete ctxo;
}
}
@ -794,19 +796,20 @@ void astcenc_context_free(
/**
* @brief Compress an image, after any preflight has completed.
*
* @param[out] ctx The compressor context.
* @param[out] ctxo The compressor context.
* @param thread_index The thread index.
* @param image The intput image.
* @param swizzle The input swizzle.
* @param[out] buffer The output array for the compressed data.
*/
static void compress_image(
astcenc_context& ctx,
astcenc_context& ctxo,
unsigned int thread_index,
const astcenc_image& image,
const astcenc_swizzle& swizzle,
uint8_t* buffer
) {
astcenc_contexti& ctx = ctxo.context;
const block_size_descriptor& bsd = *ctx.bsd;
astcenc_profile decode_mode = ctx.config.profile;
@ -839,7 +842,7 @@ static void compress_image(
auto& temp_buffers = ctx.working_buffers[thread_index];
// Only the first thread actually runs the initializer
ctx.manage_compress.init(block_count);
ctxo.manage_compress.init(block_count);
// Determine if we can use an optimized load function
bool needs_swz = (swizzle.r != ASTCENC_SWZ_R) || (swizzle.g != ASTCENC_SWZ_G) ||
@ -861,7 +864,7 @@ static void compress_image(
while (true)
{
unsigned int count;
unsigned int base = ctx.manage_compress.get_task_assignment(16, count);
unsigned int base = ctxo.manage_compress.get_task_assignment(16, count);
if (!count)
{
break;
@ -945,15 +948,77 @@ static void compress_image(
compress_block(ctx, blk, *pcb, temp_buffers);
}
ctx.manage_compress.complete_task_assignment(count);
ctxo.manage_compress.complete_task_assignment(count);
}
}
/**
* @brief Compute regional averages in an image.
*
* This function can be called by multiple threads, but only after a single
* thread calls the setup function @c init_compute_averages().
*
* Results are written back into @c img->input_alpha_averages.
*
* @param[out] ctx The context.
* @param ag The average and variance arguments created during setup.
*/
static void compute_averages(
astcenc_context& ctx,
const avg_args &ag
) {
pixel_region_args arg = ag.arg;
arg.work_memory = new vfloat4[ag.work_memory_size];
int size_x = ag.img_size_x;
int size_y = ag.img_size_y;
int size_z = ag.img_size_z;
int step_xy = ag.blk_size_xy;
int step_z = ag.blk_size_z;
int y_tasks = (size_y + step_xy - 1) / step_xy;
// All threads run this processing loop until there is no work remaining
while (true)
{
unsigned int count;
unsigned int base = ctx.manage_avg.get_task_assignment(16, count);
if (!count)
{
break;
}
for (unsigned int i = base; i < base + count; i++)
{
int z = (i / (y_tasks)) * step_z;
int y = (i - (z * y_tasks)) * step_xy;
arg.size_z = astc::min(step_z, size_z - z);
arg.offset_z = z;
arg.size_y = astc::min(step_xy, size_y - y);
arg.offset_y = y;
for (int x = 0; x < size_x; x += step_xy)
{
arg.size_x = astc::min(step_xy, size_x - x);
arg.offset_x = x;
compute_pixel_region_variance(ctx.context, arg);
}
}
ctx.manage_avg.complete_task_assignment(count);
}
delete[] arg.work_memory;
}
#endif
/* See header for documentation. */
astcenc_error astcenc_compress_image(
astcenc_context* ctx,
astcenc_context* ctxo,
astcenc_image* imagep,
const astcenc_swizzle* swizzle,
uint8_t* data_out,
@ -961,7 +1026,7 @@ astcenc_error astcenc_compress_image(
unsigned int thread_index
) {
#if defined(ASTCENC_DECOMPRESS_ONLY)
(void)ctx;
(void)ctxo;
(void)imagep;
(void)swizzle;
(void)data_out;
@ -969,6 +1034,7 @@ astcenc_error astcenc_compress_image(
(void)thread_index;
return ASTCENC_ERR_BAD_CONTEXT;
#else
astcenc_contexti* ctx = &ctxo->context;
astcenc_error status;
astcenc_image& image = *imagep;
@ -1006,7 +1072,7 @@ astcenc_error astcenc_compress_image(
// If context thread count is one then implicitly reset
if (ctx->thread_count == 1)
{
astcenc_compress_reset(ctx);
astcenc_compress_reset(ctxo);
}
if (ctx->config.a_scale_radius != 0)
@ -1024,19 +1090,19 @@ astcenc_error astcenc_compress_image(
};
// Only the first thread actually runs the initializer
ctx->manage_avg.init(init_avg);
ctxo->manage_avg.init(init_avg);
// All threads will enter this function and dynamically grab work
compute_averages(*ctx, ctx->avg_preprocess_args);
compute_averages(*ctxo, ctx->avg_preprocess_args);
}
// Wait for compute_averages to complete before compressing
ctx->manage_avg.wait();
ctxo->manage_avg.wait();
compress_image(*ctx, thread_index, image, *swizzle, data_out);
compress_image(*ctxo, thread_index, image, *swizzle, data_out);
// Wait for compress to complete before freeing memory
ctx->manage_compress.wait();
ctxo->manage_compress.wait();
auto term_compress = [ctx]() {
delete[] ctx->input_alpha_averages;
@ -1044,7 +1110,7 @@ astcenc_error astcenc_compress_image(
};
// Only the first thread to arrive actually runs the term
ctx->manage_compress.term(term_compress);
ctxo->manage_compress.term(term_compress);
return ASTCENC_SUCCESS;
#endif
@ -1052,26 +1118,27 @@ astcenc_error astcenc_compress_image(
/* See header for documentation. */
astcenc_error astcenc_compress_reset(
astcenc_context* ctx
astcenc_context* ctxo
) {
#if defined(ASTCENC_DECOMPRESS_ONLY)
(void)ctx;
(void)ctxo;
return ASTCENC_ERR_BAD_CONTEXT;
#else
astcenc_contexti* ctx = &ctxo->context;
if (ctx->config.flags & ASTCENC_FLG_DECOMPRESS_ONLY)
{
return ASTCENC_ERR_BAD_CONTEXT;
}
ctx->manage_avg.reset();
ctx->manage_compress.reset();
ctxo->manage_avg.reset();
ctxo->manage_compress.reset();
return ASTCENC_SUCCESS;
#endif
}
/* See header for documentation. */
astcenc_error astcenc_decompress_image(
astcenc_context* ctx,
astcenc_context* ctxo,
const uint8_t* data,
size_t data_len,
astcenc_image* image_outp,
@ -1080,6 +1147,7 @@ astcenc_error astcenc_decompress_image(
) {
astcenc_error status;
astcenc_image& image_out = *image_outp;
astcenc_contexti* ctx = &ctxo->context;
// Today this doesn't matter (working set on stack) but might in future ...
if (thread_index >= ctx->thread_count)
@ -1117,17 +1185,17 @@ astcenc_error astcenc_decompress_image(
// If context thread count is one then implicitly reset
if (ctx->thread_count == 1)
{
astcenc_decompress_reset(ctx);
astcenc_decompress_reset(ctxo);
}
// Only the first thread actually runs the initializer
ctx->manage_decompress.init(zblocks * yblocks * xblocks);
ctxo->manage_decompress.init(zblocks * yblocks * xblocks);
// All threads run this processing loop until there is no work remaining
while (true)
{
unsigned int count;
unsigned int base = ctx->manage_decompress.get_task_assignment(128, count);
unsigned int base = ctxo->manage_decompress.get_task_assignment(128, count);
if (!count)
{
break;
@ -1157,7 +1225,7 @@ astcenc_error astcenc_decompress_image(
x * block_x, y * block_y, z * block_z, *swizzle);
}
ctx->manage_decompress.complete_task_assignment(count);
ctxo->manage_decompress.complete_task_assignment(count);
}
return ASTCENC_SUCCESS;
@ -1165,24 +1233,26 @@ astcenc_error astcenc_decompress_image(
/* See header for documentation. */
astcenc_error astcenc_decompress_reset(
astcenc_context* ctx
astcenc_context* ctxo
) {
ctx->manage_decompress.reset();
ctxo->manage_decompress.reset();
return ASTCENC_SUCCESS;
}
/* See header for documentation. */
astcenc_error astcenc_get_block_info(
astcenc_context* ctx,
astcenc_context* ctxo,
const uint8_t data[16],
astcenc_block_info* info
) {
#if defined(ASTCENC_DECOMPRESS_ONLY)
(void)ctx;
(void)ctxo;
(void)data;
(void)info;
return ASTCENC_ERR_BAD_CONTEXT;
#else
astcenc_contexti* ctx = &ctxo->context;
// Decode the compressed data into a symbolic form
const physical_compressed_block&pcb = *reinterpret_cast<const physical_compressed_block*>(data);
symbolic_compressed_block scb;

View File

@ -23,15 +23,12 @@
#define ASTCENC_INTERNAL_INCLUDED
#include <algorithm>
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#if defined(ASTCENC_DIAGNOSTICS)
#include <cstdio>
#endif
#include <cstdlib>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <type_traits>
#include "astcenc.h"
#include "astcenc_mathlib.h"
@ -161,223 +158,6 @@ static_assert((WEIGHTS_MAX_BLOCK_MODES % ASTCENC_SIMD_WIDTH) == 0,
"WEIGHTS_MAX_BLOCK_MODES must be multiple of ASTCENC_SIMD_WIDTH");
/* ============================================================================
Parallel execution control
============================================================================ */
/**
* @brief A simple counter-based manager for parallel task execution.
*
* The task processing execution consists of:
*
* * A single-threaded init stage.
* * A multi-threaded processing stage.
* * A condition variable so threads can wait for processing completion.
*
* The init stage will be executed by the first thread to arrive in the critical section, there is
* no main thread in the thread pool.
*
* The processing stage uses dynamic dispatch to assign task tickets to threads on an on-demand
* basis. Threads may each therefore executed different numbers of tasks, depending on their
* processing complexity. The task queue and the task tickets are just counters; the caller must map
* these integers to an actual processing partition in a specific problem domain.
*
* The exit wait condition is needed to ensure processing has finished before a worker thread can
* progress to the next stage of the pipeline. Specifically a worker may exit the processing stage
* because there are no new tasks to assign to it while other worker threads are still processing.
* Calling @c wait() will ensure that all other worker have finished before the thread can proceed.
*
* The basic usage model:
*
* // --------- From single-threaded code ---------
*
* // Reset the tracker state
* manager->reset()
*
* // --------- From multi-threaded code ---------
*
* // Run the stage init; only first thread actually runs the lambda
* manager->init(<lambda>)
*
* do
* {
* // Request a task assignment
* uint task_count;
* uint base_index = manager->get_tasks(<granule>, task_count);
*
* // Process any tasks we were given (task_count <= granule size)
* if (task_count)
* {
* // Run the user task processing code for N tasks here
* ...
*
* // Flag these tasks as complete
* manager->complete_tasks(task_count);
* }
* } while (task_count);
*
* // Wait for all threads to complete tasks before progressing
* manager->wait()
*
* // Run the stage term; only first thread actually runs the lambda
* manager->term(<lambda>)
*/
class ParallelManager
{
private:
/** @brief Lock used for critical section and condition synchronization. */
std::mutex m_lock;
/** @brief True if the stage init() step has been executed. */
bool m_init_done;
/** @brief True if the stage term() step has been executed. */
bool m_term_done;
/** @brief Condition variable for tracking stage processing completion. */
std::condition_variable m_complete;
/** @brief Number of tasks started, but not necessarily finished. */
std::atomic<unsigned int> m_start_count;
/** @brief Number of tasks finished. */
unsigned int m_done_count;
/** @brief Number of tasks that need to be processed. */
unsigned int m_task_count;
public:
/** @brief Create a new ParallelManager. */
ParallelManager()
{
reset();
}
/**
* @brief Reset the tracker for a new processing batch.
*
* This must be called from single-threaded code before starting the multi-threaded processing
* operations.
*/
void reset()
{
m_init_done = false;
m_term_done = false;
m_start_count = 0;
m_done_count = 0;
m_task_count = 0;
}
/**
* @brief Trigger the pipeline stage init step.
*
* This can be called from multi-threaded code. The first thread to hit this will process the
* initialization. Other threads will block and wait for it to complete.
*
* @param init_func Callable which executes the stage initialization. It must return the
* total number of tasks in the stage.
*/
void init(std::function<unsigned int(void)> init_func)
{
std::lock_guard<std::mutex> lck(m_lock);
if (!m_init_done)
{
m_task_count = init_func();
m_init_done = true;
}
}
/**
* @brief Trigger the pipeline stage init step.
*
* This can be called from multi-threaded code. The first thread to hit this will process the
* initialization. Other threads will block and wait for it to complete.
*
* @param task_count Total number of tasks needing processing.
*/
void init(unsigned int task_count)
{
std::lock_guard<std::mutex> lck(m_lock);
if (!m_init_done)
{
m_task_count = task_count;
m_init_done = true;
}
}
/**
* @brief Request a task assignment.
*
* Assign up to @c granule tasks to the caller for processing.
*
* @param granule Maximum number of tasks that can be assigned.
* @param[out] count Actual number of tasks assigned, or zero if no tasks were assigned.
*
* @return Task index of the first assigned task; assigned tasks increment from this.
*/
unsigned int get_task_assignment(unsigned int granule, unsigned int& count)
{
unsigned int base = m_start_count.fetch_add(granule, std::memory_order_relaxed);
if (base >= m_task_count)
{
count = 0;
return 0;
}
count = astc::min(m_task_count - base, granule);
return base;
}
/**
* @brief Complete a task assignment.
*
* Mark @c count tasks as complete. This will notify all threads blocked on @c wait() if this
* completes the processing of the stage.
*
* @param count The number of completed tasks.
*/
void complete_task_assignment(unsigned int count)
{
// Note: m_done_count cannot use an atomic without the mutex; this has a race between the
// update here and the wait() for other threads
std::unique_lock<std::mutex> lck(m_lock);
this->m_done_count += count;
if (m_done_count == m_task_count)
{
lck.unlock();
m_complete.notify_all();
}
}
/**
* @brief Wait for stage processing to complete.
*/
void wait()
{
std::unique_lock<std::mutex> lck(m_lock);
m_complete.wait(lck, [this]{ return m_done_count == m_task_count; });
}
/**
* @brief Trigger the pipeline stage term step.
*
* This can be called from multi-threaded code. The first thread to hit this will process the
* work pool termination. Caller must have called @c wait() prior to calling this function to
* ensure that processing is complete.
*
* @param term_func Callable which executes the stage termination.
*/
void term(std::function<void(void)> term_func)
{
std::lock_guard<std::mutex> lck(m_lock);
if (!m_term_done)
{
term_func();
m_term_done = true;
}
}
};
/* ============================================================================
Commonly used data structures
============================================================================ */
@ -1432,7 +1212,7 @@ class TraceLog;
/**
* @brief The astcenc compression context.
*/
struct astcenc_context
struct astcenc_contexti
{
/** @brief The configuration this context was created with. */
astcenc_config config;
@ -1458,17 +1238,8 @@ struct astcenc_context
#if !defined(ASTCENC_DECOMPRESS_ONLY)
/** @brief The pixel region and variance worker arguments. */
avg_args avg_preprocess_args;
/** @brief The parallel manager for averages computation. */
ParallelManager manage_avg;
/** @brief The parallel manager for compression. */
ParallelManager manage_compress;
#endif
/** @brief The parallel manager for decompression. */
ParallelManager manage_decompress;
#if defined(ASTCENC_DIAGNOSTICS)
/**
* @brief The diagnostic trace logger.
@ -1809,20 +1580,17 @@ unsigned int init_compute_averages(
avg_args& ag);
/**
* @brief Compute regional averages in an image.
* @brief Compute averages for a pixel region.
*
* This function can be called by multiple threads, but only after a single
* thread calls the setup function @c init_compute_averages().
* The routine computes both in a single pass, using a summed-area table to decouple the running
* time from the averaging/variance kernel size.
*
* Results are written back into @c img->input_alpha_averages.
*
* @param[out] ctx The context.
* @param ag The average and variance arguments created during setup.
* @param[out] ctx The compressor context storing the output data.
* @param arg The input parameter structure.
*/
void compute_averages(
astcenc_context& ctx,
const avg_args& ag);
void compute_pixel_region_variance(
astcenc_contexti& ctx,
const pixel_region_args& arg);
/**
* @brief Load a single image block from the input image.
*
@ -2222,7 +1990,7 @@ void compute_angular_endpoints_2planes(
* @param[out] tmpbuf Preallocated scratch buffers for the compressor.
*/
void compress_block(
const astcenc_context& ctx,
const astcenc_contexti& ctx,
const image_block& blk,
physical_compressed_block& pcb,
compression_working_buffers& tmpbuf);

273
thirdparty/astc/astcenc_internal_entry.h vendored Normal file
View File

@ -0,0 +1,273 @@
// SPDX-License-Identifier: Apache-2.0
// ----------------------------------------------------------------------------
// Copyright 2011-2022 Arm Limited
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
// ----------------------------------------------------------------------------
/**
* @brief Functions and data declarations for the outer context.
*
* The outer context includes thread-pool management, which is slower to
* compile due to increased use of C++ stdlib. The inner context used in the
* majority of the codec library does not include this.
*/
#ifndef ASTCENC_INTERNAL_ENTRY_INCLUDED
#define ASTCENC_INTERNAL_ENTRY_INCLUDED
#include <atomic>
#include <condition_variable>
#include <functional>
#include <mutex>
#include "astcenc_internal.h"
/* ============================================================================
Parallel execution control
============================================================================ */
/**
* @brief A simple counter-based manager for parallel task execution.
*
* The task processing execution consists of:
*
* * A single-threaded init stage.
* * A multi-threaded processing stage.
* * A condition variable so threads can wait for processing completion.
*
* The init stage will be executed by the first thread to arrive in the critical section, there is
* no main thread in the thread pool.
*
* The processing stage uses dynamic dispatch to assign task tickets to threads on an on-demand
* basis. Threads may each therefore executed different numbers of tasks, depending on their
* processing complexity. The task queue and the task tickets are just counters; the caller must map
* these integers to an actual processing partition in a specific problem domain.
*
* The exit wait condition is needed to ensure processing has finished before a worker thread can
* progress to the next stage of the pipeline. Specifically a worker may exit the processing stage
* because there are no new tasks to assign to it while other worker threads are still processing.
* Calling @c wait() will ensure that all other worker have finished before the thread can proceed.
*
* The basic usage model:
*
* // --------- From single-threaded code ---------
*
* // Reset the tracker state
* manager->reset()
*
* // --------- From multi-threaded code ---------
*
* // Run the stage init; only first thread actually runs the lambda
* manager->init(<lambda>)
*
* do
* {
* // Request a task assignment
* uint task_count;
* uint base_index = manager->get_tasks(<granule>, task_count);
*
* // Process any tasks we were given (task_count <= granule size)
* if (task_count)
* {
* // Run the user task processing code for N tasks here
* ...
*
* // Flag these tasks as complete
* manager->complete_tasks(task_count);
* }
* } while (task_count);
*
* // Wait for all threads to complete tasks before progressing
* manager->wait()
*
* // Run the stage term; only first thread actually runs the lambda
* manager->term(<lambda>)
*/
class ParallelManager
{
private:
/** @brief Lock used for critical section and condition synchronization. */
std::mutex m_lock;
/** @brief True if the stage init() step has been executed. */
bool m_init_done;
/** @brief True if the stage term() step has been executed. */
bool m_term_done;
/** @brief Condition variable for tracking stage processing completion. */
std::condition_variable m_complete;
/** @brief Number of tasks started, but not necessarily finished. */
std::atomic<unsigned int> m_start_count;
/** @brief Number of tasks finished. */
unsigned int m_done_count;
/** @brief Number of tasks that need to be processed. */
unsigned int m_task_count;
public:
/** @brief Create a new ParallelManager. */
ParallelManager()
{
reset();
}
/**
* @brief Reset the tracker for a new processing batch.
*
* This must be called from single-threaded code before starting the multi-threaded processing
* operations.
*/
void reset()
{
m_init_done = false;
m_term_done = false;
m_start_count = 0;
m_done_count = 0;
m_task_count = 0;
}
/**
* @brief Trigger the pipeline stage init step.
*
* This can be called from multi-threaded code. The first thread to hit this will process the
* initialization. Other threads will block and wait for it to complete.
*
* @param init_func Callable which executes the stage initialization. It must return the
* total number of tasks in the stage.
*/
void init(std::function<unsigned int(void)> init_func)
{
std::lock_guard<std::mutex> lck(m_lock);
if (!m_init_done)
{
m_task_count = init_func();
m_init_done = true;
}
}
/**
* @brief Trigger the pipeline stage init step.
*
* This can be called from multi-threaded code. The first thread to hit this will process the
* initialization. Other threads will block and wait for it to complete.
*
* @param task_count Total number of tasks needing processing.
*/
void init(unsigned int task_count)
{
std::lock_guard<std::mutex> lck(m_lock);
if (!m_init_done)
{
m_task_count = task_count;
m_init_done = true;
}
}
/**
* @brief Request a task assignment.
*
* Assign up to @c granule tasks to the caller for processing.
*
* @param granule Maximum number of tasks that can be assigned.
* @param[out] count Actual number of tasks assigned, or zero if no tasks were assigned.
*
* @return Task index of the first assigned task; assigned tasks increment from this.
*/
unsigned int get_task_assignment(unsigned int granule, unsigned int& count)
{
unsigned int base = m_start_count.fetch_add(granule, std::memory_order_relaxed);
if (base >= m_task_count)
{
count = 0;
return 0;
}
count = astc::min(m_task_count - base, granule);
return base;
}
/**
* @brief Complete a task assignment.
*
* Mark @c count tasks as complete. This will notify all threads blocked on @c wait() if this
* completes the processing of the stage.
*
* @param count The number of completed tasks.
*/
void complete_task_assignment(unsigned int count)
{
// Note: m_done_count cannot use an atomic without the mutex; this has a race between the
// update here and the wait() for other threads
std::unique_lock<std::mutex> lck(m_lock);
this->m_done_count += count;
if (m_done_count == m_task_count)
{
lck.unlock();
m_complete.notify_all();
}
}
/**
* @brief Wait for stage processing to complete.
*/
void wait()
{
std::unique_lock<std::mutex> lck(m_lock);
m_complete.wait(lck, [this]{ return m_done_count == m_task_count; });
}
/**
* @brief Trigger the pipeline stage term step.
*
* This can be called from multi-threaded code. The first thread to hit this will process the
* work pool termination. Caller must have called @c wait() prior to calling this function to
* ensure that processing is complete.
*
* @param term_func Callable which executes the stage termination.
*/
void term(std::function<void(void)> term_func)
{
std::lock_guard<std::mutex> lck(m_lock);
if (!m_term_done)
{
term_func();
m_term_done = true;
}
}
};
/**
* @brief The astcenc compression context.
*/
struct astcenc_context
{
/** @brief The context internal state. */
astcenc_contexti context;
#if !defined(ASTCENC_DECOMPRESS_ONLY)
/** @brief The parallel manager for averages computation. */
ParallelManager manage_avg;
/** @brief The parallel manager for compression. */
ParallelManager manage_compress;
#endif
/** @brief The parallel manager for decompression. */
ParallelManager manage_decompress;
};
#endif

View File

@ -517,7 +517,7 @@ static void compute_color_error_for_every_integer_count_and_quant_level(
best_error[i][1] = ERROR_CALC_DEFAULT;
best_error[i][0] = ERROR_CALC_DEFAULT;
format_of_choice[i][3] = encode_hdr_alpha ? FMT_HDR_RGBA : FMT_HDR_RGB_LDR_ALPHA;
format_of_choice[i][3] = static_cast<uint8_t>(encode_hdr_alpha ? FMT_HDR_RGBA : FMT_HDR_RGB_LDR_ALPHA);
format_of_choice[i][2] = FMT_HDR_RGB;
format_of_choice[i][1] = FMT_HDR_RGB_SCALE;
format_of_choice[i][0] = FMT_HDR_LUMINANCE_LARGE_RANGE;
@ -537,7 +537,7 @@ static void compute_color_error_for_every_integer_count_and_quant_level(
float full_hdr_rgba_error = rgba_quantization_error + rgb_range_error + alpha_range_error;
best_error[i][3] = full_hdr_rgba_error;
format_of_choice[i][3] = encode_hdr_alpha ? FMT_HDR_RGBA : FMT_HDR_RGB_LDR_ALPHA;
format_of_choice[i][3] = static_cast<uint8_t>(encode_hdr_alpha ? FMT_HDR_RGBA : FMT_HDR_RGB_LDR_ALPHA);
// For 6 integers, we have one HDR-RGB encoding
float full_hdr_rgb_error = (rgb_quantization_error * mode11mult) + rgb_range_error + eci.alpha_drop_error;

View File

@ -351,7 +351,7 @@ struct vmask4
*/
template <int32_t l> ASTCENC_SIMD_INLINE uint32_t lane() const
{
return vgetq_lane_s32(m, l);
return vgetq_lane_u32(m, l);
}
/**
@ -968,13 +968,15 @@ ASTCENC_SIMD_INLINE void vtable_prepare(
*/
ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 idx)
{
int8x16_t table { t0.m };
int8x16_t table {
vreinterpretq_s8_s32(t0.m)
};
// Set index byte MSB to 1 for unused bytes so shuffle returns zero
// Set index byte above max index for unused bytes so table lookup returns zero
int32x4_t idx_masked = vorrq_s32(idx.m, vdupq_n_s32(0xFFFFFF00));
int8x16_t idx_bytes = vreinterpretq_u8_s32(idx_masked);
uint8x16_t idx_bytes = vreinterpretq_u8_s32(idx_masked);
return vint4(vqtbl1q_s8(table, idx_bytes));
return vint4(vreinterpretq_s32_s8(vqtbl1q_s8(table, idx_bytes)));
}
/**
@ -982,13 +984,16 @@ ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 idx)
*/
ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 idx)
{
int8x16x2_t table { t0.m, t1.m };
int8x16x2_t table {
vreinterpretq_s8_s32(t0.m),
vreinterpretq_s8_s32(t1.m)
};
// Set index byte MSB to 1 for unused bytes so shuffle returns zero
// Set index byte above max index for unused bytes so table lookup returns zero
int32x4_t idx_masked = vorrq_s32(idx.m, vdupq_n_s32(0xFFFFFF00));
int8x16_t idx_bytes = vreinterpretq_u8_s32(idx_masked);
uint8x16_t idx_bytes = vreinterpretq_u8_s32(idx_masked);
return vint4(vqtbl2q_s8(table, idx_bytes));
return vint4(vreinterpretq_s32_s8(vqtbl2q_s8(table, idx_bytes)));
}
/**
@ -996,13 +1001,18 @@ ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 idx)
*/
ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 t2, vint4 t3, vint4 idx)
{
int8x16x4_t table { t0.m, t1.m, t2.m, t3.m };
int8x16x4_t table {
vreinterpretq_s8_s32(t0.m),
vreinterpretq_s8_s32(t1.m),
vreinterpretq_s8_s32(t2.m),
vreinterpretq_s8_s32(t3.m)
};
// Set index byte MSB to 1 for unused bytes so shuffle returns zero
// Set index byte above max index for unused bytes so table lookup returns zero
int32x4_t idx_masked = vorrq_s32(idx.m, vdupq_n_s32(0xFFFFFF00));
int8x16_t idx_bytes = vreinterpretq_u8_s32(idx_masked);
uint8x16_t idx_bytes = vreinterpretq_u8_s32(idx_masked);
return vint4(vqtbl4q_s8(table, idx_bytes));
return vint4(vreinterpretq_s32_s8(vqtbl4q_s8(table, idx_bytes)));
}
/**

View File

@ -363,6 +363,14 @@ struct vmask4
m = _mm_castsi128_ps(mask.m);
}
/**
* @brief Get the scalar value of a single lane.
*/
template <int l> ASTCENC_SIMD_INLINE float lane() const
{
return _mm_cvtss_f32(_mm_shuffle_ps(m, m, l));
}
/**
* @brief The vector ...
*/
@ -1192,7 +1200,27 @@ ASTCENC_SIMD_INLINE void store_lanes_masked(int* base, vint4 data, vmask4 mask)
#if ASTCENC_AVX >= 2
_mm_maskstore_epi32(base, _mm_castps_si128(mask.m), data.m);
#else
_mm_maskmoveu_si128(data.m, _mm_castps_si128(mask.m), reinterpret_cast<char*>(base));
// Note - we cannot use _mm_maskmoveu_si128 as the underlying hardware doesn't guarantee
// fault suppression on masked lanes so we can get page faults at the end of an image.
if (mask.lane<3>() != 0.0f)
{
store(data, base);
}
else if(mask.lane<2>() != 0.0f)
{
base[0] = data.lane<0>();
base[1] = data.lane<1>();
base[2] = data.lane<2>();
}
else if(mask.lane<1>() != 0.0f)
{
base[0] = data.lane<0>();
base[1] = data.lane<1>();
}
else if(mask.lane<0>() != 0.0f)
{
base[0] = data.lane<0>();
}
#endif
}

68
thirdparty/flatbuffers/allocator.h vendored Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_ALLOCATOR_H_
#define FLATBUFFERS_ALLOCATOR_H_
#include "flatbuffers/base.h"
namespace flatbuffers {
// Allocator interface. This is flatbuffers-specific and meant only for
// `vector_downward` usage.
class Allocator {
public:
virtual ~Allocator() {}
// Allocate `size` bytes of memory.
virtual uint8_t *allocate(size_t size) = 0;
// Deallocate `size` bytes of memory at `p` allocated by this allocator.
virtual void deallocate(uint8_t *p, size_t size) = 0;
// Reallocate `new_size` bytes of memory, replacing the old region of size
// `old_size` at `p`. In contrast to a normal realloc, this grows downwards,
// and is intended specifcally for `vector_downward` use.
// `in_use_back` and `in_use_front` indicate how much of `old_size` is
// actually in use at each end, and needs to be copied.
virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
size_t new_size, size_t in_use_back,
size_t in_use_front) {
FLATBUFFERS_ASSERT(new_size > old_size); // vector_downward only grows
uint8_t *new_p = allocate(new_size);
memcpy_downward(old_p, old_size, new_p, new_size, in_use_back,
in_use_front);
deallocate(old_p, old_size);
return new_p;
}
protected:
// Called by `reallocate_downward` to copy memory from `old_p` of `old_size`
// to `new_p` of `new_size`. Only memory of size `in_use_front` and
// `in_use_back` will be copied from the front and back of the old memory
// allocation.
void memcpy_downward(uint8_t *old_p, size_t old_size, uint8_t *new_p,
size_t new_size, size_t in_use_back,
size_t in_use_front) {
memcpy(new_p + new_size - in_use_back, old_p + old_size - in_use_back,
in_use_back);
memcpy(new_p, old_p, in_use_front);
}
};
} // namespace flatbuffers
#endif // FLATBUFFERS_ALLOCATOR_H_

243
thirdparty/flatbuffers/array.h vendored Normal file
View File

@ -0,0 +1,243 @@
/*
* Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_ARRAY_H_
#define FLATBUFFERS_ARRAY_H_
#include "flatbuffers/base.h"
#include "flatbuffers/stl_emulation.h"
#include "flatbuffers/vector.h"
namespace flatbuffers {
// This is used as a helper type for accessing arrays.
template<typename T, uint16_t length> class Array {
// Array<T> can carry only POD data types (scalars or structs).
typedef typename flatbuffers::bool_constant<flatbuffers::is_scalar<T>::value>
scalar_tag;
typedef
typename flatbuffers::conditional<scalar_tag::value, T, const T *>::type
IndirectHelperType;
public:
typedef uint16_t size_type;
typedef typename IndirectHelper<IndirectHelperType>::return_type return_type;
typedef VectorIterator<T, return_type> const_iterator;
typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
// If T is a LE-scalar or a struct (!scalar_tag::value).
static FLATBUFFERS_CONSTEXPR bool is_span_observable =
(scalar_tag::value && (FLATBUFFERS_LITTLEENDIAN || sizeof(T) == 1)) ||
!scalar_tag::value;
FLATBUFFERS_CONSTEXPR uint16_t size() const { return length; }
return_type Get(uoffset_t i) const {
FLATBUFFERS_ASSERT(i < size());
return IndirectHelper<IndirectHelperType>::Read(Data(), i);
}
return_type operator[](uoffset_t i) const { return Get(i); }
// If this is a Vector of enums, T will be its storage type, not the enum
// type. This function makes it convenient to retrieve value with enum
// type E.
template<typename E> E GetEnum(uoffset_t i) const {
return static_cast<E>(Get(i));
}
const_iterator begin() const { return const_iterator(Data(), 0); }
const_iterator end() const { return const_iterator(Data(), size()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
const_iterator cbegin() const { return begin(); }
const_iterator cend() const { return end(); }
const_reverse_iterator crbegin() const { return rbegin(); }
const_reverse_iterator crend() const { return rend(); }
// Get a mutable pointer to elements inside this array.
// This method used to mutate arrays of structs followed by a @p Mutate
// operation. For primitive types use @p Mutate directly.
// @warning Assignments and reads to/from the dereferenced pointer are not
// automatically converted to the correct endianness.
typename flatbuffers::conditional<scalar_tag::value, void, T *>::type
GetMutablePointer(uoffset_t i) const {
FLATBUFFERS_ASSERT(i < size());
return const_cast<T *>(&data()[i]);
}
// Change elements if you have a non-const pointer to this object.
void Mutate(uoffset_t i, const T &val) { MutateImpl(scalar_tag(), i, val); }
// The raw data in little endian format. Use with care.
const uint8_t *Data() const { return data_; }
uint8_t *Data() { return data_; }
// Similarly, but typed, much like std::vector::data
const T *data() const { return reinterpret_cast<const T *>(Data()); }
T *data() { return reinterpret_cast<T *>(Data()); }
// Copy data from a span with endian conversion.
// If this Array and the span overlap, the behavior is undefined.
void CopyFromSpan(flatbuffers::span<const T, length> src) {
const auto p1 = reinterpret_cast<const uint8_t *>(src.data());
const auto p2 = Data();
FLATBUFFERS_ASSERT(!(p1 >= p2 && p1 < (p2 + length)) &&
!(p2 >= p1 && p2 < (p1 + length)));
(void)p1;
(void)p2;
CopyFromSpanImpl(flatbuffers::bool_constant<is_span_observable>(), src);
}
protected:
void MutateImpl(flatbuffers::true_type, uoffset_t i, const T &val) {
FLATBUFFERS_ASSERT(i < size());
WriteScalar(data() + i, val);
}
void MutateImpl(flatbuffers::false_type, uoffset_t i, const T &val) {
*(GetMutablePointer(i)) = val;
}
void CopyFromSpanImpl(flatbuffers::true_type,
flatbuffers::span<const T, length> src) {
// Use std::memcpy() instead of std::copy() to avoid performance degradation
// due to aliasing if T is char or unsigned char.
// The size is known at compile time, so memcpy would be inlined.
std::memcpy(data(), src.data(), length * sizeof(T));
}
// Copy data from flatbuffers::span with endian conversion.
void CopyFromSpanImpl(flatbuffers::false_type,
flatbuffers::span<const T, length> src) {
for (size_type k = 0; k < length; k++) { Mutate(k, src[k]); }
}
// This class is only used to access pre-existing data. Don't ever
// try to construct these manually.
// 'constexpr' allows us to use 'size()' at compile time.
// @note Must not use 'FLATBUFFERS_CONSTEXPR' here, as const is not allowed on
// a constructor.
#if defined(__cpp_constexpr)
constexpr Array();
#else
Array();
#endif
uint8_t data_[length * sizeof(T)];
private:
// This class is a pointer. Copying will therefore create an invalid object.
// Private and unimplemented copy constructor.
Array(const Array &);
Array &operator=(const Array &);
};
// Specialization for Array[struct] with access using Offset<void> pointer.
// This specialization used by idl_gen_text.cpp.
template<typename T, uint16_t length> class Array<Offset<T>, length> {
static_assert(flatbuffers::is_same<T, void>::value, "unexpected type T");
public:
typedef const void *return_type;
const uint8_t *Data() const { return data_; }
// Make idl_gen_text.cpp::PrintContainer happy.
return_type operator[](uoffset_t) const {
FLATBUFFERS_ASSERT(false);
return nullptr;
}
private:
// This class is only used to access pre-existing data.
Array();
Array(const Array &);
Array &operator=(const Array &);
uint8_t data_[1];
};
template<class U, uint16_t N>
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<U, N> make_span(Array<U, N> &arr)
FLATBUFFERS_NOEXCEPT {
static_assert(
Array<U, N>::is_span_observable,
"wrong type U, only plain struct, LE-scalar, or byte types are allowed");
return span<U, N>(arr.data(), N);
}
template<class U, uint16_t N>
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const U, N> make_span(
const Array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
static_assert(
Array<U, N>::is_span_observable,
"wrong type U, only plain struct, LE-scalar, or byte types are allowed");
return span<const U, N>(arr.data(), N);
}
template<class U, uint16_t N>
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<uint8_t, sizeof(U) * N>
make_bytes_span(Array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
static_assert(Array<U, N>::is_span_observable,
"internal error, Array<T> might hold only scalars or structs");
return span<uint8_t, sizeof(U) * N>(arr.Data(), sizeof(U) * N);
}
template<class U, uint16_t N>
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const uint8_t, sizeof(U) * N>
make_bytes_span(const Array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
static_assert(Array<U, N>::is_span_observable,
"internal error, Array<T> might hold only scalars or structs");
return span<const uint8_t, sizeof(U) * N>(arr.Data(), sizeof(U) * N);
}
// Cast a raw T[length] to a raw flatbuffers::Array<T, length>
// without endian conversion. Use with care.
// TODO: move these Cast-methods to `internal` namespace.
template<typename T, uint16_t length>
Array<T, length> &CastToArray(T (&arr)[length]) {
return *reinterpret_cast<Array<T, length> *>(arr);
}
template<typename T, uint16_t length>
const Array<T, length> &CastToArray(const T (&arr)[length]) {
return *reinterpret_cast<const Array<T, length> *>(arr);
}
template<typename E, typename T, uint16_t length>
Array<E, length> &CastToArrayOfEnum(T (&arr)[length]) {
static_assert(sizeof(E) == sizeof(T), "invalid enum type E");
return *reinterpret_cast<Array<E, length> *>(arr);
}
template<typename E, typename T, uint16_t length>
const Array<E, length> &CastToArrayOfEnum(const T (&arr)[length]) {
static_assert(sizeof(E) == sizeof(T), "invalid enum type E");
return *reinterpret_cast<const Array<E, length> *>(arr);
}
} // namespace flatbuffers
#endif // FLATBUFFERS_ARRAY_H_

View File

@ -50,10 +50,6 @@
#include <unistd.h>
#endif
#ifdef _STLPORT_VERSION
#define FLATBUFFERS_CPP98_STL
#endif
#ifdef __ANDROID__
#include <android/api-level.h>
#endif
@ -144,7 +140,7 @@
#define FLATBUFFERS_VERSION_MAJOR 2
#define FLATBUFFERS_VERSION_MINOR 0
#define FLATBUFFERS_VERSION_REVISION 0
#define FLATBUFFERS_VERSION_REVISION 8
#define FLATBUFFERS_STRING_EXPAND(X) #X
#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
namespace flatbuffers {
@ -247,6 +243,11 @@ namespace flatbuffers {
#endif // __has_include
#endif // !FLATBUFFERS_HAS_STRING_VIEW
#ifndef FLATBUFFERS_GENERAL_HEAP_ALLOC_OK
// Allow heap allocations to be used
#define FLATBUFFERS_GENERAL_HEAP_ALLOC_OK 1
#endif // !FLATBUFFERS_GENERAL_HEAP_ALLOC_OK
#ifndef FLATBUFFERS_HAS_NEW_STRTOD
// Modern (C++11) strtod and strtof functions are available for use.
// 1) nan/inf strings as argument of strtod;
@ -259,9 +260,12 @@ namespace flatbuffers {
#endif // !FLATBUFFERS_HAS_NEW_STRTOD
#ifndef FLATBUFFERS_LOCALE_INDEPENDENT
// Enable locale independent functions {strtof_l, strtod_l,strtoll_l, strtoull_l}.
#if ((defined(_MSC_VER) && _MSC_VER >= 1800) || \
(defined(_XOPEN_VERSION) && (_XOPEN_VERSION>=700)) && (!defined(__ANDROID_API__) || (defined(__ANDROID_API__) && (__ANDROID_API__>=21))))
// Enable locale independent functions {strtof_l, strtod_l,strtoll_l,
// strtoull_l}.
#if (defined(_MSC_VER) && _MSC_VER >= 1800) || \
(defined(__ANDROID_API__) && __ANDROID_API__>= 21) || \
(defined(_XOPEN_VERSION) && (_XOPEN_VERSION >= 700)) && \
(!defined(__Fuchsia__) && !defined(__ANDROID_API__))
#define FLATBUFFERS_LOCALE_INDEPENDENT 1
#else
#define FLATBUFFERS_LOCALE_INDEPENDENT 0
@ -269,14 +273,14 @@ namespace flatbuffers {
#endif // !FLATBUFFERS_LOCALE_INDEPENDENT
// Suppress Undefined Behavior Sanitizer (recoverable only). Usage:
// - __supress_ubsan__("undefined")
// - __supress_ubsan__("signed-integer-overflow")
// - __suppress_ubsan__("undefined")
// - __suppress_ubsan__("signed-integer-overflow")
#if defined(__clang__) && (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >=7))
#define __supress_ubsan__(type) __attribute__((no_sanitize(type)))
#define __suppress_ubsan__(type) __attribute__((no_sanitize(type)))
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)
#define __supress_ubsan__(type) __attribute__((no_sanitize_undefined))
#define __suppress_ubsan__(type) __attribute__((no_sanitize_undefined))
#else
#define __supress_ubsan__(type)
#define __suppress_ubsan__(type)
#endif
// This is constexpr function used for checking compile-time constants.
@ -289,7 +293,7 @@ template<typename T> FLATBUFFERS_CONSTEXPR inline bool IsConstTrue(T t) {
#if ((__cplusplus >= 201703L) \
|| (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)))
// All attributes unknown to an implementation are ignored without causing an error.
#define FLATBUFFERS_ATTRIBUTE(attr) [[attr]]
#define FLATBUFFERS_ATTRIBUTE(attr) attr
#define FLATBUFFERS_FALLTHROUGH() [[fallthrough]]
#else
@ -327,8 +331,20 @@ typedef uintmax_t largest_scalar_t;
// In 32bits, this evaluates to 2GB - 1
#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(::flatbuffers::soffset_t) * 8 - 1)) - 1)
// The minimum size buffer that can be a valid flatbuffer.
// Includes the offset to the root table (uoffset_t), the offset to the vtable
// of the root table (soffset_t), the size of the vtable (uint16_t), and the
// size of the referring table (uint16_t).
#define FLATBUFFERS_MIN_BUFFER_SIZE sizeof(uoffset_t) + sizeof(soffset_t) + \
sizeof(uint16_t) + sizeof(uint16_t)
// We support aligning the contents of buffers up to this size.
#define FLATBUFFERS_MAX_ALIGNMENT 16
#ifndef FLATBUFFERS_MAX_ALIGNMENT
#define FLATBUFFERS_MAX_ALIGNMENT 32
#endif
/// @brief The length of a FlatBuffer file header.
static const size_t kFileIdentifierLength = 4;
inline bool VerifyAlignmentRequirements(size_t align, size_t min_align = 1) {
return (min_align <= align) && (align <= (FLATBUFFERS_MAX_ALIGNMENT)) &&
@ -397,7 +413,7 @@ template<typename T> T EndianScalar(T t) {
template<typename T>
// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details.
__supress_ubsan__("alignment")
__suppress_ubsan__("alignment")
T ReadScalar(const void *p) {
return EndianScalar(*reinterpret_cast<const T *>(p));
}
@ -411,13 +427,13 @@ T ReadScalar(const void *p) {
template<typename T>
// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details.
__supress_ubsan__("alignment")
__suppress_ubsan__("alignment")
void WriteScalar(void *p, T t) {
*reinterpret_cast<T *>(p) = EndianScalar(t);
}
template<typename T> struct Offset;
template<typename T> __supress_ubsan__("alignment") void WriteScalar(void *p, Offset<T> t) {
template<typename T> __suppress_ubsan__("alignment") void WriteScalar(void *p, Offset<T> t) {
*reinterpret_cast<uoffset_t *>(p) = EndianScalar(t.o);
}
@ -428,10 +444,43 @@ template<typename T> __supress_ubsan__("alignment") void WriteScalar(void *p, Of
// Computes how many bytes you'd have to pad to be able to write an
// "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in
// memory).
__supress_ubsan__("unsigned-integer-overflow")
__suppress_ubsan__("unsigned-integer-overflow")
inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) {
return ((~buf_size) + 1) & (scalar_size - 1);
}
// Generic 'operator==' with conditional specialisations.
// T e - new value of a scalar field.
// T def - default of scalar (is known at compile-time).
template<typename T> inline bool IsTheSameAs(T e, T def) { return e == def; }
#if defined(FLATBUFFERS_NAN_DEFAULTS) && \
defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
// Like `operator==(e, def)` with weak NaN if T=(float|double).
template<typename T> inline bool IsFloatTheSameAs(T e, T def) {
return (e == def) || ((def != def) && (e != e));
}
template<> inline bool IsTheSameAs<float>(float e, float def) {
return IsFloatTheSameAs(e, def);
}
template<> inline bool IsTheSameAs<double>(double e, double def) {
return IsFloatTheSameAs(e, def);
}
#endif
// Check 'v' is out of closed range [low; high].
// Workaround for GCC warning [-Werror=type-limits]:
// comparison is always true due to limited range of data type.
template<typename T>
inline bool IsOutRange(const T &v, const T &low, const T &high) {
return (v < low) || (high < v);
}
// Check 'v' is in closed range [low; high].
template<typename T>
inline bool IsInRange(const T &v, const T &low, const T &high) {
return !IsOutRange(v, low, high);
}
} // namespace flatbuffers
#endif // FLATBUFFERS_BASE_H_

142
thirdparty/flatbuffers/buffer.h vendored Normal file
View File

@ -0,0 +1,142 @@
/*
* Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_BUFFER_H_
#define FLATBUFFERS_BUFFER_H_
#include "flatbuffers/base.h"
namespace flatbuffers {
// Wrapper for uoffset_t to allow safe template specialization.
// Value is allowed to be 0 to indicate a null object (see e.g. AddOffset).
template<typename T> struct Offset {
uoffset_t o;
Offset() : o(0) {}
Offset(uoffset_t _o) : o(_o) {}
Offset<void> Union() const { return Offset<void>(o); }
bool IsNull() const { return !o; }
};
inline void EndianCheck() {
int endiantest = 1;
// If this fails, see FLATBUFFERS_LITTLEENDIAN above.
FLATBUFFERS_ASSERT(*reinterpret_cast<char *>(&endiantest) ==
FLATBUFFERS_LITTLEENDIAN);
(void)endiantest;
}
template<typename T> FLATBUFFERS_CONSTEXPR size_t AlignOf() {
// clang-format off
#ifdef _MSC_VER
return __alignof(T);
#else
#ifndef alignof
return __alignof__(T);
#else
return alignof(T);
#endif
#endif
// clang-format on
}
// Lexicographically compare two strings (possibly containing nulls), and
// return true if the first is less than the second.
static inline bool StringLessThan(const char *a_data, uoffset_t a_size,
const char *b_data, uoffset_t b_size) {
const auto cmp = memcmp(a_data, b_data, (std::min)(a_size, b_size));
return cmp == 0 ? a_size < b_size : cmp < 0;
}
// When we read serialized data from memory, in the case of most scalars,
// we want to just read T, but in the case of Offset, we want to actually
// perform the indirection and return a pointer.
// The template specialization below does just that.
// It is wrapped in a struct since function templates can't overload on the
// return type like this.
// The typedef is for the convenience of callers of this function
// (avoiding the need for a trailing return decltype)
template<typename T> struct IndirectHelper {
typedef T return_type;
typedef T mutable_return_type;
static const size_t element_stride = sizeof(T);
static return_type Read(const uint8_t *p, uoffset_t i) {
return EndianScalar((reinterpret_cast<const T *>(p))[i]);
}
};
template<typename T> struct IndirectHelper<Offset<T>> {
typedef const T *return_type;
typedef T *mutable_return_type;
static const size_t element_stride = sizeof(uoffset_t);
static return_type Read(const uint8_t *p, uoffset_t i) {
p += i * sizeof(uoffset_t);
return reinterpret_cast<return_type>(p + ReadScalar<uoffset_t>(p));
}
};
template<typename T> struct IndirectHelper<const T *> {
typedef const T *return_type;
typedef T *mutable_return_type;
static const size_t element_stride = sizeof(T);
static return_type Read(const uint8_t *p, uoffset_t i) {
return reinterpret_cast<const T *>(p + i * sizeof(T));
}
};
/// @brief Get a pointer to the file_identifier section of the buffer.
/// @return Returns a const char pointer to the start of the file_identifier
/// characters in the buffer. The returned char * has length
/// 'flatbuffers::FlatBufferBuilder::kFileIdentifierLength'.
/// This function is UNDEFINED for FlatBuffers whose schema does not include
/// a file_identifier (likely points at padding or the start of a the root
/// vtable).
inline const char *GetBufferIdentifier(const void *buf,
bool size_prefixed = false) {
return reinterpret_cast<const char *>(buf) +
((size_prefixed) ? 2 * sizeof(uoffset_t) : sizeof(uoffset_t));
}
// Helper to see if the identifier in a buffer has the expected value.
inline bool BufferHasIdentifier(const void *buf, const char *identifier,
bool size_prefixed = false) {
return strncmp(GetBufferIdentifier(buf, size_prefixed), identifier,
flatbuffers::kFileIdentifierLength) == 0;
}
/// @cond FLATBUFFERS_INTERNAL
// Helpers to get a typed pointer to the root object contained in the buffer.
template<typename T> T *GetMutableRoot(void *buf) {
EndianCheck();
return reinterpret_cast<T *>(
reinterpret_cast<uint8_t *>(buf) +
EndianScalar(*reinterpret_cast<uoffset_t *>(buf)));
}
template<typename T> T *GetMutableSizePrefixedRoot(void *buf) {
return GetMutableRoot<T>(reinterpret_cast<uint8_t *>(buf) +
sizeof(uoffset_t));
}
template<typename T> const T *GetRoot(const void *buf) {
return GetMutableRoot<T>(const_cast<void *>(buf));
}
template<typename T> const T *GetSizePrefixedRoot(const void *buf) {
return GetRoot<T>(reinterpret_cast<const uint8_t *>(buf) + sizeof(uoffset_t));
}
} // namespace flatbuffers
#endif // FLATBUFFERS_BUFFER_H_

53
thirdparty/flatbuffers/buffer_ref.h vendored Normal file
View File

@ -0,0 +1,53 @@
/*
* Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_BUFFER_REF_H_
#define FLATBUFFERS_BUFFER_REF_H_
#include "flatbuffers/base.h"
#include "flatbuffers/verifier.h"
namespace flatbuffers {
// Convenient way to bundle a buffer and its length, to pass it around
// typed by its root.
// A BufferRef does not own its buffer.
struct BufferRefBase {}; // for std::is_base_of
template<typename T> struct BufferRef : BufferRefBase {
BufferRef() : buf(nullptr), len(0), must_free(false) {}
BufferRef(uint8_t *_buf, uoffset_t _len)
: buf(_buf), len(_len), must_free(false) {}
~BufferRef() {
if (must_free) free(buf);
}
const T *GetRoot() const { return flatbuffers::GetRoot<T>(buf); }
bool Verify() {
Verifier verifier(buf, len);
return verifier.VerifyBuffer<T>(nullptr);
}
uint8_t *buf;
uoffset_t len;
bool must_free;
};
} // namespace flatbuffers
#endif // FLATBUFFERS_BUFFER_REF_H_

View File

@ -0,0 +1,64 @@
/*
* Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_DEFAULT_ALLOCATOR_H_
#define FLATBUFFERS_DEFAULT_ALLOCATOR_H_
#include "flatbuffers/allocator.h"
#include "flatbuffers/base.h"
namespace flatbuffers {
// DefaultAllocator uses new/delete to allocate memory regions
class DefaultAllocator : public Allocator {
public:
uint8_t *allocate(size_t size) FLATBUFFERS_OVERRIDE {
return new uint8_t[size];
}
void deallocate(uint8_t *p, size_t) FLATBUFFERS_OVERRIDE { delete[] p; }
static void dealloc(void *p, size_t) { delete[] static_cast<uint8_t *>(p); }
};
// These functions allow for a null allocator to mean use the default allocator,
// as used by DetachedBuffer and vector_downward below.
// This is to avoid having a statically or dynamically allocated default
// allocator, or having to move it between the classes that may own it.
inline uint8_t *Allocate(Allocator *allocator, size_t size) {
return allocator ? allocator->allocate(size)
: DefaultAllocator().allocate(size);
}
inline void Deallocate(Allocator *allocator, uint8_t *p, size_t size) {
if (allocator)
allocator->deallocate(p, size);
else
DefaultAllocator().deallocate(p, size);
}
inline uint8_t *ReallocateDownward(Allocator *allocator, uint8_t *old_p,
size_t old_size, size_t new_size,
size_t in_use_back, size_t in_use_front) {
return allocator ? allocator->reallocate_downward(old_p, old_size, new_size,
in_use_back, in_use_front)
: DefaultAllocator().reallocate_downward(
old_p, old_size, new_size, in_use_back, in_use_front);
}
} // namespace flatbuffers
#endif // FLATBUFFERS_DEFAULT_ALLOCATOR_H_

114
thirdparty/flatbuffers/detached_buffer.h vendored Normal file
View File

@ -0,0 +1,114 @@
/*
* Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_DETACHED_BUFFER_H_
#define FLATBUFFERS_DETACHED_BUFFER_H_
#include "flatbuffers/allocator.h"
#include "flatbuffers/base.h"
#include "flatbuffers/default_allocator.h"
namespace flatbuffers {
// DetachedBuffer is a finished flatbuffer memory region, detached from its
// builder. The original memory region and allocator are also stored so that
// the DetachedBuffer can manage the memory lifetime.
class DetachedBuffer {
public:
DetachedBuffer()
: allocator_(nullptr),
own_allocator_(false),
buf_(nullptr),
reserved_(0),
cur_(nullptr),
size_(0) {}
DetachedBuffer(Allocator *allocator, bool own_allocator, uint8_t *buf,
size_t reserved, uint8_t *cur, size_t sz)
: allocator_(allocator),
own_allocator_(own_allocator),
buf_(buf),
reserved_(reserved),
cur_(cur),
size_(sz) {}
DetachedBuffer(DetachedBuffer &&other)
: allocator_(other.allocator_),
own_allocator_(other.own_allocator_),
buf_(other.buf_),
reserved_(other.reserved_),
cur_(other.cur_),
size_(other.size_) {
other.reset();
}
DetachedBuffer &operator=(DetachedBuffer &&other) {
if (this == &other) return *this;
destroy();
allocator_ = other.allocator_;
own_allocator_ = other.own_allocator_;
buf_ = other.buf_;
reserved_ = other.reserved_;
cur_ = other.cur_;
size_ = other.size_;
other.reset();
return *this;
}
~DetachedBuffer() { destroy(); }
const uint8_t *data() const { return cur_; }
uint8_t *data() { return cur_; }
size_t size() const { return size_; }
// These may change access mode, leave these at end of public section
FLATBUFFERS_DELETE_FUNC(DetachedBuffer(const DetachedBuffer &other));
FLATBUFFERS_DELETE_FUNC(
DetachedBuffer &operator=(const DetachedBuffer &other));
protected:
Allocator *allocator_;
bool own_allocator_;
uint8_t *buf_;
size_t reserved_;
uint8_t *cur_;
size_t size_;
inline void destroy() {
if (buf_) Deallocate(allocator_, buf_, reserved_);
if (own_allocator_ && allocator_) { delete allocator_; }
reset();
}
inline void reset() {
allocator_ = nullptr;
own_allocator_ = false;
buf_ = nullptr;
reserved_ = 0;
cur_ = nullptr;
size_ = 0;
}
};
} // namespace flatbuffers
#endif // FLATBUFFERS_DETACHED_BUFFER_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -26,36 +26,33 @@
#include <memory>
#include <limits>
#if defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
#define FLATBUFFERS_CPP98_STL
#endif // defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
#ifndef FLATBUFFERS_USE_STD_OPTIONAL
// Detect C++17 compatible compiler.
// __cplusplus >= 201703L - a compiler has support of 'static inline' variables.
#if (defined(__cplusplus) && __cplusplus >= 201703L) \
|| (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
#define FLATBUFFERS_USE_STD_OPTIONAL 1
#else
#define FLATBUFFERS_USE_STD_OPTIONAL 0
#endif // (defined(__cplusplus) && __cplusplus >= 201703L) ...
#endif // FLATBUFFERS_USE_STD_OPTIONAL
#if defined(FLATBUFFERS_CPP98_STL)
#include <cctype>
#endif // defined(FLATBUFFERS_CPP98_STL)
// Detect C++17 compatible compiler.
// __cplusplus >= 201703L - a compiler has support of 'static inline' variables.
#if defined(FLATBUFFERS_USE_STD_OPTIONAL) \
|| (defined(__cplusplus) && __cplusplus >= 201703L) \
|| (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L))
#if FLATBUFFERS_USE_STD_OPTIONAL
#include <optional>
#ifndef FLATBUFFERS_USE_STD_OPTIONAL
#define FLATBUFFERS_USE_STD_OPTIONAL
#endif
#endif // defined(FLATBUFFERS_USE_STD_OPTIONAL) ...
#endif
// The __cpp_lib_span is the predefined feature macro.
#if defined(FLATBUFFERS_USE_STD_SPAN)
#include <span>
#elif defined(__cpp_lib_span) && defined(__has_include)
#if __has_include(<span>)
#include <array>
#include <span>
#define FLATBUFFERS_USE_STD_SPAN
#endif
#else
// Disable non-trivial ctors if FLATBUFFERS_SPAN_MINIMAL defined.
#if !defined(FLATBUFFERS_TEMPLATES_ALIASES) || defined(FLATBUFFERS_CPP98_STL)
#if !defined(FLATBUFFERS_TEMPLATES_ALIASES)
#define FLATBUFFERS_SPAN_MINIMAL
#else
// Enable implicit construction of a span<T,N> from a std::array<T,N>.
@ -63,135 +60,32 @@
#endif
#endif // defined(FLATBUFFERS_USE_STD_SPAN)
// This header provides backwards compatibility for C++98 STLs like stlport.
// This header provides backwards compatibility for older versions of the STL.
namespace flatbuffers {
// Retrieve ::back() from a string in a way that is compatible with pre C++11
// STLs (e.g stlport).
inline char& string_back(std::string &value) {
return value[value.length() - 1];
}
inline char string_back(const std::string &value) {
return value[value.length() - 1];
}
// Helper method that retrieves ::data() from a vector in a way that is
// compatible with pre C++11 STLs (e.g stlport).
template <typename T> inline T *vector_data(std::vector<T> &vector) {
// In some debug environments, operator[] does bounds checking, so &vector[0]
// can't be used.
return vector.empty() ? nullptr : &vector[0];
}
template <typename T> inline const T *vector_data(
const std::vector<T> &vector) {
return vector.empty() ? nullptr : &vector[0];
}
template <typename T, typename V>
inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
#if defined(FLATBUFFERS_CPP98_STL)
vector->push_back(data);
#else
vector->emplace_back(std::forward<V>(data));
#endif // defined(FLATBUFFERS_CPP98_STL)
}
#ifndef FLATBUFFERS_CPP98_STL
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
template <typename T>
using numeric_limits = std::numeric_limits<T>;
#else
template <typename T> class numeric_limits :
public std::numeric_limits<T> {};
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
template <typename T>
using numeric_limits = std::numeric_limits<T>;
#else
template <typename T> class numeric_limits :
public std::numeric_limits<T> {
public:
// Android NDK fix.
static T lowest() {
return std::numeric_limits<T>::min();
}
};
template <> class numeric_limits<float> :
public std::numeric_limits<float> {
public:
static float lowest() { return -FLT_MAX; }
};
template <> class numeric_limits<double> :
public std::numeric_limits<double> {
public:
static double lowest() { return -DBL_MAX; }
};
template <> class numeric_limits<unsigned long long> {
public:
static unsigned long long min() { return 0ULL; }
static unsigned long long max() { return ~0ULL; }
static unsigned long long lowest() {
return numeric_limits<unsigned long long>::min();
}
};
template <> class numeric_limits<long long> {
public:
static long long min() {
return static_cast<long long>(1ULL << ((sizeof(long long) << 3) - 1));
}
static long long max() {
return static_cast<long long>(
(1ULL << ((sizeof(long long) << 3) - 1)) - 1);
}
static long long lowest() {
return numeric_limits<long long>::min();
}
};
#endif // FLATBUFFERS_CPP98_STL
public std::numeric_limits<T> {};
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
#ifndef FLATBUFFERS_CPP98_STL
template <typename T> using is_scalar = std::is_scalar<T>;
template <typename T, typename U> using is_same = std::is_same<T,U>;
template <typename T> using is_floating_point = std::is_floating_point<T>;
template <typename T> using is_unsigned = std::is_unsigned<T>;
template <typename T> using is_enum = std::is_enum<T>;
template <typename T> using make_unsigned = std::make_unsigned<T>;
template<bool B, class T, class F>
using conditional = std::conditional<B, T, F>;
template<class T, T v>
using integral_constant = std::integral_constant<T, v>;
template <bool B>
using bool_constant = integral_constant<bool, B>;
#else
// Map C++ TR1 templates defined by stlport.
template <typename T> using is_scalar = std::tr1::is_scalar<T>;
template <typename T, typename U> using is_same = std::tr1::is_same<T,U>;
template <typename T> using is_floating_point =
std::tr1::is_floating_point<T>;
template <typename T> using is_unsigned = std::tr1::is_unsigned<T>;
template <typename T> using is_enum = std::tr1::is_enum<T>;
// Android NDK doesn't have std::make_unsigned or std::tr1::make_unsigned.
template<typename T> struct make_unsigned {
static_assert(is_unsigned<T>::value, "Specialization not implemented!");
using type = T;
};
template<> struct make_unsigned<char> { using type = unsigned char; };
template<> struct make_unsigned<short> { using type = unsigned short; };
template<> struct make_unsigned<int> { using type = unsigned int; };
template<> struct make_unsigned<long> { using type = unsigned long; };
template<>
struct make_unsigned<long long> { using type = unsigned long long; };
template<bool B, class T, class F>
using conditional = std::tr1::conditional<B, T, F>;
template<class T, T v>
using integral_constant = std::tr1::integral_constant<T, v>;
template <bool B>
using bool_constant = integral_constant<bool, B>;
#endif // !FLATBUFFERS_CPP98_STL
template <typename T> using is_scalar = std::is_scalar<T>;
template <typename T, typename U> using is_same = std::is_same<T,U>;
template <typename T> using is_floating_point = std::is_floating_point<T>;
template <typename T> using is_unsigned = std::is_unsigned<T>;
template <typename T> using is_enum = std::is_enum<T>;
template <typename T> using make_unsigned = std::make_unsigned<T>;
template<bool B, class T, class F>
using conditional = std::conditional<B, T, F>;
template<class T, T v>
using integral_constant = std::integral_constant<T, v>;
template <bool B>
using bool_constant = integral_constant<bool, B>;
using true_type = std::true_type;
using false_type = std::false_type;
#else
// MSVC 2010 doesn't support C++11 aliases.
template <typename T> struct is_scalar : public std::is_scalar<T> {};
@ -207,128 +101,39 @@ inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
struct integral_constant : public std::integral_constant<T, v> {};
template <bool B>
struct bool_constant : public integral_constant<bool, B> {};
typedef bool_constant<true> true_type;
typedef bool_constant<false> false_type;
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
#ifndef FLATBUFFERS_CPP98_STL
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
template <class T> using unique_ptr = std::unique_ptr<T>;
#else
// MSVC 2010 doesn't support C++11 aliases.
// We're manually "aliasing" the class here as we want to bring unique_ptr
// into the flatbuffers namespace. We have unique_ptr in the flatbuffers
// namespace we have a completely independent implementation (see below)
// for C++98 STL implementations.
template <class T> class unique_ptr : public std::unique_ptr<T> {
public:
unique_ptr() {}
explicit unique_ptr(T* p) : std::unique_ptr<T>(p) {}
unique_ptr(std::unique_ptr<T>&& u) { *this = std::move(u); }
unique_ptr(unique_ptr&& u) { *this = std::move(u); }
unique_ptr& operator=(std::unique_ptr<T>&& u) {
std::unique_ptr<T>::reset(u.release());
return *this;
}
unique_ptr& operator=(unique_ptr&& u) {
std::unique_ptr<T>::reset(u.release());
return *this;
}
unique_ptr& operator=(T* p) {
return std::unique_ptr<T>::operator=(p);
}
};
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
template <class T> using unique_ptr = std::unique_ptr<T>;
#else
// Very limited implementation of unique_ptr.
// This is provided simply to allow the C++ code generated from the default
// settings to function in C++98 environments with no modifications.
template <class T> class unique_ptr {
public:
typedef T element_type;
unique_ptr() : ptr_(nullptr) {}
explicit unique_ptr(T* p) : ptr_(p) {}
unique_ptr(unique_ptr&& u) : ptr_(nullptr) { reset(u.release()); }
unique_ptr(const unique_ptr& u) : ptr_(nullptr) {
reset(const_cast<unique_ptr*>(&u)->release());
}
~unique_ptr() { reset(); }
unique_ptr& operator=(const unique_ptr& u) {
reset(const_cast<unique_ptr*>(&u)->release());
// MSVC 2010 doesn't support C++11 aliases.
// We're manually "aliasing" the class here as we want to bring unique_ptr
// into the flatbuffers namespace. We have unique_ptr in the flatbuffers
// namespace we have a completely independent implementation (see below)
// for C++98 STL implementations.
template <class T> class unique_ptr : public std::unique_ptr<T> {
public:
unique_ptr() {}
explicit unique_ptr(T* p) : std::unique_ptr<T>(p) {}
unique_ptr(std::unique_ptr<T>&& u) { *this = std::move(u); }
unique_ptr(unique_ptr&& u) { *this = std::move(u); }
unique_ptr& operator=(std::unique_ptr<T>&& u) {
std::unique_ptr<T>::reset(u.release());
return *this;
}
unique_ptr& operator=(unique_ptr&& u) {
reset(u.release());
std::unique_ptr<T>::reset(u.release());
return *this;
}
unique_ptr& operator=(T* p) {
reset(p);
return *this;
return std::unique_ptr<T>::operator=(p);
}
const T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
T* get() const noexcept { return ptr_; }
explicit operator bool() const { return ptr_ != nullptr; }
// modifiers
T* release() {
T* value = ptr_;
ptr_ = nullptr;
return value;
}
void reset(T* p = nullptr) {
T* value = ptr_;
ptr_ = p;
if (value) delete value;
}
void swap(unique_ptr& u) {
T* temp_ptr = ptr_;
ptr_ = u.ptr_;
u.ptr_ = temp_ptr;
}
private:
T* ptr_;
};
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
template <class T> bool operator==(const unique_ptr<T>& x,
const unique_ptr<T>& y) {
return x.get() == y.get();
}
template <class T, class D> bool operator==(const unique_ptr<T>& x,
const D* y) {
return static_cast<D*>(x.get()) == y;
}
template <class T> bool operator==(const unique_ptr<T>& x, intptr_t y) {
return reinterpret_cast<intptr_t>(x.get()) == y;
}
template <class T> bool operator!=(const unique_ptr<T>& x, decltype(nullptr)) {
return !!x;
}
template <class T> bool operator!=(decltype(nullptr), const unique_ptr<T>& x) {
return !!x;
}
template <class T> bool operator==(const unique_ptr<T>& x, decltype(nullptr)) {
return !x;
}
template <class T> bool operator==(decltype(nullptr), const unique_ptr<T>& x) {
return !x;
}
#endif // !FLATBUFFERS_CPP98_STL
#ifdef FLATBUFFERS_USE_STD_OPTIONAL
#if FLATBUFFERS_USE_STD_OPTIONAL
template<class T>
using Optional = std::optional<T>;
using nullopt_t = std::nullopt_t;
@ -484,17 +289,43 @@ FLATBUFFERS_CONSTEXPR std::size_t dynamic_extent = static_cast<std::size_t>(-1);
namespace internal {
// This is SFINAE helper class for checking of a common condition:
// > This overload only participates in overload resolution
// > Check whether a pointer to an array of U can be converted
// > to a pointer to an array of E.
// This helper is used for checking of 'U -> const U'.
template<class E, std::size_t Extent, class U, std::size_t N>
struct is_span_convertable {
// > Check whether a pointer to an array of From can be converted
// > to a pointer to an array of To.
// This helper is used for checking of 'From -> const From'.
template<class To, std::size_t Extent, class From, std::size_t N>
struct is_span_convertible {
using type =
typename std::conditional<std::is_convertible<U (*)[], E (*)[]>::value
typename std::conditional<std::is_convertible<From (*)[], To (*)[]>::value
&& (Extent == dynamic_extent || N == Extent),
int, void>::type;
};
template<typename T>
struct SpanIterator {
// TODO: upgrade to std::random_access_iterator_tag.
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = typename std::remove_cv<T>::type;
using reference = T&;
using pointer = T*;
// Convince MSVC compiler that this iterator is trusted (it is verified).
#ifdef _MSC_VER
using _Unchecked_type = pointer;
#endif // _MSC_VER
SpanIterator(pointer ptr) : ptr_(ptr) {}
reference operator*() const { return *ptr_; }
pointer operator->() { return ptr_; }
SpanIterator& operator++() { ptr_++; return *this; }
SpanIterator operator++(int) { auto tmp = *this; ++(*this); return tmp; }
friend bool operator== (const SpanIterator& lhs, const SpanIterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
friend bool operator!= (const SpanIterator& lhs, const SpanIterator& rhs) { return lhs.ptr_ != rhs.ptr_; }
private:
pointer ptr_;
};
} // namespace internal
#endif // !defined(FLATBUFFERS_SPAN_MINIMAL)
@ -534,6 +365,13 @@ class span FLATBUFFERS_FINAL_CLASS {
return data_;
}
#if !defined(FLATBUFFERS_SPAN_MINIMAL)
using Iterator = internal::SpanIterator<T>;
Iterator begin() const { return Iterator(data()); }
Iterator end() const { return Iterator(data() + size()); }
#endif
// Returns a reference to the idx-th element of the sequence.
// The behavior is undefined if the idx is greater than or equal to size().
FLATBUFFERS_CONSTEXPR_CPP11 reference operator[](size_type idx) const {
@ -577,7 +415,7 @@ class span FLATBUFFERS_FINAL_CLASS {
// extent == 0 || extent == flatbuffers::dynamic_extent.
// A dummy template argument N is need dependency for SFINAE.
template<std::size_t N = 0,
typename internal::is_span_convertable<element_type, Extent, element_type, (N - N)>::type = 0>
typename internal::is_span_convertible<element_type, Extent, element_type, (N - N)>::type = 0>
FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr),
count_(0) {
static_assert(extent == 0 || extent == dynamic_extent, "invalid span");
@ -590,12 +428,12 @@ class span FLATBUFFERS_FINAL_CLASS {
// std::remove_pointer_t<decltype(std::data(arr))>(*)[]
// is convertible to element_type (*)[].
template<std::size_t N,
typename internal::is_span_convertable<element_type, Extent, element_type, N>::type = 0>
typename internal::is_span_convertible<element_type, Extent, element_type, N>::type = 0>
FLATBUFFERS_CONSTEXPR_CPP11 span(element_type (&arr)[N]) FLATBUFFERS_NOEXCEPT
: data_(arr), count_(N) {}
template<class U, std::size_t N,
typename internal::is_span_convertable<element_type, Extent, U, N>::type = 0>
typename internal::is_span_convertible<element_type, Extent, U, N>::type = 0>
FLATBUFFERS_CONSTEXPR_CPP11 span(std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT
: data_(arr.data()), count_(N) {}
@ -605,7 +443,7 @@ class span FLATBUFFERS_FINAL_CLASS {
// : data_(arr.data()), count_(N) {}
template<class U, std::size_t N,
typename internal::is_span_convertable<element_type, Extent, U, N>::type = 0>
typename internal::is_span_convertible<element_type, Extent, U, N>::type = 0>
FLATBUFFERS_CONSTEXPR_CPP11 span(const std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT
: data_(arr.data()), count_(N) {}
@ -615,7 +453,7 @@ class span FLATBUFFERS_FINAL_CLASS {
// if extent == std::dynamic_extent || N == extent is true and U (*)[]
// is convertible to element_type (*)[].
template<class U, std::size_t N,
typename internal::is_span_convertable<element_type, Extent, U, N>::type = 0>
typename internal::is_span_convertible<element_type, Extent, U, N>::type = 0>
FLATBUFFERS_CONSTEXPR_CPP11 span(const flatbuffers::span<U, N> &s) FLATBUFFERS_NOEXCEPT
: span(s.data(), s.size()) {
}
@ -625,49 +463,48 @@ class span FLATBUFFERS_FINAL_CLASS {
private:
// This is a naive implementation with 'count_' member even if (Extent != dynamic_extent).
pointer const data_;
const size_type count_;
size_type count_;
};
#if !defined(FLATBUFFERS_SPAN_MINIMAL)
template<class U, std::size_t N>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<U, N> make_span(U(&arr)[N]) FLATBUFFERS_NOEXCEPT {
return span<U, N>(arr);
}
template<class U, std::size_t N>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<const U, N> make_span(const U(&arr)[N]) FLATBUFFERS_NOEXCEPT {
return span<const U, N>(arr);
}
template<class U, std::size_t N>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<U, N> make_span(std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
return span<U, N>(arr);
}
template<class U, std::size_t N>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<const U, N> make_span(const std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
return span<const U, N>(arr);
}
template<class U, std::size_t N>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<U, dynamic_extent> make_span(U *first, std::size_t count) FLATBUFFERS_NOEXCEPT {
return span<U, dynamic_extent>(first, count);
}
template<class U, std::size_t N>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<const U, dynamic_extent> make_span(const U *first, std::size_t count) FLATBUFFERS_NOEXCEPT {
return span<const U, dynamic_extent>(first, count);
}
#endif
#endif // defined(FLATBUFFERS_USE_STD_SPAN)
#if !defined(FLATBUFFERS_SPAN_MINIMAL)
template<class ElementType, std::size_t Extent>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<ElementType, Extent> make_span(ElementType(&arr)[Extent]) FLATBUFFERS_NOEXCEPT {
return span<ElementType, Extent>(arr);
}
template<class ElementType, std::size_t Extent>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<const ElementType, Extent> make_span(const ElementType(&arr)[Extent]) FLATBUFFERS_NOEXCEPT {
return span<const ElementType, Extent>(arr);
}
template<class ElementType, std::size_t Extent>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<ElementType, Extent> make_span(std::array<ElementType, Extent> &arr) FLATBUFFERS_NOEXCEPT {
return span<ElementType, Extent>(arr);
}
template<class ElementType, std::size_t Extent>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<const ElementType, Extent> make_span(const std::array<ElementType, Extent> &arr) FLATBUFFERS_NOEXCEPT {
return span<const ElementType, Extent>(arr);
}
template<class ElementType, std::size_t Extent>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<ElementType, dynamic_extent> make_span(ElementType *first, std::size_t count) FLATBUFFERS_NOEXCEPT {
return span<ElementType, dynamic_extent>(first, count);
}
template<class ElementType, std::size_t Extent>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<const ElementType, dynamic_extent> make_span(const ElementType *first, std::size_t count) FLATBUFFERS_NOEXCEPT {
return span<const ElementType, dynamic_extent>(first, count);
}
#endif // !defined(FLATBUFFERS_SPAN_MINIMAL)
} // namespace flatbuffers
#endif // FLATBUFFERS_STL_EMULATION_H_

64
thirdparty/flatbuffers/string.h vendored Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_STRING_H_
#define FLATBUFFERS_STRING_H_
#include "flatbuffers/base.h"
#include "flatbuffers/vector.h"
namespace flatbuffers {
struct String : public Vector<char> {
const char *c_str() const { return reinterpret_cast<const char *>(Data()); }
std::string str() const { return std::string(c_str(), size()); }
// clang-format off
#ifdef FLATBUFFERS_HAS_STRING_VIEW
flatbuffers::string_view string_view() const {
return flatbuffers::string_view(c_str(), size());
}
#endif // FLATBUFFERS_HAS_STRING_VIEW
// clang-format on
bool operator<(const String &o) const {
return StringLessThan(this->data(), this->size(), o.data(), o.size());
}
};
// Convenience function to get std::string from a String returning an empty
// string on null pointer.
static inline std::string GetString(const String *str) {
return str ? str->str() : "";
}
// Convenience function to get char* from a String returning an empty string on
// null pointer.
static inline const char *GetCstring(const String *str) {
return str ? str->c_str() : "";
}
#ifdef FLATBUFFERS_HAS_STRING_VIEW
// Convenience function to get string_view from a String returning an empty
// string_view on null pointer.
static inline flatbuffers::string_view GetStringView(const String *str) {
return str ? str->string_view() : flatbuffers::string_view();
}
#endif // FLATBUFFERS_HAS_STRING_VIEW
} // namespace flatbuffers
#endif // FLATBUFFERS_STRING_H_

53
thirdparty/flatbuffers/struct.h vendored Normal file
View File

@ -0,0 +1,53 @@
/*
* Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_STRUCT_H_
#define FLATBUFFERS_STRUCT_H_
#include "flatbuffers/base.h"
namespace flatbuffers {
// "structs" are flat structures that do not have an offset table, thus
// always have all members present and do not support forwards/backwards
// compatible extensions.
class Struct FLATBUFFERS_FINAL_CLASS {
public:
template<typename T> T GetField(uoffset_t o) const {
return ReadScalar<T>(&data_[o]);
}
template<typename T> T GetStruct(uoffset_t o) const {
return reinterpret_cast<T>(&data_[o]);
}
const uint8_t *GetAddressOf(uoffset_t o) const { return &data_[o]; }
uint8_t *GetAddressOf(uoffset_t o) { return &data_[o]; }
private:
// private constructor & copy constructor: you obtain instances of this
// class by pointing to existing data only
Struct();
Struct(const Struct &);
Struct &operator=(const Struct &);
uint8_t data_[1];
};
} // namespace flatbuffers
#endif // FLATBUFFERS_STRUCT_H_

168
thirdparty/flatbuffers/table.h vendored Normal file
View File

@ -0,0 +1,168 @@
/*
* Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_TABLE_H_
#define FLATBUFFERS_TABLE_H_
#include "flatbuffers/base.h"
#include "flatbuffers/verifier.h"
namespace flatbuffers {
// "tables" use an offset table (possibly shared) that allows fields to be
// omitted and added at will, but uses an extra indirection to read.
class Table {
public:
const uint8_t *GetVTable() const {
return data_ - ReadScalar<soffset_t>(data_);
}
// This gets the field offset for any of the functions below it, or 0
// if the field was not present.
voffset_t GetOptionalFieldOffset(voffset_t field) const {
// The vtable offset is always at the start.
auto vtable = GetVTable();
// The first element is the size of the vtable (fields + type id + itself).
auto vtsize = ReadScalar<voffset_t>(vtable);
// If the field we're accessing is outside the vtable, we're reading older
// data, so it's the same as if the offset was 0 (not present).
return field < vtsize ? ReadScalar<voffset_t>(vtable + field) : 0;
}
template<typename T> T GetField(voffset_t field, T defaultval) const {
auto field_offset = GetOptionalFieldOffset(field);
return field_offset ? ReadScalar<T>(data_ + field_offset) : defaultval;
}
template<typename P> P GetPointer(voffset_t field) {
auto field_offset = GetOptionalFieldOffset(field);
auto p = data_ + field_offset;
return field_offset ? reinterpret_cast<P>(p + ReadScalar<uoffset_t>(p))
: nullptr;
}
template<typename P> P GetPointer(voffset_t field) const {
return const_cast<Table *>(this)->GetPointer<P>(field);
}
template<typename P> P GetStruct(voffset_t field) const {
auto field_offset = GetOptionalFieldOffset(field);
auto p = const_cast<uint8_t *>(data_ + field_offset);
return field_offset ? reinterpret_cast<P>(p) : nullptr;
}
template<typename Raw, typename Face>
flatbuffers::Optional<Face> GetOptional(voffset_t field) const {
auto field_offset = GetOptionalFieldOffset(field);
auto p = data_ + field_offset;
return field_offset ? Optional<Face>(static_cast<Face>(ReadScalar<Raw>(p)))
: Optional<Face>();
}
template<typename T> bool SetField(voffset_t field, T val, T def) {
auto field_offset = GetOptionalFieldOffset(field);
if (!field_offset) return IsTheSameAs(val, def);
WriteScalar(data_ + field_offset, val);
return true;
}
template<typename T> bool SetField(voffset_t field, T val) {
auto field_offset = GetOptionalFieldOffset(field);
if (!field_offset) return false;
WriteScalar(data_ + field_offset, val);
return true;
}
bool SetPointer(voffset_t field, const uint8_t *val) {
auto field_offset = GetOptionalFieldOffset(field);
if (!field_offset) return false;
WriteScalar(data_ + field_offset,
static_cast<uoffset_t>(val - (data_ + field_offset)));
return true;
}
uint8_t *GetAddressOf(voffset_t field) {
auto field_offset = GetOptionalFieldOffset(field);
return field_offset ? data_ + field_offset : nullptr;
}
const uint8_t *GetAddressOf(voffset_t field) const {
return const_cast<Table *>(this)->GetAddressOf(field);
}
bool CheckField(voffset_t field) const {
return GetOptionalFieldOffset(field) != 0;
}
// Verify the vtable of this table.
// Call this once per table, followed by VerifyField once per field.
bool VerifyTableStart(Verifier &verifier) const {
return verifier.VerifyTableStart(data_);
}
// Verify a particular field.
template<typename T>
bool VerifyField(const Verifier &verifier, voffset_t field,
size_t align) const {
// Calling GetOptionalFieldOffset should be safe now thanks to
// VerifyTable().
auto field_offset = GetOptionalFieldOffset(field);
// Check the actual field.
return !field_offset || verifier.VerifyField<T>(data_, field_offset, align);
}
// VerifyField for required fields.
template<typename T>
bool VerifyFieldRequired(const Verifier &verifier, voffset_t field,
size_t align) const {
auto field_offset = GetOptionalFieldOffset(field);
return verifier.Check(field_offset != 0) &&
verifier.VerifyField<T>(data_, field_offset, align);
}
// Versions for offsets.
bool VerifyOffset(const Verifier &verifier, voffset_t field) const {
auto field_offset = GetOptionalFieldOffset(field);
return !field_offset || verifier.VerifyOffset(data_, field_offset);
}
bool VerifyOffsetRequired(const Verifier &verifier, voffset_t field) const {
auto field_offset = GetOptionalFieldOffset(field);
return verifier.Check(field_offset != 0) &&
verifier.VerifyOffset(data_, field_offset);
}
private:
// private constructor & copy constructor: you obtain instances of this
// class by pointing to existing data only
Table();
Table(const Table &other);
Table &operator=(const Table &);
uint8_t data_[1];
};
// This specialization allows avoiding warnings like:
// MSVC C4800: type: forcing value to bool 'true' or 'false'.
template<>
inline flatbuffers::Optional<bool> Table::GetOptional<uint8_t, bool>(
voffset_t field) const {
auto field_offset = GetOptionalFieldOffset(field);
auto p = data_ + field_offset;
return field_offset ? Optional<bool>(ReadScalar<uint8_t>(p) != 0)
: Optional<bool>();
}
} // namespace flatbuffers
#endif // FLATBUFFERS_TABLE_H_

389
thirdparty/flatbuffers/vector.h vendored Normal file
View File

@ -0,0 +1,389 @@
/*
* Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_VECTOR_H_
#define FLATBUFFERS_VECTOR_H_
#include "flatbuffers/base.h"
#include "flatbuffers/buffer.h"
#include "flatbuffers/stl_emulation.h"
namespace flatbuffers {
struct String;
// An STL compatible iterator implementation for Vector below, effectively
// calling Get() for every element.
template<typename T, typename IT> struct VectorIterator {
typedef std::random_access_iterator_tag iterator_category;
typedef IT value_type;
typedef ptrdiff_t difference_type;
typedef IT *pointer;
typedef IT &reference;
VectorIterator(const uint8_t *data, uoffset_t i)
: data_(data + IndirectHelper<T>::element_stride * i) {}
VectorIterator(const VectorIterator &other) : data_(other.data_) {}
VectorIterator() : data_(nullptr) {}
VectorIterator &operator=(const VectorIterator &other) {
data_ = other.data_;
return *this;
}
VectorIterator &operator=(VectorIterator &&other) {
data_ = other.data_;
return *this;
}
bool operator==(const VectorIterator &other) const {
return data_ == other.data_;
}
bool operator<(const VectorIterator &other) const {
return data_ < other.data_;
}
bool operator!=(const VectorIterator &other) const {
return data_ != other.data_;
}
difference_type operator-(const VectorIterator &other) const {
return (data_ - other.data_) / IndirectHelper<T>::element_stride;
}
// Note: return type is incompatible with the standard
// `reference operator*()`.
IT operator*() const { return IndirectHelper<T>::Read(data_, 0); }
// Note: return type is incompatible with the standard
// `pointer operator->()`.
IT operator->() const { return IndirectHelper<T>::Read(data_, 0); }
VectorIterator &operator++() {
data_ += IndirectHelper<T>::element_stride;
return *this;
}
VectorIterator operator++(int) {
VectorIterator temp(data_, 0);
data_ += IndirectHelper<T>::element_stride;
return temp;
}
VectorIterator operator+(const uoffset_t &offset) const {
return VectorIterator(data_ + offset * IndirectHelper<T>::element_stride,
0);
}
VectorIterator &operator+=(const uoffset_t &offset) {
data_ += offset * IndirectHelper<T>::element_stride;
return *this;
}
VectorIterator &operator--() {
data_ -= IndirectHelper<T>::element_stride;
return *this;
}
VectorIterator operator--(int) {
VectorIterator temp(data_, 0);
data_ -= IndirectHelper<T>::element_stride;
return temp;
}
VectorIterator operator-(const uoffset_t &offset) const {
return VectorIterator(data_ - offset * IndirectHelper<T>::element_stride,
0);
}
VectorIterator &operator-=(const uoffset_t &offset) {
data_ -= offset * IndirectHelper<T>::element_stride;
return *this;
}
private:
const uint8_t *data_;
};
template<typename Iterator>
struct VectorReverseIterator : public std::reverse_iterator<Iterator> {
explicit VectorReverseIterator(Iterator iter)
: std::reverse_iterator<Iterator>(iter) {}
// Note: return type is incompatible with the standard
// `reference operator*()`.
typename Iterator::value_type operator*() const {
auto tmp = std::reverse_iterator<Iterator>::current;
return *--tmp;
}
// Note: return type is incompatible with the standard
// `pointer operator->()`.
typename Iterator::value_type operator->() const {
auto tmp = std::reverse_iterator<Iterator>::current;
return *--tmp;
}
};
// This is used as a helper type for accessing vectors.
// Vector::data() assumes the vector elements start after the length field.
template<typename T> class Vector {
public:
typedef VectorIterator<T, typename IndirectHelper<T>::mutable_return_type>
iterator;
typedef VectorIterator<T, typename IndirectHelper<T>::return_type>
const_iterator;
typedef VectorReverseIterator<iterator> reverse_iterator;
typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
typedef typename flatbuffers::bool_constant<flatbuffers::is_scalar<T>::value>
scalar_tag;
static FLATBUFFERS_CONSTEXPR bool is_span_observable =
scalar_tag::value && (FLATBUFFERS_LITTLEENDIAN || sizeof(T) == 1);
uoffset_t size() const { return EndianScalar(length_); }
// Deprecated: use size(). Here for backwards compatibility.
FLATBUFFERS_ATTRIBUTE([[deprecated("use size() instead")]])
uoffset_t Length() const { return size(); }
typedef typename IndirectHelper<T>::return_type return_type;
typedef typename IndirectHelper<T>::mutable_return_type mutable_return_type;
typedef return_type value_type;
return_type Get(uoffset_t i) const {
FLATBUFFERS_ASSERT(i < size());
return IndirectHelper<T>::Read(Data(), i);
}
return_type operator[](uoffset_t i) const { return Get(i); }
// If this is a Vector of enums, T will be its storage type, not the enum
// type. This function makes it convenient to retrieve value with enum
// type E.
template<typename E> E GetEnum(uoffset_t i) const {
return static_cast<E>(Get(i));
}
// If this a vector of unions, this does the cast for you. There's no check
// to make sure this is the right type!
template<typename U> const U *GetAs(uoffset_t i) const {
return reinterpret_cast<const U *>(Get(i));
}
// If this a vector of unions, this does the cast for you. There's no check
// to make sure this is actually a string!
const String *GetAsString(uoffset_t i) const {
return reinterpret_cast<const String *>(Get(i));
}
const void *GetStructFromOffset(size_t o) const {
return reinterpret_cast<const void *>(Data() + o);
}
iterator begin() { return iterator(Data(), 0); }
const_iterator begin() const { return const_iterator(Data(), 0); }
iterator end() { return iterator(Data(), size()); }
const_iterator end() const { return const_iterator(Data(), size()); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
const_iterator cbegin() const { return begin(); }
const_iterator cend() const { return end(); }
const_reverse_iterator crbegin() const { return rbegin(); }
const_reverse_iterator crend() const { return rend(); }
// Change elements if you have a non-const pointer to this object.
// Scalars only. See reflection.h, and the documentation.
void Mutate(uoffset_t i, const T &val) {
FLATBUFFERS_ASSERT(i < size());
WriteScalar(data() + i, val);
}
// Change an element of a vector of tables (or strings).
// "val" points to the new table/string, as you can obtain from
// e.g. reflection::AddFlatBuffer().
void MutateOffset(uoffset_t i, const uint8_t *val) {
FLATBUFFERS_ASSERT(i < size());
static_assert(sizeof(T) == sizeof(uoffset_t), "Unrelated types");
WriteScalar(data() + i,
static_cast<uoffset_t>(val - (Data() + i * sizeof(uoffset_t))));
}
// Get a mutable pointer to tables/strings inside this vector.
mutable_return_type GetMutableObject(uoffset_t i) const {
FLATBUFFERS_ASSERT(i < size());
return const_cast<mutable_return_type>(IndirectHelper<T>::Read(Data(), i));
}
// The raw data in little endian format. Use with care.
const uint8_t *Data() const {
return reinterpret_cast<const uint8_t *>(&length_ + 1);
}
uint8_t *Data() { return reinterpret_cast<uint8_t *>(&length_ + 1); }
// Similarly, but typed, much like std::vector::data
const T *data() const { return reinterpret_cast<const T *>(Data()); }
T *data() { return reinterpret_cast<T *>(Data()); }
template<typename K> return_type LookupByKey(K key) const {
void *search_result = std::bsearch(
&key, Data(), size(), IndirectHelper<T>::element_stride, KeyCompare<K>);
if (!search_result) {
return nullptr; // Key not found.
}
const uint8_t *element = reinterpret_cast<const uint8_t *>(search_result);
return IndirectHelper<T>::Read(element, 0);
}
template<typename K> mutable_return_type MutableLookupByKey(K key) {
return const_cast<mutable_return_type>(LookupByKey(key));
}
protected:
// This class is only used to access pre-existing data. Don't ever
// try to construct these manually.
Vector();
uoffset_t length_;
private:
// This class is a pointer. Copying will therefore create an invalid object.
// Private and unimplemented copy constructor.
Vector(const Vector &);
Vector &operator=(const Vector &);
template<typename K> static int KeyCompare(const void *ap, const void *bp) {
const K *key = reinterpret_cast<const K *>(ap);
const uint8_t *data = reinterpret_cast<const uint8_t *>(bp);
auto table = IndirectHelper<T>::Read(data, 0);
// std::bsearch compares with the operands transposed, so we negate the
// result here.
return -table->KeyCompareWithValue(*key);
}
};
template<class U>
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<U> make_span(Vector<U> &vec)
FLATBUFFERS_NOEXCEPT {
static_assert(Vector<U>::is_span_observable,
"wrong type U, only LE-scalar, or byte types are allowed");
return span<U>(vec.data(), vec.size());
}
template<class U>
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const U> make_span(
const Vector<U> &vec) FLATBUFFERS_NOEXCEPT {
static_assert(Vector<U>::is_span_observable,
"wrong type U, only LE-scalar, or byte types are allowed");
return span<const U>(vec.data(), vec.size());
}
template<class U>
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<uint8_t> make_bytes_span(
Vector<U> &vec) FLATBUFFERS_NOEXCEPT {
static_assert(Vector<U>::scalar_tag::value,
"wrong type U, only LE-scalar, or byte types are allowed");
return span<uint8_t>(vec.Data(), vec.size() * sizeof(U));
}
template<class U>
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const uint8_t> make_bytes_span(
const Vector<U> &vec) FLATBUFFERS_NOEXCEPT {
static_assert(Vector<U>::scalar_tag::value,
"wrong type U, only LE-scalar, or byte types are allowed");
return span<const uint8_t>(vec.Data(), vec.size() * sizeof(U));
}
// Convenient helper functions to get a span of any vector, regardless
// of whether it is null or not (the field is not set).
template<class U>
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<U> make_span(Vector<U> *ptr)
FLATBUFFERS_NOEXCEPT {
static_assert(Vector<U>::is_span_observable,
"wrong type U, only LE-scalar, or byte types are allowed");
return ptr ? make_span(*ptr) : span<U>();
}
template<class U>
FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const U> make_span(
const Vector<U> *ptr) FLATBUFFERS_NOEXCEPT {
static_assert(Vector<U>::is_span_observable,
"wrong type U, only LE-scalar, or byte types are allowed");
return ptr ? make_span(*ptr) : span<const U>();
}
// Represent a vector much like the template above, but in this case we
// don't know what the element types are (used with reflection.h).
class VectorOfAny {
public:
uoffset_t size() const { return EndianScalar(length_); }
const uint8_t *Data() const {
return reinterpret_cast<const uint8_t *>(&length_ + 1);
}
uint8_t *Data() { return reinterpret_cast<uint8_t *>(&length_ + 1); }
protected:
VectorOfAny();
uoffset_t length_;
private:
VectorOfAny(const VectorOfAny &);
VectorOfAny &operator=(const VectorOfAny &);
};
template<typename T, typename U>
Vector<Offset<T>> *VectorCast(Vector<Offset<U>> *ptr) {
static_assert(std::is_base_of<T, U>::value, "Unrelated types");
return reinterpret_cast<Vector<Offset<T>> *>(ptr);
}
template<typename T, typename U>
const Vector<Offset<T>> *VectorCast(const Vector<Offset<U>> *ptr) {
static_assert(std::is_base_of<T, U>::value, "Unrelated types");
return reinterpret_cast<const Vector<Offset<T>> *>(ptr);
}
// Convenient helper function to get the length of any vector, regardless
// of whether it is null or not (the field is not set).
template<typename T> static inline size_t VectorLength(const Vector<T> *v) {
return v ? v->size() : 0;
}
} // namespace flatbuffers
#endif // FLATBUFFERS_VERIFIER_H_

271
thirdparty/flatbuffers/vector_downward.h vendored Normal file
View File

@ -0,0 +1,271 @@
/*
* Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_VECTOR_DOWNWARD_H_
#define FLATBUFFERS_VECTOR_DOWNWARD_H_
#include "flatbuffers/base.h"
#include "flatbuffers/default_allocator.h"
#include "flatbuffers/detached_buffer.h"
namespace flatbuffers {
// This is a minimal replication of std::vector<uint8_t> functionality,
// except growing from higher to lower addresses. i.e. push_back() inserts data
// in the lowest address in the vector.
// Since this vector leaves the lower part unused, we support a "scratch-pad"
// that can be stored there for temporary data, to share the allocated space.
// Essentially, this supports 2 std::vectors in a single buffer.
class vector_downward {
public:
explicit vector_downward(size_t initial_size, Allocator *allocator,
bool own_allocator, size_t buffer_minalign)
: allocator_(allocator),
own_allocator_(own_allocator),
initial_size_(initial_size),
buffer_minalign_(buffer_minalign),
reserved_(0),
size_(0),
buf_(nullptr),
cur_(nullptr),
scratch_(nullptr) {}
vector_downward(vector_downward &&other)
// clang-format on
: allocator_(other.allocator_),
own_allocator_(other.own_allocator_),
initial_size_(other.initial_size_),
buffer_minalign_(other.buffer_minalign_),
reserved_(other.reserved_),
size_(other.size_),
buf_(other.buf_),
cur_(other.cur_),
scratch_(other.scratch_) {
// No change in other.allocator_
// No change in other.initial_size_
// No change in other.buffer_minalign_
other.own_allocator_ = false;
other.reserved_ = 0;
other.buf_ = nullptr;
other.cur_ = nullptr;
other.scratch_ = nullptr;
}
vector_downward &operator=(vector_downward &&other) {
// Move construct a temporary and swap idiom
vector_downward temp(std::move(other));
swap(temp);
return *this;
}
~vector_downward() {
clear_buffer();
clear_allocator();
}
void reset() {
clear_buffer();
clear();
}
void clear() {
if (buf_) {
cur_ = buf_ + reserved_;
} else {
reserved_ = 0;
cur_ = nullptr;
}
size_ = 0;
clear_scratch();
}
void clear_scratch() { scratch_ = buf_; }
void clear_allocator() {
if (own_allocator_ && allocator_) { delete allocator_; }
allocator_ = nullptr;
own_allocator_ = false;
}
void clear_buffer() {
if (buf_) Deallocate(allocator_, buf_, reserved_);
buf_ = nullptr;
}
// Relinquish the pointer to the caller.
uint8_t *release_raw(size_t &allocated_bytes, size_t &offset) {
auto *buf = buf_;
allocated_bytes = reserved_;
offset = static_cast<size_t>(cur_ - buf_);
// release_raw only relinquishes the buffer ownership.
// Does not deallocate or reset the allocator. Destructor will do that.
buf_ = nullptr;
clear();
return buf;
}
// Relinquish the pointer to the caller.
DetachedBuffer release() {
// allocator ownership (if any) is transferred to DetachedBuffer.
DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_,
size());
if (own_allocator_) {
allocator_ = nullptr;
own_allocator_ = false;
}
buf_ = nullptr;
clear();
return fb;
}
size_t ensure_space(size_t len) {
FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_);
if (len > static_cast<size_t>(cur_ - scratch_)) { reallocate(len); }
// Beyond this, signed offsets may not have enough range:
// (FlatBuffers > 2GB not supported).
FLATBUFFERS_ASSERT(size() < FLATBUFFERS_MAX_BUFFER_SIZE);
return len;
}
inline uint8_t *make_space(size_t len) {
if (len) {
ensure_space(len);
cur_ -= len;
size_ += static_cast<uoffset_t>(len);
}
return cur_;
}
// Returns nullptr if using the DefaultAllocator.
Allocator *get_custom_allocator() { return allocator_; }
inline uoffset_t size() const { return size_; }
uoffset_t scratch_size() const {
return static_cast<uoffset_t>(scratch_ - buf_);
}
size_t capacity() const { return reserved_; }
uint8_t *data() const {
FLATBUFFERS_ASSERT(cur_);
return cur_;
}
uint8_t *scratch_data() const {
FLATBUFFERS_ASSERT(buf_);
return buf_;
}
uint8_t *scratch_end() const {
FLATBUFFERS_ASSERT(scratch_);
return scratch_;
}
uint8_t *data_at(size_t offset) const { return buf_ + reserved_ - offset; }
void push(const uint8_t *bytes, size_t num) {
if (num > 0) { memcpy(make_space(num), bytes, num); }
}
// Specialized version of push() that avoids memcpy call for small data.
template<typename T> void push_small(const T &little_endian_t) {
make_space(sizeof(T));
*reinterpret_cast<T *>(cur_) = little_endian_t;
}
template<typename T> void scratch_push_small(const T &t) {
ensure_space(sizeof(T));
*reinterpret_cast<T *>(scratch_) = t;
scratch_ += sizeof(T);
}
// fill() is most frequently called with small byte counts (<= 4),
// which is why we're using loops rather than calling memset.
void fill(size_t zero_pad_bytes) {
make_space(zero_pad_bytes);
for (size_t i = 0; i < zero_pad_bytes; i++) cur_[i] = 0;
}
// Version for when we know the size is larger.
// Precondition: zero_pad_bytes > 0
void fill_big(size_t zero_pad_bytes) {
memset(make_space(zero_pad_bytes), 0, zero_pad_bytes);
}
void pop(size_t bytes_to_remove) {
cur_ += bytes_to_remove;
size_ -= static_cast<uoffset_t>(bytes_to_remove);
}
void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; }
void swap(vector_downward &other) {
using std::swap;
swap(allocator_, other.allocator_);
swap(own_allocator_, other.own_allocator_);
swap(initial_size_, other.initial_size_);
swap(buffer_minalign_, other.buffer_minalign_);
swap(reserved_, other.reserved_);
swap(size_, other.size_);
swap(buf_, other.buf_);
swap(cur_, other.cur_);
swap(scratch_, other.scratch_);
}
void swap_allocator(vector_downward &other) {
using std::swap;
swap(allocator_, other.allocator_);
swap(own_allocator_, other.own_allocator_);
}
private:
// You shouldn't really be copying instances of this class.
FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward &));
FLATBUFFERS_DELETE_FUNC(vector_downward &operator=(const vector_downward &));
Allocator *allocator_;
bool own_allocator_;
size_t initial_size_;
size_t buffer_minalign_;
size_t reserved_;
uoffset_t size_;
uint8_t *buf_;
uint8_t *cur_; // Points at location between empty (below) and used (above).
uint8_t *scratch_; // Points to the end of the scratchpad in use.
void reallocate(size_t len) {
auto old_reserved = reserved_;
auto old_size = size();
auto old_scratch_size = scratch_size();
reserved_ +=
(std::max)(len, old_reserved ? old_reserved / 2 : initial_size_);
reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1);
if (buf_) {
buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_,
old_size, old_scratch_size);
} else {
buf_ = Allocate(allocator_, reserved_);
}
cur_ = buf_ + reserved_ - old_size;
scratch_ = buf_ + old_scratch_size;
}
};
} // namespace flatbuffers
#endif // FLATBUFFERS_VECTOR_DOWNWARD_H_

317
thirdparty/flatbuffers/verifier.h vendored Normal file
View File

@ -0,0 +1,317 @@
/*
* Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_VERIFIER_H_
#define FLATBUFFERS_VERIFIER_H_
#include "flatbuffers/base.h"
#include "flatbuffers/vector.h"
namespace flatbuffers {
// Helper class to verify the integrity of a FlatBuffer
class Verifier FLATBUFFERS_FINAL_CLASS {
public:
struct Options {
// The maximum nesting of tables and vectors before we call it invalid.
uoffset_t max_depth = 64;
// The maximum number of tables we will verify before we call it invalid.
uoffset_t max_tables = 1000000;
// If true, verify all data is aligned.
bool check_alignment = true;
// If true, run verifier on nested flatbuffers
bool check_nested_flatbuffers = true;
};
explicit Verifier(const uint8_t *const buf, const size_t buf_len,
const Options &opts)
: buf_(buf), size_(buf_len), opts_(opts) {
FLATBUFFERS_ASSERT(size_ < FLATBUFFERS_MAX_BUFFER_SIZE);
}
// Deprecated API, please construct with Verifier::Options.
Verifier(const uint8_t *const buf, const size_t buf_len,
const uoffset_t max_depth = 64, const uoffset_t max_tables = 1000000,
const bool check_alignment = true)
: Verifier(buf, buf_len, [&] {
Options opts;
opts.max_depth = max_depth;
opts.max_tables = max_tables;
opts.check_alignment = check_alignment;
return opts;
}()) {}
// Central location where any verification failures register.
bool Check(const bool ok) const {
// clang-format off
#ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE
FLATBUFFERS_ASSERT(ok);
#endif
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
if (!ok)
upper_bound_ = 0;
#endif
// clang-format on
return ok;
}
// Verify any range within the buffer.
bool Verify(const size_t elem, const size_t elem_len) const {
// clang-format off
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
auto upper_bound = elem + elem_len;
if (upper_bound_ < upper_bound)
upper_bound_ = upper_bound;
#endif
// clang-format on
return Check(elem_len < size_ && elem <= size_ - elem_len);
}
bool VerifyAlignment(const size_t elem, const size_t align) const {
return Check((elem & (align - 1)) == 0 || !opts_.check_alignment);
}
// Verify a range indicated by sizeof(T).
template<typename T> bool Verify(const size_t elem) const {
return VerifyAlignment(elem, sizeof(T)) && Verify(elem, sizeof(T));
}
bool VerifyFromPointer(const uint8_t *const p, const size_t len) {
return Verify(static_cast<size_t>(p - buf_), len);
}
// Verify relative to a known-good base pointer.
bool VerifyFieldStruct(const uint8_t *const base, const voffset_t elem_off,
const size_t elem_len, const size_t align) const {
const auto f = static_cast<size_t>(base - buf_) + elem_off;
return VerifyAlignment(f, align) && Verify(f, elem_len);
}
template<typename T>
bool VerifyField(const uint8_t *const base, const voffset_t elem_off,
const size_t align) const {
const auto f = static_cast<size_t>(base - buf_) + elem_off;
return VerifyAlignment(f, align) && Verify(f, sizeof(T));
}
// Verify a pointer (may be NULL) of a table type.
template<typename T> bool VerifyTable(const T *const table) {
return !table || table->Verify(*this);
}
// Verify a pointer (may be NULL) of any vector type.
template<typename T> bool VerifyVector(const Vector<T> *const vec) const {
return !vec || VerifyVectorOrString(reinterpret_cast<const uint8_t *>(vec),
sizeof(T));
}
// Verify a pointer (may be NULL) of a vector to struct.
template<typename T>
bool VerifyVector(const Vector<const T *> *const vec) const {
return VerifyVector(reinterpret_cast<const Vector<T> *>(vec));
}
// Verify a pointer (may be NULL) to string.
bool VerifyString(const String *const str) const {
size_t end;
return !str || (VerifyVectorOrString(reinterpret_cast<const uint8_t *>(str),
1, &end) &&
Verify(end, 1) && // Must have terminator
Check(buf_[end] == '\0')); // Terminating byte must be 0.
}
// Common code between vectors and strings.
bool VerifyVectorOrString(const uint8_t *const vec, const size_t elem_size,
size_t *const end = nullptr) const {
const auto veco = static_cast<size_t>(vec - buf_);
// Check we can read the size field.
if (!Verify<uoffset_t>(veco)) return false;
// Check the whole array. If this is a string, the byte past the array must
// be 0.
const auto size = ReadScalar<uoffset_t>(vec);
const auto max_elems = FLATBUFFERS_MAX_BUFFER_SIZE / elem_size;
if (!Check(size < max_elems))
return false; // Protect against byte_size overflowing.
const auto byte_size = sizeof(size) + elem_size * size;
if (end) *end = veco + byte_size;
return Verify(veco, byte_size);
}
// Special case for string contents, after the above has been called.
bool VerifyVectorOfStrings(const Vector<Offset<String>> *const vec) const {
if (vec) {
for (uoffset_t i = 0; i < vec->size(); i++) {
if (!VerifyString(vec->Get(i))) return false;
}
}
return true;
}
// Special case for table contents, after the above has been called.
template<typename T>
bool VerifyVectorOfTables(const Vector<Offset<T>> *const vec) {
if (vec) {
for (uoffset_t i = 0; i < vec->size(); i++) {
if (!vec->Get(i)->Verify(*this)) return false;
}
}
return true;
}
__suppress_ubsan__("unsigned-integer-overflow") bool VerifyTableStart(
const uint8_t *const table) {
// Check the vtable offset.
const auto tableo = static_cast<size_t>(table - buf_);
if (!Verify<soffset_t>(tableo)) return false;
// This offset may be signed, but doing the subtraction unsigned always
// gives the result we want.
const auto vtableo =
tableo - static_cast<size_t>(ReadScalar<soffset_t>(table));
// Check the vtable size field, then check vtable fits in its entirety.
if (!(VerifyComplexity() && Verify<voffset_t>(vtableo) &&
VerifyAlignment(ReadScalar<voffset_t>(buf_ + vtableo),
sizeof(voffset_t))))
return false;
const auto vsize = ReadScalar<voffset_t>(buf_ + vtableo);
return Check((vsize & 1) == 0) && Verify(vtableo, vsize);
}
template<typename T>
bool VerifyBufferFromStart(const char *const identifier, const size_t start) {
// Buffers have to be of some size to be valid. The reason it is a runtime
// check instead of static_assert, is that nested flatbuffers go through
// this call and their size is determined at runtime.
if (!Check(size_ >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false;
// If an identifier is provided, check that we have a buffer
if (identifier && !Check((size_ >= 2 * sizeof(flatbuffers::uoffset_t) &&
BufferHasIdentifier(buf_ + start, identifier)))) {
return false;
}
// Call T::Verify, which must be in the generated code for this type.
const auto o = VerifyOffset(start);
return Check(o != 0) &&
reinterpret_cast<const T *>(buf_ + start + o)->Verify(*this)
// clang-format off
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
&& GetComputedSize()
#endif
;
// clang-format on
}
template<typename T>
bool VerifyNestedFlatBuffer(const Vector<uint8_t> *const buf,
const char *const identifier) {
// Caller opted out of this.
if (!opts_.check_nested_flatbuffers) return true;
// An empty buffer is OK as it indicates not present.
if (!buf) return true;
// If there is a nested buffer, it must be greater than the min size.
if (!Check(buf->size() >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false;
Verifier nested_verifier(buf->data(), buf->size());
return nested_verifier.VerifyBuffer<T>(identifier);
}
// Verify this whole buffer, starting with root type T.
template<typename T> bool VerifyBuffer() { return VerifyBuffer<T>(nullptr); }
template<typename T> bool VerifyBuffer(const char *const identifier) {
return VerifyBufferFromStart<T>(identifier, 0);
}
template<typename T>
bool VerifySizePrefixedBuffer(const char *const identifier) {
return Verify<uoffset_t>(0U) &&
Check(ReadScalar<uoffset_t>(buf_) == size_ - sizeof(uoffset_t)) &&
VerifyBufferFromStart<T>(identifier, sizeof(uoffset_t));
}
uoffset_t VerifyOffset(const size_t start) const {
if (!Verify<uoffset_t>(start)) return 0;
const auto o = ReadScalar<uoffset_t>(buf_ + start);
// May not point to itself.
if (!Check(o != 0)) return 0;
// Can't wrap around / buffers are max 2GB.
if (!Check(static_cast<soffset_t>(o) >= 0)) return 0;
// Must be inside the buffer to create a pointer from it (pointer outside
// buffer is UB).
if (!Verify(start + o, 1)) return 0;
return o;
}
uoffset_t VerifyOffset(const uint8_t *const base,
const voffset_t start) const {
return VerifyOffset(static_cast<size_t>(base - buf_) + start);
}
// Called at the start of a table to increase counters measuring data
// structure depth and amount, and possibly bails out with false if limits set
// by the constructor have been hit. Needs to be balanced with EndTable().
bool VerifyComplexity() {
depth_++;
num_tables_++;
return Check(depth_ <= opts_.max_depth && num_tables_ <= opts_.max_tables);
}
// Called at the end of a table to pop the depth count.
bool EndTable() {
depth_--;
return true;
}
// Returns the message size in bytes
size_t GetComputedSize() const {
// clang-format off
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
uintptr_t size = upper_bound_;
// Align the size to uoffset_t
size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1);
return (size > size_) ? 0 : size;
#else
// Must turn on FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE for this to work.
(void)upper_bound_;
FLATBUFFERS_ASSERT(false);
return 0;
#endif
// clang-format on
}
std::vector<uint8_t> *GetFlexReuseTracker() { return flex_reuse_tracker_; }
void SetFlexReuseTracker(std::vector<uint8_t> *const rt) {
flex_reuse_tracker_ = rt;
}
private:
const uint8_t *buf_;
const size_t size_;
const Options opts_;
mutable size_t upper_bound_ = 0;
uoffset_t depth_ = 0;
uoffset_t num_tables_ = 0;
std::vector<uint8_t> *flex_reuse_tracker_ = nullptr;
};
} // namespace flatbuffers
#endif // FLATBUFFERS_VERIFIER_H_

View File

@ -262,12 +262,6 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
endif ()
if (BUILD_SHARED_LIBS)
if (UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS" AND
NOT EMSCRIPTEN)
# Fix rpmlint warning:
# unused-direct-shlib-dependency /usr/lib/libformat.so.1.1.0 /lib/libm.so.6.
target_link_libraries(fmt -Wl,--as-needed)
endif ()
target_compile_definitions(fmt PRIVATE FMT_EXPORT INTERFACE FMT_SHARED)
endif ()
if (FMT_SAFE_DURATION_CAST)

View File

@ -1,3 +1,129 @@
9.1.0 - 2022-08-27
------------------
* ``fmt::formatted_size`` now works at compile time
(`#3026 <https://github.com/fmtlib/fmt/pull/3026>`_). For example
(`godbolt <https://godbolt.org/z/1MW5rMdf8>`__):
.. code:: c++
#include <fmt/compile.h>
int main() {
using namespace fmt::literals;
constexpr size_t n = fmt::formatted_size("{}"_cf, 42);
fmt::print("{}\n", n); // prints 2
}
Thanks `@marksantaniello (Mark Santaniello)
<https://github.com/marksantaniello>`_.
* Fixed handling of invalid UTF-8
(`#3038 <https://github.com/fmtlib/fmt/pull/3038>`_,
`#3044 <https://github.com/fmtlib/fmt/pull/3044>`_,
`#3056 <https://github.com/fmtlib/fmt/pull/3056>`_).
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_ and
`@skeeto (Christopher Wellons) <https://github.com/skeeto>`_.
* Improved Unicode support in ``ostream`` overloads of ``print``
(`#2994 <https://github.com/fmtlib/fmt/pull/2994>`_,
`#3001 <https://github.com/fmtlib/fmt/pull/3001>`_,
`#3025 <https://github.com/fmtlib/fmt/pull/3025>`_).
Thanks `@dimztimz (Dimitrij Mijoski) <https://github.com/dimztimz>`_.
* Fixed handling of the sign specifier in localized formatting on systems with
32-bit ``wchar_t`` (`#3041 <https://github.com/fmtlib/fmt/issues/3041>`_).
* Added support for wide streams to ``fmt::streamed``
(`#2994 <https://github.com/fmtlib/fmt/pull/2994>`_).
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
* Added the ``n`` specifier that disables the output of delimiters when
formatting ranges (`#2981 <https://github.com/fmtlib/fmt/pull/2981>`_,
`#2983 <https://github.com/fmtlib/fmt/pull/2983>`_).
For example (`godbolt <https://godbolt.org/z/roKqGdj8c>`__):
.. code:: c++
#include <fmt/ranges.h>
#include <vector>
int main() {
auto v = std::vector{1, 2, 3};
fmt::print("{:n}\n", v); // prints 1, 2, 3
}
Thanks `@BRevzin (Barry Revzin) <https://github.com/BRevzin>`_.
* Worked around problematic ``std::string_view`` constructors introduced in
C++23 (`#3030 <https://github.com/fmtlib/fmt/issues/3030>`_,
`#3050 <https://github.com/fmtlib/fmt/issues/3050>`_).
Thanks `@strega-nil-ms (nicole mazzuca) <https://github.com/strega-nil-ms>`_.
* Improve handling (exclusion) of recursive ranges
(`#2968 <https://github.com/fmtlib/fmt/issues/2968>`_,
`#2974 <https://github.com/fmtlib/fmt/pull/2974>`_).
Thanks `@Dani-Hub (Daniel Krügler) <https://github.com/Dani-Hub>`_.
* Improved error reporting in format string compilation
(`#3055 <https://github.com/fmtlib/fmt/issues/3055>`_).
* Improved the implementation of
`Dragonbox <https://github.com/jk-jeon/dragonbox>`_, the algorithm used for
the default floating-point formatting
(`#2984 <https://github.com/fmtlib/fmt/pull/2984>`_).
Thanks `@jk-jeon (Junekey Jeon) <https://github.com/jk-jeon>`_.
* Fixed issues with floating-point formatting on exotic platforms.
* Improved the implementation of chrono formatting
(`#3010 <https://github.com/fmtlib/fmt/pull/3010>`_).
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
* Improved documentation
(`#2966 <https://github.com/fmtlib/fmt/pull/2966>`_,
`#3009 <https://github.com/fmtlib/fmt/pull/3009>`_,
`#3020 <https://github.com/fmtlib/fmt/issues/3020>`_,
`#3037 <https://github.com/fmtlib/fmt/pull/3037>`_).
Thanks `@mwinterb <https://github.com/mwinterb>`_,
`@jcelerier (Jean-Michaël Celerier) <https://github.com/jcelerier>`_
and `@remiburtin (Rémi Burtin) <https://github.com/remiburtin>`_.
* Improved build configuration
(`#2991 <https://github.com/fmtlib/fmt/pull/2991>`_,
`#2995 <https://github.com/fmtlib/fmt/pull/2995>`_,
`#3004 <https://github.com/fmtlib/fmt/issues/3004>`_,
`#3007 <https://github.com/fmtlib/fmt/pull/3007>`_,
`#3040 <https://github.com/fmtlib/fmt/pull/3040>`_).
Thanks `@dimztimz (Dimitrij Mijoski) <https://github.com/dimztimz>`_ and
`@hwhsu1231 (Haowei Hsu) <https://github.com/hwhsu1231>`_.
* Fixed various warnings and compilation issues
(`#2969 <https://github.com/fmtlib/fmt/issues/2969>`_,
`#2971 <https://github.com/fmtlib/fmt/pull/2971>`_,
`#2975 <https://github.com/fmtlib/fmt/issues/2975>`_,
`#2982 <https://github.com/fmtlib/fmt/pull/2982>`_,
`#2985 <https://github.com/fmtlib/fmt/pull/2985>`_,
`#2988 <https://github.com/fmtlib/fmt/issues/2988>`_,
`#3000 <https://github.com/fmtlib/fmt/issues/3000>`_,
`#3006 <https://github.com/fmtlib/fmt/issues/3006>`_,
`#3014 <https://github.com/fmtlib/fmt/issues/3014>`_,
`#3015 <https://github.com/fmtlib/fmt/issues/3015>`_,
`#3021 <https://github.com/fmtlib/fmt/pull/3021>`_,
`#3023 <https://github.com/fmtlib/fmt/issues/3023>`_,
`#3024 <https://github.com/fmtlib/fmt/pull/3024>`_,
`#3029 <https://github.com/fmtlib/fmt/pull/3029>`_,
`#3043 <https://github.com/fmtlib/fmt/pull/3043>`_,
`#3052 <https://github.com/fmtlib/fmt/issues/3052>`_,
`#3053 <https://github.com/fmtlib/fmt/pull/3053>`_,
`#3054 <https://github.com/fmtlib/fmt/pull/3054>`_).
Thanks `@h-friederich (Hannes Friederich) <https://github.com/h-friederich>`_,
`@dimztimz (Dimitrij Mijoski) <https://github.com/dimztimz>`_,
`@olupton (Olli Lupton) <https://github.com/olupton>`_,
`@bernhardmgruber (Bernhard Manfred Gruber)
<https://github.com/bernhardmgruber>`_,
`@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
9.0.0 - 2022-07-04
------------------
@ -19,7 +145,7 @@
return result;
}
constexpr auto answer = compile_time_itoa(0.42);
constexpr auto answer = compile_time_dtoa(0.42);
works with the default settings.

View File

@ -12,9 +12,6 @@
.. image:: https://github.com/fmtlib/fmt/workflows/windows/badge.svg
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows
.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v?svg=true
:target: https://ci.appveyor.com/project/vitaut/fmt
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg
:alt: fmt is continuously fuzzed at oss-fuzz
:target: https://bugs.chromium.org/p/oss-fuzz/issues/list?\

View File

@ -203,7 +203,7 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
}
const auto min1 =
(std::numeric_limits<IntermediateRep>::min)() / Factor::num;
if (count < min1) {
if (!std::is_unsigned<IntermediateRep>::value && count < min1) {
ec = 1;
return {};
}
@ -1396,7 +1396,8 @@ inline bool isfinite(T) {
// Converts value to Int and checks that it's in the range [0, upper).
template <typename T, typename Int, FMT_ENABLE_IF(std::is_integral<T>::value)>
inline Int to_nonnegative_int(T value, Int upper) {
FMT_ASSERT(value >= 0 && to_unsigned(value) <= to_unsigned(upper),
FMT_ASSERT(std::is_unsigned<Int>::value ||
(value >= 0 && to_unsigned(value) <= to_unsigned(upper)),
"invalid value");
(void)upper;
return static_cast<Int>(value);
@ -1776,7 +1777,7 @@ struct chrono_formatter {
format_to(std::back_inserter(buf), runtime("{:.{}f}"),
std::fmod(val * static_cast<rep>(Period::num) /
static_cast<rep>(Period::den),
60),
static_cast<rep>(60)),
num_fractional_digits);
if (negative) *out++ = '-';
if (buf.size() < 2 || buf[1] == '.') *out++ = '0';
@ -2001,13 +2002,9 @@ template <typename Char, typename Duration>
struct formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
Char> : formatter<std::tm, Char> {
FMT_CONSTEXPR formatter() {
this->do_parse(default_specs,
default_specs + sizeof(default_specs) / sizeof(Char));
}
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return this->do_parse(ctx.begin(), ctx.end(), true);
basic_string_view<Char> default_specs =
detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
this->do_parse(default_specs.begin(), default_specs.end());
}
template <typename FormatContext>
@ -2015,15 +2012,8 @@ struct formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
FormatContext& ctx) const -> decltype(ctx.out()) {
return formatter<std::tm, Char>::format(localtime(val), ctx);
}
static constexpr const Char default_specs[] = {'%', 'F', ' ', '%', 'T'};
};
template <typename Char, typename Duration>
constexpr const Char
formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
Char>::default_specs[];
template <typename Char> struct formatter<std::tm, Char> {
private:
enum class spec {
@ -2035,13 +2025,18 @@ template <typename Char> struct formatter<std::tm, Char> {
basic_string_view<Char> specs;
protected:
template <typename It>
FMT_CONSTEXPR auto do_parse(It begin, It end, bool with_default = false)
-> It {
template <typename It> FMT_CONSTEXPR auto do_parse(It begin, It end) -> It {
if (begin != end && *begin == ':') ++begin;
end = detail::parse_chrono_format(begin, end, detail::tm_format_checker());
if (!with_default || end != begin)
specs = {begin, detail::to_unsigned(end - begin)};
// Replace default spec only if the new spec is not empty.
if (end != begin) specs = {begin, detail::to_unsigned(end - begin)};
return end;
}
public:
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
-> decltype(ctx.begin()) {
auto end = this->do_parse(ctx.begin(), ctx.end());
// basic_string_view<>::compare isn't constexpr before C++17.
if (specs.size() == 2 && specs[0] == Char('%')) {
if (specs[1] == Char('F'))
@ -2052,12 +2047,6 @@ template <typename Char> struct formatter<std::tm, Char> {
return end;
}
public:
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return this->do_parse(ctx.begin(), ctx.end());
}
template <typename FormatContext>
auto format(const std::tm& tm, FormatContext& ctx) const
-> decltype(ctx.out()) {

View File

@ -634,7 +634,7 @@ struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
**Example**::
fmt::print("Elapsed time: {s:.2f} seconds",
fmt::print("Elapsed time: {0:.2f} seconds",
fmt::styled(1.23, fmt::fg(fmt::color::green) |
fmt::bg(fmt::color::blue)));
\endrst

View File

@ -14,8 +14,8 @@ FMT_BEGIN_NAMESPACE
namespace detail {
template <typename Char, typename InputIt>
inline counting_iterator copy_str(InputIt begin, InputIt end,
counting_iterator it) {
FMT_CONSTEXPR inline counting_iterator copy_str(InputIt begin, InputIt end,
counting_iterator it) {
return it + (end - begin);
}
@ -341,7 +341,7 @@ constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
next_arg_id);
auto f = formatter<T, Char>();
auto end = f.parse(ctx);
return {f, pos + fmt::detail::to_unsigned(end - str.data()) + 1,
return {f, pos + fmt::detail::to_unsigned(end - str.data()),
next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
}
@ -397,13 +397,20 @@ constexpr auto parse_replacement_field_then_tail(S format_str) {
return parse_tail<Args, END_POS + 1, NEXT_ID>(
field<char_type, typename field_type<T>::type, ARG_INDEX>(),
format_str);
} else if constexpr (c == ':') {
} else if constexpr (c != ':') {
FMT_THROW(format_error("expected ':'"));
} else {
constexpr auto result = parse_specs<typename field_type<T>::type>(
str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
return parse_tail<Args, result.end, result.next_arg_id>(
spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
result.fmt},
format_str);
if constexpr (result.end >= str.size() || str[result.end] != '}') {
FMT_THROW(format_error("expected '}'"));
return 0;
} else {
return parse_tail<Args, result.end + 1, result.next_arg_id>(
spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
result.fmt},
format_str);
}
}
}
@ -568,7 +575,8 @@ format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
size_t formatted_size(const S& format_str, const Args&... args) {
FMT_CONSTEXPR20 size_t formatted_size(const S& format_str,
const Args&... args) {
return fmt::format_to(detail::counting_iterator(), format_str, args...)
.count();
}

View File

@ -17,7 +17,7 @@
#include <type_traits>
// The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 90000
#define FMT_VERSION 90100
#if defined(__clang__) && !defined(__ibmxl__)
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
@ -200,6 +200,9 @@
# endif
#endif
// An inline std::forward replacement.
#define FMT_FORWARD(...) static_cast<decltype(__VA_ARGS__)&&>(__VA_ARGS__)
#ifdef _MSC_VER
# define FMT_UNCHECKED_ITERATOR(It) \
using _Unchecked_type = It // Mark iterator as checked.
@ -273,7 +276,8 @@
#ifndef FMT_USE_NONTYPE_TEMPLATE_ARGS
# if defined(__cpp_nontype_template_args) && \
((FMT_GCC_VERSION >= 903 && FMT_CPLUSPLUS >= 201709L) || \
__cpp_nontype_template_args >= 201911L)
__cpp_nontype_template_args >= 201911L) && \
!defined(__NVCOMPILER)
# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1
# else
# define FMT_USE_NONTYPE_TEMPLATE_ARGS 0
@ -402,7 +406,7 @@ template <typename T> auto convert_for_visit(T) -> monostate { return {}; }
template <typename Int>
FMT_CONSTEXPR auto to_unsigned(Int value) ->
typename std::make_unsigned<Int>::type {
FMT_ASSERT(value >= 0, "negative value");
FMT_ASSERT(std::is_unsigned<Int>::value || value >= 0, "negative value");
return static_cast<typename std::make_unsigned<Int>::type>(value);
}
@ -707,8 +711,8 @@ class basic_format_parse_context : private ErrorHandler {
next_arg_id_ = -1;
do_check_arg_id(id);
}
FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {}
FMT_CONSTEXPR void check_dynamic_spec(int arg_id);
FMT_CONSTEXPR void on_error(const char* message) {
ErrorHandler::on_error(message);
@ -735,7 +739,8 @@ class compile_parse_context
ErrorHandler eh = {}, int next_arg_id = 0)
: base(format_str, eh, next_arg_id), num_args_(num_args), types_(types) {}
constexpr int num_args() const { return num_args_; }
constexpr auto num_args() const -> int { return num_args_; }
constexpr auto arg_type(int id) const -> type { return types_[id]; }
FMT_CONSTEXPR auto next_arg_id() -> int {
int id = base::next_arg_id();
@ -748,6 +753,11 @@ class compile_parse_context
if (id >= num_args_) this->on_error("argument not found");
}
using base::check_arg_id;
FMT_CONSTEXPR void check_dynamic_spec(int arg_id) {
if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id]))
this->on_error("width/precision is not integer");
}
};
FMT_END_DETAIL_NAMESPACE
@ -763,6 +773,15 @@ basic_format_parse_context<Char, ErrorHandler>::do_check_arg_id(int id) {
}
}
template <typename Char, typename ErrorHandler>
FMT_CONSTEXPR void
basic_format_parse_context<Char, ErrorHandler>::check_dynamic_spec(int arg_id) {
if (detail::is_constant_evaluated()) {
using context = detail::compile_parse_context<Char, ErrorHandler>;
static_cast<context*>(this)->check_dynamic_spec(arg_id);
}
}
template <typename Context> class basic_format_arg;
template <typename Context> class basic_format_args;
template <typename Context> class dynamic_format_arg_store;
@ -917,11 +936,11 @@ template <typename T> class buffer {
/** Appends data to the end of the buffer. */
template <typename U> void append(const U* begin, const U* end);
template <typename I> FMT_CONSTEXPR auto operator[](I index) -> T& {
template <typename Idx> FMT_CONSTEXPR auto operator[](Idx index) -> T& {
return ptr_[index];
}
template <typename I>
FMT_CONSTEXPR auto operator[](I index) const -> const T& {
template <typename Idx>
FMT_CONSTEXPR auto operator[](Idx index) const -> const T& {
return ptr_[index];
}
};
@ -1649,6 +1668,11 @@ auto copy_str(InputIt begin, InputIt end, appender out) -> appender {
return out;
}
template <typename Char, typename R, typename OutputIt>
FMT_CONSTEXPR auto copy_str(R&& rng, OutputIt out) -> OutputIt {
return detail::copy_str<Char>(rng.begin(), rng.end(), out);
}
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
// A workaround for gcc 4.8 to make void_t work in a SFINAE context.
template <typename... Ts> struct void_t_impl { using type = void; };
@ -1708,7 +1732,7 @@ constexpr auto encode_types() -> unsigned long long {
template <typename Context, typename T>
FMT_CONSTEXPR FMT_INLINE auto make_value(T&& val) -> value<Context> {
const auto& arg = arg_mapper<Context>().map(std::forward<T>(val));
const auto& arg = arg_mapper<Context>().map(FMT_FORWARD(val));
constexpr bool formattable_char =
!std::is_same<decltype(arg), const unformattable_char&>::value;
@ -1875,7 +1899,7 @@ class format_arg_store
data_{detail::make_arg<
is_packed, Context,
detail::mapped_type_constant<remove_cvref_t<T>, Context>::value>(
std::forward<T>(args))...} {
FMT_FORWARD(args))...} {
detail::init_named_args(data_.named_args(), 0, 0, args...);
}
};
@ -1891,7 +1915,7 @@ class format_arg_store
template <typename Context = format_context, typename... Args>
constexpr auto make_format_args(Args&&... args)
-> format_arg_store<Context, remove_cvref_t<Args>...> {
return {std::forward<Args>(args)...};
return {FMT_FORWARD(args)...};
}
/**
@ -2240,11 +2264,14 @@ class dynamic_specs_handler
FMT_CONSTEXPR auto make_arg_ref(int arg_id) -> arg_ref_type {
context_.check_arg_id(arg_id);
context_.check_dynamic_spec(arg_id);
return arg_ref_type(arg_id);
}
FMT_CONSTEXPR auto make_arg_ref(auto_id) -> arg_ref_type {
return arg_ref_type(context_.next_arg_id());
int arg_id = context_.next_arg_id();
context_.check_dynamic_spec(arg_id);
return arg_ref_type(arg_id);
}
FMT_CONSTEXPR auto make_arg_ref(basic_string_view<char_type> arg_id)
@ -2270,12 +2297,15 @@ constexpr auto to_ascii(Char c) -> underlying_t<Char> {
return c;
}
FMT_CONSTEXPR inline auto code_point_length_impl(char c) -> int {
return "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4"
[static_cast<unsigned char>(c) >> 3];
}
template <typename Char>
FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int {
if (const_check(sizeof(Char) != 1)) return 1;
auto lengths =
"\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4";
int len = lengths[static_cast<unsigned char>(*begin) >> 3];
int len = code_point_length_impl(static_cast<char>(*begin));
// Compute the pointer to the next character early so that the next
// iteration can start working on the next character. Neither Clang
@ -2803,7 +2833,8 @@ FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs<Char>& specs,
template <typename ErrorHandler = error_handler>
FMT_CONSTEXPR auto check_cstring_type_spec(presentation_type type,
ErrorHandler&& eh = {}) -> bool {
if (type == presentation_type::none || type == presentation_type::string)
if (type == presentation_type::none || type == presentation_type::string ||
type == presentation_type::debug)
return true;
if (type != presentation_type::pointer) eh.on_error("invalid type specifier");
return false;
@ -2921,7 +2952,10 @@ class format_string_checker {
basic_string_view<Char> format_str, ErrorHandler eh)
: context_(format_str, num_args, types_, eh),
parse_funcs_{&parse_format_specs<Args, parse_context_type>...},
types_{type_constant<Args, char>::value...} {}
types_{
mapped_type_constant<Args,
basic_format_context<Char*, Char>>::value...} {
}
FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
@ -3065,6 +3099,15 @@ struct formatter<T, Char,
return it;
}
template <detail::type U = detail::type_constant<T, Char>::value,
enable_if_t<(U == detail::type::string_type ||
U == detail::type::cstring_type ||
U == detail::type::char_type),
int> = 0>
FMT_CONSTEXPR void set_debug_format() {
specs_.type = presentation_type::debug;
}
template <typename FormatContext>
FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const
-> decltype(ctx.out());
@ -3127,7 +3170,7 @@ template <typename Char, typename... Args> class basic_format_string {
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround broken conversion on older gcc.
template <typename...> using format_string = string_view;
inline auto runtime(string_view s) -> basic_string_view<char> { return s; }
inline auto runtime(string_view s) -> string_view { return s; }
#else
template <typename... Args>
using format_string = basic_format_string<char, type_identity_t<Args>...>;

View File

@ -1337,7 +1337,7 @@ template <typename T> decimal_fp<T> to_decimal(T x) noexcept {
if (r < deltai) {
// Exclude the right endpoint if necessary.
if (r == 0 && z_mul.is_integer && !include_right_endpoint) {
if (r == 0 && (z_mul.is_integer & !include_right_endpoint)) {
--ret_value.significand;
r = float_info<T>::big_divisor;
goto small_divisor_case_label;
@ -1346,26 +1346,11 @@ template <typename T> decimal_fp<T> to_decimal(T x) noexcept {
goto small_divisor_case_label;
} else {
// r == deltai; compare fractional parts.
const carrier_uint two_fl = two_fc - 1;
const typename cache_accessor<T>::compute_mul_parity_result x_mul =
cache_accessor<T>::compute_mul_parity(two_fc - 1, cache, beta);
if (!include_left_endpoint ||
exponent < float_info<T>::case_fc_pm_half_lower_threshold ||
exponent > float_info<T>::divisibility_check_by_5_threshold) {
// If the left endpoint is not included, the condition for
// success is z^(f) < delta^(f) (odd parity).
// Otherwise, the inequalities on exponent ensure that
// x is not an integer, so if z^(f) >= delta^(f) (even parity), we in fact
// have strict inequality.
if (!cache_accessor<T>::compute_mul_parity(two_fl, cache, beta).parity) {
goto small_divisor_case_label;
}
} else {
const typename cache_accessor<T>::compute_mul_parity_result x_mul =
cache_accessor<T>::compute_mul_parity(two_fl, cache, beta);
if (!x_mul.parity && !x_mul.is_integer) {
goto small_divisor_case_label;
}
}
if (!(x_mul.parity | (x_mul.is_integer & include_left_endpoint)))
goto small_divisor_case_label;
}
ret_value.exponent = minus_k + float_info<T>::kappa + 1;
@ -1404,7 +1389,7 @@ small_divisor_case_label:
// or equivalently, when y is an integer.
if (y_mul.parity != approx_y_parity)
--ret_value.significand;
else if (y_mul.is_integer && ret_value.significand % 2 != 0)
else if (y_mul.is_integer & (ret_value.significand % 2 != 0))
--ret_value.significand;
return ret_value;
}
@ -1488,17 +1473,13 @@ FMT_FUNC std::string vformat(string_view fmt, format_args args) {
return to_string(buffer);
}
#ifdef _WIN32
namespace detail {
#ifdef _WIN32
using dword = conditional_t<sizeof(long) == 4, unsigned long, unsigned>;
extern "C" __declspec(dllimport) int __stdcall WriteConsoleW( //
void*, const void*, dword, dword*, void*);
} // namespace detail
#endif
namespace detail {
FMT_FUNC void print(std::FILE* f, string_view text) {
#ifdef _WIN32
FMT_FUNC bool write_console(std::FILE* f, string_view text) {
auto fd = _fileno(f);
if (_isatty(fd)) {
detail::utf8_to_utf16 u16(string_view(text.data(), text.size()));
@ -1506,11 +1487,20 @@ FMT_FUNC void print(std::FILE* f, string_view text) {
if (detail::WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)),
u16.c_str(), static_cast<uint32_t>(u16.size()),
&written, nullptr)) {
return;
return true;
}
// Fallback to fwrite on failure. It can happen if the output has been
// redirected to NUL.
}
// We return false if the file descriptor was not TTY, or it was but
// SetConsoleW failed which can happen if the output has been redirected to
// NUL. In both cases when we return false, we should attempt to do regular
// write via fwrite or std::ostream::write.
return false;
}
#endif
FMT_FUNC void print(std::FILE* f, string_view text) {
#ifdef _WIN32
if (write_console(f, text)) return;
#endif
detail::fwrite_fully(text.data(), 1, text.size(), f);
}

View File

@ -249,6 +249,18 @@ FMT_CONSTEXPR inline void abort_fuzzing_if(bool condition) {
#endif
}
template <typename CharT, CharT... C> struct string_literal {
static constexpr CharT value[sizeof...(C)] = {C...};
constexpr operator basic_string_view<CharT>() const {
return {value, sizeof...(C)};
}
};
#if FMT_CPLUSPLUS < 201703L
template <typename CharT, CharT... C>
constexpr CharT string_literal<CharT, C...>::value[sizeof...(C)];
#endif
template <typename Streambuf> class formatbuf : public Streambuf {
private:
using char_type = typename Streambuf::char_type;
@ -287,7 +299,8 @@ FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To {
if (is_constant_evaluated()) return std::bit_cast<To>(from);
#endif
auto to = To();
std::memcpy(&to, &from, sizeof(to));
// The cast suppresses a bogus -Wclass-memaccess on GCC.
std::memcpy(static_cast<void*>(&to), &from, sizeof(to));
return to;
}
@ -366,10 +379,12 @@ class uint128_fallback {
}
FMT_CONSTEXPR auto operator>>(int shift) const -> uint128_fallback {
if (shift == 64) return {0, hi_};
if (shift > 64) return uint128_fallback(0, hi_) >> (shift - 64);
return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)};
}
FMT_CONSTEXPR auto operator<<(int shift) const -> uint128_fallback {
if (shift == 64) return {lo_, 0};
if (shift > 64) return uint128_fallback(lo_, 0) << (shift - 64);
return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)};
}
FMT_CONSTEXPR auto operator>>=(int shift) -> uint128_fallback& {
@ -389,11 +404,11 @@ class uint128_fallback {
hi_ += (lo_ < n ? 1 : 0);
return *this;
}
#if FMT_HAS_BUILTIN(__builtin_addcll)
#if FMT_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__)
unsigned long long carry;
lo_ = __builtin_addcll(lo_, n, 0, &carry);
hi_ += carry;
#elif FMT_HAS_BUILTIN(__builtin_ia32_addcarryx_u64)
#elif FMT_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__)
unsigned long long result;
auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result);
lo_ = result;
@ -592,19 +607,23 @@ FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e)
constexpr const int shiftc[] = {0, 18, 12, 6, 0};
constexpr const int shifte[] = {0, 6, 4, 2, 0};
int len = code_point_length(s);
const char* next = s + len;
int len = code_point_length_impl(*s);
// Compute the pointer to the next character early so that the next
// iteration can start working on the next character. Neither Clang
// nor GCC figure out this reordering on their own.
const char* next = s + len + !len;
using uchar = unsigned char;
// Assume a four-byte character and load four bytes. Unused bits are
// shifted out.
*c = uint32_t(s[0] & masks[len]) << 18;
*c |= uint32_t(s[1] & 0x3f) << 12;
*c |= uint32_t(s[2] & 0x3f) << 6;
*c |= uint32_t(s[3] & 0x3f) << 0;
*c = uint32_t(uchar(s[0]) & masks[len]) << 18;
*c |= uint32_t(uchar(s[1]) & 0x3f) << 12;
*c |= uint32_t(uchar(s[2]) & 0x3f) << 6;
*c |= uint32_t(uchar(s[3]) & 0x3f) << 0;
*c >>= shiftc[len];
// Accumulate the various error conditions.
using uchar = unsigned char;
*e = (*c < mins[len]) << 6; // non-canonical encoding
*e |= ((*c >> 11) == 0x1b) << 7; // surrogate half?
*e |= (*c > 0x10FFFF) << 8; // out of range?
@ -628,8 +647,8 @@ FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) {
auto error = 0;
auto end = utf8_decode(buf_ptr, &cp, &error);
bool result = f(error ? invalid_code_point : cp,
string_view(ptr, to_unsigned(end - buf_ptr)));
return result ? end : nullptr;
string_view(ptr, error ? 1 : to_unsigned(end - buf_ptr)));
return result ? (error ? buf_ptr + 1 : end) : nullptr;
};
auto p = s.data();
const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars.
@ -919,8 +938,11 @@ struct is_contiguous<basic_memory_buffer<T, SIZE, Allocator>> : std::true_type {
};
namespace detail {
#ifdef _WIN32
FMT_API bool write_console(std::FILE* f, string_view text);
#endif
FMT_API void print(std::FILE*, string_view);
}
} // namespace detail
/** A formatting error such as invalid format string. */
FMT_CLASS_API
@ -1213,7 +1235,7 @@ FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size)
template <typename Char, typename UInt, typename Iterator,
FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<Iterator>>::value)>
inline auto format_decimal(Iterator out, UInt value, int size)
FMT_CONSTEXPR inline auto format_decimal(Iterator out, UInt value, int size)
-> format_decimal_result<Iterator> {
// Buffer is large enough to hold all digits (digits10 + 1).
Char buffer[digits10<UInt>() + 1];
@ -1274,8 +1296,6 @@ template <> struct float_info<float> {
static const int small_divisor = 10;
static const int min_k = -31;
static const int max_k = 46;
static const int divisibility_check_by_5_threshold = 39;
static const int case_fc_pm_half_lower_threshold = -1;
static const int shorter_interval_tie_lower_threshold = -35;
static const int shorter_interval_tie_upper_threshold = -35;
};
@ -1288,8 +1308,6 @@ template <> struct float_info<double> {
static const int small_divisor = 100;
static const int min_k = -292;
static const int max_k = 326;
static const int divisibility_check_by_5_threshold = 86;
static const int case_fc_pm_half_lower_threshold = -2;
static const int shorter_interval_tie_lower_threshold = -77;
static const int shorter_interval_tie_upper_threshold = -77;
};
@ -1543,7 +1561,10 @@ FMT_CONSTEXPR inline fp get_cached_power(int min_exponent,
const int dec_exp_step = 8;
index = (index - first_dec_exp - 1) / dec_exp_step + 1;
pow10_exponent = first_dec_exp + index * dec_exp_step;
return {data::pow10_significands[index], data::pow10_exponents[index]};
// Using *(x + index) instead of x[index] avoids an issue with some compilers
// using the EDG frontend (e.g. nvhpc/22.3 in C++17 mode).
return {*(data::pow10_significands + index),
*(data::pow10_exponents + index)};
}
#ifndef _MSC_VER
@ -1724,18 +1745,18 @@ inline auto find_escape(const char* begin, const char* end)
return result;
}
#define FMT_STRING_IMPL(s, base, explicit) \
[] { \
/* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \
/* Use a macro-like name to avoid shadowing warnings. */ \
struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \
using char_type = fmt::remove_cvref_t<decltype(s[0])>; \
FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \
operator fmt::basic_string_view<char_type>() const { \
return fmt::detail_exported::compile_string_to_view<char_type>(s); \
} \
}; \
return FMT_COMPILE_STRING(); \
#define FMT_STRING_IMPL(s, base, explicit) \
[] { \
/* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \
/* Use a macro-like name to avoid shadowing warnings. */ \
struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \
using char_type FMT_MAYBE_UNUSED = fmt::remove_cvref_t<decltype(s[0])>; \
FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \
operator fmt::basic_string_view<char_type>() const { \
return fmt::detail_exported::compile_string_to_view<char_type>(s); \
} \
}; \
return FMT_COMPILE_STRING(); \
}()
/**
@ -1981,7 +2002,10 @@ auto write_int_localized(OutputIt out, UInt value, unsigned prefix,
grouping.count_separators(num_digits));
return write_padded<align::right>(
out, specs, size, size, [&](reserve_iterator<OutputIt> it) {
if (prefix != 0) *it++ = static_cast<Char>(prefix);
if (prefix != 0) {
char sign = static_cast<char>(prefix);
*it++ = static_cast<Char>(sign);
}
return grouping.apply(it, string_view(digits, to_unsigned(num_digits)));
});
}
@ -2123,29 +2147,30 @@ class counting_iterator {
FMT_UNCHECKED_ITERATOR(counting_iterator);
struct value_type {
template <typename T> void operator=(const T&) {}
template <typename T> FMT_CONSTEXPR void operator=(const T&) {}
};
counting_iterator() : count_(0) {}
FMT_CONSTEXPR counting_iterator() : count_(0) {}
size_t count() const { return count_; }
FMT_CONSTEXPR size_t count() const { return count_; }
counting_iterator& operator++() {
FMT_CONSTEXPR counting_iterator& operator++() {
++count_;
return *this;
}
counting_iterator operator++(int) {
FMT_CONSTEXPR counting_iterator operator++(int) {
auto it = *this;
++*this;
return it;
}
friend counting_iterator operator+(counting_iterator it, difference_type n) {
FMT_CONSTEXPR friend counting_iterator operator+(counting_iterator it,
difference_type n) {
it.count_ += static_cast<size_t>(n);
return it;
}
value_type operator*() const { return {}; }
FMT_CONSTEXPR value_type operator*() const { return {}; }
};
template <typename Char, typename OutputIt>
@ -2991,7 +3016,7 @@ FMT_CONSTEXPR20 inline void format_dragon(basic_fp<uint128_t> value,
upper = &upper_store;
}
}
bool even = (value.f & 1) == 0;
int even = static_cast<int>((value.f & 1) == 0);
if (!upper) upper = &lower;
if ((flags & dragon::fixup) != 0) {
if (add_compare(numerator, *upper, denominator) + even <= 0) {

View File

@ -10,6 +10,12 @@
#include <fstream>
#include <ostream>
#if defined(_WIN32) && defined(__GLIBCXX__)
# include <ext/stdio_filebuf.h>
# include <ext/stdio_sync_filebuf.h>
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
# include <__std_stream>
#endif
#include "format.h"
@ -51,43 +57,50 @@ struct is_streamable<
(std::is_convertible<T, int>::value && !std::is_enum<T>::value)>>
: std::false_type {};
template <typename Char> FILE* get_file(std::basic_filebuf<Char>&) {
return nullptr;
}
struct dummy_filebuf {
FILE* _Myfile;
};
template <typename T, typename U = int> struct ms_filebuf {
using type = dummy_filebuf;
};
template <typename T> struct ms_filebuf<T, decltype(T::_Myfile, 0)> {
using type = T;
};
using filebuf_type = ms_filebuf<std::filebuf>::type;
FILE* get_file(filebuf_type& buf);
// Generate a unique explicit instantion in every translation unit using a tag
// type in an anonymous namespace.
namespace {
struct filebuf_access_tag {};
struct file_access_tag {};
} // namespace
template <typename Tag, typename FileMemberPtr, FileMemberPtr file>
class filebuf_access {
friend FILE* get_file(filebuf_type& buf) { return buf.*file; }
template <class Tag, class BufType, FILE* BufType::*FileMemberPtr>
class file_access {
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
};
template class filebuf_access<filebuf_access_tag,
decltype(&filebuf_type::_Myfile),
&filebuf_type::_Myfile>;
inline bool write(std::filebuf& buf, fmt::string_view data) {
FILE* f = get_file(buf);
if (!f) return false;
print(f, data);
return true;
#if FMT_MSC_VERSION
template class file_access<file_access_tag, std::filebuf,
&std::filebuf::_Myfile>;
auto get_file(std::filebuf&) -> FILE*;
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
template class file_access<file_access_tag, std::__stdoutbuf<char>,
&std::__stdoutbuf<char>::__file_>;
auto get_file(std::__stdoutbuf<char>&) -> FILE*;
#endif
inline bool write_ostream_unicode(std::ostream& os, fmt::string_view data) {
#if FMT_MSC_VERSION
if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
if (FILE* f = get_file(*buf)) return write_console(f, data);
#elif defined(_WIN32) && defined(__GLIBCXX__)
auto* rdbuf = os.rdbuf();
FILE* c_file;
if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
c_file = fbuf->file();
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
c_file = fbuf->file();
else
return false;
if (c_file) return write_console(c_file, data);
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
if (auto* buf = dynamic_cast<std::__stdoutbuf<char>*>(os.rdbuf()))
if (FILE* f = get_file(*buf)) return write_console(f, data);
#else
ignore_unused(os, data);
#endif
return false;
}
inline bool write(std::wfilebuf&, fmt::basic_string_view<wchar_t>) {
inline bool write_ostream_unicode(std::wostream&,
fmt::basic_string_view<wchar_t>) {
return false;
}
@ -95,10 +108,6 @@ inline bool write(std::wfilebuf&, fmt::basic_string_view<wchar_t>) {
// It is a separate function rather than a part of vprint to simplify testing.
template <typename Char>
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
if (const_check(FMT_MSC_VERSION)) {
auto filebuf = dynamic_cast<std::basic_filebuf<Char>*>(os.rdbuf());
if (filebuf && write(*filebuf, {buf.data(), buf.size()})) return;
}
const Char* buf_data = buf.data();
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
unsigned_streamsize size = buf.size();
@ -130,6 +139,8 @@ template <typename T> struct streamed_view { const T& value; };
// Formats an object of type T that has an overloaded ostream operator<<.
template <typename Char>
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
void set_debug_format() = delete;
template <typename T, typename OutputIt>
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const
-> OutputIt {
@ -142,12 +153,13 @@ struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
using ostream_formatter = basic_ostream_formatter<char>;
template <typename T>
struct formatter<detail::streamed_view<T>> : ostream_formatter {
template <typename T, typename Char>
struct formatter<detail::streamed_view<T>, Char>
: basic_ostream_formatter<Char> {
template <typename OutputIt>
auto format(detail::streamed_view<T> view,
basic_format_context<OutputIt, char>& ctx) const -> OutputIt {
return ostream_formatter::format(view.value, ctx);
basic_format_context<OutputIt, Char>& ctx) const -> OutputIt {
return basic_ostream_formatter<Char>::format(view.value, ctx);
}
};
@ -175,6 +187,13 @@ struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
using basic_ostream_formatter<Char>::format;
};
inline void vprint_directly(std::ostream& os, string_view format_str,
format_args args) {
auto buffer = memory_buffer();
detail::vformat_to(buffer, format_str, args);
detail::write_buffer(os, buffer);
}
} // namespace detail
FMT_MODULE_EXPORT template <typename Char>
@ -183,6 +202,7 @@ void vprint(std::basic_ostream<Char>& os,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
auto buffer = basic_memory_buffer<Char>();
detail::vformat_to(buffer, format_str, args);
if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return;
detail::write_buffer(os, buffer);
}
@ -197,7 +217,11 @@ void vprint(std::basic_ostream<Char>& os,
*/
FMT_MODULE_EXPORT template <typename... T>
void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
vprint(os, fmt, fmt::make_format_args(args...));
const auto& vargs = fmt::make_format_args(args...);
if (detail::is_utf8())
vprint(os, fmt, vargs);
else
detail::vprint_directly(os, fmt, vargs);
}
FMT_MODULE_EXPORT

View File

@ -270,8 +270,8 @@ template <typename Range>
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
template <typename Range>
using uncvref_first_type = remove_cvref_t<
decltype(std::declval<range_reference_type<Range>>().first)>;
using uncvref_first_type =
remove_cvref_t<decltype(std::declval<range_reference_type<Range>>().first)>;
template <typename Range>
using uncvref_second_type = remove_cvref_t<
@ -326,18 +326,37 @@ struct formatter<TupleT, Char,
enable_if_t<fmt::is_tuple_like<TupleT>::value &&
fmt::is_tuple_formattable<TupleT, Char>::value>> {
private:
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
basic_string_view<Char> opening_bracket_ =
detail::string_literal<Char, '('>{};
basic_string_view<Char> closing_bracket_ =
detail::string_literal<Char, ')'>{};
// C++11 generic lambda for format().
template <typename FormatContext> struct format_each {
template <typename T> void operator()(const T& v) {
if (i > 0) out = detail::write_delimiter(out);
if (i > 0) out = detail::copy_str<Char>(separator, out);
out = detail::write_range_entry<Char>(out, v);
++i;
}
int i;
typename FormatContext::iterator& out;
basic_string_view<Char> separator;
};
public:
FMT_CONSTEXPR formatter() {}
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
separator_ = sep;
}
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
basic_string_view<Char> close) {
opening_bracket_ = open;
closing_bracket_ = close;
}
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
@ -347,9 +366,9 @@ struct formatter<TupleT, Char,
auto format(const TupleT& values, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
*out++ = '(';
detail::for_each(values, format_each<FormatContext>{0, out});
*out++ = ')';
out = detail::copy_str<Char>(opening_bracket_, out);
detail::for_each(values, format_each<FormatContext>{0, out, separator_});
out = detail::copy_str<Char>(closing_bracket_, out);
return out;
}
};
@ -357,9 +376,8 @@ struct formatter<TupleT, Char,
template <typename T, typename Char> struct is_range {
static constexpr const bool value =
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
!detail::is_map<T>::value &&
!std::is_convertible<T, std::basic_string<Char>>::value &&
!std::is_constructible<detail::std_string_view<Char>, T>::value;
!std::is_convertible<T, detail::std_string_view<Char>>::value;
};
namespace detail {
@ -390,40 +408,88 @@ using range_formatter_type = conditional_t<
template <typename R>
using maybe_const_range =
conditional_t<has_const_begin_end<R>::value, const R, R>;
// Workaround a bug in MSVC 2015 and earlier.
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
template <typename R, typename Char>
struct is_formattable_delayed
: disjunction<
is_formattable<uncvref_type<maybe_const_range<R>>, Char>,
has_fallback_formatter<uncvref_type<maybe_const_range<R>>, Char>> {};
#endif
} // namespace detail
template <typename R, typename Char>
struct formatter<
R, Char,
enable_if_t<
conjunction<fmt::is_range<R, Char>
// Workaround a bug in MSVC 2017 and earlier.
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1920
,
disjunction<
is_formattable<detail::uncvref_type<detail::maybe_const_range<R>>,
Char>,
detail::has_fallback_formatter<
detail::uncvref_type<detail::maybe_const_range<R>>, Char>
>
#endif
>::value
>> {
template <typename T, typename Char, typename Enable = void>
struct range_formatter;
using range_type = detail::maybe_const_range<R>;
using formatter_type =
detail::range_formatter_type<Char, detail::uncvref_type<range_type>>;
formatter_type underlying_;
template <typename T, typename Char>
struct range_formatter<
T, Char,
enable_if_t<conjunction<
std::is_same<T, remove_cvref_t<T>>,
disjunction<is_formattable<T, Char>,
detail::has_fallback_formatter<T, Char>>>::value>> {
private:
detail::range_formatter_type<Char, T> underlying_;
bool custom_specs_ = false;
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
basic_string_view<Char> opening_bracket_ =
detail::string_literal<Char, '['>{};
basic_string_view<Char> closing_bracket_ =
detail::string_literal<Char, ']'>{};
template <class U>
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, int)
-> decltype(u.set_debug_format()) {
u.set_debug_format();
}
template <class U>
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
FMT_CONSTEXPR void maybe_set_debug_format() {
maybe_set_debug_format(underlying_, 0);
}
public:
FMT_CONSTEXPR range_formatter() {}
FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& {
return underlying_;
}
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
separator_ = sep;
}
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
basic_string_view<Char> close) {
opening_bracket_ = open;
closing_bracket_ = close;
}
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
auto it = ctx.begin();
auto end = ctx.end();
if (it == end || *it == '}') return it;
if (it == end || *it == '}') {
maybe_set_debug_format();
return it;
}
if (*it == 'n') {
set_brackets({}, {});
++it;
}
if (*it == '}') {
maybe_set_debug_format();
return it;
}
if (*it != ':')
FMT_THROW(format_error("no top-level range formatters supported"));
FMT_THROW(format_error("no other top-level range formatters supported"));
custom_specs_ = true;
++it;
@ -431,75 +497,100 @@ struct formatter<
return underlying_.parse(ctx);
}
template <typename FormatContext>
auto format(range_type& range, FormatContext& ctx) const
-> decltype(ctx.out()) {
Char prefix = detail::is_set<R>::value ? '{' : '[';
Char postfix = detail::is_set<R>::value ? '}' : ']';
template <typename R, class FormatContext>
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
detail::range_mapper<buffer_context<Char>> mapper;
auto out = ctx.out();
*out++ = prefix;
out = detail::copy_str<Char>(opening_bracket_, out);
int i = 0;
auto it = detail::range_begin(range);
auto end = detail::range_end(range);
for (; it != end; ++it) {
if (i > 0) out = detail::write_delimiter(out);
if (custom_specs_) {
ctx.advance_to(out);
out = underlying_.format(mapper.map(*it), ctx);
} else {
out = detail::write_range_entry<Char>(out, *it);
}
if (i > 0) out = detail::copy_str<Char>(separator_, out);
;
ctx.advance_to(out);
out = underlying_.format(mapper.map(*it), ctx);
++i;
}
*out++ = postfix;
out = detail::copy_str<Char>(closing_bracket_, out);
return out;
}
};
template <typename T, typename Char>
struct formatter<
T, Char,
enable_if_t<conjunction<detail::is_map<T>
// Workaround a bug in MSVC 2017 and earlier.
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1920
,
disjunction<
is_formattable<detail::uncvref_first_type<T>, Char>,
detail::has_fallback_formatter<detail::uncvref_first_type<T>, Char>
>,
disjunction<
is_formattable<detail::uncvref_second_type<T>, Char>,
detail::has_fallback_formatter<detail::uncvref_second_type<T>, Char>
>
#endif
>::value
>> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
enum class range_format { disabled, map, set, sequence, string, debug_string };
namespace detail {
template <typename T> struct range_format_kind_ {
static constexpr auto value = std::is_same<range_reference_type<T>, T>::value
? range_format::disabled
: is_map<T>::value ? range_format::map
: is_set<T>::value ? range_format::set
: range_format::sequence;
};
template <range_format K, typename R, typename Char, typename Enable = void>
struct range_default_formatter;
template <range_format K>
using range_format_constant = std::integral_constant<range_format, K>;
template <range_format K, typename R, typename Char>
struct range_default_formatter<
K, R, Char,
enable_if_t<(K == range_format::sequence || K == range_format::map ||
K == range_format::set)>> {
using range_type = detail::maybe_const_range<R>;
range_formatter<detail::uncvref_type<range_type>, Char> underlying_;
FMT_CONSTEXPR range_default_formatter() { init(range_format_constant<K>()); }
FMT_CONSTEXPR void init(range_format_constant<range_format::set>) {
underlying_.set_brackets(detail::string_literal<Char, '{'>{},
detail::string_literal<Char, '}'>{});
}
template <
typename FormatContext, typename U,
FMT_ENABLE_IF(
std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
const T, T>>::value)>
auto format(U& map, FormatContext& ctx) const -> decltype(ctx.out()) {
auto out = ctx.out();
*out++ = '{';
int i = 0;
for (const auto& item : map) {
if (i > 0) out = detail::write_delimiter(out);
out = detail::write_range_entry<Char>(out, item.first);
*out++ = ':';
*out++ = ' ';
out = detail::write_range_entry<Char>(out, item.second);
++i;
}
*out++ = '}';
return out;
FMT_CONSTEXPR void init(range_format_constant<range_format::map>) {
underlying_.set_brackets(detail::string_literal<Char, '{'>{},
detail::string_literal<Char, '}'>{});
underlying_.underlying().set_brackets({}, {});
underlying_.underlying().set_separator(
detail::string_literal<Char, ':', ' '>{});
}
FMT_CONSTEXPR void init(range_format_constant<range_format::sequence>) {}
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return underlying_.parse(ctx);
}
template <typename FormatContext>
auto format(range_type& range, FormatContext& ctx) const
-> decltype(ctx.out()) {
return underlying_.format(range, ctx);
}
};
} // namespace detail
template <typename T, typename Char, typename Enable = void>
struct range_format_kind
: conditional_t<
is_range<T, Char>::value, detail::range_format_kind_<T>,
std::integral_constant<range_format, range_format::disabled>> {};
template <typename R, typename Char>
struct formatter<
R, Char,
enable_if_t<conjunction<bool_constant<range_format_kind<R, Char>::value !=
range_format::disabled>
// Workaround a bug in MSVC 2015 and earlier.
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
,
detail::is_formattable_delayed<R, Char>
#endif
>::value>>
: detail::range_default_formatter<range_format_kind<R, Char>::value, R,
Char> {
};
template <typename Char, typename... T> struct tuple_join_view : detail::view {

View File

@ -57,10 +57,6 @@ inline void write_escaped_path<std::filesystem::path::value_type>(
} // namespace detail
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1920
// For MSVC 2017 and earlier using the partial specialization
// would cause an ambiguity error, therefore we provide it only
// conditionally.
template <typename Char>
struct formatter<std::filesystem::path, Char>
: formatter<basic_string_view<Char>> {
@ -73,7 +69,6 @@ struct formatter<std::filesystem::path, Char>
basic_string_view<Char>(quoted.data(), quoted.size()), ctx);
}
};
#endif
FMT_END_NAMESPACE
#endif

View File

@ -9,7 +9,6 @@
#define FMT_XCHAR_H_
#include <cwchar>
#include <tuple>
#include "format.h"
@ -30,9 +29,11 @@ using wmemory_buffer = basic_memory_buffer<wchar_t>;
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround broken conversion on older gcc.
template <typename... Args> using wformat_string = wstring_view;
inline auto runtime(wstring_view s) -> wstring_view { return s; }
#else
template <typename... Args>
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
inline auto runtime(wstring_view s) -> basic_runtime<wchar_t> { return {{s}}; }
#endif
template <> struct is_char<wchar_t> : std::true_type {};
@ -82,20 +83,16 @@ auto vformat(basic_string_view<Char> format_str,
return to_string(buffer);
}
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 409
template <typename... Args>
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
#endif
template <typename... T>
auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring {
return vformat(fmt, fmt::make_wformat_args(args...));
return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...));
}
// Pass char_t as a default template parameter instead of using
// std::basic_string<char_t<S>> to reduce the symbol size.
template <typename S, typename... Args, typename Char = char_t<S>,
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
FMT_ENABLE_IF(!std::is_same<Char, char>::value &&
!std::is_same<Char, wchar_t>::value)>
auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
return vformat(detail::to_string_view(format_str),
fmt::make_format_args<buffer_context<Char>>(args...));

View File

@ -1,43 +0,0 @@
#!/usr/bin/env python
# Build the project on AppVeyor.
import os
from subprocess import check_call
build = os.environ['BUILD']
config = os.environ['CONFIGURATION']
platform = os.environ['PLATFORM']
path = os.environ['PATH']
image = os.environ['APPVEYOR_BUILD_WORKER_IMAGE']
jobid = os.environ['APPVEYOR_JOB_ID']
cmake_command = ['cmake', '-DFMT_PEDANTIC=ON', '-DCMAKE_BUILD_TYPE=' + config, '..']
if build == 'mingw':
cmake_command.append('-GMinGW Makefiles')
build_command = ['mingw32-make', '-j4']
test_command = ['mingw32-make', 'test']
# Remove the path to Git bin directory from $PATH because it breaks
# MinGW config.
path = path.replace(r'C:\Program Files (x86)\Git\bin', '')
os.environ['PATH'] = r'C:\MinGW\bin;' + path
else:
# Add MSBuild 14.0 to PATH as described in
# http://help.appveyor.com/discussions/problems/2229-v140-not-found-on-vs2105rc.
os.environ['PATH'] = r'C:\Program Files (x86)\MSBuild\15.0\Bin;' + path
if image == 'Visual Studio 2019':
generator = 'Visual Studio 16 2019'
if platform == 'x64':
cmake_command.extend(['-A', 'x64'])
else:
if image == 'Visual Studio 2015':
generator = 'Visual Studio 14 2015'
elif image == 'Visual Studio 2017':
generator = 'Visual Studio 15 2017'
if platform == 'x64':
generator += ' Win64'
cmake_command.append('-G' + generator)
build_command = ['cmake', '--build', '.', '--config', config, '--', '/m:4']
test_command = ['ctest', '-C', config]
check_call(cmake_command)
check_call(build_command)
check_call(test_command)

View File

@ -1,31 +0,0 @@
configuration:
- Debug
- Release
clone_depth: 1
image:
- Visual Studio 2015
platform:
- x64
environment:
CTEST_OUTPUT_ON_FAILURE: 1
MSVC_DEFAULT_OPTIONS: ON
BUILD: msvc
before_build:
- mkdir build
- cd build
build_script:
- python ../support/appveyor-build.py
on_failure:
- appveyor PushArtifact Testing/Temporary/LastTest.log
- appveyor AddTest test
# Uncomment this to debug AppVeyor failures.
#on_finish:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

View File

@ -183,6 +183,12 @@ def update_site(env):
with rewrite(index) as b:
b.data = b.data.replace(
'doc/latest/index.html#format-string-syntax', 'syntax.html')
# Fix issues in syntax.rst.
index = os.path.join(target_doc_dir, 'syntax.rst')
with rewrite(index) as b:
b.data = b.data.replace(
'..productionlist:: sf\n', '.. productionlist:: sf\n ')
b.data = b.data.replace('Examples:\n', 'Examples::\n')
# Build the docs.
html_dir = os.path.join(env.build_dir, 'html')
if os.path.exists(html_dir):

View File

@ -3,7 +3,7 @@
#define LLHTTP_VERSION_MAJOR 6
#define LLHTTP_VERSION_MINOR 0
#define LLHTTP_VERSION_PATCH 7
#define LLHTTP_VERSION_PATCH 9
#ifndef LLHTTP_STRICT_MODE
# define LLHTTP_STRICT_MODE 0
@ -102,7 +102,8 @@ enum llhttp_lenient_flags {
LENIENT_HEADERS = 0x1,
LENIENT_CHUNKED_LENGTH = 0x2,
LENIENT_KEEP_ALIVE = 0x4,
LENIENT_TRANSFER_ENCODING = 0x8
LENIENT_TRANSFER_ENCODING = 0x8,
LENIENT_VERSION = 0x10
};
typedef enum llhttp_lenient_flags llhttp_lenient_flags_t;

File diff suppressed because it is too large Load Diff

498
thirdparty/webp/sharpyuv/sharpyuv.c vendored Normal file
View File

@ -0,0 +1,498 @@
// Copyright 2022 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Sharp RGB to YUV conversion.
//
// Author: Skal (pascal.massimino@gmail.com)
#include "sharpyuv/sharpyuv.h"
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "src/webp/types.h"
#include "src/dsp/cpu.h"
#include "sharpyuv/sharpyuv_dsp.h"
#include "sharpyuv/sharpyuv_gamma.h"
//------------------------------------------------------------------------------
// Sharp RGB->YUV conversion
static const int kNumIterations = 4;
#define YUV_FIX 16 // fixed-point precision for RGB->YUV
static const int kYuvHalf = 1 << (YUV_FIX - 1);
// Max bit depth so that intermediate calculations fit in 16 bits.
static const int kMaxBitDepth = 14;
// Returns the precision shift to use based on the input rgb_bit_depth.
static int GetPrecisionShift(int rgb_bit_depth) {
// Try to add 2 bits of precision if it fits in kMaxBitDepth. Otherwise remove
// bits if needed.
return ((rgb_bit_depth + 2) <= kMaxBitDepth) ? 2
: (kMaxBitDepth - rgb_bit_depth);
}
typedef int16_t fixed_t; // signed type with extra precision for UV
typedef uint16_t fixed_y_t; // unsigned type with extra precision for W
//------------------------------------------------------------------------------
static uint8_t clip_8b(fixed_t v) {
return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u;
}
static uint16_t clip(fixed_t v, int max) {
return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
}
static fixed_y_t clip_bit_depth(int y, int bit_depth) {
const int max = (1 << bit_depth) - 1;
return (!(y & ~max)) ? (fixed_y_t)y : (y < 0) ? 0 : max;
}
//------------------------------------------------------------------------------
static int RGBToGray(int64_t r, int64_t g, int64_t b) {
const int64_t luma = 13933 * r + 46871 * g + 4732 * b + kYuvHalf;
return (int)(luma >> YUV_FIX);
}
static uint32_t ScaleDown(uint16_t a, uint16_t b, uint16_t c, uint16_t d,
int rgb_bit_depth) {
const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
const uint32_t A = SharpYuvGammaToLinear(a, bit_depth);
const uint32_t B = SharpYuvGammaToLinear(b, bit_depth);
const uint32_t C = SharpYuvGammaToLinear(c, bit_depth);
const uint32_t D = SharpYuvGammaToLinear(d, bit_depth);
return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth);
}
static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w,
int rgb_bit_depth) {
const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
int i;
for (i = 0; i < w; ++i) {
const uint32_t R = SharpYuvGammaToLinear(src[0 * w + i], bit_depth);
const uint32_t G = SharpYuvGammaToLinear(src[1 * w + i], bit_depth);
const uint32_t B = SharpYuvGammaToLinear(src[2 * w + i], bit_depth);
const uint32_t Y = RGBToGray(R, G, B);
dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth);
}
}
static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
fixed_t* dst, int uv_w, int rgb_bit_depth) {
int i;
for (i = 0; i < uv_w; ++i) {
const int r =
ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1], src2[0 * uv_w + 0],
src2[0 * uv_w + 1], rgb_bit_depth);
const int g =
ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1], src2[2 * uv_w + 0],
src2[2 * uv_w + 1], rgb_bit_depth);
const int b =
ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1], src2[4 * uv_w + 0],
src2[4 * uv_w + 1], rgb_bit_depth);
const int W = RGBToGray(r, g, b);
dst[0 * uv_w] = (fixed_t)(r - W);
dst[1 * uv_w] = (fixed_t)(g - W);
dst[2 * uv_w] = (fixed_t)(b - W);
dst += 1;
src1 += 2;
src2 += 2;
}
}
static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) {
int i;
assert(w > 0);
for (i = 0; i < w; ++i) {
y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]);
}
}
//------------------------------------------------------------------------------
static WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0, int bit_depth) {
const int v0 = (A * 3 + B + 2) >> 2;
return clip_bit_depth(v0 + W0, bit_depth);
}
//------------------------------------------------------------------------------
static WEBP_INLINE int Shift(int v, int shift) {
return (shift >= 0) ? (v << shift) : (v >> -shift);
}
static void ImportOneRow(const uint8_t* const r_ptr,
const uint8_t* const g_ptr,
const uint8_t* const b_ptr,
int rgb_step,
int rgb_bit_depth,
int pic_width,
fixed_y_t* const dst) {
// Convert the rgb_step from a number of bytes to a number of uint8_t or
// uint16_t values depending the bit depth.
const int step = (rgb_bit_depth > 8) ? rgb_step / 2 : rgb_step;
int i;
const int w = (pic_width + 1) & ~1;
for (i = 0; i < pic_width; ++i) {
const int off = i * step;
const int shift = GetPrecisionShift(rgb_bit_depth);
if (rgb_bit_depth == 8) {
dst[i + 0 * w] = Shift(r_ptr[off], shift);
dst[i + 1 * w] = Shift(g_ptr[off], shift);
dst[i + 2 * w] = Shift(b_ptr[off], shift);
} else {
dst[i + 0 * w] = Shift(((uint16_t*)r_ptr)[off], shift);
dst[i + 1 * w] = Shift(((uint16_t*)g_ptr)[off], shift);
dst[i + 2 * w] = Shift(((uint16_t*)b_ptr)[off], shift);
}
}
if (pic_width & 1) { // replicate rightmost pixel
dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1];
dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1];
dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1];
}
}
static void InterpolateTwoRows(const fixed_y_t* const best_y,
const fixed_t* prev_uv,
const fixed_t* cur_uv,
const fixed_t* next_uv,
int w,
fixed_y_t* out1,
fixed_y_t* out2,
int rgb_bit_depth) {
const int uv_w = w >> 1;
const int len = (w - 1) >> 1; // length to filter
int k = 3;
const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
while (k-- > 0) { // process each R/G/B segments in turn
// special boundary case for i==0
out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0], bit_depth);
out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w], bit_depth);
SharpYuvFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1,
bit_depth);
SharpYuvFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1,
bit_depth);
// special boundary case for i == w - 1 when w is even
if (!(w & 1)) {
out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1],
best_y[w - 1 + 0], bit_depth);
out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1],
best_y[w - 1 + w], bit_depth);
}
out1 += w;
out2 += w;
prev_uv += uv_w;
cur_uv += uv_w;
next_uv += uv_w;
}
}
static WEBP_INLINE int RGBToYUVComponent(int r, int g, int b,
const int coeffs[4], int sfix) {
const int srounder = 1 << (YUV_FIX + sfix - 1);
const int luma = coeffs[0] * r + coeffs[1] * g + coeffs[2] * b +
coeffs[3] + srounder;
return (luma >> (YUV_FIX + sfix));
}
static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
uint8_t* y_ptr, int y_stride, uint8_t* u_ptr,
int u_stride, uint8_t* v_ptr, int v_stride,
int rgb_bit_depth,
int yuv_bit_depth, int width, int height,
const SharpYuvConversionMatrix* yuv_matrix) {
int i, j;
const fixed_t* const best_uv_base = best_uv;
const int w = (width + 1) & ~1;
const int h = (height + 1) & ~1;
const int uv_w = w >> 1;
const int uv_h = h >> 1;
const int sfix = GetPrecisionShift(rgb_bit_depth);
const int yuv_max = (1 << yuv_bit_depth) - 1;
for (best_uv = best_uv_base, j = 0; j < height; ++j) {
for (i = 0; i < width; ++i) {
const int off = (i >> 1);
const int W = best_y[i];
const int r = best_uv[off + 0 * uv_w] + W;
const int g = best_uv[off + 1 * uv_w] + W;
const int b = best_uv[off + 2 * uv_w] + W;
const int y = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_y, sfix);
if (yuv_bit_depth <= 8) {
y_ptr[i] = clip_8b(y);
} else {
((uint16_t*)y_ptr)[i] = clip(y, yuv_max);
}
}
best_y += w;
best_uv += (j & 1) * 3 * uv_w;
y_ptr += y_stride;
}
for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) {
for (i = 0; i < uv_w; ++i) {
const int off = i;
// Note r, g and b values here are off by W, but a constant offset on all
// 3 components doesn't change the value of u and v with a YCbCr matrix.
const int r = best_uv[off + 0 * uv_w];
const int g = best_uv[off + 1 * uv_w];
const int b = best_uv[off + 2 * uv_w];
const int u = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_u, sfix);
const int v = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_v, sfix);
if (yuv_bit_depth <= 8) {
u_ptr[i] = clip_8b(u);
v_ptr[i] = clip_8b(v);
} else {
((uint16_t*)u_ptr)[i] = clip(u, yuv_max);
((uint16_t*)v_ptr)[i] = clip(v, yuv_max);
}
}
best_uv += 3 * uv_w;
u_ptr += u_stride;
v_ptr += v_stride;
}
return 1;
}
//------------------------------------------------------------------------------
// Main function
static void* SafeMalloc(uint64_t nmemb, size_t size) {
const uint64_t total_size = nmemb * (uint64_t)size;
if (total_size != (size_t)total_size) return NULL;
return malloc((size_t)total_size);
}
#define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((W) * (H), sizeof(T)))
static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
const uint8_t* b_ptr, int rgb_step, int rgb_stride,
int rgb_bit_depth, uint8_t* y_ptr, int y_stride,
uint8_t* u_ptr, int u_stride, uint8_t* v_ptr,
int v_stride, int yuv_bit_depth, int width,
int height,
const SharpYuvConversionMatrix* yuv_matrix) {
// we expand the right/bottom border if needed
const int w = (width + 1) & ~1;
const int h = (height + 1) & ~1;
const int uv_w = w >> 1;
const int uv_h = h >> 1;
uint64_t prev_diff_y_sum = ~0;
int j, iter;
// TODO(skal): allocate one big memory chunk. But for now, it's easier
// for valgrind debugging to have several chunks.
fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch
fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t);
fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t);
fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t);
fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t);
fixed_y_t* best_y = best_y_base;
fixed_y_t* target_y = target_y_base;
fixed_t* best_uv = best_uv_base;
fixed_t* target_uv = target_uv_base;
const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h);
int ok;
assert(w > 0);
assert(h > 0);
if (best_y_base == NULL || best_uv_base == NULL ||
target_y_base == NULL || target_uv_base == NULL ||
best_rgb_y == NULL || best_rgb_uv == NULL ||
tmp_buffer == NULL) {
ok = 0;
goto End;
}
// Import RGB samples to W/RGB representation.
for (j = 0; j < height; j += 2) {
const int is_last_row = (j == height - 1);
fixed_y_t* const src1 = tmp_buffer + 0 * w;
fixed_y_t* const src2 = tmp_buffer + 3 * w;
// prepare two rows of input
ImportOneRow(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth, width,
src1);
if (!is_last_row) {
ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride,
rgb_step, rgb_bit_depth, width, src2);
} else {
memcpy(src2, src1, 3 * w * sizeof(*src2));
}
StoreGray(src1, best_y + 0, w);
StoreGray(src2, best_y + w, w);
UpdateW(src1, target_y, w, rgb_bit_depth);
UpdateW(src2, target_y + w, w, rgb_bit_depth);
UpdateChroma(src1, src2, target_uv, uv_w, rgb_bit_depth);
memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv));
best_y += 2 * w;
best_uv += 3 * uv_w;
target_y += 2 * w;
target_uv += 3 * uv_w;
r_ptr += 2 * rgb_stride;
g_ptr += 2 * rgb_stride;
b_ptr += 2 * rgb_stride;
}
// Iterate and resolve clipping conflicts.
for (iter = 0; iter < kNumIterations; ++iter) {
const fixed_t* cur_uv = best_uv_base;
const fixed_t* prev_uv = best_uv_base;
uint64_t diff_y_sum = 0;
best_y = best_y_base;
best_uv = best_uv_base;
target_y = target_y_base;
target_uv = target_uv_base;
for (j = 0; j < h; j += 2) {
fixed_y_t* const src1 = tmp_buffer + 0 * w;
fixed_y_t* const src2 = tmp_buffer + 3 * w;
{
const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0);
InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w,
src1, src2, rgb_bit_depth);
prev_uv = cur_uv;
cur_uv = next_uv;
}
UpdateW(src1, best_rgb_y + 0 * w, w, rgb_bit_depth);
UpdateW(src2, best_rgb_y + 1 * w, w, rgb_bit_depth);
UpdateChroma(src1, src2, best_rgb_uv, uv_w, rgb_bit_depth);
// update two rows of Y and one row of RGB
diff_y_sum +=
SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w,
rgb_bit_depth + GetPrecisionShift(rgb_bit_depth));
SharpYuvUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w);
best_y += 2 * w;
best_uv += 3 * uv_w;
target_y += 2 * w;
target_uv += 3 * uv_w;
}
// test exit condition
if (iter > 0) {
if (diff_y_sum < diff_y_threshold) break;
if (diff_y_sum > prev_diff_y_sum) break;
}
prev_diff_y_sum = diff_y_sum;
}
// final reconstruction
ok = ConvertWRGBToYUV(best_y_base, best_uv_base, y_ptr, y_stride, u_ptr,
u_stride, v_ptr, v_stride, rgb_bit_depth, yuv_bit_depth,
width, height, yuv_matrix);
End:
free(best_y_base);
free(best_uv_base);
free(target_y_base);
free(target_uv_base);
free(best_rgb_y);
free(best_rgb_uv);
free(tmp_buffer);
return ok;
}
#undef SAFE_ALLOC
// Hidden exported init function.
// By default SharpYuvConvert calls it with NULL. If needed, users can declare
// it as extern and call it with a VP8CPUInfo function.
extern void SharpYuvInit(VP8CPUInfo cpu_info_func);
void SharpYuvInit(VP8CPUInfo cpu_info_func) {
static volatile VP8CPUInfo sharpyuv_last_cpuinfo_used =
(VP8CPUInfo)&sharpyuv_last_cpuinfo_used;
const int initialized =
(sharpyuv_last_cpuinfo_used != (VP8CPUInfo)&sharpyuv_last_cpuinfo_used);
if (cpu_info_func == NULL && initialized) return;
if (sharpyuv_last_cpuinfo_used == cpu_info_func) return;
SharpYuvInitDsp(cpu_info_func);
if (!initialized) {
SharpYuvInitGammaTables();
}
sharpyuv_last_cpuinfo_used = cpu_info_func;
}
int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
const void* b_ptr, int rgb_step, int rgb_stride,
int rgb_bit_depth, void* y_ptr, int y_stride,
void* u_ptr, int u_stride, void* v_ptr,
int v_stride, int yuv_bit_depth, int width,
int height, const SharpYuvConversionMatrix* yuv_matrix) {
SharpYuvConversionMatrix scaled_matrix;
const int rgb_max = (1 << rgb_bit_depth) - 1;
const int rgb_round = 1 << (rgb_bit_depth - 1);
const int yuv_max = (1 << yuv_bit_depth) - 1;
const int sfix = GetPrecisionShift(rgb_bit_depth);
if (width < 1 || height < 1 || width == INT_MAX || height == INT_MAX ||
r_ptr == NULL || g_ptr == NULL || b_ptr == NULL || y_ptr == NULL ||
u_ptr == NULL || v_ptr == NULL) {
return 0;
}
if (rgb_bit_depth != 8 && rgb_bit_depth != 10 && rgb_bit_depth != 12 &&
rgb_bit_depth != 16) {
return 0;
}
if (yuv_bit_depth != 8 && yuv_bit_depth != 10 && yuv_bit_depth != 12) {
return 0;
}
if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride %2 != 0)) {
// Step/stride should be even for uint16_t buffers.
return 0;
}
if (yuv_bit_depth > 8 &&
(y_stride % 2 != 0 || u_stride % 2 != 0 || v_stride % 2 != 0)) {
// Stride should be even for uint16_t buffers.
return 0;
}
SharpYuvInit(NULL);
// Add scaling factor to go from rgb_bit_depth to yuv_bit_depth, to the
// rgb->yuv conversion matrix.
if (rgb_bit_depth == yuv_bit_depth) {
memcpy(&scaled_matrix, yuv_matrix, sizeof(scaled_matrix));
} else {
int i;
for (i = 0; i < 3; ++i) {
scaled_matrix.rgb_to_y[i] =
(yuv_matrix->rgb_to_y[i] * yuv_max + rgb_round) / rgb_max;
scaled_matrix.rgb_to_u[i] =
(yuv_matrix->rgb_to_u[i] * yuv_max + rgb_round) / rgb_max;
scaled_matrix.rgb_to_v[i] =
(yuv_matrix->rgb_to_v[i] * yuv_max + rgb_round) / rgb_max;
}
}
// Also incorporate precision change scaling.
scaled_matrix.rgb_to_y[3] = Shift(yuv_matrix->rgb_to_y[3], sfix);
scaled_matrix.rgb_to_u[3] = Shift(yuv_matrix->rgb_to_u[3], sfix);
scaled_matrix.rgb_to_v[3] = Shift(yuv_matrix->rgb_to_v[3], sfix);
return DoSharpArgbToYuv(r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride,
rgb_bit_depth, y_ptr, y_stride, u_ptr, u_stride,
v_ptr, v_stride, yuv_bit_depth, width, height,
&scaled_matrix);
}
//------------------------------------------------------------------------------

81
thirdparty/webp/sharpyuv/sharpyuv.h vendored Normal file
View File

@ -0,0 +1,81 @@
// Copyright 2022 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Sharp RGB to YUV conversion.
#ifndef WEBP_SHARPYUV_SHARPYUV_H_
#define WEBP_SHARPYUV_SHARPYUV_H_
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
// SharpYUV API version following the convention from semver.org
#define SHARPYUV_VERSION_MAJOR 0
#define SHARPYUV_VERSION_MINOR 1
#define SHARPYUV_VERSION_PATCH 0
// Version as a uint32_t. The major number is the high 8 bits.
// The minor number is the middle 8 bits. The patch number is the low 16 bits.
#define SHARPYUV_MAKE_VERSION(MAJOR, MINOR, PATCH) \
(((MAJOR) << 24) | ((MINOR) << 16) | (PATCH))
#define SHARPYUV_VERSION \
SHARPYUV_MAKE_VERSION(SHARPYUV_VERSION_MAJOR, SHARPYUV_VERSION_MINOR, \
SHARPYUV_VERSION_PATCH)
// RGB to YUV conversion matrix, in 16 bit fixed point.
// y = rgb_to_y[0] * r + rgb_to_y[1] * g + rgb_to_y[2] * b + rgb_to_y[3]
// u = rgb_to_u[0] * r + rgb_to_u[1] * g + rgb_to_u[2] * b + rgb_to_u[3]
// v = rgb_to_v[0] * r + rgb_to_v[1] * g + rgb_to_v[2] * b + rgb_to_v[3]
// Then y, u and v values are divided by 1<<16 and rounded.
typedef struct {
int rgb_to_y[4];
int rgb_to_u[4];
int rgb_to_v[4];
} SharpYuvConversionMatrix;
// Converts RGB to YUV420 using a downsampling algorithm that minimizes
// artefacts caused by chroma subsampling.
// This is slower than standard downsampling (averaging of 4 UV values).
// Assumes that the image will be upsampled using a bilinear filter. If nearest
// neighbor is used instead, the upsampled image might look worse than with
// standard downsampling.
// r_ptr, g_ptr, b_ptr: pointers to the source r, g and b channels. Should point
// to uint8_t buffers if rgb_bit_depth is 8, or uint16_t buffers otherwise.
// rgb_step: distance in bytes between two horizontally adjacent pixels on the
// r, g and b channels. If rgb_bit_depth is > 8, it should be a
// multiple of 2.
// rgb_stride: distance in bytes between two vertically adjacent pixels on the
// r, g, and b channels. If rgb_bit_depth is > 8, it should be a
// multiple of 2.
// rgb_bit_depth: number of bits for each r/g/b value. One of: 8, 10, 12, 16.
// Note: 16 bit input is truncated to 14 bits before conversion to yuv.
// yuv_bit_depth: number of bits for each y/u/v value. One of: 8, 10, 12.
// y_ptr, u_ptr, v_ptr: pointers to the destination y, u and v channels. Should
// point to uint8_t buffers if yuv_bit_depth is 8, or uint16_t buffers
// otherwise.
// y_stride, u_stride, v_stride: distance in bytes between two vertically
// adjacent pixels on the y, u and v channels. If yuv_bit_depth > 8, they
// should be multiples of 2.
// width, height: width and height of the image in pixels
int SharpYuvConvert(const void* r_ptr, const void* g_ptr, const void* b_ptr,
int rgb_step, int rgb_stride, int rgb_bit_depth,
void* y_ptr, int y_stride, void* u_ptr, int u_stride,
void* v_ptr, int v_stride, int yuv_bit_depth, int width,
int height, const SharpYuvConversionMatrix* yuv_matrix);
// TODO(b/194336375): Add YUV444 to YUV420 conversion. Maybe also add 422
// support (it's rarely used in practice, especially for images).
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_SHARPYUV_SHARPYUV_H_

110
thirdparty/webp/sharpyuv/sharpyuv_csp.c vendored Normal file
View File

@ -0,0 +1,110 @@
// Copyright 2022 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Colorspace utilities.
#include "sharpyuv/sharpyuv_csp.h"
#include <assert.h>
#include <math.h>
#include <string.h>
static int ToFixed16(float f) { return (int)floor(f * (1 << 16) + 0.5f); }
void SharpYuvComputeConversionMatrix(const SharpYuvColorSpace* yuv_color_space,
SharpYuvConversionMatrix* matrix) {
const float kr = yuv_color_space->kr;
const float kb = yuv_color_space->kb;
const float kg = 1.0f - kr - kb;
const float cr = 0.5f / (1.0f - kb);
const float cb = 0.5f / (1.0f - kr);
const int shift = yuv_color_space->bit_depth - 8;
const float denom = (float)((1 << yuv_color_space->bit_depth) - 1);
float scale_y = 1.0f;
float add_y = 0.0f;
float scale_u = cr;
float scale_v = cb;
float add_uv = (float)(128 << shift);
assert(yuv_color_space->bit_depth >= 8);
if (yuv_color_space->range == kSharpYuvRangeLimited) {
scale_y *= (219 << shift) / denom;
scale_u *= (224 << shift) / denom;
scale_v *= (224 << shift) / denom;
add_y = (float)(16 << shift);
}
matrix->rgb_to_y[0] = ToFixed16(kr * scale_y);
matrix->rgb_to_y[1] = ToFixed16(kg * scale_y);
matrix->rgb_to_y[2] = ToFixed16(kb * scale_y);
matrix->rgb_to_y[3] = ToFixed16(add_y);
matrix->rgb_to_u[0] = ToFixed16(-kr * scale_u);
matrix->rgb_to_u[1] = ToFixed16(-kg * scale_u);
matrix->rgb_to_u[2] = ToFixed16((1 - kb) * scale_u);
matrix->rgb_to_u[3] = ToFixed16(add_uv);
matrix->rgb_to_v[0] = ToFixed16((1 - kr) * scale_v);
matrix->rgb_to_v[1] = ToFixed16(-kg * scale_v);
matrix->rgb_to_v[2] = ToFixed16(-kb * scale_v);
matrix->rgb_to_v[3] = ToFixed16(add_uv);
}
// Matrices are in YUV_FIX fixed point precision.
// WebP's matrix, similar but not identical to kRec601LimitedMatrix.
static const SharpYuvConversionMatrix kWebpMatrix = {
{16839, 33059, 6420, 16 << 16},
{-9719, -19081, 28800, 128 << 16},
{28800, -24116, -4684, 128 << 16},
};
// Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeLimited
static const SharpYuvConversionMatrix kRec601LimitedMatrix = {
{16829, 33039, 6416, 16 << 16},
{-9714, -19071, 28784, 128 << 16},
{28784, -24103, -4681, 128 << 16},
};
// Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeFull
static const SharpYuvConversionMatrix kRec601FullMatrix = {
{19595, 38470, 7471, 0},
{-11058, -21710, 32768, 128 << 16},
{32768, -27439, -5329, 128 << 16},
};
// Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeLimited
static const SharpYuvConversionMatrix kRec709LimitedMatrix = {
{11966, 40254, 4064, 16 << 16},
{-6596, -22189, 28784, 128 << 16},
{28784, -26145, -2639, 128 << 16},
};
// Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeFull
static const SharpYuvConversionMatrix kRec709FullMatrix = {
{13933, 46871, 4732, 0},
{-7509, -25259, 32768, 128 << 16},
{32768, -29763, -3005, 128 << 16},
};
const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix(
SharpYuvMatrixType matrix_type) {
switch (matrix_type) {
case kSharpYuvMatrixWebp:
return &kWebpMatrix;
case kSharpYuvMatrixRec601Limited:
return &kRec601LimitedMatrix;
case kSharpYuvMatrixRec601Full:
return &kRec601FullMatrix;
case kSharpYuvMatrixRec709Limited:
return &kRec709LimitedMatrix;
case kSharpYuvMatrixRec709Full:
return &kRec709FullMatrix;
case kSharpYuvMatrixNum:
return NULL;
}
return NULL;
}

59
thirdparty/webp/sharpyuv/sharpyuv_csp.h vendored Normal file
View File

@ -0,0 +1,59 @@
// Copyright 2022 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Colorspace utilities.
#ifndef WEBP_SHARPYUV_SHARPYUV_CSP_H_
#define WEBP_SHARPYUV_SHARPYUV_CSP_H_
#include "sharpyuv/sharpyuv.h"
#ifdef __cplusplus
extern "C" {
#endif
// Range of YUV values.
typedef enum {
kSharpYuvRangeFull, // YUV values between [0;255] (for 8 bit)
kSharpYuvRangeLimited // Y in [16;235], YUV in [16;240] (for 8 bit)
} SharpYuvRange;
// Constants that define a YUV color space.
typedef struct {
// Kr and Kb are defined such that:
// Y = Kr * r + Kg * g + Kb * b where Kg = 1 - Kr - Kb.
float kr;
float kb;
int bit_depth; // 8, 10 or 12
SharpYuvRange range;
} SharpYuvColorSpace;
// Fills in 'matrix' for the given YUVColorSpace.
void SharpYuvComputeConversionMatrix(const SharpYuvColorSpace* yuv_color_space,
SharpYuvConversionMatrix* matrix);
// Enums for precomputed conversion matrices.
typedef enum {
kSharpYuvMatrixWebp = 0,
kSharpYuvMatrixRec601Limited,
kSharpYuvMatrixRec601Full,
kSharpYuvMatrixRec709Limited,
kSharpYuvMatrixRec709Full,
kSharpYuvMatrixNum
} SharpYuvMatrixType;
// Returns a pointer to a matrix for one of the predefined colorspaces.
const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix(
SharpYuvMatrixType matrix_type);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_SHARPYUV_SHARPYUV_CSP_H_

102
thirdparty/webp/sharpyuv/sharpyuv_dsp.c vendored Normal file
View File

@ -0,0 +1,102 @@
// Copyright 2022 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Speed-critical functions for Sharp YUV.
//
// Author: Skal (pascal.massimino@gmail.com)
#include "sharpyuv/sharpyuv_dsp.h"
#include <assert.h>
#include <stdlib.h>
#include "src/dsp/cpu.h"
//-----------------------------------------------------------------------------
#if !WEBP_NEON_OMIT_C_CODE
static uint16_t clip(int v, int max) {
return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
}
static uint64_t SharpYuvUpdateY_C(const uint16_t* ref, const uint16_t* src,
uint16_t* dst, int len, int bit_depth) {
uint64_t diff = 0;
int i;
const int max_y = (1 << bit_depth) - 1;
for (i = 0; i < len; ++i) {
const int diff_y = ref[i] - src[i];
const int new_y = (int)dst[i] + diff_y;
dst[i] = clip(new_y, max_y);
diff += (uint64_t)abs(diff_y);
}
return diff;
}
static void SharpYuvUpdateRGB_C(const int16_t* ref, const int16_t* src,
int16_t* dst, int len) {
int i;
for (i = 0; i < len; ++i) {
const int diff_uv = ref[i] - src[i];
dst[i] += diff_uv;
}
}
static void SharpYuvFilterRow_C(const int16_t* A, const int16_t* B, int len,
const uint16_t* best_y, uint16_t* out,
int bit_depth) {
int i;
const int max_y = (1 << bit_depth) - 1;
for (i = 0; i < len; ++i, ++A, ++B) {
const int v0 = (A[0] * 9 + A[1] * 3 + B[0] * 3 + B[1] + 8) >> 4;
const int v1 = (A[1] * 9 + A[0] * 3 + B[1] * 3 + B[0] + 8) >> 4;
out[2 * i + 0] = clip(best_y[2 * i + 0] + v0, max_y);
out[2 * i + 1] = clip(best_y[2 * i + 1] + v1, max_y);
}
}
#endif // !WEBP_NEON_OMIT_C_CODE
//-----------------------------------------------------------------------------
uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref,
uint16_t* dst, int len, int bit_depth);
void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, int16_t* dst,
int len);
void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
const uint16_t* best_y, uint16_t* out,
int bit_depth);
extern void InitSharpYuvSSE2(void);
extern void InitSharpYuvNEON(void);
void SharpYuvInitDsp(VP8CPUInfo cpu_info_func) {
(void)cpu_info_func;
#if !WEBP_NEON_OMIT_C_CODE
SharpYuvUpdateY = SharpYuvUpdateY_C;
SharpYuvUpdateRGB = SharpYuvUpdateRGB_C;
SharpYuvFilterRow = SharpYuvFilterRow_C;
#endif
#if defined(WEBP_HAVE_SSE2)
if (cpu_info_func == NULL || cpu_info_func(kSSE2)) {
InitSharpYuvSSE2();
}
#endif // WEBP_HAVE_SSE2
#if defined(WEBP_HAVE_NEON)
if (WEBP_NEON_OMIT_C_CODE || cpu_info_func == NULL || cpu_info_func(kNEON)) {
InitSharpYuvNEON();
}
#endif // WEBP_HAVE_NEON
assert(SharpYuvUpdateY != NULL);
assert(SharpYuvUpdateRGB != NULL);
assert(SharpYuvFilterRow != NULL);
}

29
thirdparty/webp/sharpyuv/sharpyuv_dsp.h vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2022 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Speed-critical functions for Sharp YUV.
#ifndef WEBP_SHARPYUV_SHARPYUV_DSP_H_
#define WEBP_SHARPYUV_SHARPYUV_DSP_H_
#include <stdint.h>
#include "src/dsp/cpu.h"
extern uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref,
uint16_t* dst, int len, int bit_depth);
extern void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref,
int16_t* dst, int len);
extern void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
const uint16_t* best_y, uint16_t* out,
int bit_depth);
void SharpYuvInitDsp(VP8CPUInfo cpu_info_func);
#endif // WEBP_SHARPYUV_SHARPYUV_DSP_H_

View File

@ -0,0 +1,114 @@
// Copyright 2022 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Gamma correction utilities.
#include "sharpyuv/sharpyuv_gamma.h"
#include <assert.h>
#include <math.h>
#include <stdint.h>
#include "src/webp/types.h"
// Gamma correction compensates loss of resolution during chroma subsampling.
// Size of pre-computed table for converting from gamma to linear.
#define GAMMA_TO_LINEAR_TAB_BITS 10
#define GAMMA_TO_LINEAR_TAB_SIZE (1 << GAMMA_TO_LINEAR_TAB_BITS)
static uint32_t kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE + 2];
#define LINEAR_TO_GAMMA_TAB_BITS 9
#define LINEAR_TO_GAMMA_TAB_SIZE (1 << LINEAR_TO_GAMMA_TAB_BITS)
static uint32_t kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE + 2];
static const double kGammaF = 1. / 0.45;
#define GAMMA_TO_LINEAR_BITS 16
static volatile int kGammaTablesSOk = 0;
void SharpYuvInitGammaTables(void) {
assert(GAMMA_TO_LINEAR_BITS <= 16);
if (!kGammaTablesSOk) {
int v;
const double a = 0.09929682680944;
const double thresh = 0.018053968510807;
const double final_scale = 1 << GAMMA_TO_LINEAR_BITS;
// Precompute gamma to linear table.
{
const double norm = 1. / GAMMA_TO_LINEAR_TAB_SIZE;
const double a_rec = 1. / (1. + a);
for (v = 0; v <= GAMMA_TO_LINEAR_TAB_SIZE; ++v) {
const double g = norm * v;
double value;
if (g <= thresh * 4.5) {
value = g / 4.5;
} else {
value = pow(a_rec * (g + a), kGammaF);
}
kGammaToLinearTabS[v] = (uint32_t)(value * final_scale + .5);
}
// to prevent small rounding errors to cause read-overflow:
kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE + 1] =
kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE];
}
// Precompute linear to gamma table.
{
const double scale = 1. / LINEAR_TO_GAMMA_TAB_SIZE;
for (v = 0; v <= LINEAR_TO_GAMMA_TAB_SIZE; ++v) {
const double g = scale * v;
double value;
if (g <= thresh) {
value = 4.5 * g;
} else {
value = (1. + a) * pow(g, 1. / kGammaF) - a;
}
kLinearToGammaTabS[v] =
(uint32_t)(final_scale * value + 0.5);
}
// to prevent small rounding errors to cause read-overflow:
kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE + 1] =
kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE];
}
kGammaTablesSOk = 1;
}
}
static WEBP_INLINE int Shift(int v, int shift) {
return (shift >= 0) ? (v << shift) : (v >> -shift);
}
static WEBP_INLINE uint32_t FixedPointInterpolation(int v, uint32_t* tab,
int tab_pos_shift_right,
int tab_value_shift) {
const uint32_t tab_pos = Shift(v, -tab_pos_shift_right);
// fractional part, in 'tab_pos_shift' fixed-point precision
const uint32_t x = v - (tab_pos << tab_pos_shift_right); // fractional part
// v0 / v1 are in kGammaToLinearBits fixed-point precision (range [0..1])
const uint32_t v0 = Shift(tab[tab_pos + 0], tab_value_shift);
const uint32_t v1 = Shift(tab[tab_pos + 1], tab_value_shift);
// Final interpolation.
const uint32_t v2 = (v1 - v0) * x; // note: v1 >= v0.
const int half =
(tab_pos_shift_right > 0) ? 1 << (tab_pos_shift_right - 1) : 0;
const uint32_t result = v0 + ((v2 + half) >> tab_pos_shift_right);
return result;
}
uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth) {
const int shift = GAMMA_TO_LINEAR_TAB_BITS - bit_depth;
if (shift > 0) {
return kGammaToLinearTabS[v << shift];
}
return FixedPointInterpolation(v, kGammaToLinearTabS, -shift, 0);
}
uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth) {
return FixedPointInterpolation(
value, kLinearToGammaTabS,
(GAMMA_TO_LINEAR_BITS - LINEAR_TO_GAMMA_TAB_BITS),
bit_depth - GAMMA_TO_LINEAR_BITS);
}

View File

@ -0,0 +1,35 @@
// Copyright 2022 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Gamma correction utilities.
#ifndef WEBP_SHARPYUV_SHARPYUV_GAMMA_H_
#define WEBP_SHARPYUV_SHARPYUV_GAMMA_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// Initializes precomputed tables. Must be called once before calling
// SharpYuvGammaToLinear or SharpYuvLinearToGamma.
void SharpYuvInitGammaTables(void);
// Converts a gamma color value on 'bit_depth' bits to a 16 bit linear value.
uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth);
// Converts a 16 bit linear color value to a gamma value on 'bit_depth' bits.
uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_SHARPYUV_SHARPYUV_GAMMA_H_

182
thirdparty/webp/sharpyuv/sharpyuv_neon.c vendored Normal file
View File

@ -0,0 +1,182 @@
// Copyright 2022 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Speed-critical functions for Sharp YUV.
//
// Author: Skal (pascal.massimino@gmail.com)
#include "sharpyuv/sharpyuv_dsp.h"
#if defined(WEBP_USE_NEON)
#include <assert.h>
#include <stdlib.h>
#include <arm_neon.h>
#endif
extern void InitSharpYuvNEON(void);
#if defined(WEBP_USE_NEON)
static uint16_t clip_NEON(int v, int max) {
return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
}
static uint64_t SharpYuvUpdateY_NEON(const uint16_t* ref, const uint16_t* src,
uint16_t* dst, int len, int bit_depth) {
const int max_y = (1 << bit_depth) - 1;
int i;
const int16x8_t zero = vdupq_n_s16(0);
const int16x8_t max = vdupq_n_s16(max_y);
uint64x2_t sum = vdupq_n_u64(0);
uint64_t diff;
for (i = 0; i + 8 <= len; i += 8) {
const int16x8_t A = vreinterpretq_s16_u16(vld1q_u16(ref + i));
const int16x8_t B = vreinterpretq_s16_u16(vld1q_u16(src + i));
const int16x8_t C = vreinterpretq_s16_u16(vld1q_u16(dst + i));
const int16x8_t D = vsubq_s16(A, B); // diff_y
const int16x8_t F = vaddq_s16(C, D); // new_y
const uint16x8_t H =
vreinterpretq_u16_s16(vmaxq_s16(vminq_s16(F, max), zero));
const int16x8_t I = vabsq_s16(D); // abs(diff_y)
vst1q_u16(dst + i, H);
sum = vpadalq_u32(sum, vpaddlq_u16(vreinterpretq_u16_s16(I)));
}
diff = vgetq_lane_u64(sum, 0) + vgetq_lane_u64(sum, 1);
for (; i < len; ++i) {
const int diff_y = ref[i] - src[i];
const int new_y = (int)(dst[i]) + diff_y;
dst[i] = clip_NEON(new_y, max_y);
diff += (uint64_t)(abs(diff_y));
}
return diff;
}
static void SharpYuvUpdateRGB_NEON(const int16_t* ref, const int16_t* src,
int16_t* dst, int len) {
int i;
for (i = 0; i + 8 <= len; i += 8) {
const int16x8_t A = vld1q_s16(ref + i);
const int16x8_t B = vld1q_s16(src + i);
const int16x8_t C = vld1q_s16(dst + i);
const int16x8_t D = vsubq_s16(A, B); // diff_uv
const int16x8_t E = vaddq_s16(C, D); // new_uv
vst1q_s16(dst + i, E);
}
for (; i < len; ++i) {
const int diff_uv = ref[i] - src[i];
dst[i] += diff_uv;
}
}
static void SharpYuvFilterRow16_NEON(const int16_t* A, const int16_t* B,
int len, const uint16_t* best_y,
uint16_t* out, int bit_depth) {
const int max_y = (1 << bit_depth) - 1;
int i;
const int16x8_t max = vdupq_n_s16(max_y);
const int16x8_t zero = vdupq_n_s16(0);
for (i = 0; i + 8 <= len; i += 8) {
const int16x8_t a0 = vld1q_s16(A + i + 0);
const int16x8_t a1 = vld1q_s16(A + i + 1);
const int16x8_t b0 = vld1q_s16(B + i + 0);
const int16x8_t b1 = vld1q_s16(B + i + 1);
const int16x8_t a0b1 = vaddq_s16(a0, b1);
const int16x8_t a1b0 = vaddq_s16(a1, b0);
const int16x8_t a0a1b0b1 = vaddq_s16(a0b1, a1b0); // A0+A1+B0+B1
const int16x8_t a0b1_2 = vaddq_s16(a0b1, a0b1); // 2*(A0+B1)
const int16x8_t a1b0_2 = vaddq_s16(a1b0, a1b0); // 2*(A1+B0)
const int16x8_t c0 = vshrq_n_s16(vaddq_s16(a0b1_2, a0a1b0b1), 3);
const int16x8_t c1 = vshrq_n_s16(vaddq_s16(a1b0_2, a0a1b0b1), 3);
const int16x8_t e0 = vrhaddq_s16(c1, a0);
const int16x8_t e1 = vrhaddq_s16(c0, a1);
const int16x8x2_t f = vzipq_s16(e0, e1);
const int16x8_t g0 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 0));
const int16x8_t g1 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 8));
const int16x8_t h0 = vaddq_s16(g0, f.val[0]);
const int16x8_t h1 = vaddq_s16(g1, f.val[1]);
const int16x8_t i0 = vmaxq_s16(vminq_s16(h0, max), zero);
const int16x8_t i1 = vmaxq_s16(vminq_s16(h1, max), zero);
vst1q_u16(out + 2 * i + 0, vreinterpretq_u16_s16(i0));
vst1q_u16(out + 2 * i + 8, vreinterpretq_u16_s16(i1));
}
for (; i < len; ++i) {
const int a0b1 = A[i + 0] + B[i + 1];
const int a1b0 = A[i + 1] + B[i + 0];
const int a0a1b0b1 = a0b1 + a1b0 + 8;
const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
out[2 * i + 0] = clip_NEON(best_y[2 * i + 0] + v0, max_y);
out[2 * i + 1] = clip_NEON(best_y[2 * i + 1] + v1, max_y);
}
}
static void SharpYuvFilterRow32_NEON(const int16_t* A, const int16_t* B,
int len, const uint16_t* best_y,
uint16_t* out, int bit_depth) {
const int max_y = (1 << bit_depth) - 1;
int i;
const uint16x8_t max = vdupq_n_u16(max_y);
for (i = 0; i + 4 <= len; i += 4) {
const int16x4_t a0 = vld1_s16(A + i + 0);
const int16x4_t a1 = vld1_s16(A + i + 1);
const int16x4_t b0 = vld1_s16(B + i + 0);
const int16x4_t b1 = vld1_s16(B + i + 1);
const int32x4_t a0b1 = vaddl_s16(a0, b1);
const int32x4_t a1b0 = vaddl_s16(a1, b0);
const int32x4_t a0a1b0b1 = vaddq_s32(a0b1, a1b0); // A0+A1+B0+B1
const int32x4_t a0b1_2 = vaddq_s32(a0b1, a0b1); // 2*(A0+B1)
const int32x4_t a1b0_2 = vaddq_s32(a1b0, a1b0); // 2*(A1+B0)
const int32x4_t c0 = vshrq_n_s32(vaddq_s32(a0b1_2, a0a1b0b1), 3);
const int32x4_t c1 = vshrq_n_s32(vaddq_s32(a1b0_2, a0a1b0b1), 3);
const int32x4_t e0 = vrhaddq_s32(c1, vmovl_s16(a0));
const int32x4_t e1 = vrhaddq_s32(c0, vmovl_s16(a1));
const int32x4x2_t f = vzipq_s32(e0, e1);
const int16x8_t g = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i));
const int32x4_t h0 = vaddw_s16(f.val[0], vget_low_s16(g));
const int32x4_t h1 = vaddw_s16(f.val[1], vget_high_s16(g));
const uint16x8_t i_16 = vcombine_u16(vqmovun_s32(h0), vqmovun_s32(h1));
const uint16x8_t i_clamped = vminq_u16(i_16, max);
vst1q_u16(out + 2 * i + 0, i_clamped);
}
for (; i < len; ++i) {
const int a0b1 = A[i + 0] + B[i + 1];
const int a1b0 = A[i + 1] + B[i + 0];
const int a0a1b0b1 = a0b1 + a1b0 + 8;
const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
out[2 * i + 0] = clip_NEON(best_y[2 * i + 0] + v0, max_y);
out[2 * i + 1] = clip_NEON(best_y[2 * i + 1] + v1, max_y);
}
}
static void SharpYuvFilterRow_NEON(const int16_t* A, const int16_t* B, int len,
const uint16_t* best_y, uint16_t* out,
int bit_depth) {
if (bit_depth <= 10) {
SharpYuvFilterRow16_NEON(A, B, len, best_y, out, bit_depth);
} else {
SharpYuvFilterRow32_NEON(A, B, len, best_y, out, bit_depth);
}
}
//------------------------------------------------------------------------------
WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvNEON(void) {
SharpYuvUpdateY = SharpYuvUpdateY_NEON;
SharpYuvUpdateRGB = SharpYuvUpdateRGB_NEON;
SharpYuvFilterRow = SharpYuvFilterRow_NEON;
}
#else // !WEBP_USE_NEON
void InitSharpYuvNEON(void) {}
#endif // WEBP_USE_NEON

204
thirdparty/webp/sharpyuv/sharpyuv_sse2.c vendored Normal file
View File

@ -0,0 +1,204 @@
// Copyright 2022 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Speed-critical functions for Sharp YUV.
//
// Author: Skal (pascal.massimino@gmail.com)
#include "sharpyuv/sharpyuv_dsp.h"
#if defined(WEBP_USE_SSE2)
#include <stdlib.h>
#include <emmintrin.h>
#endif
extern void InitSharpYuvSSE2(void);
#if defined(WEBP_USE_SSE2)
static uint16_t clip_SSE2(int v, int max) {
return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
}
static uint64_t SharpYuvUpdateY_SSE2(const uint16_t* ref, const uint16_t* src,
uint16_t* dst, int len, int bit_depth) {
const int max_y = (1 << bit_depth) - 1;
uint64_t diff = 0;
uint32_t tmp[4];
int i;
const __m128i zero = _mm_setzero_si128();
const __m128i max = _mm_set1_epi16(max_y);
const __m128i one = _mm_set1_epi16(1);
__m128i sum = zero;
for (i = 0; i + 8 <= len; i += 8) {
const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i));
const __m128i B = _mm_loadu_si128((const __m128i*)(src + i));
const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i));
const __m128i D = _mm_sub_epi16(A, B); // diff_y
const __m128i E = _mm_cmpgt_epi16(zero, D); // sign (-1 or 0)
const __m128i F = _mm_add_epi16(C, D); // new_y
const __m128i G = _mm_or_si128(E, one); // -1 or 1
const __m128i H = _mm_max_epi16(_mm_min_epi16(F, max), zero);
const __m128i I = _mm_madd_epi16(D, G); // sum(abs(...))
_mm_storeu_si128((__m128i*)(dst + i), H);
sum = _mm_add_epi32(sum, I);
}
_mm_storeu_si128((__m128i*)tmp, sum);
diff = tmp[3] + tmp[2] + tmp[1] + tmp[0];
for (; i < len; ++i) {
const int diff_y = ref[i] - src[i];
const int new_y = (int)dst[i] + diff_y;
dst[i] = clip_SSE2(new_y, max_y);
diff += (uint64_t)abs(diff_y);
}
return diff;
}
static void SharpYuvUpdateRGB_SSE2(const int16_t* ref, const int16_t* src,
int16_t* dst, int len) {
int i = 0;
for (i = 0; i + 8 <= len; i += 8) {
const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i));
const __m128i B = _mm_loadu_si128((const __m128i*)(src + i));
const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i));
const __m128i D = _mm_sub_epi16(A, B); // diff_uv
const __m128i E = _mm_add_epi16(C, D); // new_uv
_mm_storeu_si128((__m128i*)(dst + i), E);
}
for (; i < len; ++i) {
const int diff_uv = ref[i] - src[i];
dst[i] += diff_uv;
}
}
static void SharpYuvFilterRow16_SSE2(const int16_t* A, const int16_t* B,
int len, const uint16_t* best_y,
uint16_t* out, int bit_depth) {
const int max_y = (1 << bit_depth) - 1;
int i;
const __m128i kCst8 = _mm_set1_epi16(8);
const __m128i max = _mm_set1_epi16(max_y);
const __m128i zero = _mm_setzero_si128();
for (i = 0; i + 8 <= len; i += 8) {
const __m128i a0 = _mm_loadu_si128((const __m128i*)(A + i + 0));
const __m128i a1 = _mm_loadu_si128((const __m128i*)(A + i + 1));
const __m128i b0 = _mm_loadu_si128((const __m128i*)(B + i + 0));
const __m128i b1 = _mm_loadu_si128((const __m128i*)(B + i + 1));
const __m128i a0b1 = _mm_add_epi16(a0, b1);
const __m128i a1b0 = _mm_add_epi16(a1, b0);
const __m128i a0a1b0b1 = _mm_add_epi16(a0b1, a1b0); // A0+A1+B0+B1
const __m128i a0a1b0b1_8 = _mm_add_epi16(a0a1b0b1, kCst8);
const __m128i a0b1_2 = _mm_add_epi16(a0b1, a0b1); // 2*(A0+B1)
const __m128i a1b0_2 = _mm_add_epi16(a1b0, a1b0); // 2*(A1+B0)
const __m128i c0 = _mm_srai_epi16(_mm_add_epi16(a0b1_2, a0a1b0b1_8), 3);
const __m128i c1 = _mm_srai_epi16(_mm_add_epi16(a1b0_2, a0a1b0b1_8), 3);
const __m128i d0 = _mm_add_epi16(c1, a0);
const __m128i d1 = _mm_add_epi16(c0, a1);
const __m128i e0 = _mm_srai_epi16(d0, 1);
const __m128i e1 = _mm_srai_epi16(d1, 1);
const __m128i f0 = _mm_unpacklo_epi16(e0, e1);
const __m128i f1 = _mm_unpackhi_epi16(e0, e1);
const __m128i g0 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0));
const __m128i g1 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 8));
const __m128i h0 = _mm_add_epi16(g0, f0);
const __m128i h1 = _mm_add_epi16(g1, f1);
const __m128i i0 = _mm_max_epi16(_mm_min_epi16(h0, max), zero);
const __m128i i1 = _mm_max_epi16(_mm_min_epi16(h1, max), zero);
_mm_storeu_si128((__m128i*)(out + 2 * i + 0), i0);
_mm_storeu_si128((__m128i*)(out + 2 * i + 8), i1);
}
for (; i < len; ++i) {
// (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 =
// = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4
// We reuse the common sub-expressions.
const int a0b1 = A[i + 0] + B[i + 1];
const int a1b0 = A[i + 1] + B[i + 0];
const int a0a1b0b1 = a0b1 + a1b0 + 8;
const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
out[2 * i + 0] = clip_SSE2(best_y[2 * i + 0] + v0, max_y);
out[2 * i + 1] = clip_SSE2(best_y[2 * i + 1] + v1, max_y);
}
}
static WEBP_INLINE __m128i s16_to_s32(__m128i in) {
return _mm_srai_epi32(_mm_unpacklo_epi16(in, in), 16);
}
static void SharpYuvFilterRow32_SSE2(const int16_t* A, const int16_t* B,
int len, const uint16_t* best_y,
uint16_t* out, int bit_depth) {
const int max_y = (1 << bit_depth) - 1;
int i;
const __m128i kCst8 = _mm_set1_epi32(8);
const __m128i max = _mm_set1_epi16(max_y);
const __m128i zero = _mm_setzero_si128();
for (i = 0; i + 4 <= len; i += 4) {
const __m128i a0 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(A + i + 0)));
const __m128i a1 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(A + i + 1)));
const __m128i b0 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(B + i + 0)));
const __m128i b1 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(B + i + 1)));
const __m128i a0b1 = _mm_add_epi32(a0, b1);
const __m128i a1b0 = _mm_add_epi32(a1, b0);
const __m128i a0a1b0b1 = _mm_add_epi32(a0b1, a1b0); // A0+A1+B0+B1
const __m128i a0a1b0b1_8 = _mm_add_epi32(a0a1b0b1, kCst8);
const __m128i a0b1_2 = _mm_add_epi32(a0b1, a0b1); // 2*(A0+B1)
const __m128i a1b0_2 = _mm_add_epi32(a1b0, a1b0); // 2*(A1+B0)
const __m128i c0 = _mm_srai_epi32(_mm_add_epi32(a0b1_2, a0a1b0b1_8), 3);
const __m128i c1 = _mm_srai_epi32(_mm_add_epi32(a1b0_2, a0a1b0b1_8), 3);
const __m128i d0 = _mm_add_epi32(c1, a0);
const __m128i d1 = _mm_add_epi32(c0, a1);
const __m128i e0 = _mm_srai_epi32(d0, 1);
const __m128i e1 = _mm_srai_epi32(d1, 1);
const __m128i f0 = _mm_unpacklo_epi32(e0, e1);
const __m128i f1 = _mm_unpackhi_epi32(e0, e1);
const __m128i g = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0));
const __m128i h_16 = _mm_add_epi16(g, _mm_packs_epi32(f0, f1));
const __m128i final = _mm_max_epi16(_mm_min_epi16(h_16, max), zero);
_mm_storeu_si128((__m128i*)(out + 2 * i + 0), final);
}
for (; i < len; ++i) {
// (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 =
// = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4
// We reuse the common sub-expressions.
const int a0b1 = A[i + 0] + B[i + 1];
const int a1b0 = A[i + 1] + B[i + 0];
const int a0a1b0b1 = a0b1 + a1b0 + 8;
const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
out[2 * i + 0] = clip_SSE2(best_y[2 * i + 0] + v0, max_y);
out[2 * i + 1] = clip_SSE2(best_y[2 * i + 1] + v1, max_y);
}
}
static void SharpYuvFilterRow_SSE2(const int16_t* A, const int16_t* B, int len,
const uint16_t* best_y, uint16_t* out,
int bit_depth) {
if (bit_depth <= 10) {
SharpYuvFilterRow16_SSE2(A, B, len, best_y, out, bit_depth);
} else {
SharpYuvFilterRow32_SSE2(A, B, len, best_y, out, bit_depth);
}
}
//------------------------------------------------------------------------------
extern void InitSharpYuvSSE2(void);
WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvSSE2(void) {
SharpYuvUpdateY = SharpYuvUpdateY_SSE2;
SharpYuvUpdateRGB = SharpYuvUpdateRGB_SSE2;
SharpYuvFilterRow = SharpYuvFilterRow_SSE2;
}
#else // !WEBP_USE_SSE2
void InitSharpYuvSSE2(void) {}
#endif // WEBP_USE_SSE2

View File

@ -32,7 +32,7 @@ extern "C" {
// version numbers
#define DEC_MAJ_VERSION 1
#define DEC_MIN_VERSION 2
#define DEC_REV_VERSION 2
#define DEC_REV_VERSION 4
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
// Constraints are: We need to store one 16x16 block of luma samples (y),

View File

@ -178,7 +178,7 @@ static WEBP_INLINE int PlaneCodeToDistance(int xsize, int plane_code) {
//------------------------------------------------------------------------------
// Decodes the next Huffman code from bit-stream.
// FillBitWindow(br) needs to be called at minimum every second call
// VP8LFillBitWindow(br) needs to be called at minimum every second call
// to ReadSymbol, in order to pre-fetch enough bits.
static WEBP_INLINE int ReadSymbol(const HuffmanCode* table,
VP8LBitReader* const br) {
@ -321,7 +321,7 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
// The first code is either 1 bit or 8 bit code.
int symbol = VP8LReadBits(br, (first_symbol_len_code == 0) ? 1 : 8);
code_lengths[symbol] = 1;
// The second code (if present), is always 8 bit long.
// The second code (if present), is always 8 bits long.
if (num_symbols == 2) {
symbol = VP8LReadBits(br, 8);
code_lengths[symbol] = 1;
@ -1281,7 +1281,7 @@ static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
uint8_t* const new_data = (uint8_t*)new_color_map;
new_color_map[0] = transform->data_[0];
for (i = 4; i < 4 * num_colors; ++i) {
// Equivalent to AddPixelEq(), on a byte-basis.
// Equivalent to VP8LAddPixels(), on a byte-basis.
new_data[i] = (data[i] + new_data[i - 4]) & 0xff;
}
for (; i < 4 * final_num_colors; ++i) {

View File

@ -25,7 +25,7 @@
#define DMUX_MAJ_VERSION 1
#define DMUX_MIN_VERSION 2
#define DMUX_REV_VERSION 2
#define DMUX_REV_VERSION 4
typedef struct {
size_t start_; // start location of the data
@ -614,7 +614,6 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
while (f != NULL) {
const int cur_frame_set = f->frame_num_;
int frame_count = 0;
// Check frame properties.
for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) {
@ -649,8 +648,6 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
dmux->canvas_width_, dmux->canvas_height_)) {
return 0;
}
++frame_count;
}
}
return 1;

View File

@ -83,7 +83,7 @@ static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first,
static int DispatchAlpha_NEON(const uint8_t* WEBP_RESTRICT alpha,
int alpha_stride, int width, int height,
uint8_t* WEBP_RESTRICT dst, int dst_stride) {
uint32_t alpha_mask = 0xffffffffu;
uint32_t alpha_mask = 0xffu;
uint8x8_t mask8 = vdup_n_u8(0xff);
uint32_t tmp[2];
int i, j;
@ -107,6 +107,7 @@ static int DispatchAlpha_NEON(const uint8_t* WEBP_RESTRICT alpha,
dst += dst_stride;
}
vst1_u8((uint8_t*)tmp, mask8);
alpha_mask *= 0x01010101;
alpha_mask &= tmp[0];
alpha_mask &= tmp[1];
return (alpha_mask != 0xffffffffu);
@ -135,7 +136,7 @@ static void DispatchAlphaToGreen_NEON(const uint8_t* WEBP_RESTRICT alpha,
static int ExtractAlpha_NEON(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
int width, int height,
uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
uint32_t alpha_mask = 0xffffffffu;
uint32_t alpha_mask = 0xffu;
uint8x8_t mask8 = vdup_n_u8(0xff);
uint32_t tmp[2];
int i, j;
@ -157,6 +158,7 @@ static int ExtractAlpha_NEON(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
alpha += alpha_stride;
}
vst1_u8((uint8_t*)tmp, mask8);
alpha_mask *= 0x01010101;
alpha_mask &= tmp[0];
alpha_mask &= tmp[1];
return (alpha_mask == 0xffffffffu);

View File

@ -11,7 +11,7 @@
//
// Author: Christian Duvivier (cduvivier@google.com)
#include "src/dsp/dsp.h"
#include "src/dsp/cpu.h"
#if defined(WEBP_HAVE_NEON_RTCD)
#include <stdio.h>

254
thirdparty/webp/src/dsp/cpu.h vendored Normal file
View File

@ -0,0 +1,254 @@
// Copyright 2022 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// CPU detection functions and macros.
//
// Author: Skal (pascal.massimino@gmail.com)
#ifndef WEBP_DSP_CPU_H_
#define WEBP_DSP_CPU_H_
#ifdef HAVE_CONFIG_H
#include "src/webp/config.h"
#endif
#include "src/webp/types.h"
#if defined(__GNUC__)
#define LOCAL_GCC_VERSION ((__GNUC__ << 8) | __GNUC_MINOR__)
#define LOCAL_GCC_PREREQ(maj, min) (LOCAL_GCC_VERSION >= (((maj) << 8) | (min)))
#else
#define LOCAL_GCC_VERSION 0
#define LOCAL_GCC_PREREQ(maj, min) 0
#endif
#if defined(__clang__)
#define LOCAL_CLANG_VERSION ((__clang_major__ << 8) | __clang_minor__)
#define LOCAL_CLANG_PREREQ(maj, min) \
(LOCAL_CLANG_VERSION >= (((maj) << 8) | (min)))
#else
#define LOCAL_CLANG_VERSION 0
#define LOCAL_CLANG_PREREQ(maj, min) 0
#endif
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#if !defined(HAVE_CONFIG_H)
#if defined(_MSC_VER) && _MSC_VER > 1310 && \
(defined(_M_X64) || defined(_M_IX86))
#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
#endif
#if defined(_MSC_VER) && _MSC_VER >= 1500 && \
(defined(_M_X64) || defined(_M_IX86))
#define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets
#endif
#endif
// WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp
// files without intrinsics, allowing the corresponding Init() to be called.
// Files containing intrinsics will need to be built targeting the instruction
// set so should succeed on one of the earlier tests.
#if (defined(__SSE2__) || defined(WEBP_MSC_SSE2)) && \
(!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE2))
#define WEBP_USE_SSE2
#endif
#if defined(WEBP_USE_SSE2) && !defined(WEBP_HAVE_SSE2)
#define WEBP_HAVE_SSE2
#endif
#if (defined(__SSE4_1__) || defined(WEBP_MSC_SSE41)) && \
(!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE41))
#define WEBP_USE_SSE41
#endif
#if defined(WEBP_USE_SSE41) && !defined(WEBP_HAVE_SSE41)
#define WEBP_HAVE_SSE41
#endif
#undef WEBP_MSC_SSE41
#undef WEBP_MSC_SSE2
// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
// inline assembly would need to be modified for use with Native Client.
#if ((defined(__ARM_NEON__) || defined(__aarch64__)) && \
(!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_NEON))) && \
!defined(__native_client__)
#define WEBP_USE_NEON
#endif
#if !defined(WEBP_USE_NEON) && defined(__ANDROID__) && \
defined(__ARM_ARCH_7A__) && defined(HAVE_CPU_FEATURES_H)
#define WEBP_ANDROID_NEON // Android targets that may have NEON
#define WEBP_USE_NEON
#endif
// Note: ARM64 is supported in Visual Studio 2017, but requires the direct
// inclusion of arm64_neon.h; Visual Studio 2019 includes this file in
// arm_neon.h. Compile errors were seen with Visual Studio 2019 16.4 with
// vtbl4_u8(); a fix was made in 16.6.
#if defined(_MSC_VER) && ((_MSC_VER >= 1700 && defined(_M_ARM)) || \
(_MSC_VER >= 1926 && defined(_M_ARM64)))
#define WEBP_USE_NEON
#define WEBP_USE_INTRINSICS
#endif
#if defined(WEBP_USE_NEON) && !defined(WEBP_HAVE_NEON)
#define WEBP_HAVE_NEON
#endif
#if defined(__mips__) && !defined(__mips64) && defined(__mips_isa_rev) && \
(__mips_isa_rev >= 1) && (__mips_isa_rev < 6)
#define WEBP_USE_MIPS32
#if (__mips_isa_rev >= 2)
#define WEBP_USE_MIPS32_R2
#if defined(__mips_dspr2) || (defined(__mips_dsp_rev) && __mips_dsp_rev >= 2)
#define WEBP_USE_MIPS_DSP_R2
#endif
#endif
#endif
#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5)
#define WEBP_USE_MSA
#endif
#ifndef WEBP_DSP_OMIT_C_CODE
#define WEBP_DSP_OMIT_C_CODE 1
#endif
#if defined(WEBP_USE_NEON) && WEBP_DSP_OMIT_C_CODE
#define WEBP_NEON_OMIT_C_CODE 1
#else
#define WEBP_NEON_OMIT_C_CODE 0
#endif
#if !(LOCAL_CLANG_PREREQ(3, 8) || LOCAL_GCC_PREREQ(4, 8) || \
defined(__aarch64__))
#define WEBP_NEON_WORK_AROUND_GCC 1
#else
#define WEBP_NEON_WORK_AROUND_GCC 0
#endif
// This macro prevents thread_sanitizer from reporting known concurrent writes.
#define WEBP_TSAN_IGNORE_FUNCTION
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#undef WEBP_TSAN_IGNORE_FUNCTION
#define WEBP_TSAN_IGNORE_FUNCTION __attribute__((no_sanitize_thread))
#endif
#endif
#if defined(__has_feature)
#if __has_feature(memory_sanitizer)
#define WEBP_MSAN
#endif
#endif
#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
#include <pthread.h> // NOLINT
#define WEBP_DSP_INIT(func) \
do { \
static volatile VP8CPUInfo func##_last_cpuinfo_used = \
(VP8CPUInfo)&func##_last_cpuinfo_used; \
static pthread_mutex_t func##_lock = PTHREAD_MUTEX_INITIALIZER; \
if (pthread_mutex_lock(&func##_lock)) break; \
if (func##_last_cpuinfo_used != VP8GetCPUInfo) func(); \
func##_last_cpuinfo_used = VP8GetCPUInfo; \
(void)pthread_mutex_unlock(&func##_lock); \
} while (0)
#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32))
#define WEBP_DSP_INIT(func) \
do { \
static volatile VP8CPUInfo func##_last_cpuinfo_used = \
(VP8CPUInfo)&func##_last_cpuinfo_used; \
if (func##_last_cpuinfo_used == VP8GetCPUInfo) break; \
func(); \
func##_last_cpuinfo_used = VP8GetCPUInfo; \
} while (0)
#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32)
// Defines an Init + helper function that control multiple initialization of
// function pointers / tables.
/* Usage:
WEBP_DSP_INIT_FUNC(InitFunc) {
...function body
}
*/
#define WEBP_DSP_INIT_FUNC(name) \
static WEBP_TSAN_IGNORE_FUNCTION void name##_body(void); \
WEBP_TSAN_IGNORE_FUNCTION void name(void) { WEBP_DSP_INIT(name##_body); } \
static WEBP_TSAN_IGNORE_FUNCTION void name##_body(void)
#define WEBP_UBSAN_IGNORE_UNDEF
#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
#if defined(__clang__) && defined(__has_attribute)
#if __has_attribute(no_sanitize)
// This macro prevents the undefined behavior sanitizer from reporting
// failures. This is only meant to silence unaligned loads on platforms that
// are known to support them.
#undef WEBP_UBSAN_IGNORE_UNDEF
#define WEBP_UBSAN_IGNORE_UNDEF __attribute__((no_sanitize("undefined")))
// This macro prevents the undefined behavior sanitizer from reporting
// failures related to unsigned integer overflows. This is only meant to
// silence cases where this well defined behavior is expected.
#undef WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW \
__attribute__((no_sanitize("unsigned-integer-overflow")))
#endif
#endif
// If 'ptr' is NULL, returns NULL. Otherwise returns 'ptr + off'.
// Prevents undefined behavior sanitizer nullptr-with-nonzero-offset warning.
#if !defined(WEBP_OFFSET_PTR)
#define WEBP_OFFSET_PTR(ptr, off) (((ptr) == NULL) ? NULL : ((ptr) + (off)))
#endif
// Regularize the definition of WEBP_SWAP_16BIT_CSP (backward compatibility)
#if !defined(WEBP_SWAP_16BIT_CSP)
#define WEBP_SWAP_16BIT_CSP 0
#endif
// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__)
#if !defined(WORDS_BIGENDIAN) && \
(defined(__BIG_ENDIAN__) || defined(_M_PPC) || \
(defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
#define WORDS_BIGENDIAN
#endif
typedef enum {
kSSE2,
kSSE3,
kSlowSSSE3, // special feature for slow SSSE3 architectures
kSSE4_1,
kAVX,
kAVX2,
kNEON,
kMIPS32,
kMIPSdspR2,
kMSA
} CPUFeature;
#ifdef __cplusplus
extern "C" {
#endif
// returns true if the CPU supports the feature.
typedef int (*VP8CPUInfo)(CPUFeature feature);
WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WEBP_DSP_CPU_H_

View File

@ -18,6 +18,7 @@
#include "src/webp/config.h"
#endif
#include "src/dsp/cpu.h"
#include "src/webp/types.h"
#ifdef __cplusplus
@ -43,225 +44,6 @@ extern "C" {
#define WEBP_RESTRICT
#endif
//------------------------------------------------------------------------------
// CPU detection
#if defined(__GNUC__)
# define LOCAL_GCC_VERSION ((__GNUC__ << 8) | __GNUC_MINOR__)
# define LOCAL_GCC_PREREQ(maj, min) \
(LOCAL_GCC_VERSION >= (((maj) << 8) | (min)))
#else
# define LOCAL_GCC_VERSION 0
# define LOCAL_GCC_PREREQ(maj, min) 0
#endif
#if defined(__clang__)
# define LOCAL_CLANG_VERSION ((__clang_major__ << 8) | __clang_minor__)
# define LOCAL_CLANG_PREREQ(maj, min) \
(LOCAL_CLANG_VERSION >= (((maj) << 8) | (min)))
#else
# define LOCAL_CLANG_VERSION 0
# define LOCAL_CLANG_PREREQ(maj, min) 0
#endif
#ifndef __has_builtin
# define __has_builtin(x) 0
#endif
#if !defined(HAVE_CONFIG_H)
#if defined(_MSC_VER) && _MSC_VER > 1310 && \
(defined(_M_X64) || defined(_M_IX86))
#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
#endif
#if defined(_MSC_VER) && _MSC_VER >= 1500 && \
(defined(_M_X64) || defined(_M_IX86))
#define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets
#endif
#endif
// WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp
// files without intrinsics, allowing the corresponding Init() to be called.
// Files containing intrinsics will need to be built targeting the instruction
// set so should succeed on one of the earlier tests.
#if (defined(__SSE2__) || defined(WEBP_MSC_SSE2)) && \
(!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE2))
#define WEBP_USE_SSE2
#endif
#if defined(WEBP_USE_SSE2) && !defined(WEBP_HAVE_SSE2)
#define WEBP_HAVE_SSE2
#endif
#if (defined(__SSE4_1__) || defined(WEBP_MSC_SSE41)) && \
(!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE41))
#define WEBP_USE_SSE41
#endif
#if defined(WEBP_USE_SSE41) && !defined(WEBP_HAVE_SSE41)
#define WEBP_HAVE_SSE41
#endif
#undef WEBP_MSC_SSE41
#undef WEBP_MSC_SSE2
// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
// inline assembly would need to be modified for use with Native Client.
#if ((defined(__ARM_NEON__) || defined(__aarch64__)) && \
(!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_NEON))) && \
!defined(__native_client__)
#define WEBP_USE_NEON
#endif
#if !defined(WEBP_USE_NEON) && defined(__ANDROID__) && \
defined(__ARM_ARCH_7A__) && defined(HAVE_CPU_FEATURES_H)
#define WEBP_ANDROID_NEON // Android targets that may have NEON
#define WEBP_USE_NEON
#endif
// Note: ARM64 is supported in Visual Studio 2017, but requires the direct
// inclusion of arm64_neon.h; Visual Studio 2019 includes this file in
// arm_neon.h.
#if defined(_MSC_VER) && \
((_MSC_VER >= 1700 && defined(_M_ARM)) || \
(_MSC_VER >= 1920 && defined(_M_ARM64)))
#define WEBP_USE_NEON
#define WEBP_USE_INTRINSICS
#endif
#if defined(WEBP_USE_NEON) && !defined(WEBP_HAVE_NEON)
#define WEBP_HAVE_NEON
#endif
#if defined(__mips__) && !defined(__mips64) && \
defined(__mips_isa_rev) && (__mips_isa_rev >= 1) && (__mips_isa_rev < 6)
#define WEBP_USE_MIPS32
#if (__mips_isa_rev >= 2)
#define WEBP_USE_MIPS32_R2
#if defined(__mips_dspr2) || (defined(__mips_dsp_rev) && __mips_dsp_rev >= 2)
#define WEBP_USE_MIPS_DSP_R2
#endif
#endif
#endif
#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5)
#define WEBP_USE_MSA
#endif
#ifndef WEBP_DSP_OMIT_C_CODE
#define WEBP_DSP_OMIT_C_CODE 1
#endif
#if defined(WEBP_USE_NEON) && WEBP_DSP_OMIT_C_CODE
#define WEBP_NEON_OMIT_C_CODE 1
#else
#define WEBP_NEON_OMIT_C_CODE 0
#endif
#if !(LOCAL_CLANG_PREREQ(3,8) || LOCAL_GCC_PREREQ(4,8) || defined(__aarch64__))
#define WEBP_NEON_WORK_AROUND_GCC 1
#else
#define WEBP_NEON_WORK_AROUND_GCC 0
#endif
// This macro prevents thread_sanitizer from reporting known concurrent writes.
#define WEBP_TSAN_IGNORE_FUNCTION
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#undef WEBP_TSAN_IGNORE_FUNCTION
#define WEBP_TSAN_IGNORE_FUNCTION __attribute__((no_sanitize_thread))
#endif
#endif
#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
#include <pthread.h> // NOLINT
#define WEBP_DSP_INIT(func) do { \
static volatile VP8CPUInfo func ## _last_cpuinfo_used = \
(VP8CPUInfo)&func ## _last_cpuinfo_used; \
static pthread_mutex_t func ## _lock = PTHREAD_MUTEX_INITIALIZER; \
if (pthread_mutex_lock(&func ## _lock)) break; \
if (func ## _last_cpuinfo_used != VP8GetCPUInfo) func(); \
func ## _last_cpuinfo_used = VP8GetCPUInfo; \
(void)pthread_mutex_unlock(&func ## _lock); \
} while (0)
#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32))
#define WEBP_DSP_INIT(func) do { \
static volatile VP8CPUInfo func ## _last_cpuinfo_used = \
(VP8CPUInfo)&func ## _last_cpuinfo_used; \
if (func ## _last_cpuinfo_used == VP8GetCPUInfo) break; \
func(); \
func ## _last_cpuinfo_used = VP8GetCPUInfo; \
} while (0)
#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32)
// Defines an Init + helper function that control multiple initialization of
// function pointers / tables.
/* Usage:
WEBP_DSP_INIT_FUNC(InitFunc) {
...function body
}
*/
#define WEBP_DSP_INIT_FUNC(name) \
static WEBP_TSAN_IGNORE_FUNCTION void name ## _body(void); \
WEBP_TSAN_IGNORE_FUNCTION void name(void) { \
WEBP_DSP_INIT(name ## _body); \
} \
static WEBP_TSAN_IGNORE_FUNCTION void name ## _body(void)
#define WEBP_UBSAN_IGNORE_UNDEF
#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
#if defined(__clang__) && defined(__has_attribute)
#if __has_attribute(no_sanitize)
// This macro prevents the undefined behavior sanitizer from reporting
// failures. This is only meant to silence unaligned loads on platforms that
// are known to support them.
#undef WEBP_UBSAN_IGNORE_UNDEF
#define WEBP_UBSAN_IGNORE_UNDEF \
__attribute__((no_sanitize("undefined")))
// This macro prevents the undefined behavior sanitizer from reporting
// failures related to unsigned integer overflows. This is only meant to
// silence cases where this well defined behavior is expected.
#undef WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW \
__attribute__((no_sanitize("unsigned-integer-overflow")))
#endif
#endif
// If 'ptr' is NULL, returns NULL. Otherwise returns 'ptr + off'.
// Prevents undefined behavior sanitizer nullptr-with-nonzero-offset warning.
#if !defined(WEBP_OFFSET_PTR)
#define WEBP_OFFSET_PTR(ptr, off) (((ptr) == NULL) ? NULL : ((ptr) + (off)))
#endif
// Regularize the definition of WEBP_SWAP_16BIT_CSP (backward compatibility)
#if !defined(WEBP_SWAP_16BIT_CSP)
#define WEBP_SWAP_16BIT_CSP 0
#endif
// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__)
#if !defined(WORDS_BIGENDIAN) && \
(defined(__BIG_ENDIAN__) || defined(_M_PPC) || \
(defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
#define WORDS_BIGENDIAN
#endif
typedef enum {
kSSE2,
kSSE3,
kSlowSSSE3, // special feature for slow SSSE3 architectures
kSSE4_1,
kAVX,
kAVX2,
kNEON,
kMIPS32,
kMIPSdspR2,
kMSA
} CPUFeature;
// returns true if the CPU supports the feature.
typedef int (*VP8CPUInfo)(CPUFeature feature);
WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
//------------------------------------------------------------------------------
// Init stub generator
@ -550,15 +332,6 @@ extern void WebPConvertARGBToUV_C(const uint32_t* argb, uint8_t* u, uint8_t* v,
extern void WebPConvertRGBA32ToUV_C(const uint16_t* rgb,
uint8_t* u, uint8_t* v, int width);
// utilities for accurate RGB->YUV conversion
extern uint64_t (*WebPSharpYUVUpdateY)(const uint16_t* src, const uint16_t* ref,
uint16_t* dst, int len);
extern void (*WebPSharpYUVUpdateRGB)(const int16_t* src, const int16_t* ref,
int16_t* dst, int len);
extern void (*WebPSharpYUVFilterRow)(const int16_t* A, const int16_t* B,
int len,
const uint16_t* best_y, uint16_t* out);
// Must be called before using the above.
void WebPInitConvertARGBToYUV(void);

View File

@ -182,9 +182,9 @@ extern VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16];
// -----------------------------------------------------------------------------
// Huffman-cost related functions.
typedef double (*VP8LCostFunc)(const uint32_t* population, int length);
typedef double (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y,
int length);
typedef float (*VP8LCostFunc)(const uint32_t* population, int length);
typedef float (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y,
int length);
typedef float (*VP8LCombinedShannonEntropyFunc)(const int X[256],
const int Y[256]);
@ -198,7 +198,7 @@ typedef struct { // small struct to hold counters
} VP8LStreaks;
typedef struct { // small struct to hold bit entropy results
double entropy; // entropy
float entropy; // entropy
uint32_t sum; // sum of the population
int nonzeros; // number of non-zero elements in the population
uint32_t max_val; // maximum value in the population

View File

@ -402,7 +402,7 @@ static float FastLog2Slow_C(uint32_t v) {
// Compute the combined Shanon's entropy for distribution {X} and {X+Y}
static float CombinedShannonEntropy_C(const int X[256], const int Y[256]) {
int i;
double retval = 0.;
float retval = 0.f;
int sumX = 0, sumXY = 0;
for (i = 0; i < 256; ++i) {
const int x = X[i];
@ -418,7 +418,7 @@ static float CombinedShannonEntropy_C(const int X[256], const int Y[256]) {
}
}
retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY);
return (float)retval;
return retval;
}
void VP8LBitEntropyInit(VP8LBitEntropy* const entropy) {
@ -636,17 +636,17 @@ void VP8LBundleColorMap_C(const uint8_t* const row, int width, int xbits,
//------------------------------------------------------------------------------
static double ExtraCost_C(const uint32_t* population, int length) {
static float ExtraCost_C(const uint32_t* population, int length) {
int i;
double cost = 0.;
float cost = 0.f;
for (i = 2; i < length - 2; ++i) cost += (i >> 1) * population[i + 2];
return cost;
}
static double ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y,
static float ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y,
int length) {
int i;
double cost = 0.;
float cost = 0.f;
for (i = 2; i < length - 2; ++i) {
const int xy = X[i + 2] + Y[i + 2];
cost += (i >> 1) * xy;

View File

@ -103,8 +103,8 @@ static float FastLog2Slow_MIPS32(uint32_t v) {
// cost += i * *(pop + 1);
// pop += 2;
// }
// return (double)cost;
static double ExtraCost_MIPS32(const uint32_t* const population, int length) {
// return (float)cost;
static float ExtraCost_MIPS32(const uint32_t* const population, int length) {
int i, temp0, temp1;
const uint32_t* pop = &population[4];
const uint32_t* const LoopEnd = &population[length];
@ -130,7 +130,7 @@ static double ExtraCost_MIPS32(const uint32_t* const population, int length) {
: "memory", "hi", "lo"
);
return (double)((int64_t)temp0 << 32 | temp1);
return (float)((int64_t)temp0 << 32 | temp1);
}
// C version of this function:
@ -148,9 +148,9 @@ static double ExtraCost_MIPS32(const uint32_t* const population, int length) {
// pX += 2;
// pY += 2;
// }
// return (double)cost;
static double ExtraCostCombined_MIPS32(const uint32_t* const X,
const uint32_t* const Y, int length) {
// return (float)cost;
static float ExtraCostCombined_MIPS32(const uint32_t* const X,
const uint32_t* const Y, int length) {
int i, temp0, temp1, temp2, temp3;
const uint32_t* pX = &X[4];
const uint32_t* pY = &Y[4];
@ -183,7 +183,7 @@ static double ExtraCostCombined_MIPS32(const uint32_t* const X,
: "memory", "hi", "lo"
);
return (double)((int64_t)temp0 << 32 | temp1);
return (float)((int64_t)temp0 << 32 | temp1);
}
#define HUFFMAN_COST_PASS \
@ -347,24 +347,24 @@ static void GetCombinedEntropyUnrefined_MIPS32(const uint32_t X[],
static void AddVector_MIPS32(const uint32_t* pa, const uint32_t* pb,
uint32_t* pout, int size) {
uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
const uint32_t end = ((size) / 4) * 4;
const int end = ((size) / 4) * 4;
const uint32_t* const LoopEnd = pa + end;
int i;
ASM_START
ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout)
ASM_END_0
for (i = end; i < size; ++i) pout[i] = pa[i] + pb[i];
for (i = 0; i < size - end; ++i) pout[i] = pa[i] + pb[i];
}
static void AddVectorEq_MIPS32(const uint32_t* pa, uint32_t* pout, int size) {
uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
const uint32_t end = ((size) / 4) * 4;
const int end = ((size) / 4) * 4;
const uint32_t* const LoopEnd = pa + end;
int i;
ASM_START
ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout)
ASM_END_1
for (i = end; i < size; ++i) pout[i] += pa[i];
for (i = 0; i < size - end; ++i) pout[i] += pa[i];
}
#undef ASM_END_1

View File

@ -239,7 +239,7 @@ static void AddVectorEq_SSE2(const uint32_t* a, uint32_t* out, int size) {
static float CombinedShannonEntropy_SSE2(const int X[256], const int Y[256]) {
int i;
double retval = 0.;
float retval = 0.f;
int sumX = 0, sumXY = 0;
const __m128i zero = _mm_setzero_si128();
@ -273,7 +273,7 @@ static float CombinedShannonEntropy_SSE2(const int X[256], const int Y[256]) {
}
}
retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY);
return (float)retval;
return retval;
}
#else

View File

@ -194,50 +194,6 @@ void WebPConvertRGBA32ToUV_C(const uint16_t* rgb,
//-----------------------------------------------------------------------------
#if !WEBP_NEON_OMIT_C_CODE
#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic
static uint16_t clip_y(int v) {
return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v;
}
static uint64_t SharpYUVUpdateY_C(const uint16_t* ref, const uint16_t* src,
uint16_t* dst, int len) {
uint64_t diff = 0;
int i;
for (i = 0; i < len; ++i) {
const int diff_y = ref[i] - src[i];
const int new_y = (int)dst[i] + diff_y;
dst[i] = clip_y(new_y);
diff += (uint64_t)abs(diff_y);
}
return diff;
}
static void SharpYUVUpdateRGB_C(const int16_t* ref, const int16_t* src,
int16_t* dst, int len) {
int i;
for (i = 0; i < len; ++i) {
const int diff_uv = ref[i] - src[i];
dst[i] += diff_uv;
}
}
static void SharpYUVFilterRow_C(const int16_t* A, const int16_t* B, int len,
const uint16_t* best_y, uint16_t* out) {
int i;
for (i = 0; i < len; ++i, ++A, ++B) {
const int v0 = (A[0] * 9 + A[1] * 3 + B[0] * 3 + B[1] + 8) >> 4;
const int v1 = (A[1] * 9 + A[0] * 3 + B[1] * 3 + B[0] + 8) >> 4;
out[2 * i + 0] = clip_y(best_y[2 * i + 0] + v0);
out[2 * i + 1] = clip_y(best_y[2 * i + 1] + v1);
}
}
#endif // !WEBP_NEON_OMIT_C_CODE
#undef MAX_Y
//-----------------------------------------------------------------------------
void (*WebPConvertRGB24ToY)(const uint8_t* rgb, uint8_t* y, int width);
void (*WebPConvertBGR24ToY)(const uint8_t* bgr, uint8_t* y, int width);
void (*WebPConvertRGBA32ToUV)(const uint16_t* rgb,
@ -247,18 +203,9 @@ void (*WebPConvertARGBToY)(const uint32_t* argb, uint8_t* y, int width);
void (*WebPConvertARGBToUV)(const uint32_t* argb, uint8_t* u, uint8_t* v,
int src_width, int do_store);
uint64_t (*WebPSharpYUVUpdateY)(const uint16_t* ref, const uint16_t* src,
uint16_t* dst, int len);
void (*WebPSharpYUVUpdateRGB)(const int16_t* ref, const int16_t* src,
int16_t* dst, int len);
void (*WebPSharpYUVFilterRow)(const int16_t* A, const int16_t* B, int len,
const uint16_t* best_y, uint16_t* out);
extern void WebPInitConvertARGBToYUVSSE2(void);
extern void WebPInitConvertARGBToYUVSSE41(void);
extern void WebPInitConvertARGBToYUVNEON(void);
extern void WebPInitSharpYUVSSE2(void);
extern void WebPInitSharpYUVNEON(void);
WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
WebPConvertARGBToY = ConvertARGBToY_C;
@ -269,17 +216,10 @@ WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
WebPConvertRGBA32ToUV = WebPConvertRGBA32ToUV_C;
#if !WEBP_NEON_OMIT_C_CODE
WebPSharpYUVUpdateY = SharpYUVUpdateY_C;
WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_C;
WebPSharpYUVFilterRow = SharpYUVFilterRow_C;
#endif
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitConvertARGBToYUVSSE2();
WebPInitSharpYUVSSE2();
}
#endif // WEBP_HAVE_SSE2
#if defined(WEBP_HAVE_SSE41)
@ -293,7 +233,6 @@ WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
WebPInitConvertARGBToYUVNEON();
WebPInitSharpYUVNEON();
}
#endif // WEBP_HAVE_NEON
@ -302,7 +241,4 @@ WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
assert(WebPConvertRGB24ToY != NULL);
assert(WebPConvertBGR24ToY != NULL);
assert(WebPConvertRGBA32ToUV != NULL);
assert(WebPSharpYUVUpdateY != NULL);
assert(WebPSharpYUVUpdateRGB != NULL);
assert(WebPSharpYUVFilterRow != NULL);
}

View File

@ -173,116 +173,8 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVNEON(void) {
WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_NEON;
}
//------------------------------------------------------------------------------
#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic
static uint16_t clip_y_NEON(int v) {
return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v;
}
static uint64_t SharpYUVUpdateY_NEON(const uint16_t* ref, const uint16_t* src,
uint16_t* dst, int len) {
int i;
const int16x8_t zero = vdupq_n_s16(0);
const int16x8_t max = vdupq_n_s16(MAX_Y);
uint64x2_t sum = vdupq_n_u64(0);
uint64_t diff;
for (i = 0; i + 8 <= len; i += 8) {
const int16x8_t A = vreinterpretq_s16_u16(vld1q_u16(ref + i));
const int16x8_t B = vreinterpretq_s16_u16(vld1q_u16(src + i));
const int16x8_t C = vreinterpretq_s16_u16(vld1q_u16(dst + i));
const int16x8_t D = vsubq_s16(A, B); // diff_y
const int16x8_t F = vaddq_s16(C, D); // new_y
const uint16x8_t H =
vreinterpretq_u16_s16(vmaxq_s16(vminq_s16(F, max), zero));
const int16x8_t I = vabsq_s16(D); // abs(diff_y)
vst1q_u16(dst + i, H);
sum = vpadalq_u32(sum, vpaddlq_u16(vreinterpretq_u16_s16(I)));
}
diff = vgetq_lane_u64(sum, 0) + vgetq_lane_u64(sum, 1);
for (; i < len; ++i) {
const int diff_y = ref[i] - src[i];
const int new_y = (int)(dst[i]) + diff_y;
dst[i] = clip_y_NEON(new_y);
diff += (uint64_t)(abs(diff_y));
}
return diff;
}
static void SharpYUVUpdateRGB_NEON(const int16_t* ref, const int16_t* src,
int16_t* dst, int len) {
int i;
for (i = 0; i + 8 <= len; i += 8) {
const int16x8_t A = vld1q_s16(ref + i);
const int16x8_t B = vld1q_s16(src + i);
const int16x8_t C = vld1q_s16(dst + i);
const int16x8_t D = vsubq_s16(A, B); // diff_uv
const int16x8_t E = vaddq_s16(C, D); // new_uv
vst1q_s16(dst + i, E);
}
for (; i < len; ++i) {
const int diff_uv = ref[i] - src[i];
dst[i] += diff_uv;
}
}
static void SharpYUVFilterRow_NEON(const int16_t* A, const int16_t* B, int len,
const uint16_t* best_y, uint16_t* out) {
int i;
const int16x8_t max = vdupq_n_s16(MAX_Y);
const int16x8_t zero = vdupq_n_s16(0);
for (i = 0; i + 8 <= len; i += 8) {
const int16x8_t a0 = vld1q_s16(A + i + 0);
const int16x8_t a1 = vld1q_s16(A + i + 1);
const int16x8_t b0 = vld1q_s16(B + i + 0);
const int16x8_t b1 = vld1q_s16(B + i + 1);
const int16x8_t a0b1 = vaddq_s16(a0, b1);
const int16x8_t a1b0 = vaddq_s16(a1, b0);
const int16x8_t a0a1b0b1 = vaddq_s16(a0b1, a1b0); // A0+A1+B0+B1
const int16x8_t a0b1_2 = vaddq_s16(a0b1, a0b1); // 2*(A0+B1)
const int16x8_t a1b0_2 = vaddq_s16(a1b0, a1b0); // 2*(A1+B0)
const int16x8_t c0 = vshrq_n_s16(vaddq_s16(a0b1_2, a0a1b0b1), 3);
const int16x8_t c1 = vshrq_n_s16(vaddq_s16(a1b0_2, a0a1b0b1), 3);
const int16x8_t d0 = vaddq_s16(c1, a0);
const int16x8_t d1 = vaddq_s16(c0, a1);
const int16x8_t e0 = vrshrq_n_s16(d0, 1);
const int16x8_t e1 = vrshrq_n_s16(d1, 1);
const int16x8x2_t f = vzipq_s16(e0, e1);
const int16x8_t g0 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 0));
const int16x8_t g1 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 8));
const int16x8_t h0 = vaddq_s16(g0, f.val[0]);
const int16x8_t h1 = vaddq_s16(g1, f.val[1]);
const int16x8_t i0 = vmaxq_s16(vminq_s16(h0, max), zero);
const int16x8_t i1 = vmaxq_s16(vminq_s16(h1, max), zero);
vst1q_u16(out + 2 * i + 0, vreinterpretq_u16_s16(i0));
vst1q_u16(out + 2 * i + 8, vreinterpretq_u16_s16(i1));
}
for (; i < len; ++i) {
const int a0b1 = A[i + 0] + B[i + 1];
const int a1b0 = A[i + 1] + B[i + 0];
const int a0a1b0b1 = a0b1 + a1b0 + 8;
const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
out[2 * i + 0] = clip_y_NEON(best_y[2 * i + 0] + v0);
out[2 * i + 1] = clip_y_NEON(best_y[2 * i + 1] + v1);
}
}
#undef MAX_Y
//------------------------------------------------------------------------------
extern void WebPInitSharpYUVNEON(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPInitSharpYUVNEON(void) {
WebPSharpYUVUpdateY = SharpYUVUpdateY_NEON;
WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_NEON;
WebPSharpYUVFilterRow = SharpYUVFilterRow_NEON;
}
#else // !WEBP_USE_NEON
WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVNEON)
WEBP_DSP_INIT_STUB(WebPInitSharpYUVNEON)
#endif // WEBP_USE_NEON

View File

@ -747,128 +747,9 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVSSE2(void) {
WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_SSE2;
}
//------------------------------------------------------------------------------
#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic
static uint16_t clip_y(int v) {
return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v;
}
static uint64_t SharpYUVUpdateY_SSE2(const uint16_t* ref, const uint16_t* src,
uint16_t* dst, int len) {
uint64_t diff = 0;
uint32_t tmp[4];
int i;
const __m128i zero = _mm_setzero_si128();
const __m128i max = _mm_set1_epi16(MAX_Y);
const __m128i one = _mm_set1_epi16(1);
__m128i sum = zero;
for (i = 0; i + 8 <= len; i += 8) {
const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i));
const __m128i B = _mm_loadu_si128((const __m128i*)(src + i));
const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i));
const __m128i D = _mm_sub_epi16(A, B); // diff_y
const __m128i E = _mm_cmpgt_epi16(zero, D); // sign (-1 or 0)
const __m128i F = _mm_add_epi16(C, D); // new_y
const __m128i G = _mm_or_si128(E, one); // -1 or 1
const __m128i H = _mm_max_epi16(_mm_min_epi16(F, max), zero);
const __m128i I = _mm_madd_epi16(D, G); // sum(abs(...))
_mm_storeu_si128((__m128i*)(dst + i), H);
sum = _mm_add_epi32(sum, I);
}
_mm_storeu_si128((__m128i*)tmp, sum);
diff = tmp[3] + tmp[2] + tmp[1] + tmp[0];
for (; i < len; ++i) {
const int diff_y = ref[i] - src[i];
const int new_y = (int)dst[i] + diff_y;
dst[i] = clip_y(new_y);
diff += (uint64_t)abs(diff_y);
}
return diff;
}
static void SharpYUVUpdateRGB_SSE2(const int16_t* ref, const int16_t* src,
int16_t* dst, int len) {
int i = 0;
for (i = 0; i + 8 <= len; i += 8) {
const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i));
const __m128i B = _mm_loadu_si128((const __m128i*)(src + i));
const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i));
const __m128i D = _mm_sub_epi16(A, B); // diff_uv
const __m128i E = _mm_add_epi16(C, D); // new_uv
_mm_storeu_si128((__m128i*)(dst + i), E);
}
for (; i < len; ++i) {
const int diff_uv = ref[i] - src[i];
dst[i] += diff_uv;
}
}
static void SharpYUVFilterRow_SSE2(const int16_t* A, const int16_t* B, int len,
const uint16_t* best_y, uint16_t* out) {
int i;
const __m128i kCst8 = _mm_set1_epi16(8);
const __m128i max = _mm_set1_epi16(MAX_Y);
const __m128i zero = _mm_setzero_si128();
for (i = 0; i + 8 <= len; i += 8) {
const __m128i a0 = _mm_loadu_si128((const __m128i*)(A + i + 0));
const __m128i a1 = _mm_loadu_si128((const __m128i*)(A + i + 1));
const __m128i b0 = _mm_loadu_si128((const __m128i*)(B + i + 0));
const __m128i b1 = _mm_loadu_si128((const __m128i*)(B + i + 1));
const __m128i a0b1 = _mm_add_epi16(a0, b1);
const __m128i a1b0 = _mm_add_epi16(a1, b0);
const __m128i a0a1b0b1 = _mm_add_epi16(a0b1, a1b0); // A0+A1+B0+B1
const __m128i a0a1b0b1_8 = _mm_add_epi16(a0a1b0b1, kCst8);
const __m128i a0b1_2 = _mm_add_epi16(a0b1, a0b1); // 2*(A0+B1)
const __m128i a1b0_2 = _mm_add_epi16(a1b0, a1b0); // 2*(A1+B0)
const __m128i c0 = _mm_srai_epi16(_mm_add_epi16(a0b1_2, a0a1b0b1_8), 3);
const __m128i c1 = _mm_srai_epi16(_mm_add_epi16(a1b0_2, a0a1b0b1_8), 3);
const __m128i d0 = _mm_add_epi16(c1, a0);
const __m128i d1 = _mm_add_epi16(c0, a1);
const __m128i e0 = _mm_srai_epi16(d0, 1);
const __m128i e1 = _mm_srai_epi16(d1, 1);
const __m128i f0 = _mm_unpacklo_epi16(e0, e1);
const __m128i f1 = _mm_unpackhi_epi16(e0, e1);
const __m128i g0 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0));
const __m128i g1 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 8));
const __m128i h0 = _mm_add_epi16(g0, f0);
const __m128i h1 = _mm_add_epi16(g1, f1);
const __m128i i0 = _mm_max_epi16(_mm_min_epi16(h0, max), zero);
const __m128i i1 = _mm_max_epi16(_mm_min_epi16(h1, max), zero);
_mm_storeu_si128((__m128i*)(out + 2 * i + 0), i0);
_mm_storeu_si128((__m128i*)(out + 2 * i + 8), i1);
}
for (; i < len; ++i) {
// (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 =
// = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4
// We reuse the common sub-expressions.
const int a0b1 = A[i + 0] + B[i + 1];
const int a1b0 = A[i + 1] + B[i + 0];
const int a0a1b0b1 = a0b1 + a1b0 + 8;
const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
out[2 * i + 0] = clip_y(best_y[2 * i + 0] + v0);
out[2 * i + 1] = clip_y(best_y[2 * i + 1] + v1);
}
}
#undef MAX_Y
//------------------------------------------------------------------------------
extern void WebPInitSharpYUVSSE2(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPInitSharpYUVSSE2(void) {
WebPSharpYUVUpdateY = SharpYUVUpdateY_SSE2;
WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_SSE2;
WebPSharpYUVFilterRow = SharpYUVFilterRow_SSE2;
}
#else // !WEBP_USE_SSE2
WEBP_DSP_INIT_STUB(WebPInitSamplersSSE2)
WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVSSE2)
WEBP_DSP_INIT_STUB(WebPInitSharpYUVSSE2)
#endif // WEBP_USE_SSE2

View File

@ -86,7 +86,7 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
// a decoder bug related to alpha with color cache.
// See: https://code.google.com/p/webp/issues/detail?id=239
// Need to re-enable this later.
ok = (VP8LEncodeStream(&config, &picture, bw, 0 /*use_cache*/) == VP8_ENC_OK);
ok = VP8LEncodeStream(&config, &picture, bw, /*use_cache=*/0);
WebPPictureFree(&picture);
ok = ok && !bw->error_;
if (!ok) {

View File

@ -15,10 +15,11 @@
//
#include <assert.h>
#include <float.h>
#include "src/dsp/lossless_common.h"
#include "src/enc/backward_references_enc.h"
#include "src/enc/histogram_enc.h"
#include "src/dsp/lossless_common.h"
#include "src/utils/color_cache_utils.h"
#include "src/utils/utils.h"
@ -30,15 +31,15 @@ extern void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs,
const PixOrCopy v);
typedef struct {
double alpha_[VALUES_IN_BYTE];
double red_[VALUES_IN_BYTE];
double blue_[VALUES_IN_BYTE];
double distance_[NUM_DISTANCE_CODES];
double* literal_;
float alpha_[VALUES_IN_BYTE];
float red_[VALUES_IN_BYTE];
float blue_[VALUES_IN_BYTE];
float distance_[NUM_DISTANCE_CODES];
float* literal_;
} CostModel;
static void ConvertPopulationCountTableToBitEstimates(
int num_symbols, const uint32_t population_counts[], double output[]) {
int num_symbols, const uint32_t population_counts[], float output[]) {
uint32_t sum = 0;
int nonzeros = 0;
int i;
@ -51,7 +52,7 @@ static void ConvertPopulationCountTableToBitEstimates(
if (nonzeros <= 1) {
memset(output, 0, num_symbols * sizeof(*output));
} else {
const double logsum = VP8LFastLog2(sum);
const float logsum = VP8LFastLog2(sum);
for (i = 0; i < num_symbols; ++i) {
output[i] = logsum - VP8LFastLog2(population_counts[i]);
}
@ -75,8 +76,8 @@ static int CostModelBuild(CostModel* const m, int xsize, int cache_bits,
}
ConvertPopulationCountTableToBitEstimates(
VP8LHistogramNumCodes(histo->palette_code_bits_),
histo->literal_, m->literal_);
VP8LHistogramNumCodes(histo->palette_code_bits_), histo->literal_,
m->literal_);
ConvertPopulationCountTableToBitEstimates(
VALUES_IN_BYTE, histo->red_, m->red_);
ConvertPopulationCountTableToBitEstimates(
@ -92,27 +93,27 @@ static int CostModelBuild(CostModel* const m, int xsize, int cache_bits,
return ok;
}
static WEBP_INLINE double GetLiteralCost(const CostModel* const m, uint32_t v) {
static WEBP_INLINE float GetLiteralCost(const CostModel* const m, uint32_t v) {
return m->alpha_[v >> 24] +
m->red_[(v >> 16) & 0xff] +
m->literal_[(v >> 8) & 0xff] +
m->blue_[v & 0xff];
}
static WEBP_INLINE double GetCacheCost(const CostModel* const m, uint32_t idx) {
static WEBP_INLINE float GetCacheCost(const CostModel* const m, uint32_t idx) {
const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx;
return m->literal_[literal_idx];
}
static WEBP_INLINE double GetLengthCost(const CostModel* const m,
uint32_t length) {
static WEBP_INLINE float GetLengthCost(const CostModel* const m,
uint32_t length) {
int code, extra_bits;
VP8LPrefixEncodeBits(length, &code, &extra_bits);
return m->literal_[VALUES_IN_BYTE + code] + extra_bits;
}
static WEBP_INLINE double GetDistanceCost(const CostModel* const m,
uint32_t distance) {
static WEBP_INLINE float GetDistanceCost(const CostModel* const m,
uint32_t distance) {
int code, extra_bits;
VP8LPrefixEncodeBits(distance, &code, &extra_bits);
return m->distance_[code] + extra_bits;
@ -122,20 +123,20 @@ static WEBP_INLINE void AddSingleLiteralWithCostModel(
const uint32_t* const argb, VP8LColorCache* const hashers,
const CostModel* const cost_model, int idx, int use_color_cache,
float prev_cost, float* const cost, uint16_t* const dist_array) {
double cost_val = prev_cost;
float cost_val = prev_cost;
const uint32_t color = argb[idx];
const int ix = use_color_cache ? VP8LColorCacheContains(hashers, color) : -1;
if (ix >= 0) {
// use_color_cache is true and hashers contains color
const double mul0 = 0.68;
const float mul0 = 0.68f;
cost_val += GetCacheCost(cost_model, ix) * mul0;
} else {
const double mul1 = 0.82;
const float mul1 = 0.82f;
if (use_color_cache) VP8LColorCacheInsert(hashers, color);
cost_val += GetLiteralCost(cost_model, color) * mul1;
}
if (cost[idx] > cost_val) {
cost[idx] = (float)cost_val;
cost[idx] = cost_val;
dist_array[idx] = 1; // only one is inserted.
}
}
@ -172,7 +173,7 @@ struct CostInterval {
// The GetLengthCost(cost_model, k) are cached in a CostCacheInterval.
typedef struct {
double cost_;
float cost_;
int start_;
int end_; // Exclusive.
} CostCacheInterval;
@ -187,7 +188,7 @@ typedef struct {
int count_; // The number of stored intervals.
CostCacheInterval* cache_intervals_;
size_t cache_intervals_size_;
double cost_cache_[MAX_LENGTH]; // Contains the GetLengthCost(cost_model, k).
float cost_cache_[MAX_LENGTH]; // Contains the GetLengthCost(cost_model, k).
float* costs_;
uint16_t* dist_array_;
// Most of the time, we only need few intervals -> use a free-list, to avoid
@ -262,10 +263,13 @@ static int CostManagerInit(CostManager* const manager,
CostManagerInitFreeList(manager);
// Fill in the cost_cache_.
manager->cache_intervals_size_ = 1;
manager->cost_cache_[0] = GetLengthCost(cost_model, 0);
for (i = 1; i < cost_cache_size; ++i) {
// Has to be done in two passes due to a GCC bug on i686
// related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323
for (i = 0; i < cost_cache_size; ++i) {
manager->cost_cache_[i] = GetLengthCost(cost_model, i);
}
manager->cache_intervals_size_ = 1;
for (i = 1; i < cost_cache_size; ++i) {
// Get the number of bound intervals.
if (manager->cost_cache_[i] != manager->cost_cache_[i - 1]) {
++manager->cache_intervals_size_;
@ -294,7 +298,7 @@ static int CostManagerInit(CostManager* const manager,
cur->end_ = 1;
cur->cost_ = manager->cost_cache_[0];
for (i = 1; i < cost_cache_size; ++i) {
const double cost_val = manager->cost_cache_[i];
const float cost_val = manager->cost_cache_[i];
if (cost_val != cur->cost_) {
++cur;
// Initialize an interval.
@ -303,6 +307,8 @@ static int CostManagerInit(CostManager* const manager,
}
cur->end_ = i + 1;
}
assert((size_t)(cur - manager->cache_intervals_) + 1 ==
manager->cache_intervals_size_);
}
manager->costs_ = (float*)WebPSafeMalloc(pix_count, sizeof(*manager->costs_));
@ -311,7 +317,7 @@ static int CostManagerInit(CostManager* const manager,
return 0;
}
// Set the initial costs_ high for every pixel as we will keep the minimum.
for (i = 0; i < pix_count; ++i) manager->costs_[i] = 1e38f;
for (i = 0; i < pix_count; ++i) manager->costs_[i] = FLT_MAX;
return 1;
}
@ -457,7 +463,7 @@ static WEBP_INLINE void InsertInterval(CostManager* const manager,
// If handling the interval or one of its subintervals becomes to heavy, its
// contribution is added to the costs right away.
static WEBP_INLINE void PushInterval(CostManager* const manager,
double distance_cost, int position,
float distance_cost, int position,
int len) {
size_t i;
CostInterval* interval = manager->head_;
@ -474,7 +480,7 @@ static WEBP_INLINE void PushInterval(CostManager* const manager,
const int k = j - position;
float cost_tmp;
assert(k >= 0 && k < MAX_LENGTH);
cost_tmp = (float)(distance_cost + manager->cost_cache_[k]);
cost_tmp = distance_cost + manager->cost_cache_[k];
if (manager->costs_[j] > cost_tmp) {
manager->costs_[j] = cost_tmp;
@ -492,7 +498,7 @@ static WEBP_INLINE void PushInterval(CostManager* const manager,
const int end = position + (cost_cache_intervals[i].end_ > len
? len
: cost_cache_intervals[i].end_);
const float cost = (float)(distance_cost + cost_cache_intervals[i].cost_);
const float cost = distance_cost + cost_cache_intervals[i].cost_;
for (; interval != NULL && interval->start_ < end;
interval = interval_next) {
@ -570,22 +576,21 @@ static int BackwardReferencesHashChainDistanceOnly(
const int pix_count = xsize * ysize;
const int use_color_cache = (cache_bits > 0);
const size_t literal_array_size =
sizeof(double) * (NUM_LITERAL_CODES + NUM_LENGTH_CODES +
((cache_bits > 0) ? (1 << cache_bits) : 0));
sizeof(float) * (VP8LHistogramNumCodes(cache_bits));
const size_t cost_model_size = sizeof(CostModel) + literal_array_size;
CostModel* const cost_model =
(CostModel*)WebPSafeCalloc(1ULL, cost_model_size);
VP8LColorCache hashers;
CostManager* cost_manager =
(CostManager*)WebPSafeMalloc(1ULL, sizeof(*cost_manager));
(CostManager*)WebPSafeCalloc(1ULL, sizeof(*cost_manager));
int offset_prev = -1, len_prev = -1;
double offset_cost = -1;
float offset_cost = -1.f;
int first_offset_is_constant = -1; // initialized with 'impossible' value
int reach = 0;
if (cost_model == NULL || cost_manager == NULL) goto Error;
cost_model->literal_ = (double*)(cost_model + 1);
cost_model->literal_ = (float*)(cost_model + 1);
if (use_color_cache) {
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
if (!cc_init) goto Error;
@ -675,7 +680,7 @@ static int BackwardReferencesHashChainDistanceOnly(
}
ok = !refs->error_;
Error:
Error:
if (cc_init) VP8LColorCacheClear(&hashers);
CostManagerClear(cost_manager);
WebPSafeFree(cost_model);

View File

@ -10,6 +10,8 @@
// Author: Jyrki Alakuijala (jyrki@google.com)
//
#include "src/enc/backward_references_enc.h"
#include <assert.h>
#include <float.h>
#include <math.h>
@ -17,10 +19,11 @@
#include "src/dsp/dsp.h"
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
#include "src/enc/backward_references_enc.h"
#include "src/enc/histogram_enc.h"
#include "src/enc/vp8i_enc.h"
#include "src/utils/color_cache_utils.h"
#include "src/utils/utils.h"
#include "src/webp/encode.h"
#define MIN_BLOCK_SIZE 256 // minimum block size for backward references
@ -255,10 +258,13 @@ static WEBP_INLINE int MaxFindCopyLength(int len) {
int VP8LHashChainFill(VP8LHashChain* const p, int quality,
const uint32_t* const argb, int xsize, int ysize,
int low_effort) {
int low_effort, const WebPPicture* const pic,
int percent_range, int* const percent) {
const int size = xsize * ysize;
const int iter_max = GetMaxItersForQuality(quality);
const uint32_t window_size = GetWindowSizeForHashChain(quality, xsize);
int remaining_percent = percent_range;
int percent_start = *percent;
int pos;
int argb_comp;
uint32_t base_position;
@ -276,7 +282,13 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality,
hash_to_first_index =
(int32_t*)WebPSafeMalloc(HASH_SIZE, sizeof(*hash_to_first_index));
if (hash_to_first_index == NULL) return 0;
if (hash_to_first_index == NULL) {
WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
return 0;
}
percent_range = remaining_percent / 2;
remaining_percent -= percent_range;
// Set the int32_t array to -1.
memset(hash_to_first_index, 0xff, HASH_SIZE * sizeof(*hash_to_first_index));
@ -323,12 +335,22 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality,
hash_to_first_index[hash_code] = pos++;
argb_comp = argb_comp_next;
}
if (!WebPReportProgress(
pic, percent_start + percent_range * pos / (size - 2), percent)) {
WebPSafeFree(hash_to_first_index);
return 0;
}
}
// Process the penultimate pixel.
chain[pos] = hash_to_first_index[GetPixPairHash64(argb + pos)];
WebPSafeFree(hash_to_first_index);
percent_start += percent_range;
if (!WebPReportProgress(pic, percent_start, percent)) return 0;
percent_range = remaining_percent;
// Find the best match interval at each pixel, defined by an offset to the
// pixel and a length. The right-most pixel cannot match anything to the right
// (hence a best length of 0) and the left-most pixel nothing to the left
@ -417,8 +439,17 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality,
max_base_position = base_position;
}
}
if (!WebPReportProgress(pic,
percent_start + percent_range *
(size - 2 - base_position) /
(size - 2),
percent)) {
return 0;
}
}
return 1;
return WebPReportProgress(pic, percent_start + percent_range, percent);
}
static WEBP_INLINE void AddSingleLiteral(uint32_t pixel, int use_color_cache,
@ -728,7 +759,7 @@ static int CalculateBestCacheSize(const uint32_t* argb, int quality,
int* const best_cache_bits) {
int i;
const int cache_bits_max = (quality <= 25) ? 0 : *best_cache_bits;
double entropy_min = MAX_ENTROPY;
float entropy_min = MAX_ENTROPY;
int cc_init[MAX_COLOR_CACHE_BITS + 1] = { 0 };
VP8LColorCache hashers[MAX_COLOR_CACHE_BITS + 1];
VP8LRefsCursor c = VP8LRefsCursorInit(refs);
@ -813,14 +844,14 @@ static int CalculateBestCacheSize(const uint32_t* argb, int quality,
}
for (i = 0; i <= cache_bits_max; ++i) {
const double entropy = VP8LHistogramEstimateBits(histos[i]);
const float entropy = VP8LHistogramEstimateBits(histos[i]);
if (i == 0 || entropy < entropy_min) {
entropy_min = entropy;
*best_cache_bits = i;
}
}
ok = 1;
Error:
Error:
for (i = 0; i <= cache_bits_max; ++i) {
if (cc_init[i]) VP8LColorCacheClear(&hashers[i]);
VP8LFreeHistogram(histos[i]);
@ -890,7 +921,7 @@ static int GetBackwardReferences(int width, int height,
int i, lz77_type;
// Index 0 is for a color cache, index 1 for no cache (if needed).
int lz77_types_best[2] = {0, 0};
double bit_costs_best[2] = {DBL_MAX, DBL_MAX};
float bit_costs_best[2] = {FLT_MAX, FLT_MAX};
VP8LHashChain hash_chain_box;
VP8LBackwardRefs* const refs_tmp = &refs[do_no_cache ? 2 : 1];
int status = 0;
@ -902,7 +933,7 @@ static int GetBackwardReferences(int width, int height,
for (lz77_type = 1; lz77_types_to_try;
lz77_types_to_try &= ~lz77_type, lz77_type <<= 1) {
int res = 0;
double bit_cost = 0.;
float bit_cost = 0.f;
if ((lz77_types_to_try & lz77_type) == 0) continue;
switch (lz77_type) {
case kLZ77RLE:
@ -976,15 +1007,16 @@ static int GetBackwardReferences(int width, int height,
const VP8LHashChain* const hash_chain_tmp =
(lz77_types_best[i] == kLZ77Standard) ? hash_chain : &hash_chain_box;
const int cache_bits = (i == 1) ? 0 : *cache_bits_best;
if (VP8LBackwardReferencesTraceBackwards(width, height, argb, cache_bits,
hash_chain_tmp, &refs[i],
refs_tmp)) {
double bit_cost_trace;
VP8LHistogramCreate(histo, refs_tmp, cache_bits);
bit_cost_trace = VP8LHistogramEstimateBits(histo);
if (bit_cost_trace < bit_costs_best[i]) {
BackwardRefsSwap(refs_tmp, &refs[i]);
}
float bit_cost_trace;
if (!VP8LBackwardReferencesTraceBackwards(width, height, argb, cache_bits,
hash_chain_tmp, &refs[i],
refs_tmp)) {
goto Error;
}
VP8LHistogramCreate(histo, refs_tmp, cache_bits);
bit_cost_trace = VP8LHistogramEstimateBits(histo);
if (bit_cost_trace < bit_costs_best[i]) {
BackwardRefsSwap(refs_tmp, &refs[i]);
}
}
@ -1000,31 +1032,37 @@ static int GetBackwardReferences(int width, int height,
}
status = 1;
Error:
Error:
VP8LHashChainClear(&hash_chain_box);
VP8LFreeHistogram(histo);
return status;
}
WebPEncodingError VP8LGetBackwardReferences(
int VP8LGetBackwardReferences(
int width, int height, const uint32_t* const argb, int quality,
int low_effort, int lz77_types_to_try, int cache_bits_max, int do_no_cache,
const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs,
int* const cache_bits_best) {
int* const cache_bits_best, const WebPPicture* const pic, int percent_range,
int* const percent) {
if (low_effort) {
VP8LBackwardRefs* refs_best;
*cache_bits_best = cache_bits_max;
refs_best = GetBackwardReferencesLowEffort(
width, height, argb, cache_bits_best, hash_chain, refs);
if (refs_best == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
if (refs_best == NULL) {
WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
return 0;
}
// Set it in first position.
BackwardRefsSwap(refs_best, &refs[0]);
} else {
if (!GetBackwardReferences(width, height, argb, quality, lz77_types_to_try,
cache_bits_max, do_no_cache, hash_chain, refs,
cache_bits_best)) {
return VP8_ENC_ERROR_OUT_OF_MEMORY;
WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
return 0;
}
}
return VP8_ENC_OK;
return WebPReportProgress(pic, *percent + percent_range, percent);
}

View File

@ -134,10 +134,11 @@ struct VP8LHashChain {
// Must be called first, to set size.
int VP8LHashChainInit(VP8LHashChain* const p, int size);
// Pre-compute the best matches for argb.
// Pre-compute the best matches for argb. pic and percent are for progress.
int VP8LHashChainFill(VP8LHashChain* const p, int quality,
const uint32_t* const argb, int xsize, int ysize,
int low_effort);
int low_effort, const WebPPicture* const pic,
int percent_range, int* const percent);
void VP8LHashChainClear(VP8LHashChain* const p); // release memory
static WEBP_INLINE int VP8LHashChainFindOffset(const VP8LHashChain* const p,
@ -227,11 +228,14 @@ enum VP8LLZ77Type {
// VP8LBackwardRefs is put in the first element, the best value with no-cache in
// the second element.
// In both cases, the last element is used as temporary internally.
WebPEncodingError VP8LGetBackwardReferences(
// pic and percent are for progress.
// Returns false in case of error (stored in pic->error_code).
int VP8LGetBackwardReferences(
int width, int height, const uint32_t* const argb, int quality,
int low_effort, int lz77_types_to_try, int cache_bits_max, int do_no_cache,
const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs,
int* const cache_bits_best);
int* const cache_bits_best, const WebPPicture* const pic, int percent_range,
int* const percent);
#ifdef __cplusplus
}

View File

@ -13,15 +13,17 @@
#include "src/webp/config.h"
#endif
#include <float.h>
#include <math.h>
#include "src/enc/backward_references_enc.h"
#include "src/enc/histogram_enc.h"
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
#include "src/enc/backward_references_enc.h"
#include "src/enc/histogram_enc.h"
#include "src/enc/vp8i_enc.h"
#include "src/utils/utils.h"
#define MAX_COST 1.e38
#define MAX_BIT_COST FLT_MAX
// Number of partitions for the three dominant (literal, red and blue) symbol
// costs.
@ -228,8 +230,8 @@ void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
// -----------------------------------------------------------------------------
// Entropy-related functions.
static WEBP_INLINE double BitsEntropyRefine(const VP8LBitEntropy* entropy) {
double mix;
static WEBP_INLINE float BitsEntropyRefine(const VP8LBitEntropy* entropy) {
float mix;
if (entropy->nonzeros < 5) {
if (entropy->nonzeros <= 1) {
return 0;
@ -238,67 +240,67 @@ static WEBP_INLINE double BitsEntropyRefine(const VP8LBitEntropy* entropy) {
// Let's mix in a bit of entropy to favor good clustering when
// distributions of these are combined.
if (entropy->nonzeros == 2) {
return 0.99 * entropy->sum + 0.01 * entropy->entropy;
return 0.99f * entropy->sum + 0.01f * entropy->entropy;
}
// No matter what the entropy says, we cannot be better than min_limit
// with Huffman coding. I am mixing a bit of entropy into the
// min_limit since it produces much better (~0.5 %) compression results
// perhaps because of better entropy clustering.
if (entropy->nonzeros == 3) {
mix = 0.95;
mix = 0.95f;
} else {
mix = 0.7; // nonzeros == 4.
mix = 0.7f; // nonzeros == 4.
}
} else {
mix = 0.627;
mix = 0.627f;
}
{
double min_limit = 2 * entropy->sum - entropy->max_val;
min_limit = mix * min_limit + (1.0 - mix) * entropy->entropy;
float min_limit = 2.f * entropy->sum - entropy->max_val;
min_limit = mix * min_limit + (1.f - mix) * entropy->entropy;
return (entropy->entropy < min_limit) ? min_limit : entropy->entropy;
}
}
double VP8LBitsEntropy(const uint32_t* const array, int n) {
float VP8LBitsEntropy(const uint32_t* const array, int n) {
VP8LBitEntropy entropy;
VP8LBitsEntropyUnrefined(array, n, &entropy);
return BitsEntropyRefine(&entropy);
}
static double InitialHuffmanCost(void) {
static float InitialHuffmanCost(void) {
// Small bias because Huffman code length is typically not stored in
// full length.
static const int kHuffmanCodeOfHuffmanCodeSize = CODE_LENGTH_CODES * 3;
static const double kSmallBias = 9.1;
static const float kSmallBias = 9.1f;
return kHuffmanCodeOfHuffmanCodeSize - kSmallBias;
}
// Finalize the Huffman cost based on streak numbers and length type (<3 or >=3)
static double FinalHuffmanCost(const VP8LStreaks* const stats) {
static float FinalHuffmanCost(const VP8LStreaks* const stats) {
// The constants in this function are experimental and got rounded from
// their original values in 1/8 when switched to 1/1024.
double retval = InitialHuffmanCost();
float retval = InitialHuffmanCost();
// Second coefficient: Many zeros in the histogram are covered efficiently
// by a run-length encode. Originally 2/8.
retval += stats->counts[0] * 1.5625 + 0.234375 * stats->streaks[0][1];
retval += stats->counts[0] * 1.5625f + 0.234375f * stats->streaks[0][1];
// Second coefficient: Constant values are encoded less efficiently, but still
// RLE'ed. Originally 6/8.
retval += stats->counts[1] * 2.578125 + 0.703125 * stats->streaks[1][1];
retval += stats->counts[1] * 2.578125f + 0.703125f * stats->streaks[1][1];
// 0s are usually encoded more efficiently than non-0s.
// Originally 15/8.
retval += 1.796875 * stats->streaks[0][0];
retval += 1.796875f * stats->streaks[0][0];
// Originally 26/8.
retval += 3.28125 * stats->streaks[1][0];
retval += 3.28125f * stats->streaks[1][0];
return retval;
}
// Get the symbol entropy for the distribution 'population'.
// Set 'trivial_sym', if there's only one symbol present in the distribution.
static double PopulationCost(const uint32_t* const population, int length,
uint32_t* const trivial_sym,
uint8_t* const is_used) {
static float PopulationCost(const uint32_t* const population, int length,
uint32_t* const trivial_sym,
uint8_t* const is_used) {
VP8LBitEntropy bit_entropy;
VP8LStreaks stats;
VP8LGetEntropyUnrefined(population, length, &bit_entropy, &stats);
@ -314,11 +316,10 @@ static double PopulationCost(const uint32_t* const population, int length,
// trivial_at_end is 1 if the two histograms only have one element that is
// non-zero: both the zero-th one, or both the last one.
static WEBP_INLINE double GetCombinedEntropy(const uint32_t* const X,
const uint32_t* const Y,
int length, int is_X_used,
int is_Y_used,
int trivial_at_end) {
static WEBP_INLINE float GetCombinedEntropy(const uint32_t* const X,
const uint32_t* const Y, int length,
int is_X_used, int is_Y_used,
int trivial_at_end) {
VP8LStreaks stats;
if (trivial_at_end) {
// This configuration is due to palettization that transforms an indexed
@ -356,7 +357,7 @@ static WEBP_INLINE double GetCombinedEntropy(const uint32_t* const X,
}
// Estimates the Entropy + Huffman + other block overhead size cost.
double VP8LHistogramEstimateBits(VP8LHistogram* const p) {
float VP8LHistogramEstimateBits(VP8LHistogram* const p) {
return
PopulationCost(p->literal_, VP8LHistogramNumCodes(p->palette_code_bits_),
NULL, &p->is_used_[0])
@ -373,8 +374,7 @@ double VP8LHistogramEstimateBits(VP8LHistogram* const p) {
static int GetCombinedHistogramEntropy(const VP8LHistogram* const a,
const VP8LHistogram* const b,
double cost_threshold,
double* cost) {
float cost_threshold, float* cost) {
const int palette_code_bits = a->palette_code_bits_;
int trivial_at_end = 0;
assert(a->palette_code_bits_ == b->palette_code_bits_);
@ -439,12 +439,11 @@ static WEBP_INLINE void HistogramAdd(const VP8LHistogram* const a,
// Since the previous score passed is 'cost_threshold', we only need to compare
// the partial cost against 'cost_threshold + C(a) + C(b)' to possibly bail-out
// early.
static double HistogramAddEval(const VP8LHistogram* const a,
const VP8LHistogram* const b,
VP8LHistogram* const out,
double cost_threshold) {
double cost = 0;
const double sum_cost = a->bit_cost_ + b->bit_cost_;
static float HistogramAddEval(const VP8LHistogram* const a,
const VP8LHistogram* const b,
VP8LHistogram* const out, float cost_threshold) {
float cost = 0;
const float sum_cost = a->bit_cost_ + b->bit_cost_;
cost_threshold += sum_cost;
if (GetCombinedHistogramEntropy(a, b, cost_threshold, &cost)) {
@ -459,10 +458,10 @@ static double HistogramAddEval(const VP8LHistogram* const a,
// Same as HistogramAddEval(), except that the resulting histogram
// is not stored. Only the cost C(a+b) - C(a) is evaluated. We omit
// the term C(b) which is constant over all the evaluations.
static double HistogramAddThresh(const VP8LHistogram* const a,
const VP8LHistogram* const b,
double cost_threshold) {
double cost;
static float HistogramAddThresh(const VP8LHistogram* const a,
const VP8LHistogram* const b,
float cost_threshold) {
float cost;
assert(a != NULL && b != NULL);
cost = -a->bit_cost_;
GetCombinedHistogramEntropy(a, b, cost_threshold, &cost);
@ -473,24 +472,22 @@ static double HistogramAddThresh(const VP8LHistogram* const a,
// The structure to keep track of cost range for the three dominant entropy
// symbols.
// TODO(skal): Evaluate if float can be used here instead of double for
// representing the entropy costs.
typedef struct {
double literal_max_;
double literal_min_;
double red_max_;
double red_min_;
double blue_max_;
double blue_min_;
float literal_max_;
float literal_min_;
float red_max_;
float red_min_;
float blue_max_;
float blue_min_;
} DominantCostRange;
static void DominantCostRangeInit(DominantCostRange* const c) {
c->literal_max_ = 0.;
c->literal_min_ = MAX_COST;
c->literal_min_ = MAX_BIT_COST;
c->red_max_ = 0.;
c->red_min_ = MAX_COST;
c->red_min_ = MAX_BIT_COST;
c->blue_max_ = 0.;
c->blue_min_ = MAX_COST;
c->blue_min_ = MAX_BIT_COST;
}
static void UpdateDominantCostRange(
@ -505,10 +502,9 @@ static void UpdateDominantCostRange(
static void UpdateHistogramCost(VP8LHistogram* const h) {
uint32_t alpha_sym, red_sym, blue_sym;
const double alpha_cost =
PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym,
&h->is_used_[3]);
const double distance_cost =
const float alpha_cost =
PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym, &h->is_used_[3]);
const float distance_cost =
PopulationCost(h->distance_, NUM_DISTANCE_CODES, NULL, &h->is_used_[4]) +
VP8LExtraCost(h->distance_, NUM_DISTANCE_CODES);
const int num_codes = VP8LHistogramNumCodes(h->palette_code_bits_);
@ -529,10 +525,10 @@ static void UpdateHistogramCost(VP8LHistogram* const h) {
}
}
static int GetBinIdForEntropy(double min, double max, double val) {
const double range = max - min;
static int GetBinIdForEntropy(float min, float max, float val) {
const float range = max - min;
if (range > 0.) {
const double delta = val - min;
const float delta = val - min;
return (int)((NUM_PARTITIONS - 1e-6) * delta / range);
} else {
return 0;
@ -641,15 +637,11 @@ static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo,
// Merges some histograms with same bin_id together if it's advantageous.
// Sets the remaining histograms to NULL.
static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo,
int* num_used,
const uint16_t* const clusters,
uint16_t* const cluster_mappings,
VP8LHistogram* cur_combo,
const uint16_t* const bin_map,
int num_bins,
double combine_cost_factor,
int low_effort) {
static void HistogramCombineEntropyBin(
VP8LHistogramSet* const image_histo, int* num_used,
const uint16_t* const clusters, uint16_t* const cluster_mappings,
VP8LHistogram* cur_combo, const uint16_t* const bin_map, int num_bins,
float combine_cost_factor, int low_effort) {
VP8LHistogram** const histograms = image_histo->histograms;
int idx;
struct {
@ -679,11 +671,10 @@ static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo,
cluster_mappings[clusters[idx]] = clusters[first];
} else {
// try to merge #idx into #first (both share the same bin_id)
const double bit_cost = histograms[idx]->bit_cost_;
const double bit_cost_thresh = -bit_cost * combine_cost_factor;
const double curr_cost_diff =
HistogramAddEval(histograms[first], histograms[idx],
cur_combo, bit_cost_thresh);
const float bit_cost = histograms[idx]->bit_cost_;
const float bit_cost_thresh = -bit_cost * combine_cost_factor;
const float curr_cost_diff = HistogramAddEval(
histograms[first], histograms[idx], cur_combo, bit_cost_thresh);
if (curr_cost_diff < bit_cost_thresh) {
// Try to merge two histograms only if the combo is a trivial one or
// the two candidate histograms are already non-trivial.
@ -731,8 +722,8 @@ static uint32_t MyRand(uint32_t* const seed) {
typedef struct {
int idx1;
int idx2;
double cost_diff;
double cost_combo;
float cost_diff;
float cost_combo;
} HistogramPair;
typedef struct {
@ -787,10 +778,9 @@ static void HistoQueueUpdateHead(HistoQueue* const histo_queue,
// Update the cost diff and combo of a pair of histograms. This needs to be
// called when the the histograms have been merged with a third one.
static void HistoQueueUpdatePair(const VP8LHistogram* const h1,
const VP8LHistogram* const h2,
double threshold,
const VP8LHistogram* const h2, float threshold,
HistogramPair* const pair) {
const double sum_cost = h1->bit_cost_ + h2->bit_cost_;
const float sum_cost = h1->bit_cost_ + h2->bit_cost_;
pair->cost_combo = 0.;
GetCombinedHistogramEntropy(h1, h2, sum_cost + threshold, &pair->cost_combo);
pair->cost_diff = pair->cost_combo - sum_cost;
@ -799,9 +789,9 @@ static void HistoQueueUpdatePair(const VP8LHistogram* const h1,
// Create a pair from indices "idx1" and "idx2" provided its cost
// is inferior to "threshold", a negative entropy.
// It returns the cost of the pair, or 0. if it superior to threshold.
static double HistoQueuePush(HistoQueue* const histo_queue,
VP8LHistogram** const histograms, int idx1,
int idx2, double threshold) {
static float HistoQueuePush(HistoQueue* const histo_queue,
VP8LHistogram** const histograms, int idx1,
int idx2, float threshold) {
const VP8LHistogram* h1;
const VP8LHistogram* h2;
HistogramPair pair;
@ -945,8 +935,8 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
++tries_with_no_success < num_tries_no_success;
++iter) {
int* mapping_index;
double best_cost =
(histo_queue.size == 0) ? 0. : histo_queue.queue[0].cost_diff;
float best_cost =
(histo_queue.size == 0) ? 0.f : histo_queue.queue[0].cost_diff;
int best_idx1 = -1, best_idx2 = 1;
const uint32_t rand_range = (*num_used - 1) * (*num_used);
// (*num_used) / 2 was chosen empirically. Less means faster but worse
@ -955,7 +945,7 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
// Pick random samples.
for (j = 0; *num_used >= 2 && j < num_tries; ++j) {
double curr_cost;
float curr_cost;
// Choose two different histograms at random and try to combine them.
const uint32_t tmp = MyRand(&seed) % rand_range;
uint32_t idx1 = tmp / (*num_used - 1);
@ -1034,7 +1024,7 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
*do_greedy = (*num_used <= min_cluster_size);
ok = 1;
End:
End:
HistoQueueClear(&histo_queue);
WebPSafeFree(mappings);
return ok;
@ -1057,7 +1047,7 @@ static void HistogramRemap(const VP8LHistogramSet* const in,
if (out_size > 1) {
for (i = 0; i < in_size; ++i) {
int best_out = 0;
double best_bits = MAX_COST;
float best_bits = MAX_BIT_COST;
int k;
if (in_histo[i] == NULL) {
// Arbitrarily set to the previous value if unused to help future LZ77.
@ -1065,7 +1055,7 @@ static void HistogramRemap(const VP8LHistogramSet* const in,
continue;
}
for (k = 0; k < out_size; ++k) {
double cur_bits;
float cur_bits;
cur_bits = HistogramAddThresh(out_histo[k], in_histo[i], best_bits);
if (k == 0 || cur_bits < best_bits) {
best_bits = cur_bits;
@ -1093,13 +1083,13 @@ static void HistogramRemap(const VP8LHistogramSet* const in,
}
}
static double GetCombineCostFactor(int histo_size, int quality) {
double combine_cost_factor = 0.16;
static float GetCombineCostFactor(int histo_size, int quality) {
float combine_cost_factor = 0.16f;
if (quality < 90) {
if (histo_size > 256) combine_cost_factor /= 2.;
if (histo_size > 512) combine_cost_factor /= 2.;
if (histo_size > 1024) combine_cost_factor /= 2.;
if (quality <= 50) combine_cost_factor /= 2.;
if (histo_size > 256) combine_cost_factor /= 2.f;
if (histo_size > 512) combine_cost_factor /= 2.f;
if (histo_size > 1024) combine_cost_factor /= 2.f;
if (quality <= 50) combine_cost_factor /= 2.f;
}
return combine_cost_factor;
}
@ -1169,13 +1159,13 @@ static void RemoveEmptyHistograms(VP8LHistogramSet* const image_histo) {
}
int VP8LGetHistoImageSymbols(int xsize, int ysize,
const VP8LBackwardRefs* const refs,
int quality, int low_effort,
int histogram_bits, int cache_bits,
const VP8LBackwardRefs* const refs, int quality,
int low_effort, int histogram_bits, int cache_bits,
VP8LHistogramSet* const image_histo,
VP8LHistogram* const tmp_histo,
uint16_t* const histogram_symbols) {
int ok = 0;
uint16_t* const histogram_symbols,
const WebPPicture* const pic, int percent_range,
int* const percent) {
const int histo_xsize =
histogram_bits ? VP8LSubSampleSize(xsize, histogram_bits) : 1;
const int histo_ysize =
@ -1192,7 +1182,10 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
WebPSafeMalloc(2 * image_histo_raw_size, sizeof(map_tmp));
uint16_t* const cluster_mappings = map_tmp + image_histo_raw_size;
int num_used = image_histo_raw_size;
if (orig_histo == NULL || map_tmp == NULL) goto Error;
if (orig_histo == NULL || map_tmp == NULL) {
WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
// Construct the histograms from backward references.
HistogramBuild(xsize, histogram_bits, refs, orig_histo);
@ -1206,16 +1199,15 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
if (entropy_combine) {
uint16_t* const bin_map = map_tmp;
const double combine_cost_factor =
const float combine_cost_factor =
GetCombineCostFactor(image_histo_raw_size, quality);
const uint32_t num_clusters = num_used;
HistogramAnalyzeEntropyBin(image_histo, bin_map, low_effort);
// Collapse histograms with similar entropy.
HistogramCombineEntropyBin(image_histo, &num_used, histogram_symbols,
cluster_mappings, tmp_histo, bin_map,
entropy_combine_num_bins, combine_cost_factor,
low_effort);
HistogramCombineEntropyBin(
image_histo, &num_used, histogram_symbols, cluster_mappings, tmp_histo,
bin_map, entropy_combine_num_bins, combine_cost_factor, low_effort);
OptimizeHistogramSymbols(image_histo, cluster_mappings, num_clusters,
map_tmp, histogram_symbols);
}
@ -1229,11 +1221,13 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
int do_greedy;
if (!HistogramCombineStochastic(image_histo, &num_used, threshold_size,
&do_greedy)) {
WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
if (do_greedy) {
RemoveEmptyHistograms(image_histo);
if (!HistogramCombineGreedy(image_histo, &num_used)) {
WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
}
@ -1243,10 +1237,12 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
RemoveEmptyHistograms(image_histo);
HistogramRemap(orig_histo, image_histo, histogram_symbols);
ok = 1;
if (!WebPReportProgress(pic, *percent + percent_range, percent)) {
goto Error;
}
Error:
VP8LFreeHistogramSet(orig_histo);
WebPSafeFree(map_tmp);
return ok;
return (pic->error_code == VP8_ENC_OK);
}

View File

@ -40,10 +40,10 @@ typedef struct {
int palette_code_bits_;
uint32_t trivial_symbol_; // True, if histograms for Red, Blue & Alpha
// literal symbols are single valued.
double bit_cost_; // cached value of bit cost.
double literal_cost_; // Cached values of dominant entropy costs:
double red_cost_; // literal, red & blue.
double blue_cost_;
float bit_cost_; // cached value of bit cost.
float literal_cost_; // Cached values of dominant entropy costs:
float red_cost_; // literal, red & blue.
float blue_cost_;
uint8_t is_used_[5]; // 5 for literal, red, blue, alpha, distance
} VP8LHistogram;
@ -105,21 +105,23 @@ static WEBP_INLINE int VP8LHistogramNumCodes(int palette_code_bits) {
((palette_code_bits > 0) ? (1 << palette_code_bits) : 0);
}
// Builds the histogram image.
// Builds the histogram image. pic and percent are for progress.
// Returns false in case of error (stored in pic->error_code).
int VP8LGetHistoImageSymbols(int xsize, int ysize,
const VP8LBackwardRefs* const refs,
int quality, int low_effort,
int histogram_bits, int cache_bits,
const VP8LBackwardRefs* const refs, int quality,
int low_effort, int histogram_bits, int cache_bits,
VP8LHistogramSet* const image_histo,
VP8LHistogram* const tmp_histo,
uint16_t* const histogram_symbols);
uint16_t* const histogram_symbols,
const WebPPicture* const pic, int percent_range,
int* const percent);
// Returns the entropy for the symbols in the input array.
double VP8LBitsEntropy(const uint32_t* const array, int n);
float VP8LBitsEntropy(const uint32_t* const array, int n);
// Estimate how many bits the combined entropy of literals and distance
// approximately maps to.
double VP8LHistogramEstimateBits(VP8LHistogram* const p);
float VP8LHistogramEstimateBits(VP8LHistogram* const p);
#ifdef __cplusplus
}

View File

@ -15,12 +15,19 @@
#include <stdlib.h>
#include <math.h>
#include "sharpyuv/sharpyuv.h"
#include "sharpyuv/sharpyuv_csp.h"
#include "src/enc/vp8i_enc.h"
#include "src/utils/random_utils.h"
#include "src/utils/utils.h"
#include "src/dsp/dsp.h"
#include "src/dsp/lossless.h"
#include "src/dsp/yuv.h"
#include "src/dsp/cpu.h"
#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
#include <pthread.h>
#endif
// Uncomment to disable gamma-compression during RGB->U/V averaging
#define USE_GAMMA_COMPRESSION
@ -76,16 +83,16 @@ int WebPPictureHasTransparency(const WebPPicture* picture) {
#if defined(USE_GAMMA_COMPRESSION)
// gamma-compensates loss of resolution during chroma subsampling
#define kGamma 0.80 // for now we use a different gamma value than kGammaF
#define kGammaFix 12 // fixed-point precision for linear values
#define kGammaScale ((1 << kGammaFix) - 1)
#define kGammaTabFix 7 // fixed-point fractional bits precision
#define kGammaTabScale (1 << kGammaTabFix)
#define kGammaTabRounder (kGammaTabScale >> 1)
#define kGammaTabSize (1 << (kGammaFix - kGammaTabFix))
// Gamma correction compensates loss of resolution during chroma subsampling.
#define GAMMA_FIX 12 // fixed-point precision for linear values
#define GAMMA_TAB_FIX 7 // fixed-point fractional bits precision
#define GAMMA_TAB_SIZE (1 << (GAMMA_FIX - GAMMA_TAB_FIX))
static const double kGamma = 0.80;
static const int kGammaScale = ((1 << GAMMA_FIX) - 1);
static const int kGammaTabScale = (1 << GAMMA_TAB_FIX);
static const int kGammaTabRounder = (1 << GAMMA_TAB_FIX >> 1);
static int kLinearToGammaTab[kGammaTabSize + 1];
static int kLinearToGammaTab[GAMMA_TAB_SIZE + 1];
static uint16_t kGammaToLinearTab[256];
static volatile int kGammaTablesOk = 0;
static void InitGammaTables(void);
@ -93,13 +100,13 @@ static void InitGammaTables(void);
WEBP_DSP_INIT_FUNC(InitGammaTables) {
if (!kGammaTablesOk) {
int v;
const double scale = (double)(1 << kGammaTabFix) / kGammaScale;
const double scale = (double)(1 << GAMMA_TAB_FIX) / kGammaScale;
const double norm = 1. / 255.;
for (v = 0; v <= 255; ++v) {
kGammaToLinearTab[v] =
(uint16_t)(pow(norm * v, kGamma) * kGammaScale + .5);
}
for (v = 0; v <= kGammaTabSize; ++v) {
for (v = 0; v <= GAMMA_TAB_SIZE; ++v) {
kLinearToGammaTab[v] = (int)(255. * pow(scale * v, 1. / kGamma) + .5);
}
kGammaTablesOk = 1;
@ -111,12 +118,12 @@ static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) {
}
static WEBP_INLINE int Interpolate(int v) {
const int tab_pos = v >> (kGammaTabFix + 2); // integer part
const int tab_pos = v >> (GAMMA_TAB_FIX + 2); // integer part
const int x = v & ((kGammaTabScale << 2) - 1); // fractional part
const int v0 = kLinearToGammaTab[tab_pos];
const int v1 = kLinearToGammaTab[tab_pos + 1];
const int y = v1 * x + v0 * ((kGammaTabScale << 2) - x); // interpolate
assert(tab_pos + 1 < kGammaTabSize + 1);
assert(tab_pos + 1 < GAMMA_TAB_SIZE + 1);
return y;
}
@ -124,7 +131,7 @@ static WEBP_INLINE int Interpolate(int v) {
// U/V value, suitable for RGBToU/V calls.
static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
const int y = Interpolate(base_value << shift); // final uplifted value
return (y + kGammaTabRounder) >> kGammaTabFix; // descale
return (y + kGammaTabRounder) >> GAMMA_TAB_FIX; // descale
}
#else
@ -158,415 +165,41 @@ static int RGBToV(int r, int g, int b, VP8Random* const rg) {
//------------------------------------------------------------------------------
// Sharp RGB->YUV conversion
static const int kNumIterations = 4;
static const int kMinDimensionIterativeConversion = 4;
// We could use SFIX=0 and only uint8_t for fixed_y_t, but it produces some
// banding sometimes. Better use extra precision.
#define SFIX 2 // fixed-point precision of RGB and Y/W
typedef int16_t fixed_t; // signed type with extra SFIX precision for UV
typedef uint16_t fixed_y_t; // unsigned type with extra SFIX precision for W
#define SHALF (1 << SFIX >> 1)
#define MAX_Y_T ((256 << SFIX) - 1)
#define SROUNDER (1 << (YUV_FIX + SFIX - 1))
#if defined(USE_GAMMA_COMPRESSION)
// We use tables of different size and precision for the Rec709 / BT2020
// transfer function.
#define kGammaF (1./0.45)
static uint32_t kLinearToGammaTabS[kGammaTabSize + 2];
#define GAMMA_TO_LINEAR_BITS 14
static uint32_t kGammaToLinearTabS[MAX_Y_T + 1]; // size scales with Y_FIX
static volatile int kGammaTablesSOk = 0;
static void InitGammaTablesS(void);
WEBP_DSP_INIT_FUNC(InitGammaTablesS) {
assert(2 * GAMMA_TO_LINEAR_BITS < 32); // we use uint32_t intermediate values
if (!kGammaTablesSOk) {
int v;
const double norm = 1. / MAX_Y_T;
const double scale = 1. / kGammaTabSize;
const double a = 0.09929682680944;
const double thresh = 0.018053968510807;
const double final_scale = 1 << GAMMA_TO_LINEAR_BITS;
for (v = 0; v <= MAX_Y_T; ++v) {
const double g = norm * v;
double value;
if (g <= thresh * 4.5) {
value = g / 4.5;
} else {
const double a_rec = 1. / (1. + a);
value = pow(a_rec * (g + a), kGammaF);
}
kGammaToLinearTabS[v] = (uint32_t)(value * final_scale + .5);
}
for (v = 0; v <= kGammaTabSize; ++v) {
const double g = scale * v;
double value;
if (g <= thresh) {
value = 4.5 * g;
} else {
value = (1. + a) * pow(g, 1. / kGammaF) - a;
}
// we already incorporate the 1/2 rounding constant here
kLinearToGammaTabS[v] =
(uint32_t)(MAX_Y_T * value) + (1 << GAMMA_TO_LINEAR_BITS >> 1);
}
// to prevent small rounding errors to cause read-overflow:
kLinearToGammaTabS[kGammaTabSize + 1] = kLinearToGammaTabS[kGammaTabSize];
kGammaTablesSOk = 1;
}
}
// return value has a fixed-point precision of GAMMA_TO_LINEAR_BITS
static WEBP_INLINE uint32_t GammaToLinearS(int v) {
return kGammaToLinearTabS[v];
}
static WEBP_INLINE uint32_t LinearToGammaS(uint32_t value) {
// 'value' is in GAMMA_TO_LINEAR_BITS fractional precision
const uint32_t v = value * kGammaTabSize;
const uint32_t tab_pos = v >> GAMMA_TO_LINEAR_BITS;
// fractional part, in GAMMA_TO_LINEAR_BITS fixed-point precision
const uint32_t x = v - (tab_pos << GAMMA_TO_LINEAR_BITS); // fractional part
// v0 / v1 are in GAMMA_TO_LINEAR_BITS fixed-point precision (range [0..1])
const uint32_t v0 = kLinearToGammaTabS[tab_pos + 0];
const uint32_t v1 = kLinearToGammaTabS[tab_pos + 1];
// Final interpolation. Note that rounding is already included.
const uint32_t v2 = (v1 - v0) * x; // note: v1 >= v0.
const uint32_t result = v0 + (v2 >> GAMMA_TO_LINEAR_BITS);
return result;
}
#else
static void InitGammaTablesS(void) {}
static WEBP_INLINE uint32_t GammaToLinearS(int v) {
return (v << GAMMA_TO_LINEAR_BITS) / MAX_Y_T;
}
static WEBP_INLINE uint32_t LinearToGammaS(uint32_t value) {
return (MAX_Y_T * value) >> GAMMA_TO_LINEAR_BITS;
}
#endif // USE_GAMMA_COMPRESSION
//------------------------------------------------------------------------------
static uint8_t clip_8b(fixed_t v) {
return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u;
}
static fixed_y_t clip_y(int y) {
return (!(y & ~MAX_Y_T)) ? (fixed_y_t)y : (y < 0) ? 0 : MAX_Y_T;
}
//------------------------------------------------------------------------------
static int RGBToGray(int r, int g, int b) {
const int luma = 13933 * r + 46871 * g + 4732 * b + YUV_HALF;
return (luma >> YUV_FIX);
}
static uint32_t ScaleDown(int a, int b, int c, int d) {
const uint32_t A = GammaToLinearS(a);
const uint32_t B = GammaToLinearS(b);
const uint32_t C = GammaToLinearS(c);
const uint32_t D = GammaToLinearS(d);
return LinearToGammaS((A + B + C + D + 2) >> 2);
}
static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w) {
int i;
for (i = 0; i < w; ++i) {
const uint32_t R = GammaToLinearS(src[0 * w + i]);
const uint32_t G = GammaToLinearS(src[1 * w + i]);
const uint32_t B = GammaToLinearS(src[2 * w + i]);
const uint32_t Y = RGBToGray(R, G, B);
dst[i] = (fixed_y_t)LinearToGammaS(Y);
}
}
static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
fixed_t* dst, int uv_w) {
int i;
for (i = 0; i < uv_w; ++i) {
const int r = ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1],
src2[0 * uv_w + 0], src2[0 * uv_w + 1]);
const int g = ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1],
src2[2 * uv_w + 0], src2[2 * uv_w + 1]);
const int b = ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1],
src2[4 * uv_w + 0], src2[4 * uv_w + 1]);
const int W = RGBToGray(r, g, b);
dst[0 * uv_w] = (fixed_t)(r - W);
dst[1 * uv_w] = (fixed_t)(g - W);
dst[2 * uv_w] = (fixed_t)(b - W);
dst += 1;
src1 += 2;
src2 += 2;
}
}
static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) {
int i;
for (i = 0; i < w; ++i) {
y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]);
}
}
//------------------------------------------------------------------------------
static WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0) {
const int v0 = (A * 3 + B + 2) >> 2;
return clip_y(v0 + W0);
}
//------------------------------------------------------------------------------
static WEBP_INLINE fixed_y_t UpLift(uint8_t a) { // 8bit -> SFIX
return ((fixed_y_t)a << SFIX) | SHALF;
}
static void ImportOneRow(const uint8_t* const r_ptr,
const uint8_t* const g_ptr,
const uint8_t* const b_ptr,
int step,
int pic_width,
fixed_y_t* const dst) {
int i;
const int w = (pic_width + 1) & ~1;
for (i = 0; i < pic_width; ++i) {
const int off = i * step;
dst[i + 0 * w] = UpLift(r_ptr[off]);
dst[i + 1 * w] = UpLift(g_ptr[off]);
dst[i + 2 * w] = UpLift(b_ptr[off]);
}
if (pic_width & 1) { // replicate rightmost pixel
dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1];
dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1];
dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1];
}
}
static void InterpolateTwoRows(const fixed_y_t* const best_y,
const fixed_t* prev_uv,
const fixed_t* cur_uv,
const fixed_t* next_uv,
int w,
fixed_y_t* out1,
fixed_y_t* out2) {
const int uv_w = w >> 1;
const int len = (w - 1) >> 1; // length to filter
int k = 3;
while (k-- > 0) { // process each R/G/B segments in turn
// special boundary case for i==0
out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0]);
out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w]);
WebPSharpYUVFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1);
WebPSharpYUVFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1);
// special boundary case for i == w - 1 when w is even
if (!(w & 1)) {
out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1],
best_y[w - 1 + 0]);
out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1],
best_y[w - 1 + w]);
}
out1 += w;
out2 += w;
prev_uv += uv_w;
cur_uv += uv_w;
next_uv += uv_w;
}
}
static WEBP_INLINE uint8_t ConvertRGBToY(int r, int g, int b) {
const int luma = 16839 * r + 33059 * g + 6420 * b + SROUNDER;
return clip_8b(16 + (luma >> (YUV_FIX + SFIX)));
}
static WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) {
const int u = -9719 * r - 19081 * g + 28800 * b + SROUNDER;
return clip_8b(128 + (u >> (YUV_FIX + SFIX)));
}
static WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) {
const int v = +28800 * r - 24116 * g - 4684 * b + SROUNDER;
return clip_8b(128 + (v >> (YUV_FIX + SFIX)));
}
static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
WebPPicture* const picture) {
int i, j;
uint8_t* dst_y = picture->y;
uint8_t* dst_u = picture->u;
uint8_t* dst_v = picture->v;
const fixed_t* const best_uv_base = best_uv;
const int w = (picture->width + 1) & ~1;
const int h = (picture->height + 1) & ~1;
const int uv_w = w >> 1;
const int uv_h = h >> 1;
for (best_uv = best_uv_base, j = 0; j < picture->height; ++j) {
for (i = 0; i < picture->width; ++i) {
const int off = (i >> 1);
const int W = best_y[i];
const int r = best_uv[off + 0 * uv_w] + W;
const int g = best_uv[off + 1 * uv_w] + W;
const int b = best_uv[off + 2 * uv_w] + W;
dst_y[i] = ConvertRGBToY(r, g, b);
}
best_y += w;
best_uv += (j & 1) * 3 * uv_w;
dst_y += picture->y_stride;
}
for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) {
for (i = 0; i < uv_w; ++i) {
const int off = i;
const int r = best_uv[off + 0 * uv_w];
const int g = best_uv[off + 1 * uv_w];
const int b = best_uv[off + 2 * uv_w];
dst_u[i] = ConvertRGBToU(r, g, b);
dst_v[i] = ConvertRGBToV(r, g, b);
}
best_uv += 3 * uv_w;
dst_u += picture->uv_stride;
dst_v += picture->uv_stride;
}
return 1;
}
//------------------------------------------------------------------------------
// Main function
#define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T)))
extern void SharpYuvInit(VP8CPUInfo cpu_info_func);
static void SafeInitSharpYuv(void) {
#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
static pthread_mutex_t initsharpyuv_lock = PTHREAD_MUTEX_INITIALIZER;
if (pthread_mutex_lock(&initsharpyuv_lock)) return;
#endif
SharpYuvInit(VP8GetCPUInfo);
#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
(void)pthread_mutex_unlock(&initsharpyuv_lock);
#endif
}
static int PreprocessARGB(const uint8_t* r_ptr,
const uint8_t* g_ptr,
const uint8_t* b_ptr,
int step, int rgb_stride,
WebPPicture* const picture) {
// we expand the right/bottom border if needed
const int w = (picture->width + 1) & ~1;
const int h = (picture->height + 1) & ~1;
const int uv_w = w >> 1;
const int uv_h = h >> 1;
uint64_t prev_diff_y_sum = ~0;
int j, iter;
// TODO(skal): allocate one big memory chunk. But for now, it's easier
// for valgrind debugging to have several chunks.
fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch
fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t);
fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t);
fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t);
fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t);
fixed_y_t* best_y = best_y_base;
fixed_y_t* target_y = target_y_base;
fixed_t* best_uv = best_uv_base;
fixed_t* target_uv = target_uv_base;
const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h);
int ok;
if (best_y_base == NULL || best_uv_base == NULL ||
target_y_base == NULL || target_uv_base == NULL ||
best_rgb_y == NULL || best_rgb_uv == NULL ||
tmp_buffer == NULL) {
ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto End;
const int ok = SharpYuvConvert(
r_ptr, g_ptr, b_ptr, step, rgb_stride, /*rgb_bit_depth=*/8,
picture->y, picture->y_stride, picture->u, picture->uv_stride, picture->v,
picture->uv_stride, /*yuv_bit_depth=*/8, picture->width,
picture->height, SharpYuvGetConversionMatrix(kSharpYuvMatrixWebp));
if (!ok) {
return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
assert(picture->width >= kMinDimensionIterativeConversion);
assert(picture->height >= kMinDimensionIterativeConversion);
WebPInitConvertARGBToYUV();
// Import RGB samples to W/RGB representation.
for (j = 0; j < picture->height; j += 2) {
const int is_last_row = (j == picture->height - 1);
fixed_y_t* const src1 = tmp_buffer + 0 * w;
fixed_y_t* const src2 = tmp_buffer + 3 * w;
// prepare two rows of input
ImportOneRow(r_ptr, g_ptr, b_ptr, step, picture->width, src1);
if (!is_last_row) {
ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride,
step, picture->width, src2);
} else {
memcpy(src2, src1, 3 * w * sizeof(*src2));
}
StoreGray(src1, best_y + 0, w);
StoreGray(src2, best_y + w, w);
UpdateW(src1, target_y, w);
UpdateW(src2, target_y + w, w);
UpdateChroma(src1, src2, target_uv, uv_w);
memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv));
best_y += 2 * w;
best_uv += 3 * uv_w;
target_y += 2 * w;
target_uv += 3 * uv_w;
r_ptr += 2 * rgb_stride;
g_ptr += 2 * rgb_stride;
b_ptr += 2 * rgb_stride;
}
// Iterate and resolve clipping conflicts.
for (iter = 0; iter < kNumIterations; ++iter) {
const fixed_t* cur_uv = best_uv_base;
const fixed_t* prev_uv = best_uv_base;
uint64_t diff_y_sum = 0;
best_y = best_y_base;
best_uv = best_uv_base;
target_y = target_y_base;
target_uv = target_uv_base;
for (j = 0; j < h; j += 2) {
fixed_y_t* const src1 = tmp_buffer + 0 * w;
fixed_y_t* const src2 = tmp_buffer + 3 * w;
{
const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0);
InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w, src1, src2);
prev_uv = cur_uv;
cur_uv = next_uv;
}
UpdateW(src1, best_rgb_y + 0 * w, w);
UpdateW(src2, best_rgb_y + 1 * w, w);
UpdateChroma(src1, src2, best_rgb_uv, uv_w);
// update two rows of Y and one row of RGB
diff_y_sum += WebPSharpYUVUpdateY(target_y, best_rgb_y, best_y, 2 * w);
WebPSharpYUVUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w);
best_y += 2 * w;
best_uv += 3 * uv_w;
target_y += 2 * w;
target_uv += 3 * uv_w;
}
// test exit condition
if (iter > 0) {
if (diff_y_sum < diff_y_threshold) break;
if (diff_y_sum > prev_diff_y_sum) break;
}
prev_diff_y_sum = diff_y_sum;
}
// final reconstruction
ok = ConvertWRGBToYUV(best_y_base, best_uv_base, picture);
End:
WebPSafeFree(best_y_base);
WebPSafeFree(best_uv_base);
WebPSafeFree(target_y_base);
WebPSafeFree(target_uv_base);
WebPSafeFree(best_rgb_y);
WebPSafeFree(best_rgb_uv);
WebPSafeFree(tmp_buffer);
return ok;
}
#undef SAFE_ALLOC
//------------------------------------------------------------------------------
// "Fast" regular RGB->YUV
@ -591,8 +224,8 @@ static const int kAlphaFix = 19;
// and constant are adjusted very tightly to fit 32b arithmetic.
// In particular, they use the fact that the operands for 'v / a' are actually
// derived as v = (a0.p0 + a1.p1 + a2.p2 + a3.p3) and a = a0 + a1 + a2 + a3
// with ai in [0..255] and pi in [0..1<<kGammaFix). The constraint to avoid
// overflow is: kGammaFix + kAlphaFix <= 31.
// with ai in [0..255] and pi in [0..1<<GAMMA_FIX). The constraint to avoid
// overflow is: GAMMA_FIX + kAlphaFix <= 31.
static const uint32_t kInvAlpha[4 * 0xff + 1] = {
0, /* alpha = 0 */
524288, 262144, 174762, 131072, 104857, 87381, 74898, 65536,
@ -818,11 +451,20 @@ static WEBP_INLINE void AccumulateRGB(const uint8_t* const r_ptr,
dst[0] = SUM4(r_ptr + j, step);
dst[1] = SUM4(g_ptr + j, step);
dst[2] = SUM4(b_ptr + j, step);
// MemorySanitizer may raise false positives with data that passes through
// RGBA32PackedToPlanar_16b_SSE41() due to incorrect modeling of shuffles.
// See https://crbug.com/webp/573.
#ifdef WEBP_MSAN
dst[3] = 0;
#endif
}
if (width & 1) {
dst[0] = SUM2(r_ptr + j);
dst[1] = SUM2(g_ptr + j);
dst[2] = SUM2(b_ptr + j);
#ifdef WEBP_MSAN
dst[3] = 0;
#endif
}
}
@ -863,18 +505,18 @@ static int ImportYUVAFromRGBA(const uint8_t* r_ptr,
use_iterative_conversion = 0;
}
if (!WebPPictureAllocYUVA(picture, width, height)) {
if (!WebPPictureAllocYUVA(picture)) {
return 0;
}
if (has_alpha) {
assert(step == 4);
#if defined(USE_GAMMA_COMPRESSION) && defined(USE_INVERSE_ALPHA_TABLE)
assert(kAlphaFix + kGammaFix <= 31);
assert(kAlphaFix + GAMMA_FIX <= 31);
#endif
}
if (use_iterative_conversion) {
InitGammaTablesS();
SafeInitSharpYuv();
if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) {
return 0;
}
@ -1044,7 +686,7 @@ int WebPPictureYUVAToARGB(WebPPicture* picture) {
return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
}
// Allocate a new argb buffer (discarding the previous one).
if (!WebPPictureAllocARGB(picture, picture->width, picture->height)) return 0;
if (!WebPPictureAllocARGB(picture)) return 0;
picture->use_argb = 1;
// Convert
@ -1106,6 +748,8 @@ static int Import(WebPPicture* const picture,
const int width = picture->width;
const int height = picture->height;
if (abs(rgb_stride) < (import_alpha ? 4 : 3) * width) return 0;
if (!picture->use_argb) {
const uint8_t* a_ptr = import_alpha ? rgb + 3 : NULL;
return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride,
@ -1163,24 +807,24 @@ static int Import(WebPPicture* const picture,
#if !defined(WEBP_REDUCE_CSP)
int WebPPictureImportBGR(WebPPicture* picture,
const uint8_t* rgb, int rgb_stride) {
return (picture != NULL && rgb != NULL)
? Import(picture, rgb, rgb_stride, 3, 1, 0)
const uint8_t* bgr, int bgr_stride) {
return (picture != NULL && bgr != NULL)
? Import(picture, bgr, bgr_stride, 3, 1, 0)
: 0;
}
int WebPPictureImportBGRA(WebPPicture* picture,
const uint8_t* rgba, int rgba_stride) {
return (picture != NULL && rgba != NULL)
? Import(picture, rgba, rgba_stride, 4, 1, 1)
const uint8_t* bgra, int bgra_stride) {
return (picture != NULL && bgra != NULL)
? Import(picture, bgra, bgra_stride, 4, 1, 1)
: 0;
}
int WebPPictureImportBGRX(WebPPicture* picture,
const uint8_t* rgba, int rgba_stride) {
return (picture != NULL && rgba != NULL)
? Import(picture, rgba, rgba_stride, 4, 1, 0)
const uint8_t* bgrx, int bgrx_stride) {
return (picture != NULL && bgrx != NULL)
? Import(picture, bgrx, bgrx_stride, 4, 1, 0)
: 0;
}
@ -1201,9 +845,9 @@ int WebPPictureImportRGBA(WebPPicture* picture,
}
int WebPPictureImportRGBX(WebPPicture* picture,
const uint8_t* rgba, int rgba_stride) {
return (picture != NULL && rgba != NULL)
? Import(picture, rgba, rgba_stride, 4, 0, 0)
const uint8_t* rgbx, int rgbx_stride) {
return (picture != NULL && rgbx != NULL)
? Import(picture, rgbx, rgbx_stride, 4, 0, 0)
: 0;
}

View File

@ -45,6 +45,22 @@ int WebPPictureInitInternal(WebPPicture* picture, int version) {
//------------------------------------------------------------------------------
int WebPValidatePicture(const WebPPicture* const picture) {
if (picture == NULL) return 0;
if (picture->width <= 0 || picture->height <= 0) {
return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
}
if (picture->width <= 0 || picture->width / 4 > INT_MAX / 4 ||
picture->height <= 0 || picture->height / 4 > INT_MAX / 4) {
return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
}
if (picture->colorspace != WEBP_YUV420 &&
picture->colorspace != WEBP_YUV420A) {
return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
}
return 1;
}
static void WebPPictureResetBufferARGB(WebPPicture* const picture) {
picture->memory_argb_ = NULL;
picture->argb = NULL;
@ -63,18 +79,17 @@ void WebPPictureResetBuffers(WebPPicture* const picture) {
WebPPictureResetBufferYUVA(picture);
}
int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height) {
int WebPPictureAllocARGB(WebPPicture* const picture) {
void* memory;
const int width = picture->width;
const int height = picture->height;
const uint64_t argb_size = (uint64_t)width * height;
assert(picture != NULL);
if (!WebPValidatePicture(picture)) return 0;
WebPSafeFree(picture->memory_argb_);
WebPPictureResetBufferARGB(picture);
if (width <= 0 || height <= 0) {
return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
}
// allocate a new buffer.
memory = WebPSafeMalloc(argb_size + WEBP_ALIGN_CST, sizeof(*picture->argb));
if (memory == NULL) {
@ -86,10 +101,10 @@ int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height) {
return 1;
}
int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height) {
const WebPEncCSP uv_csp =
(WebPEncCSP)((int)picture->colorspace & WEBP_CSP_UV_MASK);
int WebPPictureAllocYUVA(WebPPicture* const picture) {
const int has_alpha = (int)picture->colorspace & WEBP_CSP_ALPHA_BIT;
const int width = picture->width;
const int height = picture->height;
const int y_stride = width;
const int uv_width = (int)(((int64_t)width + 1) >> 1);
const int uv_height = (int)(((int64_t)height + 1) >> 1);
@ -98,15 +113,11 @@ int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height) {
uint64_t y_size, uv_size, a_size, total_size;
uint8_t* mem;
assert(picture != NULL);
if (!WebPValidatePicture(picture)) return 0;
WebPSafeFree(picture->memory_);
WebPPictureResetBufferYUVA(picture);
if (uv_csp != WEBP_YUV420) {
return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
}
// alpha
a_width = has_alpha ? width : 0;
a_stride = a_width;
@ -152,15 +163,12 @@ int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height) {
int WebPPictureAlloc(WebPPicture* picture) {
if (picture != NULL) {
const int width = picture->width;
const int height = picture->height;
WebPPictureFree(picture); // erase previous buffer
if (!picture->use_argb) {
return WebPPictureAllocYUVA(picture, width, height);
return WebPPictureAllocYUVA(picture);
} else {
return WebPPictureAllocARGB(picture, width, height);
return WebPPictureAllocARGB(picture);
}
}
return 1;

View File

@ -13,14 +13,15 @@
#include "src/webp/encode.h"
#if !defined(WEBP_REDUCE_SIZE)
#include <assert.h>
#include <stdlib.h>
#include "src/enc/vp8i_enc.h"
#if !defined(WEBP_REDUCE_SIZE)
#include "src/utils/rescaler_utils.h"
#include "src/utils/utils.h"
#endif // !defined(WEBP_REDUCE_SIZE)
#define HALVE(x) (((x) + 1) >> 1)
@ -56,6 +57,7 @@ static int AdjustAndCheckRectangle(const WebPPicture* const pic,
return 1;
}
#if !defined(WEBP_REDUCE_SIZE)
int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
if (src == NULL || dst == NULL) return 0;
if (src == dst) return 1;
@ -81,6 +83,7 @@ int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
}
return 1;
}
#endif // !defined(WEBP_REDUCE_SIZE)
int WebPPictureIsView(const WebPPicture* picture) {
if (picture == NULL) return 0;
@ -120,6 +123,7 @@ int WebPPictureView(const WebPPicture* src,
return 1;
}
#if !defined(WEBP_REDUCE_SIZE)
//------------------------------------------------------------------------------
// Picture cropping
@ -198,34 +202,34 @@ static void AlphaMultiplyY(WebPPicture* const pic, int inverse) {
}
}
int WebPPictureRescale(WebPPicture* pic, int width, int height) {
int WebPPictureRescale(WebPPicture* picture, int width, int height) {
WebPPicture tmp;
int prev_width, prev_height;
rescaler_t* work;
if (pic == NULL) return 0;
prev_width = pic->width;
prev_height = pic->height;
if (picture == NULL) return 0;
prev_width = picture->width;
prev_height = picture->height;
if (!WebPRescalerGetScaledDimensions(
prev_width, prev_height, &width, &height)) {
return 0;
}
PictureGrabSpecs(pic, &tmp);
PictureGrabSpecs(picture, &tmp);
tmp.width = width;
tmp.height = height;
if (!WebPPictureAlloc(&tmp)) return 0;
if (!pic->use_argb) {
if (!picture->use_argb) {
work = (rescaler_t*)WebPSafeMalloc(2ULL * width, sizeof(*work));
if (work == NULL) {
WebPPictureFree(&tmp);
return 0;
}
// If present, we need to rescale alpha first (for AlphaMultiplyY).
if (pic->a != NULL) {
if (picture->a != NULL) {
WebPInitAlphaProcessing();
if (!RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
if (!RescalePlane(picture->a, prev_width, prev_height, picture->a_stride,
tmp.a, width, height, tmp.a_stride, work, 1)) {
return 0;
}
@ -233,17 +237,15 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
// We take transparency into account on the luma plane only. That's not
// totally exact blending, but still is a good approximation.
AlphaMultiplyY(pic, 0);
if (!RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
AlphaMultiplyY(picture, 0);
if (!RescalePlane(picture->y, prev_width, prev_height, picture->y_stride,
tmp.y, width, height, tmp.y_stride, work, 1) ||
!RescalePlane(pic->u,
HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
tmp.u,
HALVE(width), HALVE(height), tmp.uv_stride, work, 1) ||
!RescalePlane(pic->v,
HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
tmp.v,
HALVE(width), HALVE(height), tmp.uv_stride, work, 1)) {
!RescalePlane(picture->u, HALVE(prev_width), HALVE(prev_height),
picture->uv_stride, tmp.u, HALVE(width), HALVE(height),
tmp.uv_stride, work, 1) ||
!RescalePlane(picture->v, HALVE(prev_width), HALVE(prev_height),
picture->uv_stride, tmp.v, HALVE(width), HALVE(height),
tmp.uv_stride, work, 1)) {
return 0;
}
AlphaMultiplyY(&tmp, 1);
@ -257,18 +259,17 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
// weighting first (black-matting), scale the RGB values, and remove
// the premultiplication afterward (while preserving the alpha channel).
WebPInitAlphaProcessing();
AlphaMultiplyARGB(pic, 0);
if (!RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
pic->argb_stride * 4,
(uint8_t*)tmp.argb, width, height,
tmp.argb_stride * 4, work, 4)) {
AlphaMultiplyARGB(picture, 0);
if (!RescalePlane((const uint8_t*)picture->argb, prev_width, prev_height,
picture->argb_stride * 4, (uint8_t*)tmp.argb, width,
height, tmp.argb_stride * 4, work, 4)) {
return 0;
}
AlphaMultiplyARGB(&tmp, 1);
}
WebPPictureFree(pic);
WebPPictureFree(picture);
WebPSafeFree(work);
*pic = tmp;
*picture = tmp;
return 1;
}
@ -280,23 +281,6 @@ int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
return 0;
}
int WebPPictureIsView(const WebPPicture* picture) {
(void)picture;
return 0;
}
int WebPPictureView(const WebPPicture* src,
int left, int top, int width, int height,
WebPPicture* dst) {
(void)src;
(void)left;
(void)top;
(void)width;
(void)height;
(void)dst;
return 0;
}
int WebPPictureCrop(WebPPicture* pic,
int left, int top, int width, int height) {
(void)pic;

View File

@ -190,27 +190,28 @@ static WEBP_INLINE uint32_t MakeARGB32(int r, int g, int b) {
return (0xff000000u | (r << 16) | (g << 8) | b);
}
void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
void WebPBlendAlpha(WebPPicture* picture, uint32_t background_rgb) {
const int red = (background_rgb >> 16) & 0xff;
const int green = (background_rgb >> 8) & 0xff;
const int blue = (background_rgb >> 0) & 0xff;
int x, y;
if (pic == NULL) return;
if (!pic->use_argb) {
const int uv_width = (pic->width >> 1); // omit last pixel during u/v loop
if (picture == NULL) return;
if (!picture->use_argb) {
// omit last pixel during u/v loop
const int uv_width = (picture->width >> 1);
const int Y0 = VP8RGBToY(red, green, blue, YUV_HALF);
// VP8RGBToU/V expects the u/v values summed over four pixels
const int U0 = VP8RGBToU(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF);
const int V0 = VP8RGBToV(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF);
const int has_alpha = pic->colorspace & WEBP_CSP_ALPHA_BIT;
uint8_t* y_ptr = pic->y;
uint8_t* u_ptr = pic->u;
uint8_t* v_ptr = pic->v;
uint8_t* a_ptr = pic->a;
const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT;
uint8_t* y_ptr = picture->y;
uint8_t* u_ptr = picture->u;
uint8_t* v_ptr = picture->v;
uint8_t* a_ptr = picture->a;
if (!has_alpha || a_ptr == NULL) return; // nothing to do
for (y = 0; y < pic->height; ++y) {
for (y = 0; y < picture->height; ++y) {
// Luma blending
for (x = 0; x < pic->width; ++x) {
for (x = 0; x < picture->width; ++x) {
const uint8_t alpha = a_ptr[x];
if (alpha < 0xff) {
y_ptr[x] = BLEND(Y0, y_ptr[x], alpha);
@ -219,7 +220,7 @@ void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
// Chroma blending every even line
if ((y & 1) == 0) {
uint8_t* const a_ptr2 =
(y + 1 == pic->height) ? a_ptr : a_ptr + pic->a_stride;
(y + 1 == picture->height) ? a_ptr : a_ptr + picture->a_stride;
for (x = 0; x < uv_width; ++x) {
// Average four alpha values into a single blending weight.
// TODO(skal): might lead to visible contouring. Can we do better?
@ -229,24 +230,24 @@ void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha);
v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha);
}
if (pic->width & 1) { // rightmost pixel
if (picture->width & 1) { // rightmost pixel
const uint32_t alpha = 2 * (a_ptr[2 * x + 0] + a_ptr2[2 * x + 0]);
u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha);
v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha);
}
} else {
u_ptr += pic->uv_stride;
v_ptr += pic->uv_stride;
u_ptr += picture->uv_stride;
v_ptr += picture->uv_stride;
}
memset(a_ptr, 0xff, pic->width); // reset alpha value to opaque
a_ptr += pic->a_stride;
y_ptr += pic->y_stride;
memset(a_ptr, 0xff, picture->width); // reset alpha value to opaque
a_ptr += picture->a_stride;
y_ptr += picture->y_stride;
}
} else {
uint32_t* argb = pic->argb;
uint32_t* argb = picture->argb;
const uint32_t background = MakeARGB32(red, green, blue);
for (y = 0; y < pic->height; ++y) {
for (x = 0; x < pic->width; ++x) {
for (y = 0; y < picture->height; ++y) {
for (x = 0; x < picture->width; ++x) {
const int alpha = (argb[x] >> 24) & 0xff;
if (alpha != 0xff) {
if (alpha > 0) {
@ -262,7 +263,7 @@ void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
}
}
}
argb += pic->argb_stride;
argb += picture->argb_stride;
}
}
}

View File

@ -16,6 +16,7 @@
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
#include "src/enc/vp8i_enc.h"
#include "src/enc/vp8li_enc.h"
#define MAX_DIFF_COST (1e30f)
@ -31,10 +32,10 @@ static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; }
// Methods to calculate Entropy (Shannon).
static float PredictionCostSpatial(const int counts[256], int weight_0,
double exp_val) {
float exp_val) {
const int significant_symbols = 256 >> 4;
const double exp_decay_factor = 0.6;
double bits = weight_0 * counts[0];
const float exp_decay_factor = 0.6f;
float bits = (float)weight_0 * counts[0];
int i;
for (i = 1; i < significant_symbols; ++i) {
bits += exp_val * (counts[i] + counts[256 - i]);
@ -46,9 +47,9 @@ static float PredictionCostSpatial(const int counts[256], int weight_0,
static float PredictionCostSpatialHistogram(const int accumulated[4][256],
const int tile[4][256]) {
int i;
double retval = 0;
float retval = 0.f;
for (i = 0; i < 4; ++i) {
const double kExpValue = 0.94;
const float kExpValue = 0.94f;
retval += PredictionCostSpatial(tile[i], 1, kExpValue);
retval += VP8LCombinedShannonEntropy(tile[i], accumulated[i]);
}
@ -472,12 +473,15 @@ static void CopyImageWithPrediction(int width, int height,
// with respect to predictions. If near_lossless_quality < 100, applies
// near lossless processing, shaving off more bits of residuals for lower
// qualities.
void VP8LResidualImage(int width, int height, int bits, int low_effort,
uint32_t* const argb, uint32_t* const argb_scratch,
uint32_t* const image, int near_lossless_quality,
int exact, int used_subtract_green) {
int VP8LResidualImage(int width, int height, int bits, int low_effort,
uint32_t* const argb, uint32_t* const argb_scratch,
uint32_t* const image, int near_lossless_quality,
int exact, int used_subtract_green,
const WebPPicture* const pic, int percent_range,
int* const percent) {
const int tiles_per_row = VP8LSubSampleSize(width, bits);
const int tiles_per_col = VP8LSubSampleSize(height, bits);
int percent_start = *percent;
int tile_y;
int histo[4][256];
const int max_quantization = 1 << VP8LNearLosslessBits(near_lossless_quality);
@ -491,17 +495,24 @@ void VP8LResidualImage(int width, int height, int bits, int low_effort,
for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) {
int tile_x;
for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
const int pred = GetBestPredictorForTile(width, height, tile_x, tile_y,
bits, histo, argb_scratch, argb, max_quantization, exact,
used_subtract_green, image);
const int pred = GetBestPredictorForTile(
width, height, tile_x, tile_y, bits, histo, argb_scratch, argb,
max_quantization, exact, used_subtract_green, image);
image[tile_y * tiles_per_row + tile_x] = ARGB_BLACK | (pred << 8);
}
if (!WebPReportProgress(
pic, percent_start + percent_range * tile_y / tiles_per_col,
percent)) {
return 0;
}
}
}
CopyImageWithPrediction(width, height, bits, image, argb_scratch, argb,
low_effort, max_quantization, exact,
used_subtract_green);
return WebPReportProgress(pic, percent_start + percent_range, percent);
}
//------------------------------------------------------------------------------
@ -532,7 +543,7 @@ static float PredictionCostCrossColor(const int accumulated[256],
const int counts[256]) {
// Favor low entropy, locally and globally.
// Favor small absolute values for PredictionCostSpatial
static const double kExpValue = 2.4;
static const float kExpValue = 2.4f;
return VP8LCombinedShannonEntropy(counts, accumulated) +
PredictionCostSpatial(counts, 3, kExpValue);
}
@ -714,11 +725,14 @@ static void CopyTileWithColorTransform(int xsize, int ysize,
}
}
void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
uint32_t* const argb, uint32_t* image) {
int VP8LColorSpaceTransform(int width, int height, int bits, int quality,
uint32_t* const argb, uint32_t* image,
const WebPPicture* const pic, int percent_range,
int* const percent) {
const int max_tile_size = 1 << bits;
const int tile_xsize = VP8LSubSampleSize(width, bits);
const int tile_ysize = VP8LSubSampleSize(height, bits);
int percent_start = *percent;
int accumulated_red_histo[256] = { 0 };
int accumulated_blue_histo[256] = { 0 };
int tile_x, tile_y;
@ -768,5 +782,11 @@ void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
}
}
}
if (!WebPReportProgress(
pic, percent_start + percent_range * tile_y / tile_ysize,
percent)) {
return 0;
}
}
return 1;
}

View File

@ -533,7 +533,8 @@ static void InitScore(VP8ModeScore* const rd) {
rd->score = MAX_COST;
}
static void CopyScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
static void CopyScore(VP8ModeScore* WEBP_RESTRICT const dst,
const VP8ModeScore* WEBP_RESTRICT const src) {
dst->D = src->D;
dst->SD = src->SD;
dst->R = src->R;
@ -542,7 +543,8 @@ static void CopyScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
dst->score = src->score;
}
static void AddScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
static void AddScore(VP8ModeScore* WEBP_RESTRICT const dst,
const VP8ModeScore* WEBP_RESTRICT const src) {
dst->D += src->D;
dst->SD += src->SD;
dst->R += src->R;
@ -588,10 +590,10 @@ static WEBP_INLINE score_t RDScoreTrellis(int lambda, score_t rate,
// Coefficient type.
enum { TYPE_I16_AC = 0, TYPE_I16_DC = 1, TYPE_CHROMA_A = 2, TYPE_I4_AC = 3 };
static int TrellisQuantizeBlock(const VP8Encoder* const enc,
static int TrellisQuantizeBlock(const VP8Encoder* WEBP_RESTRICT const enc,
int16_t in[16], int16_t out[16],
int ctx0, int coeff_type,
const VP8Matrix* const mtx,
const VP8Matrix* WEBP_RESTRICT const mtx,
int lambda) {
const ProbaArray* const probas = enc->proba_.coeffs_[coeff_type];
CostArrayPtr const costs =
@ -767,9 +769,9 @@ static int TrellisQuantizeBlock(const VP8Encoder* const enc,
// all at once. Output is the reconstructed block in *yuv_out, and the
// quantized levels in *levels.
static int ReconstructIntra16(VP8EncIterator* const it,
VP8ModeScore* const rd,
uint8_t* const yuv_out,
static int ReconstructIntra16(VP8EncIterator* WEBP_RESTRICT const it,
VP8ModeScore* WEBP_RESTRICT const rd,
uint8_t* WEBP_RESTRICT const yuv_out,
int mode) {
const VP8Encoder* const enc = it->enc_;
const uint8_t* const ref = it->yuv_p_ + VP8I16ModeOffsets[mode];
@ -819,10 +821,10 @@ static int ReconstructIntra16(VP8EncIterator* const it,
return nz;
}
static int ReconstructIntra4(VP8EncIterator* const it,
static int ReconstructIntra4(VP8EncIterator* WEBP_RESTRICT const it,
int16_t levels[16],
const uint8_t* const src,
uint8_t* const yuv_out,
const uint8_t* WEBP_RESTRICT const src,
uint8_t* WEBP_RESTRICT const yuv_out,
int mode) {
const VP8Encoder* const enc = it->enc_;
const uint8_t* const ref = it->yuv_p_ + VP8I4ModeOffsets[mode];
@ -855,7 +857,8 @@ static int ReconstructIntra4(VP8EncIterator* const it,
// Quantize as usual, but also compute and return the quantization error.
// Error is already divided by DSHIFT.
static int QuantizeSingle(int16_t* const v, const VP8Matrix* const mtx) {
static int QuantizeSingle(int16_t* WEBP_RESTRICT const v,
const VP8Matrix* WEBP_RESTRICT const mtx) {
int V = *v;
const int sign = (V < 0);
if (sign) V = -V;
@ -869,9 +872,10 @@ static int QuantizeSingle(int16_t* const v, const VP8Matrix* const mtx) {
return (sign ? -V : V) >> DSCALE;
}
static void CorrectDCValues(const VP8EncIterator* const it,
const VP8Matrix* const mtx,
int16_t tmp[][16], VP8ModeScore* const rd) {
static void CorrectDCValues(const VP8EncIterator* WEBP_RESTRICT const it,
const VP8Matrix* WEBP_RESTRICT const mtx,
int16_t tmp[][16],
VP8ModeScore* WEBP_RESTRICT const rd) {
// | top[0] | top[1]
// --------+--------+---------
// left[0] | tmp[0] tmp[1] <-> err0 err1
@ -902,8 +906,8 @@ static void CorrectDCValues(const VP8EncIterator* const it,
}
}
static void StoreDiffusionErrors(VP8EncIterator* const it,
const VP8ModeScore* const rd) {
static void StoreDiffusionErrors(VP8EncIterator* WEBP_RESTRICT const it,
const VP8ModeScore* WEBP_RESTRICT const rd) {
int ch;
for (ch = 0; ch <= 1; ++ch) {
int8_t* const top = it->top_derr_[it->x_][ch];
@ -922,8 +926,9 @@ static void StoreDiffusionErrors(VP8EncIterator* const it,
//------------------------------------------------------------------------------
static int ReconstructUV(VP8EncIterator* const it, VP8ModeScore* const rd,
uint8_t* const yuv_out, int mode) {
static int ReconstructUV(VP8EncIterator* WEBP_RESTRICT const it,
VP8ModeScore* WEBP_RESTRICT const rd,
uint8_t* WEBP_RESTRICT const yuv_out, int mode) {
const VP8Encoder* const enc = it->enc_;
const uint8_t* const ref = it->yuv_p_ + VP8UVModeOffsets[mode];
const uint8_t* const src = it->yuv_in_ + U_OFF_ENC;
@ -994,7 +999,8 @@ static void SwapOut(VP8EncIterator* const it) {
SwapPtr(&it->yuv_out_, &it->yuv_out2_);
}
static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) {
static void PickBestIntra16(VP8EncIterator* WEBP_RESTRICT const it,
VP8ModeScore* WEBP_RESTRICT rd) {
const int kNumBlocks = 16;
VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_];
const int lambda = dqm->lambda_i16_;
@ -1054,7 +1060,7 @@ static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) {
//------------------------------------------------------------------------------
// return the cost array corresponding to the surrounding prediction modes.
static const uint16_t* GetCostModeI4(VP8EncIterator* const it,
static const uint16_t* GetCostModeI4(VP8EncIterator* WEBP_RESTRICT const it,
const uint8_t modes[16]) {
const int preds_w = it->enc_->preds_w_;
const int x = (it->i4_ & 3), y = it->i4_ >> 2;
@ -1063,7 +1069,8 @@ static const uint16_t* GetCostModeI4(VP8EncIterator* const it,
return VP8FixedCostsI4[top][left];
}
static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
static int PickBestIntra4(VP8EncIterator* WEBP_RESTRICT const it,
VP8ModeScore* WEBP_RESTRICT const rd) {
const VP8Encoder* const enc = it->enc_;
const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_];
const int lambda = dqm->lambda_i4_;
@ -1159,7 +1166,8 @@ static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
//------------------------------------------------------------------------------
static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) {
static void PickBestUV(VP8EncIterator* WEBP_RESTRICT const it,
VP8ModeScore* WEBP_RESTRICT const rd) {
const int kNumBlocks = 8;
const VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_];
const int lambda = dqm->lambda_uv_;
@ -1211,7 +1219,8 @@ static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) {
//------------------------------------------------------------------------------
// Final reconstruction and quantization.
static void SimpleQuantize(VP8EncIterator* const it, VP8ModeScore* const rd) {
static void SimpleQuantize(VP8EncIterator* WEBP_RESTRICT const it,
VP8ModeScore* WEBP_RESTRICT const rd) {
const VP8Encoder* const enc = it->enc_;
const int is_i16 = (it->mb_->type_ == 1);
int nz = 0;
@ -1236,9 +1245,9 @@ static void SimpleQuantize(VP8EncIterator* const it, VP8ModeScore* const rd) {
}
// Refine intra16/intra4 sub-modes based on distortion only (not rate).
static void RefineUsingDistortion(VP8EncIterator* const it,
static void RefineUsingDistortion(VP8EncIterator* WEBP_RESTRICT const it,
int try_both_modes, int refine_uv_mode,
VP8ModeScore* const rd) {
VP8ModeScore* WEBP_RESTRICT const rd) {
score_t best_score = MAX_COST;
int nz = 0;
int mode;
@ -1352,7 +1361,8 @@ static void RefineUsingDistortion(VP8EncIterator* const it,
//------------------------------------------------------------------------------
// Entry point
int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd,
int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const it,
VP8ModeScore* WEBP_RESTRICT const rd,
VP8RDLevel rd_opt) {
int is_skipped;
const int method = it->enc_->method_;

View File

@ -32,7 +32,7 @@ extern "C" {
// version numbers
#define ENC_MAJ_VERSION 1
#define ENC_MIN_VERSION 2
#define ENC_REV_VERSION 2
#define ENC_REV_VERSION 4
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
@ -470,7 +470,8 @@ int VP8EncAnalyze(VP8Encoder* const enc);
// Sets up segment's quantization values, base_quant_ and filter strengths.
void VP8SetSegmentParams(VP8Encoder* const enc, float quality);
// Pick best modes and fills the levels. Returns true if skipped.
int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd,
int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const it,
VP8ModeScore* WEBP_RESTRICT const rd,
VP8RDLevel rd_opt);
// in alpha.c
@ -490,19 +491,24 @@ int VP8FilterStrengthFromDelta(int sharpness, int delta);
// misc utils for picture_*.c:
// Returns true if 'picture' is non-NULL and dimensions/colorspace are within
// their valid ranges. If returning false, the 'error_code' in 'picture' is
// updated.
int WebPValidatePicture(const WebPPicture* const picture);
// Remove reference to the ARGB/YUVA buffer (doesn't free anything).
void WebPPictureResetBuffers(WebPPicture* const picture);
// Allocates ARGB buffer of given dimension (previous one is always free'd).
// Preserves the YUV(A) buffer. Returns false in case of error (invalid param,
// out-of-memory).
int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height);
// Allocates ARGB buffer according to set width/height (previous one is
// always free'd). Preserves the YUV(A) buffer. Returns false in case of error
// (invalid param, out-of-memory).
int WebPPictureAllocARGB(WebPPicture* const picture);
// Allocates YUVA buffer of given dimension (previous one is always free'd).
// Uses picture->csp to determine whether an alpha buffer is needed.
// Allocates YUVA buffer according to set width/height (previous one is always
// free'd). Uses picture->csp to determine whether an alpha buffer is needed.
// Preserves the ARGB buffer.
// Returns false in case of error (invalid param, out-of-memory).
int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height);
int WebPPictureAllocYUVA(WebPPicture* const picture);
// Replace samples that are fully transparent by 'color' to help compressibility
// (no guarantee, though). Assumes pic->use_argb is true.

File diff suppressed because it is too large Load Diff

View File

@ -89,9 +89,10 @@ int VP8LEncodeImage(const WebPConfig* const config,
// Encodes the main image stream using the supplied bit writer.
// If 'use_cache' is false, disables the use of color cache.
WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
const WebPPicture* const picture,
VP8LBitWriter* const bw, int use_cache);
// Returns false in case of error (stored in picture->error_code).
int VP8LEncodeStream(const WebPConfig* const config,
const WebPPicture* const picture, VP8LBitWriter* const bw,
int use_cache);
#if (WEBP_NEAR_LOSSLESS == 1)
// in near_lossless.c
@ -103,13 +104,18 @@ int VP8ApplyNearLossless(const WebPPicture* const picture, int quality,
//------------------------------------------------------------------------------
// Image transforms in predictor.c.
void VP8LResidualImage(int width, int height, int bits, int low_effort,
uint32_t* const argb, uint32_t* const argb_scratch,
uint32_t* const image, int near_lossless, int exact,
int used_subtract_green);
// pic and percent are for progress.
// Returns false in case of error (stored in pic->error_code).
int VP8LResidualImage(int width, int height, int bits, int low_effort,
uint32_t* const argb, uint32_t* const argb_scratch,
uint32_t* const image, int near_lossless, int exact,
int used_subtract_green, const WebPPicture* const pic,
int percent_range, int* const percent);
void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
uint32_t* const argb, uint32_t* image);
int VP8LColorSpaceTransform(int width, int height, int bits, int quality,
uint32_t* const argb, uint32_t* image,
const WebPPicture* const pic, int percent_range,
int* const percent);
//------------------------------------------------------------------------------

View File

@ -336,9 +336,7 @@ int WebPEncode(const WebPConfig* config, WebPPicture* pic) {
if (!WebPValidateConfig(config)) {
return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION);
}
if (pic->width <= 0 || pic->height <= 0) {
return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
}
if (!WebPValidatePicture(pic)) return 0;
if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION) {
return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
}

View File

@ -70,6 +70,7 @@ void WebPMuxDelete(WebPMux* mux) {
err = ChunkAssignData(&chunk, data, copy_data, tag); \
if (err == WEBP_MUX_OK) { \
err = ChunkSetHead(&chunk, (LIST)); \
if (err != WEBP_MUX_OK) ChunkRelease(&chunk); \
} \
return err; \
}

View File

@ -29,7 +29,7 @@ extern "C" {
#define MUX_MAJ_VERSION 1
#define MUX_MIN_VERSION 2
#define MUX_REV_VERSION 2
#define MUX_REV_VERSION 4
// Chunk object.
typedef struct WebPChunk WebPChunk;

View File

@ -155,17 +155,18 @@ WebPMuxError ChunkSetHead(WebPChunk* const chunk,
WebPMuxError ChunkAppend(WebPChunk* const chunk,
WebPChunk*** const chunk_list) {
WebPMuxError err;
assert(chunk_list != NULL && *chunk_list != NULL);
if (**chunk_list == NULL) {
ChunkSetHead(chunk, *chunk_list);
err = ChunkSetHead(chunk, *chunk_list);
} else {
WebPChunk* last_chunk = **chunk_list;
while (last_chunk->next_ != NULL) last_chunk = last_chunk->next_;
ChunkSetHead(chunk, &last_chunk->next_);
*chunk_list = &last_chunk->next_;
err = ChunkSetHead(chunk, &last_chunk->next_);
if (err == WEBP_MUX_OK) *chunk_list = &last_chunk->next_;
}
return WEBP_MUX_OK;
return err;
}
//------------------------------------------------------------------------------

View File

@ -441,7 +441,7 @@ WEBP_EXTERN int WebPPictureCrop(WebPPicture* picture,
// the original dimension will be lost). Picture 'dst' need not be initialized
// with WebPPictureInit() if it is different from 'src', since its content will
// be overwritten.
// Returns false in case of memory allocation error or invalid parameters.
// Returns false in case of invalid parameters.
WEBP_EXTERN int WebPPictureView(const WebPPicture* src,
int left, int top, int width, int height,
WebPPicture* dst);
@ -455,7 +455,7 @@ WEBP_EXTERN int WebPPictureIsView(const WebPPicture* picture);
// dimension will be calculated preserving the aspect ratio.
// No gamma correction is applied.
// Returns false in case of error (invalid parameter or insufficient memory).
WEBP_EXTERN int WebPPictureRescale(WebPPicture* pic, int width, int height);
WEBP_EXTERN int WebPPictureRescale(WebPPicture* picture, int width, int height);
// Colorspace conversion function to import RGB samples.
// Previous buffer will be free'd, if any.
@ -526,7 +526,7 @@ WEBP_EXTERN int WebPPictureHasTransparency(const WebPPicture* picture);
// Remove the transparency information (if present) by blending the color with
// the background color 'background_rgb' (specified as 24bit RGB triplet).
// After this call, all alpha values are reset to 0xff.
WEBP_EXTERN void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb);
WEBP_EXTERN void WebPBlendAlpha(WebPPicture* picture, uint32_t background_rgb);
//------------------------------------------------------------------------------
// Main call