Add string view variant of Star::String and use it
it's 1:30 AM AGAIN !! !!!!! This might have broken the inventory icons of custom hats a little, need to look into that
This commit is contained in:
parent
13a74602bd
commit
09d26d43b5
@ -844,7 +844,7 @@ shared_ptr<Assets::AssetData> Assets::loadImage(AssetPath const& path) const {
|
||||
return {};
|
||||
StringMap<ImageConstPtr> references;
|
||||
StringList referencePaths;
|
||||
path.directives.forEach([&](auto const& entry) {
|
||||
path.directives.forEach([&](auto const& entry, Directives const& directives) {
|
||||
addImageOperationReferences(entry.operation, referencePaths);
|
||||
}); // TODO: This can definitely be better, was changed quickly to support the new Directives.
|
||||
|
||||
@ -861,7 +861,7 @@ shared_ptr<Assets::AssetData> Assets::loadImage(AssetPath const& path) const {
|
||||
return unlockDuring([&]() {
|
||||
auto newData = make_shared<ImageData>();
|
||||
Image newImage = *source->image;
|
||||
path.directives.forEach([&](auto const& entry) {
|
||||
path.directives.forEach([&](auto const& entry, Directives const& directives) {
|
||||
if (auto error = entry.operation.ptr<ErrorImageOperation>())
|
||||
std::rethrow_exception(error->exception);
|
||||
else
|
||||
|
@ -106,6 +106,7 @@ SET (star_core_HEADERS
|
||||
StarStaticRandom.hpp
|
||||
StarStaticVector.hpp
|
||||
StarString.hpp
|
||||
StarStringView.hpp
|
||||
StarStrongTypedef.hpp
|
||||
StarTcp.hpp
|
||||
StarThread.hpp
|
||||
@ -163,6 +164,7 @@ SET (star_core_SOURCES
|
||||
StarShellParser.cpp
|
||||
StarSocket.cpp
|
||||
StarString.cpp
|
||||
StarStringView.cpp
|
||||
StarTcp.cpp
|
||||
StarThread.cpp
|
||||
StarTime.cpp
|
||||
|
@ -175,9 +175,9 @@ std::ostream& operator<<(std::ostream& os, AssetPath const& rhs) {
|
||||
os << *rhs.subPath;
|
||||
}
|
||||
|
||||
rhs.directives.forEach([&](auto const& entry) {
|
||||
rhs.directives.forEach([&](auto const& entry, Directives const& directives) {
|
||||
os << "?";
|
||||
os << entry.string;
|
||||
os << entry.string(*directives.shared);
|
||||
});
|
||||
|
||||
return os;
|
||||
|
@ -302,7 +302,7 @@ uint32_t Color::toUint32() const {
|
||||
return val;
|
||||
}
|
||||
|
||||
Color Color::fromHex(String const& s) {
|
||||
Color Color::fromHex(StringView s) {
|
||||
return Color::rgba(hexToVec4B(s));
|
||||
}
|
||||
|
||||
@ -601,7 +601,7 @@ Vec4B Color::hueShiftVec4B(Vec4B color, float hue) {
|
||||
}
|
||||
}
|
||||
|
||||
Vec4B Color::hexToVec4B(String const& s) {
|
||||
Vec4B Color::hexToVec4B(StringView s) {
|
||||
Array<uint8_t, 4> cbytes;
|
||||
|
||||
if (s.utf8Size() == 3) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef STAR_COLOR_HPP
|
||||
#define STAR_COLOR_HPP
|
||||
|
||||
#include "StarString.hpp"
|
||||
#include "StarStringView.hpp"
|
||||
#include "StarVector.hpp"
|
||||
|
||||
namespace Star {
|
||||
@ -58,7 +58,7 @@ public:
|
||||
static Color gray(uint8_t g);
|
||||
|
||||
// Only supports 8 bit color
|
||||
static Color fromHex(String const& s);
|
||||
static Color fromHex(StringView s);
|
||||
|
||||
// #AARRGGBB
|
||||
static Color fromUint32(uint32_t v);
|
||||
@ -67,7 +67,7 @@ public:
|
||||
static Color temperature(float temp);
|
||||
|
||||
static Vec4B hueShiftVec4B(Vec4B color, float hue);
|
||||
static Vec4B Color::hexToVec4B(String const& s);
|
||||
static Vec4B Color::hexToVec4B(StringView s);
|
||||
// Black
|
||||
Color();
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "StarPch.hpp"
|
||||
|
||||
#ifndef STAR_CONFIG_HPP
|
||||
#define STAR_CONFIG_HPP
|
||||
|
||||
#include "StarPch.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
// Some really common std namespace includes
|
||||
|
@ -1,92 +1,125 @@
|
||||
#include "StarDirectives.hpp"
|
||||
#include "StarImage.hpp"
|
||||
#include "StarImageProcessing.hpp"
|
||||
#include "StarDirectives.hpp"
|
||||
#include "StarXXHash.hpp"
|
||||
#include "StarLogging.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
Directives::Entry::Entry(ImageOperation&& newOperation, String&& newString) {
|
||||
Directives::Entry::Entry(ImageOperation&& newOperation, size_t strBegin, size_t strLength) {
|
||||
operation = move(newOperation);
|
||||
string = move(newString);
|
||||
begin = strBegin;
|
||||
length = strLength;
|
||||
}
|
||||
|
||||
Directives::Entry::Entry(ImageOperation const& newOperation, String const& newString) {
|
||||
Directives::Entry::Entry(ImageOperation const& newOperation, size_t strBegin, size_t strLength) {
|
||||
operation = newOperation;
|
||||
string = newString;
|
||||
begin = strBegin;
|
||||
length = strLength;
|
||||
}
|
||||
|
||||
Directives::Entry::Entry(Entry const& other) {
|
||||
operation = other.operation;
|
||||
string = other.string;
|
||||
begin = other.begin;
|
||||
length = other.length;
|
||||
}
|
||||
|
||||
Directives::Directives() : hash(0) {}
|
||||
Directives::Directives(String const& directives) : hash(0) {
|
||||
string = directives;
|
||||
parse(string);
|
||||
StringView Directives::Entry::string(Shared const& parent) const {
|
||||
StringView result(parent.string);
|
||||
result = result.substr(begin, length);
|
||||
return result;
|
||||
}
|
||||
|
||||
Directives::Directives(String&& directives) : hash(0) {
|
||||
string = move(directives);
|
||||
parse(string);
|
||||
bool Directives::Shared::empty() const {
|
||||
return entries.empty();
|
||||
}
|
||||
|
||||
Directives::Directives(const char* directives) : hash(0), string(directives) {
|
||||
parse(string);
|
||||
}
|
||||
|
||||
Directives::Directives(List<Entry>&& newEntries) {
|
||||
entries = std::make_shared<List<Entry> const>(move(newEntries));
|
||||
String newString;
|
||||
string = move(buildString(newString));
|
||||
Directives::Shared::Shared(List<Entry>&& givenEntries, String&& givenString) {
|
||||
entries = move(givenEntries);
|
||||
string = move(givenString);
|
||||
hash = XXH3_64bits(string.utf8Ptr(), string.utf8Size());
|
||||
}
|
||||
|
||||
void Directives::parse(String const& directives) {
|
||||
Directives::Directives() {}
|
||||
Directives::Directives(String const& directives) {
|
||||
parse(String(directives));
|
||||
}
|
||||
|
||||
Directives::Directives(String&& directives) {
|
||||
parse(move(directives));
|
||||
}
|
||||
|
||||
Directives::Directives(const char* directives) {
|
||||
parse(directives);
|
||||
}
|
||||
|
||||
void Directives::parse(String&& directives) {
|
||||
if (directives.empty())
|
||||
return;
|
||||
|
||||
List<Entry> newList;
|
||||
StringList split = directives.split('?');
|
||||
newList.reserve(split.size());
|
||||
for (String& str : split) {
|
||||
if (!str.empty()) {
|
||||
|
||||
StringView(directives).forEachSplitView("?", [&](StringView split, size_t beg, size_t end) {
|
||||
if (!split.empty()) {
|
||||
try {
|
||||
ImageOperation operation = imageOperationFromString(str);
|
||||
newList.emplace_back(move(operation), move(str));
|
||||
} catch (StarException const& e) {
|
||||
newList.emplace_back(ErrorImageOperation{ std::current_exception() }, move(str));
|
||||
ImageOperation operation = imageOperationFromString(split);
|
||||
newList.emplace_back(move(operation), beg, end);
|
||||
}
|
||||
catch (StarException const& e) {
|
||||
newList.emplace_back(ErrorImageOperation{ std::current_exception() }, beg, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (newList.empty())
|
||||
return;
|
||||
|
||||
entries = std::make_shared<List<Entry> const>(move(newList));
|
||||
hash = XXH3_64bits(directives.utf8Ptr(), directives.utf8Size());
|
||||
//if (directives.utf8Size() > 1000)
|
||||
// Logger::logf(LogLevel::Debug, "Directives: Parsed %u character long string", directives.utf8Size());
|
||||
shared = std::make_shared<Shared const>(move(newList), move(directives));
|
||||
}
|
||||
|
||||
String& Directives::buildString(String& out) const {
|
||||
if (entries) {
|
||||
for (auto& entry : *entries) {
|
||||
out += "?";
|
||||
out += entry.string;
|
||||
String Directives::string() const {
|
||||
if (!shared)
|
||||
return "";
|
||||
else
|
||||
return shared->string;
|
||||
}
|
||||
|
||||
String const* Directives::stringPtr() const {
|
||||
if (!shared)
|
||||
return nullptr;
|
||||
else
|
||||
return &shared->string;
|
||||
}
|
||||
|
||||
|
||||
String Directives::buildString() const {
|
||||
String built;
|
||||
if (shared) {
|
||||
for (auto& entry : shared->entries) {
|
||||
built += "?";
|
||||
built += entry.string(*shared);
|
||||
}
|
||||
}
|
||||
|
||||
return built;
|
||||
}
|
||||
|
||||
String& Directives::addToString(String& out) const {
|
||||
if (!empty())
|
||||
out += shared->string;
|
||||
return out;
|
||||
}
|
||||
|
||||
String Directives::toString() const {
|
||||
return string;
|
||||
size_t Directives::hash() const {
|
||||
return shared ? shared->hash : 0;
|
||||
}
|
||||
|
||||
size_t Directives::size() const {
|
||||
return shared ? shared->entries.size() : 0;
|
||||
}
|
||||
|
||||
inline bool Directives::empty() const {
|
||||
return !entries || entries->empty();
|
||||
return !shared || shared->empty();
|
||||
}
|
||||
|
||||
inline Directives::operator bool() const {
|
||||
@ -98,13 +131,16 @@ DataStream& operator>>(DataStream& ds, Directives& directives) {
|
||||
String string;
|
||||
ds.read(string);
|
||||
|
||||
directives.parse(string);
|
||||
directives.parse(move(string));
|
||||
|
||||
return ds;
|
||||
}
|
||||
|
||||
DataStream& operator<<(DataStream& ds, Directives const& directives) {
|
||||
ds.write(directives.toString());
|
||||
if (directives)
|
||||
ds.write(directives.shared->string);
|
||||
else
|
||||
ds.write(String());
|
||||
|
||||
return ds;
|
||||
}
|
||||
@ -117,7 +153,7 @@ DirectivesGroup::DirectivesGroup(String const& directives) : m_count(0) {
|
||||
Directives parsed(directives);
|
||||
if (parsed) {
|
||||
m_directives.emplace_back(move(parsed));
|
||||
m_count = m_directives.back().entries->size();
|
||||
m_count = m_directives.back().size();
|
||||
}
|
||||
}
|
||||
DirectivesGroup::DirectivesGroup(String&& directives) : m_count(0) {
|
||||
@ -129,7 +165,7 @@ DirectivesGroup::DirectivesGroup(String&& directives) : m_count(0) {
|
||||
Directives parsed(move(directives));
|
||||
if (parsed) {
|
||||
m_directives.emplace_back(move(parsed));
|
||||
m_count = m_directives.back().entries->size();
|
||||
m_count = m_directives.back().size();
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,14 +189,7 @@ bool DirectivesGroup::compare(DirectivesGroup const& other) const {
|
||||
|
||||
void DirectivesGroup::append(Directives const& directives) {
|
||||
m_directives.emplace_back(directives);
|
||||
if (directives.entries)
|
||||
m_count += m_directives.back().entries->size();
|
||||
}
|
||||
|
||||
void DirectivesGroup::append(List<Directives::Entry>&& entries) {
|
||||
size_t size = entries.size();
|
||||
m_directives.emplace_back(move(entries));
|
||||
m_count += size;
|
||||
m_count += m_directives.back().size();
|
||||
}
|
||||
|
||||
void DirectivesGroup::clear() {
|
||||
@ -181,23 +210,24 @@ inline String DirectivesGroup::toString() const {
|
||||
|
||||
void DirectivesGroup::addToString(String& string) const {
|
||||
for (auto& directives : m_directives)
|
||||
string += directives.string;
|
||||
if (directives.shared)
|
||||
string += directives.shared->string;
|
||||
}
|
||||
|
||||
void DirectivesGroup::forEach(DirectivesCallback callback) const {
|
||||
for (auto& directives : m_directives) {
|
||||
if (directives.entries) {
|
||||
for (auto& entry : *directives.entries)
|
||||
callback(entry);
|
||||
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.entries) {
|
||||
for (auto& entry : *directives.entries) {
|
||||
if (!callback(entry))
|
||||
if (directives.shared) {
|
||||
for (auto& entry : directives.shared->entries) {
|
||||
if (!callback(entry, directives))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -213,7 +243,7 @@ inline Image DirectivesGroup::applyNewImage(Image const& image) const {
|
||||
}
|
||||
|
||||
void DirectivesGroup::applyExistingImage(Image& image) const {
|
||||
forEach([&](auto const& entry) {
|
||||
forEach([&](auto const& entry, Directives const& directives) {
|
||||
if (auto error = entry.operation.ptr<ErrorImageOperation>())
|
||||
std::rethrow_exception(error->exception);
|
||||
else
|
||||
@ -223,8 +253,10 @@ void DirectivesGroup::applyExistingImage(Image& image) const {
|
||||
|
||||
inline size_t DirectivesGroup::hash() const {
|
||||
XXHash3 hasher;
|
||||
for (auto& directives : m_directives)
|
||||
hasher.push((const char*)&directives.hash, sizeof(directives.hash));
|
||||
for (auto& directives : m_directives) {
|
||||
size_t hash = directives.hash();
|
||||
hasher.push((const char*)&hash, sizeof(hash));
|
||||
}
|
||||
|
||||
return hasher.digest();
|
||||
}
|
||||
@ -245,7 +277,7 @@ DataStream& operator>>(DataStream& ds, DirectivesGroup& directivesGroup) {
|
||||
String string;
|
||||
ds.read(string);
|
||||
|
||||
directivesGroup = move(DirectivesGroup(move(string)));
|
||||
directivesGroup = DirectivesGroup(move(string));
|
||||
|
||||
return ds;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "StarImageProcessing.hpp"
|
||||
#include "StarHash.hpp"
|
||||
#include "StarDataStream.hpp"
|
||||
#include "StarStringView.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
@ -14,33 +15,46 @@ STAR_EXCEPTION(DirectivesException, StarException);
|
||||
// Kae: My attempt at reducing memory allocation and per-frame string parsing for extremely long directives
|
||||
class Directives {
|
||||
public:
|
||||
struct Shared;
|
||||
struct Entry {
|
||||
ImageOperation operation;
|
||||
String string; // One day, we can make this a string_view pointing to Entry::string.
|
||||
size_t begin;
|
||||
size_t length;
|
||||
|
||||
Entry(ImageOperation&& newOperation, String&& newString);
|
||||
Entry(ImageOperation const& newOperation, String const& newString);
|
||||
inline StringView string(Shared const& parent) const;
|
||||
Entry(ImageOperation&& newOperation, size_t begin, size_t end);
|
||||
Entry(ImageOperation const& newOperation, size_t begin, size_t end);
|
||||
Entry(Entry const& other);
|
||||
};
|
||||
|
||||
struct Shared {
|
||||
List<Entry> entries;
|
||||
String string;
|
||||
size_t hash = 0;
|
||||
|
||||
bool empty() const;
|
||||
Shared(List<Entry>&& givenEntries, String&& givenString);
|
||||
};
|
||||
|
||||
Directives();
|
||||
Directives(String const& directives);
|
||||
Directives(String&& directives);
|
||||
Directives(const char* directives);
|
||||
Directives(List<Entry>&& entries);
|
||||
|
||||
void parse(String const& directives);
|
||||
String& buildString(String& out) const;
|
||||
String toString() const;
|
||||
void parse(String&& directives);
|
||||
String string() const;
|
||||
String const* stringPtr() const;
|
||||
String buildString() const;
|
||||
String& addToString(String& out) const;
|
||||
size_t hash() const;
|
||||
size_t size() const;
|
||||
bool empty() const;
|
||||
operator bool() const;
|
||||
|
||||
friend DataStream& operator>>(DataStream& ds, Directives& directives);
|
||||
friend DataStream& operator<<(DataStream& ds, Directives const& directives);
|
||||
|
||||
std::shared_ptr<List<Entry> const> entries;
|
||||
size_t hash = 0;
|
||||
String string;
|
||||
std::shared_ptr<Shared const> shared;
|
||||
};
|
||||
|
||||
class DirectivesGroup {
|
||||
@ -49,13 +63,10 @@ public:
|
||||
DirectivesGroup(String const& directives);
|
||||
DirectivesGroup(String&& directives);
|
||||
|
||||
void parseDirectivesIntoLeaf(String const& directives);
|
||||
|
||||
bool empty() const;
|
||||
operator bool() const;
|
||||
bool compare(DirectivesGroup const& other) const;
|
||||
void append(Directives const& other);
|
||||
void append(List<Directives::Entry>&& entries);
|
||||
void clear();
|
||||
|
||||
DirectivesGroup& operator+=(Directives const& other);
|
||||
@ -63,8 +74,8 @@ public:
|
||||
String toString() const;
|
||||
void addToString(String& string) const;
|
||||
|
||||
typedef function<void(Directives::Entry const&)> DirectivesCallback;
|
||||
typedef function<bool(Directives::Entry const&)> AbortableDirectivesCallback;
|
||||
typedef function<void(Directives::Entry const&, Directives const&)> DirectivesCallback;
|
||||
typedef function<bool(Directives::Entry const&, Directives const&)> AbortableDirectivesCallback;
|
||||
|
||||
void forEach(DirectivesCallback callback) const;
|
||||
bool forEachAbortable(AbortableDirectivesCallback callback) const;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "StarLexicalCast.hpp"
|
||||
#include "StarColor.hpp"
|
||||
#include "StarImage.hpp"
|
||||
#include "StarStringView.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
@ -145,9 +146,13 @@ FadeToColorImageOperation::FadeToColorImageOperation(Vec3B color, float amount)
|
||||
}
|
||||
}
|
||||
|
||||
ImageOperation imageOperationFromString(String const& string) {
|
||||
ImageOperation imageOperationFromString(StringView string) {
|
||||
try {
|
||||
auto bits = string.splitAny("=;");
|
||||
List<StringView> bits;
|
||||
string.forEachSplitAnyView("=;", [&](StringView split, size_t, size_t) {
|
||||
bits.emplace_back(split);
|
||||
});
|
||||
|
||||
String type = bits.at(0);
|
||||
|
||||
if (type == "hueshift") {
|
||||
@ -184,7 +189,7 @@ ImageOperation imageOperationFromString(String const& string) {
|
||||
else
|
||||
operation.mode = AlphaMaskImageOperation::Subtractive;
|
||||
|
||||
operation.maskImages = bits.at(1).split('+');
|
||||
operation.maskImages = String(bits.at(1)).split('+');
|
||||
|
||||
if (bits.size() > 2)
|
||||
operation.offset[0] = lexicalCast<int>(bits.at(2));
|
||||
@ -202,7 +207,7 @@ ImageOperation imageOperationFromString(String const& string) {
|
||||
else
|
||||
operation.mode = BlendImageOperation::Screen;
|
||||
|
||||
operation.blendImages = bits.at(1).split('+');
|
||||
operation.blendImages = String(bits.at(1)).split('+');
|
||||
|
||||
if (bits.size() > 2)
|
||||
operation.offset[0] = lexicalCast<int>(bits.at(2));
|
||||
@ -328,22 +333,19 @@ String imageOperationToString(ImageOperation const& operation) {
|
||||
return "";
|
||||
}
|
||||
|
||||
void parseImageOperations(String const& params, function<void(ImageOperation&&)> outputter) {
|
||||
for (auto const& op : params.split('?')) {
|
||||
void parseImageOperations(StringView params, function<void(ImageOperation&&)> outputter) {
|
||||
params.forEachSplitView("?", [&](StringView op, size_t, size_t) {
|
||||
if (!op.empty())
|
||||
outputter(imageOperationFromString(op));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
List<ImageOperation> parseImageOperations(String const& params) {
|
||||
auto split = params.split('?');
|
||||
List<ImageOperation> parseImageOperations(StringView params) {
|
||||
List<ImageOperation> operations;
|
||||
operations.reserve(split.size());
|
||||
|
||||
for (auto const& op : split) {
|
||||
params.forEachSplitView("?", [&](StringView op, size_t, size_t) {
|
||||
if (!op.empty())
|
||||
operations.append(imageOperationFromString(op));
|
||||
}
|
||||
});
|
||||
|
||||
return operations;
|
||||
}
|
||||
|
@ -137,14 +137,14 @@ typedef Variant<ErrorImageOperation, HueShiftImageOperation, SaturationShiftImag
|
||||
ScanLinesImageOperation, SetColorImageOperation, ColorReplaceImageOperation, AlphaMaskImageOperation, BlendImageOperation,
|
||||
MultiplyImageOperation, BorderImageOperation, ScaleImageOperation, CropImageOperation, FlipImageOperation> ImageOperation;
|
||||
|
||||
ImageOperation imageOperationFromString(String const& string);
|
||||
ImageOperation imageOperationFromString(StringView string);
|
||||
String imageOperationToString(ImageOperation const& operation);
|
||||
|
||||
void parseImageOperations(String const& params, function<void(ImageOperation&&)> outputter);
|
||||
void parseImageOperations(StringView params, function<void(ImageOperation&&)> outputter);
|
||||
|
||||
// Each operation is assumed to be separated by '?', with parameters
|
||||
// separated by ';' or '='
|
||||
List<ImageOperation> parseImageOperations(String const& params);
|
||||
List<ImageOperation> parseImageOperations(StringView params);
|
||||
|
||||
// Each operation separated by '?', returns string with leading '?'
|
||||
String printImageOperations(List<ImageOperation> const& operations);
|
||||
|
@ -378,8 +378,10 @@ List<Directives> jsonToDirectivesList(Json const& v) {
|
||||
|
||||
Json jsonFromDirectivesList(List<Directives> const& v) {
|
||||
JsonArray result;
|
||||
for (auto& e : v)
|
||||
result.push_back(e.toString());
|
||||
for (auto& e : v) {
|
||||
if (e)
|
||||
result.push_back(*e.stringPtr());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define STAR_LEXICAL_CAST_HPP
|
||||
|
||||
#include "StarString.hpp"
|
||||
#include "StarStringView.hpp"
|
||||
#include "StarMaybe.hpp"
|
||||
|
||||
#include <sstream>
|
||||
@ -14,9 +15,9 @@ STAR_EXCEPTION(BadLexicalCast, StarException);
|
||||
// Very simple basic lexical cast using stream input. Always operates in the
|
||||
// "C" locale.
|
||||
template <typename Type>
|
||||
Maybe<Type> maybeLexicalCast(std::string const& s, std::ios_base::fmtflags flags = std::ios_base::boolalpha) {
|
||||
Maybe<Type> maybeLexicalCast(StringView s, std::ios_base::fmtflags flags = std::ios_base::boolalpha) {
|
||||
Type result;
|
||||
std::istringstream stream(s);
|
||||
std::istringstream stream(std::string(s.utf8()));
|
||||
stream.flags(flags);
|
||||
stream.imbue(std::locale::classic());
|
||||
|
||||
@ -28,21 +29,11 @@ Maybe<Type> maybeLexicalCast(std::string const& s, std::ios_base::fmtflags flags
|
||||
if (stream >> ch)
|
||||
return {};
|
||||
|
||||
return result;
|
||||
return move(result);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Maybe<Type> maybeLexicalCast(char const* s, std::ios_base::fmtflags flags = std::ios_base::boolalpha) {
|
||||
return maybeLexicalCast<Type>(std::string(s), flags);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Maybe<Type> maybeLexicalCast(String const& s, std::ios_base::fmtflags flags = std::ios_base::boolalpha) {
|
||||
return maybeLexicalCast<Type>(s.utf8(), flags);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type lexicalCast(std::string const& s, std::ios_base::fmtflags flags = std::ios_base::boolalpha) {
|
||||
Type lexicalCast(StringView s, std::ios_base::fmtflags flags = std::ios_base::boolalpha) {
|
||||
auto m = maybeLexicalCast<Type>(s, flags);
|
||||
if (m)
|
||||
return m.take();
|
||||
@ -50,16 +41,6 @@ Type lexicalCast(std::string const& s, std::ios_base::fmtflags flags = std::ios_
|
||||
throw BadLexicalCast(strf("Lexical cast failed on '%s'", s));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type lexicalCast(char const* s, std::ios_base::fmtflags flags = std::ios_base::boolalpha) {
|
||||
return lexicalCast<Type>(std::string(s), flags);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type lexicalCast(String const& s, std::ios_base::fmtflags flags = std::ios_base::boolalpha) {
|
||||
return lexicalCast<Type>(s.utf8(), flags);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
std::string toString(Type const& t, std::ios_base::fmtflags flags = std::ios_base::boolalpha) {
|
||||
std::stringstream ss;
|
||||
|
@ -12,6 +12,7 @@ namespace Star {
|
||||
|
||||
STAR_CLASS(StringList);
|
||||
STAR_CLASS(String);
|
||||
STAR_CLASS(StringView);
|
||||
|
||||
STAR_EXCEPTION(StringException, StarException);
|
||||
|
||||
@ -268,6 +269,13 @@ public:
|
||||
friend std::ostream& operator<<(std::ostream& os, String const& s);
|
||||
friend std::istream& operator>>(std::istream& is, String& s);
|
||||
|
||||
// String view functions
|
||||
String(StringView s);
|
||||
String(std::string_view s);
|
||||
|
||||
String& operator+=(StringView s);
|
||||
String& operator+=(std::string_view s);
|
||||
|
||||
private:
|
||||
int compare(size_t selfOffset,
|
||||
size_t selfLen,
|
||||
|
429
source/core/StarStringView.cpp
Normal file
429
source/core/StarStringView.cpp
Normal file
@ -0,0 +1,429 @@
|
||||
#include "StarStringView.hpp"
|
||||
|
||||
namespace Star {
|
||||
// To string
|
||||
String::String(StringView s) : m_string(s.utf8()) {}
|
||||
String::String(std::string_view s) : m_string(s) {}
|
||||
|
||||
String& String::operator+=(StringView s) {
|
||||
m_string += s.utf8();
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& String::operator+=(std::string_view s) {
|
||||
m_string += s;
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringView::StringView() {}
|
||||
StringView::StringView(StringView const& s) : m_view(s.m_view) {}
|
||||
StringView::StringView(StringView&& s) noexcept : m_view(move(s.m_view)) {};
|
||||
StringView::StringView(String const& s) : m_view(s.utf8()) {};
|
||||
StringView::StringView(char const* s) : m_view(s) {};
|
||||
StringView::StringView(char const* s, size_t n) : m_view(s, n) {};
|
||||
|
||||
StringView::StringView(std::string_view const& s) : m_view(s) {};
|
||||
StringView::StringView(std::string_view&& s) noexcept : m_view(move(s)) {};
|
||||
StringView::StringView(std::string const& s) : m_view(s) {}
|
||||
|
||||
StringView::StringView(Char const* s) : m_view((char const*)s, sizeof(*s)) {}
|
||||
StringView::StringView(Char const* s, size_t n) : m_view((char const*)s, n * sizeof(*s)) {};
|
||||
|
||||
std::string_view const& StringView::utf8() const {
|
||||
return m_view;
|
||||
}
|
||||
|
||||
std::string_view StringView::takeUtf8() {
|
||||
return take(m_view);
|
||||
}
|
||||
|
||||
ByteArray StringView::utf8Bytes() const {
|
||||
return ByteArray(m_view.data(), m_view.size());
|
||||
}
|
||||
|
||||
char const* StringView::utf8Ptr() const {
|
||||
return m_view.data();
|
||||
}
|
||||
|
||||
size_t StringView::utf8Size() const {
|
||||
return m_view.size();
|
||||
}
|
||||
|
||||
StringView::const_iterator StringView::begin() const {
|
||||
return const_iterator(m_view.begin());
|
||||
}
|
||||
|
||||
StringView::const_iterator StringView::end() const {
|
||||
return const_iterator(m_view.end());
|
||||
}
|
||||
|
||||
size_t StringView::size() const {
|
||||
return utf8Length(m_view.data(), m_view.size());
|
||||
}
|
||||
|
||||
size_t StringView::length() const {
|
||||
return size();
|
||||
}
|
||||
|
||||
bool StringView::empty() const {
|
||||
return m_view.empty();
|
||||
}
|
||||
|
||||
StringView::Char StringView::operator[](size_t index) const {
|
||||
auto it = begin();
|
||||
for (size_t i = 0; i < index; ++i)
|
||||
++it;
|
||||
return *it;
|
||||
}
|
||||
|
||||
StringView::Char StringView::at(size_t i) const {
|
||||
if (i > size())
|
||||
throw OutOfRangeException(strf("Out of range in StringView::at(%s)", i));
|
||||
return operator[](i);
|
||||
}
|
||||
|
||||
bool StringView::endsWith(StringView end, CaseSensitivity cs) const {
|
||||
auto endsize = end.size();
|
||||
if (endsize == 0)
|
||||
return true;
|
||||
|
||||
auto mysize = size();
|
||||
if (endsize > mysize)
|
||||
return false;
|
||||
|
||||
return compare(mysize - endsize, NPos, end, 0, NPos, cs) == 0;
|
||||
}
|
||||
bool StringView::endsWith(Char end, CaseSensitivity cs) const {
|
||||
if (size() == 0)
|
||||
return false;
|
||||
|
||||
return String::charEqual(end, operator[](size() - 1), cs);
|
||||
}
|
||||
|
||||
bool StringView::beginsWith(StringView beg, CaseSensitivity cs) const {
|
||||
auto begSize = beg.size();
|
||||
if (begSize == 0)
|
||||
return true;
|
||||
|
||||
auto mysize = size();
|
||||
if (begSize > mysize)
|
||||
return false;
|
||||
|
||||
return compare(0, begSize, beg, 0, NPos, cs) == 0;
|
||||
}
|
||||
|
||||
bool StringView::beginsWith(Char beg, CaseSensitivity cs) const {
|
||||
if (size() == 0)
|
||||
return false;
|
||||
|
||||
return String::charEqual(beg, operator[](0), cs);
|
||||
}
|
||||
|
||||
void StringView::forEachSplitAnyView(StringView chars, SplitCallback callback) const {
|
||||
if (chars.empty())
|
||||
return;
|
||||
|
||||
size_t beg = 0;
|
||||
while (true) {
|
||||
size_t end = m_view.find_first_of(chars.m_view, beg);
|
||||
if (end == NPos) {
|
||||
callback(m_view.substr(beg), beg, end);
|
||||
break;
|
||||
}
|
||||
callback(m_view.substr(beg, end - beg), beg, end - beg);
|
||||
beg = end + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void StringView::forEachSplitView(StringView pattern, SplitCallback callback) const {
|
||||
if (pattern.empty())
|
||||
return;
|
||||
|
||||
size_t beg = 0;
|
||||
while (true) {
|
||||
size_t end = m_view.find(pattern.m_view, beg);
|
||||
if (end == NPos) {
|
||||
callback(m_view.substr(beg), beg, end);
|
||||
break;
|
||||
}
|
||||
callback(m_view.substr(beg, end - beg), beg, end - beg);
|
||||
beg = end + pattern.m_view.size();
|
||||
}
|
||||
}
|
||||
|
||||
bool StringView::hasChar(Char c) const {
|
||||
for (Char ch : *this)
|
||||
if (ch == c)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StringView::hasCharOrWhitespace(Char c) const {
|
||||
return empty() ? String::isSpace(c) : hasChar(c);
|
||||
}
|
||||
|
||||
size_t StringView::find(Char c, size_t pos, CaseSensitivity cs) const {
|
||||
auto it = begin();
|
||||
for (size_t i = 0; i < pos; ++i) {
|
||||
if (it == end())
|
||||
break;
|
||||
++it;
|
||||
}
|
||||
|
||||
while (it != end()) {
|
||||
if (String::charEqual(c, *it, cs))
|
||||
return pos;
|
||||
++pos;
|
||||
++it;
|
||||
}
|
||||
|
||||
return NPos;
|
||||
}
|
||||
|
||||
size_t StringView::find(StringView str, size_t pos, CaseSensitivity cs) const {
|
||||
if (str.empty())
|
||||
return 0;
|
||||
|
||||
auto it = begin();
|
||||
for (size_t i = 0; i < pos; ++i) {
|
||||
if (it == end())
|
||||
break;
|
||||
++it;
|
||||
}
|
||||
|
||||
const_iterator sit = str.begin();
|
||||
const_iterator mit = it;
|
||||
while (it != end()) {
|
||||
if (String::charEqual(*sit, *mit, cs)) {
|
||||
do {
|
||||
++mit;
|
||||
++sit;
|
||||
if (sit == str.end())
|
||||
return pos;
|
||||
else if (mit == end())
|
||||
break;
|
||||
} while (String::charEqual(*sit, *mit, cs));
|
||||
sit = str.begin();
|
||||
}
|
||||
++pos;
|
||||
mit = ++it;
|
||||
}
|
||||
|
||||
return NPos;
|
||||
}
|
||||
|
||||
size_t StringView::findLast(Char c, CaseSensitivity cs) const {
|
||||
auto it = begin();
|
||||
|
||||
size_t found = NPos;
|
||||
size_t pos = 0;
|
||||
while (it != end()) {
|
||||
if (String::charEqual(c, *it, cs))
|
||||
found = pos;
|
||||
++pos;
|
||||
++it;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
size_t StringView::findLast(StringView str, CaseSensitivity cs) const {
|
||||
if (str.empty())
|
||||
return 0;
|
||||
|
||||
size_t pos = 0;
|
||||
auto it = begin();
|
||||
size_t result = NPos;
|
||||
const_iterator sit = str.begin();
|
||||
const_iterator mit = it;
|
||||
while (it != end()) {
|
||||
if (String::charEqual(*sit, *mit, cs)) {
|
||||
do {
|
||||
++mit;
|
||||
++sit;
|
||||
if (sit == str.end()) {
|
||||
result = pos;
|
||||
break;
|
||||
}
|
||||
if (mit == end())
|
||||
break;
|
||||
} while (String::charEqual(*sit, *mit, cs));
|
||||
sit = str.begin();
|
||||
}
|
||||
++pos;
|
||||
mit = ++it;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t StringView::findFirstOf(StringView pattern, size_t beg) const {
|
||||
auto it = begin();
|
||||
size_t i;
|
||||
for (i = 0; i < beg; ++i)
|
||||
++it;
|
||||
|
||||
while (it != end()) {
|
||||
if (pattern.hasCharOrWhitespace(*it))
|
||||
return i;
|
||||
++it;
|
||||
++i;
|
||||
}
|
||||
return NPos;
|
||||
}
|
||||
|
||||
size_t StringView::findFirstNotOf(StringView pattern, size_t beg) const {
|
||||
auto it = begin();
|
||||
size_t i;
|
||||
for (i = 0; i < beg; ++i)
|
||||
++it;
|
||||
|
||||
while (it != end()) {
|
||||
if (!pattern.hasCharOrWhitespace(*it))
|
||||
return i;
|
||||
++it;
|
||||
++i;
|
||||
}
|
||||
return NPos;
|
||||
}
|
||||
|
||||
size_t StringView::findNextBoundary(size_t index, bool backwards) const {
|
||||
starAssert(index <= size());
|
||||
if (!backwards && (index == size()))
|
||||
return index;
|
||||
if (backwards) {
|
||||
if (index == 0)
|
||||
return 0;
|
||||
index--;
|
||||
}
|
||||
Char c = this->at(index);
|
||||
while (!String::isSpace(c)) {
|
||||
if (backwards && (index == 0))
|
||||
return 0;
|
||||
index += backwards ? -1 : 1;
|
||||
if (index == size())
|
||||
return size();
|
||||
c = this->at(index);
|
||||
}
|
||||
while (String::isSpace(c)) {
|
||||
if (backwards && (index == 0))
|
||||
return 0;
|
||||
index += backwards ? -1 : 1;
|
||||
if (index == size())
|
||||
return size();
|
||||
c = this->at(index);
|
||||
}
|
||||
if (backwards && !(index == size()))
|
||||
return index + 1;
|
||||
return index;
|
||||
}
|
||||
|
||||
bool StringView::contains(StringView s, CaseSensitivity cs) const {
|
||||
return find(s, 0, cs) != NPos;
|
||||
}
|
||||
|
||||
int StringView::compare(StringView s, CaseSensitivity cs) const {
|
||||
if (cs == CaseSensitivity::CaseSensitive)
|
||||
return m_view.compare(s.m_view);
|
||||
else
|
||||
return compare(0, NPos, s, 0, NPos, cs);
|
||||
}
|
||||
|
||||
bool StringView::equals(StringView s, CaseSensitivity cs) const {
|
||||
return compare(s, cs) == 0;
|
||||
}
|
||||
|
||||
bool StringView::equalsIgnoreCase(StringView s) const {
|
||||
return compare(s, CaseSensitivity::CaseInsensitive) == 0;
|
||||
}
|
||||
|
||||
StringView StringView::substr(size_t position, size_t n) const {
|
||||
auto len = size();
|
||||
if (position > len)
|
||||
throw OutOfRangeException(strf("out of range in StringView::substr(%s, %s)", position, n));
|
||||
|
||||
if (position == 0 && n >= len)
|
||||
return *this;
|
||||
|
||||
String ret;
|
||||
ret.reserve(std::min(n, len - position));
|
||||
|
||||
auto it = begin();
|
||||
std::advance(it, position);
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (it == end())
|
||||
break;
|
||||
ret.append(*it);
|
||||
++it;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int StringView::compare(size_t selfOffset, size_t selfLen, StringView other,
|
||||
size_t otherOffset, size_t otherLen, CaseSensitivity cs) const {
|
||||
auto selfIt = begin();
|
||||
auto otherIt = other.begin();
|
||||
|
||||
while (selfOffset > 0 && selfIt != end()) {
|
||||
++selfIt;
|
||||
--selfOffset;
|
||||
}
|
||||
|
||||
while (otherOffset > 0 && otherIt != other.end()) {
|
||||
++otherIt;
|
||||
--otherLen;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if ((selfIt == end() || selfLen == 0) && (otherIt == other.end() || otherLen == 0))
|
||||
return 0;
|
||||
else if (selfIt == end() || selfLen == 0)
|
||||
return -1;
|
||||
else if (otherIt == other.end() || otherLen == 0)
|
||||
return 1;
|
||||
|
||||
auto c1 = *selfIt;
|
||||
auto c2 = *otherIt;
|
||||
|
||||
if (cs == CaseSensitivity::CaseInsensitive) {
|
||||
c1 = String::toLower(c1);
|
||||
c2 = String::toLower(c2);
|
||||
}
|
||||
|
||||
if (c1 < c2)
|
||||
return -1;
|
||||
else if (c2 < c1)
|
||||
return 1;
|
||||
|
||||
++selfIt;
|
||||
++otherIt;
|
||||
--selfLen;
|
||||
--otherLen;
|
||||
}
|
||||
}
|
||||
|
||||
StringView& StringView::operator=(StringView s) {
|
||||
m_view = s.m_view;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(StringView s1, StringView s2) {
|
||||
return s1.m_view == s2.m_view;
|
||||
}
|
||||
|
||||
bool operator!=(StringView s1, StringView s2) {
|
||||
return s1.m_view != s2.m_view;
|
||||
}
|
||||
|
||||
bool operator<(StringView s1, StringView s2) {
|
||||
return s1.m_view < s2.m_view;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, StringView& s) {
|
||||
os << s.utf8();
|
||||
return os;
|
||||
}
|
||||
|
||||
}
|
117
source/core/StarStringView.hpp
Normal file
117
source/core/StarStringView.hpp
Normal file
@ -0,0 +1,117 @@
|
||||
#ifndef STAR_STRING_VIEW_HPP
|
||||
#define STAR_STRING_VIEW_HPP
|
||||
|
||||
#include "StarString.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(StringView);
|
||||
STAR_CLASS(String);
|
||||
|
||||
// This is a StringView version of Star::String
|
||||
// I literally just copy-pasted it all from there
|
||||
class StringView {
|
||||
public:
|
||||
typedef String::Char Char;
|
||||
|
||||
typedef U8ToU32Iterator<std::string_view::const_iterator> const_iterator;
|
||||
typedef Char value_type;
|
||||
typedef value_type const& const_reference;
|
||||
|
||||
using CaseSensitivity = String::CaseSensitivity;
|
||||
|
||||
StringView();
|
||||
StringView(StringView const& s);
|
||||
StringView(StringView&& s) noexcept;
|
||||
StringView(String const& s);
|
||||
|
||||
// These assume utf8 input
|
||||
StringView(char const* s);
|
||||
StringView(char const* s, size_t n);
|
||||
StringView(std::string_view const& s);
|
||||
StringView(std::string_view&& s) noexcept;
|
||||
StringView(std::string const& s);
|
||||
|
||||
StringView(Char const* s);
|
||||
StringView(Char const* s, size_t n);
|
||||
|
||||
// const& to internal utf8 data
|
||||
std::string_view const& utf8() const;
|
||||
std::string_view takeUtf8();
|
||||
ByteArray utf8Bytes() const;
|
||||
// Pointer to internal utf8 data, null-terminated.
|
||||
char const* utf8Ptr() const;
|
||||
size_t utf8Size() const;
|
||||
|
||||
const_iterator begin() const;
|
||||
const_iterator end() const;
|
||||
|
||||
size_t size() const;
|
||||
size_t length() const;
|
||||
|
||||
bool empty() const;
|
||||
|
||||
Char operator[](size_t index) const;
|
||||
// Throws StringException if i out of range.
|
||||
Char at(size_t i) const;
|
||||
|
||||
bool endsWith(StringView end, CaseSensitivity cs = CaseSensitivity::CaseSensitive) const;
|
||||
bool endsWith(Char end, CaseSensitivity cs = CaseSensitivity::CaseSensitive) const;
|
||||
bool beginsWith(StringView beg, CaseSensitivity cs = CaseSensitivity::CaseSensitive) const;
|
||||
bool beginsWith(Char beg, CaseSensitivity cs = CaseSensitivity::CaseSensitive) const;
|
||||
|
||||
typedef function<void(StringView, size_t, size_t)> SplitCallback;
|
||||
void forEachSplitAnyView(StringView pattern, SplitCallback) const;
|
||||
void forEachSplitView(StringView pattern, SplitCallback) const;
|
||||
|
||||
bool hasChar(Char c) const;
|
||||
// Identical to hasChar, except, if string is empty, tests if c is
|
||||
// whitespace.
|
||||
bool hasCharOrWhitespace(Char c) const;
|
||||
|
||||
size_t find(Char c, size_t beg = 0, CaseSensitivity cs = CaseSensitivity::CaseSensitive) const;
|
||||
size_t find(StringView s, size_t beg = 0, CaseSensitivity cs = CaseSensitivity::CaseSensitive) const;
|
||||
size_t findLast(Char c, CaseSensitivity cs = CaseSensitivity::CaseSensitive) const;
|
||||
size_t findLast(StringView s, CaseSensitivity cs = CaseSensitivity::CaseSensitive) const;
|
||||
|
||||
// If pattern is empty, finds first whitespace
|
||||
size_t findFirstOf(StringView chars = "", size_t beg = 0) const;
|
||||
|
||||
// If pattern is empty, finds first non-whitespace
|
||||
size_t findFirstNotOf(StringView chars = "", size_t beg = 0) const;
|
||||
|
||||
// finds the the start of the next 'boundary' in a string. used for quickly
|
||||
// scanning a string
|
||||
size_t findNextBoundary(size_t index, bool backwards = false) const;
|
||||
|
||||
bool contains(StringView s, CaseSensitivity cs = CaseSensitivity::CaseSensitive) const;
|
||||
|
||||
int compare(StringView s, CaseSensitivity cs = CaseSensitivity::CaseSensitive) const;
|
||||
bool equals(StringView s, CaseSensitivity cs = CaseSensitivity::CaseSensitive) const;
|
||||
// Synonym for equals(s, String::CaseInsensitive)
|
||||
bool equalsIgnoreCase(StringView s) const;
|
||||
|
||||
StringView substr(size_t position, size_t n = NPos) const;
|
||||
|
||||
StringView& operator=(StringView s);
|
||||
|
||||
friend bool operator==(StringView s1, StringView s2);
|
||||
friend bool operator!=(StringView s1, StringView s2);
|
||||
friend bool operator<(StringView s1, StringView s2);
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, StringView& s);
|
||||
|
||||
private:
|
||||
int compare(size_t selfOffset,
|
||||
size_t selfLen,
|
||||
StringView other,
|
||||
size_t otherOffset,
|
||||
size_t otherLen,
|
||||
CaseSensitivity cs) const;
|
||||
|
||||
std::string_view m_view;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -500,3 +500,4 @@ SET (star_game_SOURCES
|
||||
)
|
||||
|
||||
ADD_LIBRARY (star_game OBJECT ${star_game_SOURCES} ${star_game_HEADERS})
|
||||
TARGET_PRECOMPILE_HEADERS (star_game REUSE_FROM star_core)
|
@ -71,15 +71,15 @@ Json HumanoidIdentity::toJson() const {
|
||||
{"gender", GenderNames.getRight(gender)},
|
||||
{"hairGroup", hairGroup},
|
||||
{"hairType", hairType},
|
||||
{"hairDirectives", hairDirectives.toString()},
|
||||
{"bodyDirectives", bodyDirectives.toString()},
|
||||
{"emoteDirectives", emoteDirectives.toString()},
|
||||
{"hairDirectives", hairDirectives.string()},
|
||||
{"bodyDirectives", bodyDirectives.string()},
|
||||
{"emoteDirectives", emoteDirectives.string()},
|
||||
{"facialHairGroup", facialHairGroup},
|
||||
{"facialHairType", facialHairType},
|
||||
{"facialHairDirectives", facialHairDirectives.toString()},
|
||||
{"facialHairDirectives", facialHairDirectives.string()},
|
||||
{"facialMaskGroup", facialMaskGroup},
|
||||
{"facialMaskType", facialMaskType},
|
||||
{"facialMaskDirectives", facialMaskDirectives.toString()},
|
||||
{"facialMaskDirectives", facialMaskDirectives.string()},
|
||||
{"personalityIdle", personality.idle},
|
||||
{"personalityArmIdle", personality.armIdle},
|
||||
{"personalityHeadOffset", jsonFromVec2F(personality.headOffset)},
|
||||
|
@ -120,20 +120,21 @@ RectU ImageMetadataDatabase::nonEmptyRegion(AssetPath const& path) const {
|
||||
AssetPath ImageMetadataDatabase::filterProcessing(AssetPath const& path) {
|
||||
AssetPath newPath = { path.basePath, path.subPath, {} };
|
||||
|
||||
List<Directives::Entry> filtered;
|
||||
path.directives.forEach([&](auto const& entry) {
|
||||
String filtered;
|
||||
path.directives.forEach([&](auto const& entry, Directives const& directives) {
|
||||
ImageOperation const& operation = entry.operation;
|
||||
if (!(operation.is<HueShiftImageOperation>() ||
|
||||
operation.is<SaturationShiftImageOperation>() ||
|
||||
operation.is<BrightnessMultiplyImageOperation>() ||
|
||||
operation.is<FadeToColorImageOperation>() ||
|
||||
operation.is<ScanLinesImageOperation>() ||
|
||||
operation.is<SetColorImageOperation>())) {
|
||||
filtered.emplace_back(entry);
|
||||
if (!(operation.is<HueShiftImageOperation>() ||
|
||||
operation.is<SaturationShiftImageOperation>() ||
|
||||
operation.is<BrightnessMultiplyImageOperation>() ||
|
||||
operation.is<FadeToColorImageOperation>() ||
|
||||
operation.is<ScanLinesImageOperation>() ||
|
||||
operation.is<SetColorImageOperation>())) {
|
||||
filtered += "?";
|
||||
filtered += entry.string(*directives.shared);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
newPath.directives.append(move(filtered));
|
||||
newPath.directives = move(filtered);
|
||||
return newPath;
|
||||
}
|
||||
|
||||
@ -230,7 +231,7 @@ Vec2U ImageMetadataDatabase::calculateImageSize(AssetPath const& path) const {
|
||||
|
||||
OperationSizeAdjust osa(imageSize);
|
||||
|
||||
bool complete = path.directives.forEachAbortable([&](auto const& entry) -> bool {
|
||||
bool complete = path.directives.forEachAbortable([&](auto const& entry, Directives const& directives) -> bool {
|
||||
entry.operation.call(osa);
|
||||
return !osa.hasError;
|
||||
});
|
||||
|
@ -41,7 +41,7 @@ ParallaxLayer::ParallaxLayer(Json const& store) : ParallaxLayer() {
|
||||
Json ParallaxLayer::store() const {
|
||||
return JsonObject{
|
||||
{"textures", jsonFromStringList(textures)},
|
||||
{"directives", directives.toString()},
|
||||
{"directives", directives.string()},
|
||||
{"parallaxValue", jsonFromVec2F(parallaxValue)},
|
||||
{"repeat", jsonFromVec2B(repeat)},
|
||||
{"tileLimitTop", jsonFromMaybe(tileLimitTop)},
|
||||
@ -59,11 +59,14 @@ Json ParallaxLayer::store() const {
|
||||
void ParallaxLayer::addImageDirectives(Directives const& newDirectives) {
|
||||
if (newDirectives) { // TODO: Move to Directives +=
|
||||
if (directives) {
|
||||
List<Directives::Entry> newEntries = *directives.entries;
|
||||
for (auto const& entry : *newDirectives.entries)
|
||||
newEntries.push_back(entry);
|
||||
String newString;
|
||||
|
||||
directives = move(newEntries);
|
||||
for (auto const& entry : newDirectives.shared->entries) {
|
||||
newString += "+";
|
||||
newString += entry.string(*newDirectives.shared);
|
||||
}
|
||||
|
||||
directives = move(newString);
|
||||
}
|
||||
else
|
||||
directives = newDirectives;
|
||||
|
Loading…
Reference in New Issue
Block a user