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 {};
|
return {};
|
||||||
StringMap<ImageConstPtr> references;
|
StringMap<ImageConstPtr> references;
|
||||||
StringList referencePaths;
|
StringList referencePaths;
|
||||||
path.directives.forEach([&](auto const& entry) {
|
path.directives.forEach([&](auto const& entry, Directives const& directives) {
|
||||||
addImageOperationReferences(entry.operation, referencePaths);
|
addImageOperationReferences(entry.operation, referencePaths);
|
||||||
}); // TODO: This can definitely be better, was changed quickly to support the new Directives.
|
}); // 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([&]() {
|
return unlockDuring([&]() {
|
||||||
auto newData = make_shared<ImageData>();
|
auto newData = make_shared<ImageData>();
|
||||||
Image newImage = *source->image;
|
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>())
|
if (auto error = entry.operation.ptr<ErrorImageOperation>())
|
||||||
std::rethrow_exception(error->exception);
|
std::rethrow_exception(error->exception);
|
||||||
else
|
else
|
||||||
|
@ -106,6 +106,7 @@ SET (star_core_HEADERS
|
|||||||
StarStaticRandom.hpp
|
StarStaticRandom.hpp
|
||||||
StarStaticVector.hpp
|
StarStaticVector.hpp
|
||||||
StarString.hpp
|
StarString.hpp
|
||||||
|
StarStringView.hpp
|
||||||
StarStrongTypedef.hpp
|
StarStrongTypedef.hpp
|
||||||
StarTcp.hpp
|
StarTcp.hpp
|
||||||
StarThread.hpp
|
StarThread.hpp
|
||||||
@ -163,6 +164,7 @@ SET (star_core_SOURCES
|
|||||||
StarShellParser.cpp
|
StarShellParser.cpp
|
||||||
StarSocket.cpp
|
StarSocket.cpp
|
||||||
StarString.cpp
|
StarString.cpp
|
||||||
|
StarStringView.cpp
|
||||||
StarTcp.cpp
|
StarTcp.cpp
|
||||||
StarThread.cpp
|
StarThread.cpp
|
||||||
StarTime.cpp
|
StarTime.cpp
|
||||||
|
@ -175,9 +175,9 @@ std::ostream& operator<<(std::ostream& os, AssetPath const& rhs) {
|
|||||||
os << *rhs.subPath;
|
os << *rhs.subPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
rhs.directives.forEach([&](auto const& entry) {
|
rhs.directives.forEach([&](auto const& entry, Directives const& directives) {
|
||||||
os << "?";
|
os << "?";
|
||||||
os << entry.string;
|
os << entry.string(*directives.shared);
|
||||||
});
|
});
|
||||||
|
|
||||||
return os;
|
return os;
|
||||||
|
@ -302,7 +302,7 @@ uint32_t Color::toUint32() const {
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color Color::fromHex(String const& s) {
|
Color Color::fromHex(StringView s) {
|
||||||
return Color::rgba(hexToVec4B(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;
|
Array<uint8_t, 4> cbytes;
|
||||||
|
|
||||||
if (s.utf8Size() == 3) {
|
if (s.utf8Size() == 3) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef STAR_COLOR_HPP
|
#ifndef STAR_COLOR_HPP
|
||||||
#define STAR_COLOR_HPP
|
#define STAR_COLOR_HPP
|
||||||
|
|
||||||
#include "StarString.hpp"
|
#include "StarStringView.hpp"
|
||||||
#include "StarVector.hpp"
|
#include "StarVector.hpp"
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
@ -58,7 +58,7 @@ public:
|
|||||||
static Color gray(uint8_t g);
|
static Color gray(uint8_t g);
|
||||||
|
|
||||||
// Only supports 8 bit color
|
// Only supports 8 bit color
|
||||||
static Color fromHex(String const& s);
|
static Color fromHex(StringView s);
|
||||||
|
|
||||||
// #AARRGGBB
|
// #AARRGGBB
|
||||||
static Color fromUint32(uint32_t v);
|
static Color fromUint32(uint32_t v);
|
||||||
@ -67,7 +67,7 @@ public:
|
|||||||
static Color temperature(float temp);
|
static Color temperature(float temp);
|
||||||
|
|
||||||
static Vec4B hueShiftVec4B(Vec4B color, float hue);
|
static Vec4B hueShiftVec4B(Vec4B color, float hue);
|
||||||
static Vec4B Color::hexToVec4B(String const& s);
|
static Vec4B Color::hexToVec4B(StringView s);
|
||||||
// Black
|
// Black
|
||||||
Color();
|
Color();
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#include "StarPch.hpp"
|
|
||||||
|
|
||||||
#ifndef STAR_CONFIG_HPP
|
#ifndef STAR_CONFIG_HPP
|
||||||
#define STAR_CONFIG_HPP
|
#define STAR_CONFIG_HPP
|
||||||
|
|
||||||
|
#include "StarPch.hpp"
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
// Some really common std namespace includes
|
// Some really common std namespace includes
|
||||||
|
@ -1,92 +1,125 @@
|
|||||||
|
#include "StarDirectives.hpp"
|
||||||
#include "StarImage.hpp"
|
#include "StarImage.hpp"
|
||||||
#include "StarImageProcessing.hpp"
|
#include "StarImageProcessing.hpp"
|
||||||
#include "StarDirectives.hpp"
|
|
||||||
#include "StarXXHash.hpp"
|
#include "StarXXHash.hpp"
|
||||||
#include "StarLogging.hpp"
|
#include "StarLogging.hpp"
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
Directives::Entry::Entry(ImageOperation&& newOperation, String&& newString) {
|
Directives::Entry::Entry(ImageOperation&& newOperation, size_t strBegin, size_t strLength) {
|
||||||
operation = move(newOperation);
|
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;
|
operation = newOperation;
|
||||||
string = newString;
|
begin = strBegin;
|
||||||
|
length = strLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directives::Entry::Entry(Entry const& other) {
|
Directives::Entry::Entry(Entry const& other) {
|
||||||
operation = other.operation;
|
operation = other.operation;
|
||||||
string = other.string;
|
begin = other.begin;
|
||||||
|
length = other.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directives::Directives() : hash(0) {}
|
StringView Directives::Entry::string(Shared const& parent) const {
|
||||||
Directives::Directives(String const& directives) : hash(0) {
|
StringView result(parent.string);
|
||||||
string = directives;
|
result = result.substr(begin, length);
|
||||||
parse(string);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directives::Directives(String&& directives) : hash(0) {
|
bool Directives::Shared::empty() const {
|
||||||
string = move(directives);
|
return entries.empty();
|
||||||
parse(string);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Directives::Directives(const char* directives) : hash(0), string(directives) {
|
Directives::Shared::Shared(List<Entry>&& givenEntries, String&& givenString) {
|
||||||
parse(string);
|
entries = move(givenEntries);
|
||||||
}
|
string = move(givenString);
|
||||||
|
|
||||||
Directives::Directives(List<Entry>&& newEntries) {
|
|
||||||
entries = std::make_shared<List<Entry> const>(move(newEntries));
|
|
||||||
String newString;
|
|
||||||
string = move(buildString(newString));
|
|
||||||
hash = XXH3_64bits(string.utf8Ptr(), string.utf8Size());
|
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())
|
if (directives.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
List<Entry> newList;
|
List<Entry> newList;
|
||||||
StringList split = directives.split('?');
|
|
||||||
newList.reserve(split.size());
|
StringView(directives).forEachSplitView("?", [&](StringView split, size_t beg, size_t end) {
|
||||||
for (String& str : split) {
|
if (!split.empty()) {
|
||||||
if (!str.empty()) {
|
|
||||||
try {
|
try {
|
||||||
ImageOperation operation = imageOperationFromString(str);
|
ImageOperation operation = imageOperationFromString(split);
|
||||||
newList.emplace_back(move(operation), move(str));
|
newList.emplace_back(move(operation), beg, end);
|
||||||
} catch (StarException const& e) {
|
}
|
||||||
newList.emplace_back(ErrorImageOperation{ std::current_exception() }, move(str));
|
catch (StarException const& e) {
|
||||||
|
newList.emplace_back(ErrorImageOperation{ std::current_exception() }, beg, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
if (newList.empty())
|
if (newList.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
entries = std::make_shared<List<Entry> const>(move(newList));
|
shared = std::make_shared<Shared const>(move(newList), move(directives));
|
||||||
hash = XXH3_64bits(directives.utf8Ptr(), directives.utf8Size());
|
|
||||||
//if (directives.utf8Size() > 1000)
|
|
||||||
// Logger::logf(LogLevel::Debug, "Directives: Parsed %u character long string", directives.utf8Size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String& Directives::buildString(String& out) const {
|
String Directives::string() const {
|
||||||
if (entries) {
|
if (!shared)
|
||||||
for (auto& entry : *entries) {
|
return "";
|
||||||
out += "?";
|
else
|
||||||
out += entry.string;
|
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;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
String Directives::toString() const {
|
size_t Directives::hash() const {
|
||||||
return string;
|
return shared ? shared->hash : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Directives::size() const {
|
||||||
|
return shared ? shared->entries.size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Directives::empty() const {
|
inline bool Directives::empty() const {
|
||||||
return !entries || entries->empty();
|
return !shared || shared->empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Directives::operator bool() const {
|
inline Directives::operator bool() const {
|
||||||
@ -98,13 +131,16 @@ DataStream& operator>>(DataStream& ds, Directives& directives) {
|
|||||||
String string;
|
String string;
|
||||||
ds.read(string);
|
ds.read(string);
|
||||||
|
|
||||||
directives.parse(string);
|
directives.parse(move(string));
|
||||||
|
|
||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataStream& operator<<(DataStream& ds, Directives const& directives) {
|
DataStream& operator<<(DataStream& ds, Directives const& directives) {
|
||||||
ds.write(directives.toString());
|
if (directives)
|
||||||
|
ds.write(directives.shared->string);
|
||||||
|
else
|
||||||
|
ds.write(String());
|
||||||
|
|
||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
@ -117,7 +153,7 @@ DirectivesGroup::DirectivesGroup(String const& directives) : m_count(0) {
|
|||||||
Directives parsed(directives);
|
Directives parsed(directives);
|
||||||
if (parsed) {
|
if (parsed) {
|
||||||
m_directives.emplace_back(move(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) {
|
DirectivesGroup::DirectivesGroup(String&& directives) : m_count(0) {
|
||||||
@ -129,7 +165,7 @@ DirectivesGroup::DirectivesGroup(String&& directives) : m_count(0) {
|
|||||||
Directives parsed(move(directives));
|
Directives parsed(move(directives));
|
||||||
if (parsed) {
|
if (parsed) {
|
||||||
m_directives.emplace_back(move(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) {
|
void DirectivesGroup::append(Directives const& directives) {
|
||||||
m_directives.emplace_back(directives);
|
m_directives.emplace_back(directives);
|
||||||
if (directives.entries)
|
m_count += m_directives.back().size();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectivesGroup::clear() {
|
void DirectivesGroup::clear() {
|
||||||
@ -181,23 +210,24 @@ inline String DirectivesGroup::toString() const {
|
|||||||
|
|
||||||
void DirectivesGroup::addToString(String& string) const {
|
void DirectivesGroup::addToString(String& string) const {
|
||||||
for (auto& directives : m_directives)
|
for (auto& directives : m_directives)
|
||||||
string += directives.string;
|
if (directives.shared)
|
||||||
|
string += directives.shared->string;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectivesGroup::forEach(DirectivesCallback callback) const {
|
void DirectivesGroup::forEach(DirectivesCallback callback) const {
|
||||||
for (auto& directives : m_directives) {
|
for (auto& directives : m_directives) {
|
||||||
if (directives.entries) {
|
if (directives.shared) {
|
||||||
for (auto& entry : *directives.entries)
|
for (auto& entry : directives.shared->entries)
|
||||||
callback(entry);
|
callback(entry, directives);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirectivesGroup::forEachAbortable(AbortableDirectivesCallback callback) const {
|
bool DirectivesGroup::forEachAbortable(AbortableDirectivesCallback callback) const {
|
||||||
for (auto& directives : m_directives) {
|
for (auto& directives : m_directives) {
|
||||||
if (directives.entries) {
|
if (directives.shared) {
|
||||||
for (auto& entry : *directives.entries) {
|
for (auto& entry : directives.shared->entries) {
|
||||||
if (!callback(entry))
|
if (!callback(entry, directives))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,7 +243,7 @@ inline Image DirectivesGroup::applyNewImage(Image const& image) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DirectivesGroup::applyExistingImage(Image& 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>())
|
if (auto error = entry.operation.ptr<ErrorImageOperation>())
|
||||||
std::rethrow_exception(error->exception);
|
std::rethrow_exception(error->exception);
|
||||||
else
|
else
|
||||||
@ -223,8 +253,10 @@ void DirectivesGroup::applyExistingImage(Image& image) const {
|
|||||||
|
|
||||||
inline size_t DirectivesGroup::hash() const {
|
inline size_t DirectivesGroup::hash() const {
|
||||||
XXHash3 hasher;
|
XXHash3 hasher;
|
||||||
for (auto& directives : m_directives)
|
for (auto& directives : m_directives) {
|
||||||
hasher.push((const char*)&directives.hash, sizeof(directives.hash));
|
size_t hash = directives.hash();
|
||||||
|
hasher.push((const char*)&hash, sizeof(hash));
|
||||||
|
}
|
||||||
|
|
||||||
return hasher.digest();
|
return hasher.digest();
|
||||||
}
|
}
|
||||||
@ -245,7 +277,7 @@ DataStream& operator>>(DataStream& ds, DirectivesGroup& directivesGroup) {
|
|||||||
String string;
|
String string;
|
||||||
ds.read(string);
|
ds.read(string);
|
||||||
|
|
||||||
directivesGroup = move(DirectivesGroup(move(string)));
|
directivesGroup = DirectivesGroup(move(string));
|
||||||
|
|
||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "StarImageProcessing.hpp"
|
#include "StarImageProcessing.hpp"
|
||||||
#include "StarHash.hpp"
|
#include "StarHash.hpp"
|
||||||
#include "StarDataStream.hpp"
|
#include "StarDataStream.hpp"
|
||||||
|
#include "StarStringView.hpp"
|
||||||
|
|
||||||
namespace Star {
|
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
|
// Kae: My attempt at reducing memory allocation and per-frame string parsing for extremely long directives
|
||||||
class Directives {
|
class Directives {
|
||||||
public:
|
public:
|
||||||
|
struct Shared;
|
||||||
struct Entry {
|
struct Entry {
|
||||||
ImageOperation operation;
|
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);
|
inline StringView string(Shared const& parent) const;
|
||||||
Entry(ImageOperation const& newOperation, String const& newString);
|
Entry(ImageOperation&& newOperation, size_t begin, size_t end);
|
||||||
|
Entry(ImageOperation const& newOperation, size_t begin, size_t end);
|
||||||
Entry(Entry const& other);
|
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();
|
||||||
Directives(String const& directives);
|
Directives(String const& directives);
|
||||||
Directives(String&& directives);
|
Directives(String&& directives);
|
||||||
Directives(const char* directives);
|
Directives(const char* directives);
|
||||||
Directives(List<Entry>&& entries);
|
|
||||||
|
|
||||||
void parse(String const& directives);
|
void parse(String&& directives);
|
||||||
String& buildString(String& out) const;
|
String string() const;
|
||||||
String toString() const;
|
String const* stringPtr() const;
|
||||||
|
String buildString() const;
|
||||||
|
String& addToString(String& out) const;
|
||||||
|
size_t hash() const;
|
||||||
|
size_t size() const;
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
|
|
||||||
friend DataStream& operator>>(DataStream& ds, Directives& directives);
|
friend DataStream& operator>>(DataStream& ds, Directives& directives);
|
||||||
friend DataStream& operator<<(DataStream& ds, Directives const& directives);
|
friend DataStream& operator<<(DataStream& ds, Directives const& directives);
|
||||||
|
|
||||||
std::shared_ptr<List<Entry> const> entries;
|
std::shared_ptr<Shared const> shared;
|
||||||
size_t hash = 0;
|
|
||||||
String string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DirectivesGroup {
|
class DirectivesGroup {
|
||||||
@ -49,13 +63,10 @@ public:
|
|||||||
DirectivesGroup(String const& directives);
|
DirectivesGroup(String const& directives);
|
||||||
DirectivesGroup(String&& directives);
|
DirectivesGroup(String&& directives);
|
||||||
|
|
||||||
void parseDirectivesIntoLeaf(String const& directives);
|
|
||||||
|
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
bool compare(DirectivesGroup const& other) const;
|
bool compare(DirectivesGroup const& other) const;
|
||||||
void append(Directives const& other);
|
void append(Directives const& other);
|
||||||
void append(List<Directives::Entry>&& entries);
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
DirectivesGroup& operator+=(Directives const& other);
|
DirectivesGroup& operator+=(Directives const& other);
|
||||||
@ -63,8 +74,8 @@ public:
|
|||||||
String toString() const;
|
String toString() const;
|
||||||
void addToString(String& string) const;
|
void addToString(String& string) const;
|
||||||
|
|
||||||
typedef function<void(Directives::Entry const&)> DirectivesCallback;
|
typedef function<void(Directives::Entry const&, Directives const&)> DirectivesCallback;
|
||||||
typedef function<bool(Directives::Entry const&)> AbortableDirectivesCallback;
|
typedef function<bool(Directives::Entry const&, Directives const&)> AbortableDirectivesCallback;
|
||||||
|
|
||||||
void forEach(DirectivesCallback callback) const;
|
void forEach(DirectivesCallback callback) const;
|
||||||
bool forEachAbortable(AbortableDirectivesCallback callback) const;
|
bool forEachAbortable(AbortableDirectivesCallback callback) const;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "StarLexicalCast.hpp"
|
#include "StarLexicalCast.hpp"
|
||||||
#include "StarColor.hpp"
|
#include "StarColor.hpp"
|
||||||
#include "StarImage.hpp"
|
#include "StarImage.hpp"
|
||||||
|
#include "StarStringView.hpp"
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
@ -145,9 +146,13 @@ FadeToColorImageOperation::FadeToColorImageOperation(Vec3B color, float amount)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageOperation imageOperationFromString(String const& string) {
|
ImageOperation imageOperationFromString(StringView string) {
|
||||||
try {
|
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);
|
String type = bits.at(0);
|
||||||
|
|
||||||
if (type == "hueshift") {
|
if (type == "hueshift") {
|
||||||
@ -184,7 +189,7 @@ ImageOperation imageOperationFromString(String const& string) {
|
|||||||
else
|
else
|
||||||
operation.mode = AlphaMaskImageOperation::Subtractive;
|
operation.mode = AlphaMaskImageOperation::Subtractive;
|
||||||
|
|
||||||
operation.maskImages = bits.at(1).split('+');
|
operation.maskImages = String(bits.at(1)).split('+');
|
||||||
|
|
||||||
if (bits.size() > 2)
|
if (bits.size() > 2)
|
||||||
operation.offset[0] = lexicalCast<int>(bits.at(2));
|
operation.offset[0] = lexicalCast<int>(bits.at(2));
|
||||||
@ -202,7 +207,7 @@ ImageOperation imageOperationFromString(String const& string) {
|
|||||||
else
|
else
|
||||||
operation.mode = BlendImageOperation::Screen;
|
operation.mode = BlendImageOperation::Screen;
|
||||||
|
|
||||||
operation.blendImages = bits.at(1).split('+');
|
operation.blendImages = String(bits.at(1)).split('+');
|
||||||
|
|
||||||
if (bits.size() > 2)
|
if (bits.size() > 2)
|
||||||
operation.offset[0] = lexicalCast<int>(bits.at(2));
|
operation.offset[0] = lexicalCast<int>(bits.at(2));
|
||||||
@ -328,22 +333,19 @@ String imageOperationToString(ImageOperation const& operation) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseImageOperations(String const& params, function<void(ImageOperation&&)> outputter) {
|
void parseImageOperations(StringView params, function<void(ImageOperation&&)> outputter) {
|
||||||
for (auto const& op : params.split('?')) {
|
params.forEachSplitView("?", [&](StringView op, size_t, size_t) {
|
||||||
if (!op.empty())
|
if (!op.empty())
|
||||||
outputter(imageOperationFromString(op));
|
outputter(imageOperationFromString(op));
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ImageOperation> parseImageOperations(String const& params) {
|
List<ImageOperation> parseImageOperations(StringView params) {
|
||||||
auto split = params.split('?');
|
|
||||||
List<ImageOperation> operations;
|
List<ImageOperation> operations;
|
||||||
operations.reserve(split.size());
|
params.forEachSplitView("?", [&](StringView op, size_t, size_t) {
|
||||||
|
|
||||||
for (auto const& op : split) {
|
|
||||||
if (!op.empty())
|
if (!op.empty())
|
||||||
operations.append(imageOperationFromString(op));
|
operations.append(imageOperationFromString(op));
|
||||||
}
|
});
|
||||||
|
|
||||||
return operations;
|
return operations;
|
||||||
}
|
}
|
||||||
|
@ -137,14 +137,14 @@ typedef Variant<ErrorImageOperation, HueShiftImageOperation, SaturationShiftImag
|
|||||||
ScanLinesImageOperation, SetColorImageOperation, ColorReplaceImageOperation, AlphaMaskImageOperation, BlendImageOperation,
|
ScanLinesImageOperation, SetColorImageOperation, ColorReplaceImageOperation, AlphaMaskImageOperation, BlendImageOperation,
|
||||||
MultiplyImageOperation, BorderImageOperation, ScaleImageOperation, CropImageOperation, FlipImageOperation> ImageOperation;
|
MultiplyImageOperation, BorderImageOperation, ScaleImageOperation, CropImageOperation, FlipImageOperation> ImageOperation;
|
||||||
|
|
||||||
ImageOperation imageOperationFromString(String const& string);
|
ImageOperation imageOperationFromString(StringView string);
|
||||||
String imageOperationToString(ImageOperation const& operation);
|
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
|
// Each operation is assumed to be separated by '?', with parameters
|
||||||
// separated by ';' or '='
|
// separated by ';' or '='
|
||||||
List<ImageOperation> parseImageOperations(String const& params);
|
List<ImageOperation> parseImageOperations(StringView params);
|
||||||
|
|
||||||
// Each operation separated by '?', returns string with leading '?'
|
// Each operation separated by '?', returns string with leading '?'
|
||||||
String printImageOperations(List<ImageOperation> const& operations);
|
String printImageOperations(List<ImageOperation> const& operations);
|
||||||
|
@ -378,8 +378,10 @@ List<Directives> jsonToDirectivesList(Json const& v) {
|
|||||||
|
|
||||||
Json jsonFromDirectivesList(List<Directives> const& v) {
|
Json jsonFromDirectivesList(List<Directives> const& v) {
|
||||||
JsonArray result;
|
JsonArray result;
|
||||||
for (auto& e : v)
|
for (auto& e : v) {
|
||||||
result.push_back(e.toString());
|
if (e)
|
||||||
|
result.push_back(*e.stringPtr());
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define STAR_LEXICAL_CAST_HPP
|
#define STAR_LEXICAL_CAST_HPP
|
||||||
|
|
||||||
#include "StarString.hpp"
|
#include "StarString.hpp"
|
||||||
|
#include "StarStringView.hpp"
|
||||||
#include "StarMaybe.hpp"
|
#include "StarMaybe.hpp"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@ -14,9 +15,9 @@ STAR_EXCEPTION(BadLexicalCast, StarException);
|
|||||||
// Very simple basic lexical cast using stream input. Always operates in the
|
// Very simple basic lexical cast using stream input. Always operates in the
|
||||||
// "C" locale.
|
// "C" locale.
|
||||||
template <typename Type>
|
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;
|
Type result;
|
||||||
std::istringstream stream(s);
|
std::istringstream stream(std::string(s.utf8()));
|
||||||
stream.flags(flags);
|
stream.flags(flags);
|
||||||
stream.imbue(std::locale::classic());
|
stream.imbue(std::locale::classic());
|
||||||
|
|
||||||
@ -28,21 +29,11 @@ Maybe<Type> maybeLexicalCast(std::string const& s, std::ios_base::fmtflags flags
|
|||||||
if (stream >> ch)
|
if (stream >> ch)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
return result;
|
return move(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
Maybe<Type> maybeLexicalCast(char const* s, std::ios_base::fmtflags flags = std::ios_base::boolalpha) {
|
Type lexicalCast(StringView 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) {
|
|
||||||
auto m = maybeLexicalCast<Type>(s, flags);
|
auto m = maybeLexicalCast<Type>(s, flags);
|
||||||
if (m)
|
if (m)
|
||||||
return m.take();
|
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));
|
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>
|
template <class Type>
|
||||||
std::string toString(Type const& t, std::ios_base::fmtflags flags = std::ios_base::boolalpha) {
|
std::string toString(Type const& t, std::ios_base::fmtflags flags = std::ios_base::boolalpha) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -12,6 +12,7 @@ namespace Star {
|
|||||||
|
|
||||||
STAR_CLASS(StringList);
|
STAR_CLASS(StringList);
|
||||||
STAR_CLASS(String);
|
STAR_CLASS(String);
|
||||||
|
STAR_CLASS(StringView);
|
||||||
|
|
||||||
STAR_EXCEPTION(StringException, StarException);
|
STAR_EXCEPTION(StringException, StarException);
|
||||||
|
|
||||||
@ -268,6 +269,13 @@ public:
|
|||||||
friend std::ostream& operator<<(std::ostream& os, String const& s);
|
friend std::ostream& operator<<(std::ostream& os, String const& s);
|
||||||
friend std::istream& operator>>(std::istream& is, String& 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:
|
private:
|
||||||
int compare(size_t selfOffset,
|
int compare(size_t selfOffset,
|
||||||
size_t selfLen,
|
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})
|
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)},
|
{"gender", GenderNames.getRight(gender)},
|
||||||
{"hairGroup", hairGroup},
|
{"hairGroup", hairGroup},
|
||||||
{"hairType", hairType},
|
{"hairType", hairType},
|
||||||
{"hairDirectives", hairDirectives.toString()},
|
{"hairDirectives", hairDirectives.string()},
|
||||||
{"bodyDirectives", bodyDirectives.toString()},
|
{"bodyDirectives", bodyDirectives.string()},
|
||||||
{"emoteDirectives", emoteDirectives.toString()},
|
{"emoteDirectives", emoteDirectives.string()},
|
||||||
{"facialHairGroup", facialHairGroup},
|
{"facialHairGroup", facialHairGroup},
|
||||||
{"facialHairType", facialHairType},
|
{"facialHairType", facialHairType},
|
||||||
{"facialHairDirectives", facialHairDirectives.toString()},
|
{"facialHairDirectives", facialHairDirectives.string()},
|
||||||
{"facialMaskGroup", facialMaskGroup},
|
{"facialMaskGroup", facialMaskGroup},
|
||||||
{"facialMaskType", facialMaskType},
|
{"facialMaskType", facialMaskType},
|
||||||
{"facialMaskDirectives", facialMaskDirectives.toString()},
|
{"facialMaskDirectives", facialMaskDirectives.string()},
|
||||||
{"personalityIdle", personality.idle},
|
{"personalityIdle", personality.idle},
|
||||||
{"personalityArmIdle", personality.armIdle},
|
{"personalityArmIdle", personality.armIdle},
|
||||||
{"personalityHeadOffset", jsonFromVec2F(personality.headOffset)},
|
{"personalityHeadOffset", jsonFromVec2F(personality.headOffset)},
|
||||||
|
@ -120,20 +120,21 @@ RectU ImageMetadataDatabase::nonEmptyRegion(AssetPath const& path) const {
|
|||||||
AssetPath ImageMetadataDatabase::filterProcessing(AssetPath const& path) {
|
AssetPath ImageMetadataDatabase::filterProcessing(AssetPath const& path) {
|
||||||
AssetPath newPath = { path.basePath, path.subPath, {} };
|
AssetPath newPath = { path.basePath, path.subPath, {} };
|
||||||
|
|
||||||
List<Directives::Entry> filtered;
|
String filtered;
|
||||||
path.directives.forEach([&](auto const& entry) {
|
path.directives.forEach([&](auto const& entry, Directives const& directives) {
|
||||||
ImageOperation const& operation = entry.operation;
|
ImageOperation const& operation = entry.operation;
|
||||||
if (!(operation.is<HueShiftImageOperation>() ||
|
if (!(operation.is<HueShiftImageOperation>() ||
|
||||||
operation.is<SaturationShiftImageOperation>() ||
|
operation.is<SaturationShiftImageOperation>() ||
|
||||||
operation.is<BrightnessMultiplyImageOperation>() ||
|
operation.is<BrightnessMultiplyImageOperation>() ||
|
||||||
operation.is<FadeToColorImageOperation>() ||
|
operation.is<FadeToColorImageOperation>() ||
|
||||||
operation.is<ScanLinesImageOperation>() ||
|
operation.is<ScanLinesImageOperation>() ||
|
||||||
operation.is<SetColorImageOperation>())) {
|
operation.is<SetColorImageOperation>())) {
|
||||||
filtered.emplace_back(entry);
|
filtered += "?";
|
||||||
|
filtered += entry.string(*directives.shared);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
newPath.directives.append(move(filtered));
|
newPath.directives = move(filtered);
|
||||||
return newPath;
|
return newPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +231,7 @@ Vec2U ImageMetadataDatabase::calculateImageSize(AssetPath const& path) const {
|
|||||||
|
|
||||||
OperationSizeAdjust osa(imageSize);
|
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);
|
entry.operation.call(osa);
|
||||||
return !osa.hasError;
|
return !osa.hasError;
|
||||||
});
|
});
|
||||||
|
@ -41,7 +41,7 @@ ParallaxLayer::ParallaxLayer(Json const& store) : ParallaxLayer() {
|
|||||||
Json ParallaxLayer::store() const {
|
Json ParallaxLayer::store() const {
|
||||||
return JsonObject{
|
return JsonObject{
|
||||||
{"textures", jsonFromStringList(textures)},
|
{"textures", jsonFromStringList(textures)},
|
||||||
{"directives", directives.toString()},
|
{"directives", directives.string()},
|
||||||
{"parallaxValue", jsonFromVec2F(parallaxValue)},
|
{"parallaxValue", jsonFromVec2F(parallaxValue)},
|
||||||
{"repeat", jsonFromVec2B(repeat)},
|
{"repeat", jsonFromVec2B(repeat)},
|
||||||
{"tileLimitTop", jsonFromMaybe(tileLimitTop)},
|
{"tileLimitTop", jsonFromMaybe(tileLimitTop)},
|
||||||
@ -59,11 +59,14 @@ Json ParallaxLayer::store() const {
|
|||||||
void ParallaxLayer::addImageDirectives(Directives const& newDirectives) {
|
void ParallaxLayer::addImageDirectives(Directives const& newDirectives) {
|
||||||
if (newDirectives) { // TODO: Move to Directives +=
|
if (newDirectives) { // TODO: Move to Directives +=
|
||||||
if (directives) {
|
if (directives) {
|
||||||
List<Directives::Entry> newEntries = *directives.entries;
|
String newString;
|
||||||
for (auto const& entry : *newDirectives.entries)
|
|
||||||
newEntries.push_back(entry);
|
|
||||||
|
|
||||||
directives = move(newEntries);
|
for (auto const& entry : newDirectives.shared->entries) {
|
||||||
|
newString += "+";
|
||||||
|
newString += entry.string(*newDirectives.shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
directives = move(newString);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
directives = newDirectives;
|
directives = newDirectives;
|
||||||
|
Loading…
Reference in New Issue
Block a user