431a9c00a5
On Linux and macOS, using Clang to compile OpenStarbound produces about 400 MB worth of warnings during the build, making the compiler output unreadable and slowing the build down considerably. 99% of the warnings were unqualified uses of std::move and std::forward, which are now all properly qualified. Fixed a few other minor warnings about non-virtual destructors and some uses of std::move preventing copy elision on temporary objects. Most remaining warnings are now unused parameters.
390 lines
8.6 KiB
C++
390 lines
8.6 KiB
C++
#include "StarDirectives.hpp"
|
|
#include "StarImage.hpp"
|
|
#include "StarImageProcessing.hpp"
|
|
#include "StarXXHash.hpp"
|
|
#include "StarLogging.hpp"
|
|
|
|
namespace Star {
|
|
|
|
Directives::Entry::Entry(ImageOperation&& newOperation, size_t strBegin, size_t strLength) {
|
|
operation = std::move(newOperation);
|
|
begin = strBegin;
|
|
length = strLength;
|
|
}
|
|
|
|
Directives::Entry::Entry(ImageOperation const& newOperation, size_t strBegin, size_t strLength) {
|
|
operation = newOperation;
|
|
begin = strBegin;
|
|
length = strLength;
|
|
}
|
|
|
|
Directives::Entry::Entry(Entry const& other) {
|
|
operation = other.operation;
|
|
begin = other.begin;
|
|
length = other.length;
|
|
}
|
|
|
|
ImageOperation const& Directives::Entry::loadOperation(Shared const& parent) const {
|
|
if (operation.is<NullImageOperation>()) {
|
|
try { operation = imageOperationFromString(string(parent)); }
|
|
catch (StarException const& e) { operation = ErrorImageOperation{ std::current_exception() }; }
|
|
}
|
|
return operation;
|
|
}
|
|
|
|
StringView Directives::Entry::string(Shared const& parent) const {
|
|
StringView result = parent.string;
|
|
result = result.utf8().substr(begin, length);
|
|
return result;
|
|
}
|
|
|
|
bool Directives::Shared::empty() const {
|
|
return entries.empty();
|
|
}
|
|
|
|
Directives::Shared::Shared(List<Entry>&& givenEntries, String&& givenString, StringView givenPrefix) {
|
|
entries = std::move(givenEntries);
|
|
string = std::move(givenString);
|
|
prefix = givenPrefix;
|
|
hash = XXH3_64bits(string.utf8Ptr(), string.utf8Size());
|
|
}
|
|
|
|
Directives::Directives() {}
|
|
|
|
Directives::Directives(String const& directives) {
|
|
parse(String(directives));
|
|
}
|
|
|
|
Directives::Directives(String&& directives) {
|
|
parse(std::move(directives));
|
|
}
|
|
|
|
Directives::Directives(const char* directives) {
|
|
parse(directives);
|
|
}
|
|
|
|
Directives::Directives(Directives&& directives) {
|
|
*this = std::move(directives);
|
|
}
|
|
|
|
Directives::Directives(Directives const& directives) {
|
|
*this = directives;
|
|
}
|
|
|
|
Directives::~Directives() {}
|
|
|
|
Directives& Directives::operator=(String const& s) {
|
|
if (shared && shared->string == s)
|
|
return *this;
|
|
|
|
parse(String(s));
|
|
return *this;
|
|
}
|
|
|
|
Directives& Directives::operator=(String&& s) {
|
|
if (shared && shared->string == s) {
|
|
s.clear();
|
|
return *this;
|
|
}
|
|
|
|
parse(std::move(s));
|
|
return *this;
|
|
}
|
|
|
|
Directives& Directives::operator=(const char* s) {
|
|
if (shared && shared->string.utf8().compare(s) == 0)
|
|
return *this;
|
|
|
|
parse(s);
|
|
return *this;
|
|
}
|
|
|
|
Directives& Directives::operator=(Directives&& other) {
|
|
shared = std::move(other.shared);
|
|
return *this;
|
|
}
|
|
|
|
Directives& Directives::operator=(Directives const& other) {
|
|
shared = other.shared;
|
|
return *this;
|
|
}
|
|
|
|
void Directives::loadOperations() const {
|
|
if (!shared)
|
|
return;
|
|
|
|
MutexLocker lock(shared->mutex, true);
|
|
for (auto& entry : shared->entries)
|
|
entry.loadOperation(*shared);
|
|
}
|
|
|
|
void Directives::parse(String&& directives) {
|
|
if (directives.empty()) {
|
|
shared.reset();
|
|
return;
|
|
}
|
|
|
|
List<Entry> newList;
|
|
StringView view(directives);
|
|
StringView prefix = "";
|
|
view.forEachSplitView("?", [&](StringView split, size_t beg, size_t end) {
|
|
if (!split.empty()) {
|
|
if (beg == 0) {
|
|
try {
|
|
ImageOperation operation = imageOperationFromString(split);
|
|
newList.emplace_back(std::move(operation), beg, end);
|
|
}
|
|
catch (StarException const& e) {
|
|
prefix = split;
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
ImageOperation operation = NullImageOperation();
|
|
newList.emplace_back(std::move(operation), beg, end);
|
|
}
|
|
}
|
|
});
|
|
|
|
if (newList.empty() && !prefix.empty()) {
|
|
shared.reset();
|
|
return;
|
|
}
|
|
|
|
shared = std::make_shared<Shared const>(std::move(newList), std::move(directives), prefix);
|
|
if (view.size() < 1000) { // Pre-load short enough directives
|
|
for (auto& entry : shared->entries)
|
|
entry.loadOperation(*shared);
|
|
}
|
|
}
|
|
|
|
String Directives::string() const {
|
|
if (!shared)
|
|
return "";
|
|
else
|
|
return shared->string;
|
|
}
|
|
|
|
StringView Directives::prefix() const {
|
|
if (!shared)
|
|
return "";
|
|
else
|
|
return shared->prefix;
|
|
}
|
|
|
|
String const* Directives::stringPtr() const {
|
|
if (!shared)
|
|
return nullptr;
|
|
else
|
|
return &shared->string;
|
|
}
|
|
|
|
|
|
String Directives::buildString() const {
|
|
if (shared) {
|
|
String built = shared->prefix;
|
|
|
|
for (auto& entry : shared->entries) {
|
|
built += "?";
|
|
built += entry.string(*shared);
|
|
}
|
|
|
|
return built;
|
|
}
|
|
|
|
return String();
|
|
}
|
|
|
|
String& Directives::addToString(String& out) const {
|
|
if (!empty())
|
|
out += shared->string;
|
|
return out;
|
|
}
|
|
|
|
size_t Directives::hash() const {
|
|
return shared ? shared->hash : 0;
|
|
}
|
|
|
|
size_t Directives::size() const {
|
|
return shared ? shared->entries.size() : 0;
|
|
}
|
|
|
|
bool Directives::empty() const {
|
|
return !shared || shared->empty();
|
|
}
|
|
|
|
Directives::operator bool() const { return !empty(); }
|
|
|
|
DataStream& operator>>(DataStream& ds, Directives& directives) {
|
|
String string;
|
|
ds.read(string);
|
|
|
|
directives.parse(std::move(string));
|
|
|
|
return ds;
|
|
}
|
|
|
|
DataStream& operator<<(DataStream & ds, Directives const& directives) {
|
|
if (directives)
|
|
ds.write(directives.shared->string);
|
|
else
|
|
ds.write(String());
|
|
|
|
return ds;
|
|
}
|
|
|
|
DirectivesGroup::DirectivesGroup() : m_count(0) {}
|
|
DirectivesGroup::DirectivesGroup(String const& directives) : m_count(0) {
|
|
if (directives.empty())
|
|
return;
|
|
|
|
Directives parsed(directives);
|
|
if (parsed) {
|
|
m_directives.emplace_back(std::move(parsed));
|
|
m_count = m_directives.back().size();
|
|
}
|
|
}
|
|
DirectivesGroup::DirectivesGroup(String&& directives) : m_count(0) {
|
|
if (directives.empty()) {
|
|
directives.clear();
|
|
return;
|
|
}
|
|
|
|
Directives parsed(std::move(directives));
|
|
if (parsed) {
|
|
m_directives.emplace_back(std::move(parsed));
|
|
m_count = m_directives.back().size();
|
|
}
|
|
}
|
|
|
|
bool DirectivesGroup::empty() const {
|
|
return m_count == 0;
|
|
}
|
|
|
|
DirectivesGroup::operator bool() const {
|
|
return empty();
|
|
}
|
|
|
|
bool DirectivesGroup::compare(DirectivesGroup const& other) const {
|
|
if (m_count != other.m_count)
|
|
return false;
|
|
|
|
if (empty())
|
|
return true;
|
|
|
|
return hash() == other.hash();
|
|
}
|
|
|
|
void DirectivesGroup::append(Directives const& directives) {
|
|
m_directives.emplace_back(directives);
|
|
m_count += m_directives.back().size();
|
|
}
|
|
|
|
void DirectivesGroup::clear() {
|
|
m_directives.clear();
|
|
m_count = 0;
|
|
}
|
|
|
|
DirectivesGroup& DirectivesGroup::operator+=(Directives const& other) {
|
|
append(other);
|
|
return *this;
|
|
}
|
|
|
|
String DirectivesGroup::toString() const {
|
|
String string;
|
|
addToString(string);
|
|
return string;
|
|
}
|
|
|
|
void DirectivesGroup::addToString(String& string) const {
|
|
for (auto& directives : m_directives)
|
|
if (directives.shared) {
|
|
auto& dirString = directives.shared->string;
|
|
if (!dirString.empty()) {
|
|
if (dirString.utf8().front() != '?')
|
|
string += "?";
|
|
string += dirString;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DirectivesGroup::forEach(DirectivesCallback callback) const {
|
|
for (auto& directives : m_directives) {
|
|
if (directives.shared) {
|
|
for (auto& entry : directives.shared->entries)
|
|
callback(entry, directives);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool DirectivesGroup::forEachAbortable(AbortableDirectivesCallback callback) const {
|
|
for (auto& directives : m_directives) {
|
|
if (directives.shared) {
|
|
for (auto& entry : directives.shared->entries) {
|
|
if (!callback(entry, directives))
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Image DirectivesGroup::applyNewImage(Image const& image) const {
|
|
Image result = image;
|
|
applyExistingImage(result);
|
|
return result;
|
|
}
|
|
|
|
void DirectivesGroup::applyExistingImage(Image& image) const {
|
|
forEach([&](auto const& entry, Directives const& directives) {
|
|
ImageOperation const& operation = entry.loadOperation(*directives.shared);
|
|
if (auto error = operation.ptr<ErrorImageOperation>())
|
|
std::rethrow_exception(error->exception);
|
|
else
|
|
processImageOperation(operation, image);
|
|
});
|
|
}
|
|
|
|
size_t DirectivesGroup::hash() const {
|
|
XXHash3 hasher;
|
|
for (auto& directives : m_directives) {
|
|
size_t hash = directives.hash();
|
|
hasher.push((const char*)&hash, sizeof(hash));
|
|
}
|
|
|
|
return hasher.digest();
|
|
}
|
|
|
|
const List<Directives>& DirectivesGroup::list() const {
|
|
return m_directives;
|
|
}
|
|
|
|
bool operator==(DirectivesGroup const& a, DirectivesGroup const& b) {
|
|
return a.compare(b);
|
|
}
|
|
|
|
bool operator!=(DirectivesGroup const& a, DirectivesGroup const& b) {
|
|
return !a.compare(b);
|
|
}
|
|
|
|
DataStream& operator>>(DataStream& ds, DirectivesGroup& directivesGroup) {
|
|
String string;
|
|
ds.read(string);
|
|
|
|
directivesGroup = DirectivesGroup(std::move(string));
|
|
|
|
return ds;
|
|
}
|
|
|
|
DataStream& operator<<(DataStream& ds, DirectivesGroup const& directivesGroup) {
|
|
ds.write(directivesGroup.toString());
|
|
|
|
return ds;
|
|
}
|
|
|
|
size_t hash<DirectivesGroup>::operator()(DirectivesGroup const& s) const {
|
|
return s.hash();
|
|
}
|
|
|
|
} |