remove all uses of std::string in filament
- libbackend (except webgpu) - libfilament - libutils std::string generates a lot of code bloat, we use CString instead. We also update CString to be more compatible with std::string's api.
This commit is contained in:
committed by
Mathias Agopian
parent
1c2fe0ce39
commit
d3ff60af21
@@ -57,7 +57,7 @@ static void printParameterPack(io::ostream& out, const FIRST& first, const REMAI
|
||||
printParameterPack(out, rest...);
|
||||
}
|
||||
|
||||
static UTILS_NOINLINE UTILS_UNUSED std::string extractMethodName(std::string& command) noexcept {
|
||||
static UTILS_NOINLINE UTILS_UNUSED std::string_view extractMethodName(std::string_view command) noexcept {
|
||||
constexpr const char startPattern[] = "::Command<&filament::backend::Driver::";
|
||||
auto pos = command.rfind(startPattern);
|
||||
auto end = command.rfind('(');
|
||||
@@ -133,9 +133,9 @@ template<std::size_t... I>
|
||||
void CommandType<void (Driver::*)(ARGS...)>::Command<METHOD>::log(std::index_sequence<I...>) noexcept {
|
||||
#if DEBUG_COMMAND_STREAM
|
||||
static_assert(UTILS_HAS_RTTI, "DEBUG_COMMAND_STREAM can only be used with RTTI");
|
||||
std::string command = utils::CallStack::demangleTypeName(typeid(Command).name()).c_str();
|
||||
DLOG(INFO) << extractMethodName(command) << " : size=" << sizeof(Command);
|
||||
utils::io::sstream parameterPack;
|
||||
CString command = CallStack::demangleTypeName(typeid(Command).name());
|
||||
DLOG(INFO) << extractMethodName({command.data(), command.size()}) << " : size=" << sizeof(Command);
|
||||
io::sstream parameterPack;
|
||||
printParameterPack(parameterPack, std::get<I>(mArgs)...);
|
||||
DLOG(INFO) << "\t" << parameterPack.c_str();
|
||||
#endif
|
||||
@@ -164,7 +164,7 @@ void CommandType<void (Driver::*)(ARGS...)>::Command<METHOD>::log() noexcept {
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
void CustomCommand::execute(Driver&, CommandBase* base, intptr_t* next) {
|
||||
*next = CustomCommand::align(sizeof(CustomCommand));
|
||||
*next = align(sizeof(CustomCommand));
|
||||
static_cast<CustomCommand*>(base)->mCommand();
|
||||
static_cast<CustomCommand*>(base)->~CustomCommand();
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
# include <string>
|
||||
# include <utils/CString.h>
|
||||
# include <string_view>
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
@@ -36,11 +37,11 @@ static char const * const kOurNamespace = "filament::backend::";
|
||||
|
||||
// removes all occurrences of "what" from "str"
|
||||
UTILS_NOINLINE
|
||||
static std::string& removeAll(std::string& str, const std::string& what) noexcept {
|
||||
static CString& removeAll(CString& str, const std::string_view what) noexcept {
|
||||
if (!what.empty()) {
|
||||
const std::string empty;
|
||||
const CString empty;
|
||||
size_t pos = 0;
|
||||
while ((pos = str.find(what, pos)) != std::string::npos) {
|
||||
while ((pos = std::string_view{ str.data(), str.size() }.find(what, pos)) != std::string_view::npos) {
|
||||
str.replace(pos, what.length(), empty);
|
||||
}
|
||||
}
|
||||
@@ -49,13 +50,13 @@ static std::string& removeAll(std::string& str, const std::string& what) noexcep
|
||||
|
||||
template <typename T>
|
||||
UTILS_NOINLINE
|
||||
static io::ostream& logHandle(io::ostream& out, std::string& typeName, T id) noexcept {
|
||||
static io::ostream& logHandle(io::ostream& out, CString& typeName, T id) noexcept {
|
||||
return out << removeAll(typeName, kOurNamespace) << " @ " << id;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
io::ostream& operator<<(io::ostream& out, const Handle<T>& h) noexcept {
|
||||
std::string s(CallStack::typeName<Handle<T>>().c_str());
|
||||
CString s{ CallStack::typeName<Handle<T>>() };
|
||||
return logHandle(out, s, h.getId());
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
#include <cctype>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
@@ -67,9 +66,9 @@ constexpr uint32_t MAX_NUM_SYNCHRONOUS_PROGRAMS_PER_FRAME = 1;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
static std::string to_string(bool const b) { return b ? "true" : "false"; }
|
||||
static std::string to_string(int const i) { return std::to_string(i); }
|
||||
static std::string to_string(float const f) { return "float(" + std::to_string(f) + ")"; }
|
||||
static CString to_string(bool const b) { return CString{ b ? "true" : "false" }; }
|
||||
static CString to_string(int const i) { return utils::to_string(i); }
|
||||
static CString to_string(float const f) { return "float(" + utils::to_string(f) + ")"; }
|
||||
|
||||
static void logCompilationError(ShaderStage shaderType, const char* name, GLuint shaderId,
|
||||
Program::ShaderBlob const& sourceCode) noexcept;
|
||||
@@ -696,14 +695,14 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
|
||||
bool multiview, program_token_t const& token) noexcept {
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
auto const appendSpecConstantString = +[](std::string& s, Program::SpecializationConstant const& sc) {
|
||||
s += "#define SPIRV_CROSS_CONSTANT_ID_" + std::to_string(sc.id) + ' ';
|
||||
auto const appendSpecConstantString = +[](CString& s, Program::SpecializationConstant const& sc) {
|
||||
s += "#define SPIRV_CROSS_CONSTANT_ID_" + utils::to_string(sc.id) + ' ';
|
||||
s += std::visit([](auto&& arg) { return to_string(arg); }, sc.value);
|
||||
s += '\n';
|
||||
return s;
|
||||
};
|
||||
|
||||
std::string specializationConstantString;
|
||||
CString specializationConstantString;
|
||||
int32_t numViews = 2;
|
||||
for (auto const& sc: specializationConstants) {
|
||||
appendSpecConstantString(specializationConstantString, sc);
|
||||
@@ -766,8 +765,10 @@ void ShaderCompilerService::cancelPendingSynchronousProgram(program_token_t cons
|
||||
}
|
||||
|
||||
std::array<std::string_view, 5> sources = {
|
||||
version, prolog, specializationConstantString, packingFunctions,
|
||||
{ body.data(), body.size() - 1 }// null-terminated
|
||||
version, prolog,
|
||||
{ specializationConstantString.data(), specializationConstantString.size() },
|
||||
packingFunctions,
|
||||
{ body.data(), body.size() - 1 } // null-terminated
|
||||
};
|
||||
|
||||
// Some of the sources may be zero-length. Remove them as to avoid passing lengths of
|
||||
@@ -966,16 +967,18 @@ UTILS_NOINLINE
|
||||
sourceCode.size() };
|
||||
size_t lc = 1;
|
||||
size_t start = 0;
|
||||
std::string line;
|
||||
CString line;
|
||||
while (true) {
|
||||
size_t const end = shader.find('\n', start);
|
||||
if (end == std::string::npos) {
|
||||
line = shader.substr(start);
|
||||
if (end == std::string_view::npos) {
|
||||
auto sv = shader.substr(start);
|
||||
line = { sv.data(), sv.size() };
|
||||
} else {
|
||||
line = shader.substr(start, end - start);
|
||||
auto sv = shader.substr(start, end - start);
|
||||
line = { sv.data(), sv.size() };
|
||||
}
|
||||
LOG(ERROR) << lc++ << ": " << line.c_str();
|
||||
if (end == std::string::npos) {
|
||||
if (end == std::string_view::npos) {
|
||||
break;
|
||||
}
|
||||
start = end + 1;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "VulkanConstants.h"
|
||||
#include "VulkanContext.h"
|
||||
|
||||
#include <utils/CString.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/debug.h>
|
||||
@@ -57,26 +58,26 @@ VkCommandBuffer createCommandBuffer(VkDevice device, VkCommandPool pool) {
|
||||
} // anonymous namespace
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
void VulkanGroupMarkers::push(std::string const& marker, Timestamp start) noexcept {
|
||||
void VulkanGroupMarkers::push(CString const& marker, Timestamp start) noexcept {
|
||||
mMarkers.push_back({marker,
|
||||
start.time_since_epoch().count() > 0.0
|
||||
? start
|
||||
: std::chrono::high_resolution_clock::now()});
|
||||
}
|
||||
|
||||
std::pair<std::string, Timestamp> VulkanGroupMarkers::pop() noexcept {
|
||||
std::pair<CString, Timestamp> VulkanGroupMarkers::pop() noexcept {
|
||||
auto ret = mMarkers.back();
|
||||
mMarkers.pop_back();
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::pair<std::string, Timestamp> VulkanGroupMarkers::pop_bottom() noexcept {
|
||||
std::pair<CString, Timestamp> VulkanGroupMarkers::pop_bottom() noexcept {
|
||||
auto ret = mMarkers.front();
|
||||
mMarkers.pop_front();
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::pair<std::string, Timestamp> const& VulkanGroupMarkers::top() const {
|
||||
std::pair<CString, Timestamp> const& VulkanGroupMarkers::top() const {
|
||||
assert_invariant(!empty());
|
||||
return mMarkers.back();
|
||||
}
|
||||
@@ -353,7 +354,7 @@ void CommandBufferPool::waitFor(VkSemaphore previousAction, VkPipelineStageFlags
|
||||
}
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
std::string CommandBufferPool::topMarker() const {
|
||||
CString CommandBufferPool::topMarker() const {
|
||||
if (!mGroupMarkers || mGroupMarkers->empty()) {
|
||||
return "";
|
||||
}
|
||||
@@ -364,11 +365,11 @@ void CommandBufferPool::pushMarker(char const* marker, VulkanGroupMarkers::Times
|
||||
if (!mGroupMarkers) {
|
||||
mGroupMarkers = std::make_unique<VulkanGroupMarkers>();
|
||||
}
|
||||
mGroupMarkers->push(marker, timestamp);
|
||||
mGroupMarkers->push(CString{ marker }, timestamp);
|
||||
getRecording().pushMarker(marker);
|
||||
}
|
||||
|
||||
std::pair<std::string, VulkanGroupMarkers::Timestamp> CommandBufferPool::popMarker() {
|
||||
std::pair<CString, VulkanGroupMarkers::Timestamp> CommandBufferPool::popMarker() {
|
||||
assert_invariant(mGroupMarkers && !mGroupMarkers->empty());
|
||||
auto ret = mGroupMarkers->pop();
|
||||
|
||||
@@ -528,7 +529,7 @@ void VulkanCommands::insertEventMarker(char const* str, uint32_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string VulkanCommands::getTopGroupMarker() const {
|
||||
CString VulkanCommands::getTopGroupMarker() const {
|
||||
if (mProtectedPool) {
|
||||
return mProtectedPool->topMarker();
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "vulkan/utils/StaticVector.h"
|
||||
|
||||
#include <utils/Condition.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Mutex.h>
|
||||
|
||||
@@ -35,7 +36,6 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace filament::backend {
|
||||
@@ -47,14 +47,14 @@ class VulkanGroupMarkers {
|
||||
public:
|
||||
using Timestamp = std::chrono::time_point<std::chrono::high_resolution_clock>;
|
||||
|
||||
void push(std::string const& marker, Timestamp start = {}) noexcept;
|
||||
std::pair<std::string, Timestamp> pop() noexcept;
|
||||
std::pair<std::string, Timestamp> pop_bottom() noexcept;
|
||||
std::pair<std::string, Timestamp> const& top() const;
|
||||
void push(utils::CString const& marker, Timestamp start = {}) noexcept;
|
||||
std::pair<utils::CString, Timestamp> pop() noexcept;
|
||||
std::pair<utils::CString, Timestamp> pop_bottom() noexcept;
|
||||
std::pair<utils::CString, Timestamp> const& top() const;
|
||||
bool empty() const noexcept;
|
||||
|
||||
private:
|
||||
std::list<std::pair<std::string, Timestamp>> mMarkers;
|
||||
std::list<std::pair<utils::CString, Timestamp>> mMarkers;
|
||||
};
|
||||
|
||||
#endif // FVK_DEBUG_GROUP_MARKERS
|
||||
@@ -148,9 +148,9 @@ struct CommandBufferPool {
|
||||
void waitFor(VkSemaphore previousAction, VkPipelineStageFlags waitStage);
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
|
||||
std::string topMarker() const;
|
||||
utils::CString topMarker() const;
|
||||
void pushMarker(char const* marker, VulkanGroupMarkers::Timestamp timestamp);
|
||||
std::pair<std::string, VulkanGroupMarkers::Timestamp> popMarker();
|
||||
std::pair<utils::CString, VulkanGroupMarkers::Timestamp> popMarker();
|
||||
void insertEvent(char const* marker);
|
||||
#endif
|
||||
|
||||
@@ -249,7 +249,7 @@ public:
|
||||
void pushGroupMarker(char const* str, VulkanGroupMarkers::Timestamp timestamp = {});
|
||||
void popGroupMarker();
|
||||
void insertEventMarker(char const* string, uint32_t len);
|
||||
std::string getTopGroupMarker() const;
|
||||
utils::CString getTopGroupMarker() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <utils/compiler.h> // UTILS_FALLTHROUGH
|
||||
#include <utils/Panic.h> // ASSERT_POSTCONDITION
|
||||
#include <utils/CString.h>
|
||||
|
||||
using namespace bluevk;
|
||||
|
||||
@@ -285,7 +286,7 @@ VulkanProgram::VulkanProgram(VkDevice device, Program const& builder) noexcept
|
||||
<< " error=" << static_cast<int32_t>(result);
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
|
||||
std::string name{ builder.getName().c_str(), builder.getName().size() };
|
||||
utils::CString name{ builder.getName().c_str(), builder.getName().size() };
|
||||
switch (static_cast<ShaderStage>(i)) {
|
||||
case ShaderStage::VERTEX:
|
||||
name += "_vs";
|
||||
|
||||
@@ -95,7 +95,7 @@ ResourceType getTypeEnum() noexcept {
|
||||
return ResourceType::UNDEFINED_TYPE;
|
||||
}
|
||||
|
||||
std::string getTypeStr(ResourceType type) {
|
||||
std::string_view getTypeStr(ResourceType type) {
|
||||
switch (type) {
|
||||
case ResourceType::BUFFER_OBJECT:
|
||||
return "BufferObject";
|
||||
|
||||
@@ -58,7 +58,7 @@ enum class ResourceType : uint8_t {
|
||||
template<typename D>
|
||||
ResourceType getTypeEnum() noexcept;
|
||||
|
||||
std::string getTypeStr(ResourceType type);
|
||||
std::string_view getTypeStr(ResourceType type);
|
||||
|
||||
inline bool isThreadSafeType(ResourceType type) {
|
||||
return type == ResourceType::FENCE || type == ResourceType::TIMER_QUERY;
|
||||
|
||||
@@ -86,9 +86,9 @@ static std::unique_ptr<MaterialParser> createParser(Backend const backend,
|
||||
MaterialParser::ParseResult const materialResult = materialParser->parse();
|
||||
|
||||
if (UTILS_UNLIKELY(materialResult == MaterialParser::ParseResult::ERROR_MISSING_BACKEND)) {
|
||||
std::string languageNames;
|
||||
CString languageNames;
|
||||
for (auto it = languages.begin(); it != languages.end(); ++it) {
|
||||
languageNames.append(shaderLanguageToString(*it));
|
||||
languageNames.append(CString{shaderLanguageToString(*it)});
|
||||
if (std::next(it) != languages.end()) {
|
||||
languageNames.append(", ");
|
||||
}
|
||||
|
||||
@@ -18,7 +18,13 @@
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <cstdint>
|
||||
|
||||
namespace filament {
|
||||
|
||||
@@ -254,25 +260,23 @@ char const* DependencyGraph::Node::getName() const noexcept {
|
||||
|
||||
utils::CString DependencyGraph::Node::graphvizify() const noexcept {
|
||||
#ifndef NDEBUG
|
||||
std::string s;
|
||||
s.reserve(128);
|
||||
utils::CString s;
|
||||
|
||||
uint32_t id = getId();
|
||||
uint32_t const id = getId();
|
||||
const char* const nodeName = getName();
|
||||
uint32_t const refCount = getRefCount();
|
||||
|
||||
s.append("[label=\"");
|
||||
s.append(nodeName);
|
||||
s.append("\\nrefs: ");
|
||||
s.append(std::to_string(refCount));
|
||||
s.append(utils::to_string(refCount));
|
||||
s.append(", id: ");
|
||||
s.append(std::to_string(id));
|
||||
s.append(utils::to_string(id));
|
||||
s.append("\", style=filled, fillcolor=");
|
||||
s.append(refCount ? "skyblue" : "skyblue4");
|
||||
s.append("]");
|
||||
s.shrink_to_fit();
|
||||
|
||||
return utils::CString{ s.c_str() };
|
||||
return s;
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
|
||||
@@ -547,21 +547,16 @@ fgviewer::FrameGraphInfo FrameGraph::getFrameGraphInfo(const char *viewName) con
|
||||
// resource type so it works
|
||||
auto descriptor = static_cast<Resource<FrameGraphTexture> const*>(
|
||||
getResource(resourceHandle))->descriptor;
|
||||
emplace_resource_property("width",
|
||||
utils::CString(std::to_string(descriptor.width).data()));
|
||||
emplace_resource_property("height",
|
||||
utils::CString(std::to_string(descriptor.height).data()));
|
||||
emplace_resource_property("depth",
|
||||
utils::CString(std::to_string(descriptor.depth).data()));
|
||||
emplace_resource_property("format",
|
||||
utils::to_string(descriptor.format));
|
||||
emplace_resource_property("width", utils::to_string(descriptor.width));
|
||||
emplace_resource_property("height", utils::to_string(descriptor.height));
|
||||
emplace_resource_property("depth", utils::to_string(descriptor.depth));
|
||||
emplace_resource_property("format", utils::to_string(descriptor.format));
|
||||
|
||||
};
|
||||
|
||||
if (resourceNode->getParentNode() != nullptr) {
|
||||
emplace_resource_property("is_subresource_of",
|
||||
utils::CString(std::to_string(
|
||||
resourceNode->getParentHandle().index).data()));
|
||||
utils::to_string(resourceNode->getParentHandle().index));
|
||||
}
|
||||
emplace_resource_descriptor(resourceHandle);
|
||||
resources.emplace(resourceHandle.index, fgviewer::FrameGraphInfo::Resource(
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
|
||||
#include <details/Texture.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/CString.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace filament::backend;
|
||||
@@ -294,7 +298,7 @@ RenderPassNode::RenderPassData const* RenderPassNode::getRenderPassData(uint32_t
|
||||
|
||||
utils::CString RenderPassNode::graphvizify() const noexcept {
|
||||
#ifndef NDEBUG
|
||||
std::string s;
|
||||
utils::CString s;
|
||||
|
||||
uint32_t const id = getId();
|
||||
const char* const nodeName = getName();
|
||||
@@ -303,17 +307,17 @@ utils::CString RenderPassNode::graphvizify() const noexcept {
|
||||
s.append("[label=\"");
|
||||
s.append(nodeName);
|
||||
s.append("\\nrefs: ");
|
||||
s.append(std::to_string(refCount));
|
||||
s.append(utils::to_string(refCount));
|
||||
s.append(", id: ");
|
||||
s.append(std::to_string(id));
|
||||
s.append(utils::to_string(id));
|
||||
|
||||
for (auto const& rt :mRenderTargetData) {
|
||||
s.append("\\nS:");
|
||||
s.append(utils::to_string(rt.backend.params.flags.discardStart).c_str());
|
||||
s.append(utils::to_string(rt.backend.params.flags.discardStart));
|
||||
s.append(", E:");
|
||||
s.append(utils::to_string(rt.backend.params.flags.discardEnd).c_str());
|
||||
s.append(utils::to_string(rt.backend.params.flags.discardEnd));
|
||||
s.append(", C:");
|
||||
s.append(utils::to_string(rt.backend.params.flags.clear).c_str());
|
||||
s.append(utils::to_string(rt.backend.params.flags.clear));
|
||||
}
|
||||
|
||||
s.append("\", ");
|
||||
@@ -322,7 +326,7 @@ utils::CString RenderPassNode::graphvizify() const noexcept {
|
||||
s.append(refCount ? "darkorange" : "darkorange4");
|
||||
s.append("]");
|
||||
|
||||
return utils::CString{ s.c_str() };
|
||||
return s;
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
@@ -342,14 +346,12 @@ char const* PresentPassNode::getName() const noexcept {
|
||||
|
||||
utils::CString PresentPassNode::graphvizify() const noexcept {
|
||||
#ifndef NDEBUG
|
||||
std::string s;
|
||||
s.reserve(128);
|
||||
utils::CString s;
|
||||
uint32_t const id = getId();
|
||||
s.append("[label=\"Present , id: ");
|
||||
s.append(std::to_string(id));
|
||||
s.append(utils::to_string(id));
|
||||
s.append("\", style=filled, fillcolor=red3]");
|
||||
s.shrink_to_fit();
|
||||
return utils::CString{ s.c_str() };
|
||||
return s;
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
|
||||
@@ -14,10 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "FrameGraphId.h"
|
||||
|
||||
#include "details/DependencyGraph.h"
|
||||
|
||||
#include "fg/FrameGraph.h"
|
||||
#include "fg/details/PassNode.h"
|
||||
#include "fg/details/ResourceNode.h"
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/CString.h>
|
||||
|
||||
#include <new>
|
||||
#include <cstdint>
|
||||
|
||||
namespace filament {
|
||||
|
||||
ResourceNode::ResourceNode(FrameGraph& fg, FrameGraphHandle const h, FrameGraphHandle const parent) noexcept
|
||||
@@ -105,20 +116,20 @@ bool ResourceNode::hasWriteFrom(PassNode const* node) const noexcept {
|
||||
|
||||
void ResourceNode::setParentReadDependency(ResourceNode* parent) noexcept {
|
||||
if (!mParentReadEdge) {
|
||||
mParentReadEdge = new DependencyGraph::Edge(mFrameGraph.getGraph(), parent, this);
|
||||
mParentReadEdge = new(std::nothrow) DependencyGraph::Edge(mFrameGraph.getGraph(), parent, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ResourceNode::setParentWriteDependency(ResourceNode* parent) noexcept {
|
||||
if (!mParentWriteEdge) {
|
||||
mParentWriteEdge = new DependencyGraph::Edge(mFrameGraph.getGraph(), this, parent);
|
||||
mParentWriteEdge = new(std::nothrow) DependencyGraph::Edge(mFrameGraph.getGraph(), this, parent);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceNode::setForwardResourceDependency(ResourceNode* source) noexcept {
|
||||
assert_invariant(!mForwardedEdge);
|
||||
mForwardedEdge = new DependencyGraph::Edge(mFrameGraph.getGraph(), this, source);
|
||||
mForwardedEdge = new(std::nothrow) DependencyGraph::Edge(mFrameGraph.getGraph(), this, source);
|
||||
}
|
||||
|
||||
|
||||
@@ -132,24 +143,23 @@ void ResourceNode::resolveResourceUsage(DependencyGraph& graph) noexcept {
|
||||
|
||||
utils::CString ResourceNode::graphvizify() const noexcept {
|
||||
#ifndef NDEBUG
|
||||
std::string s;
|
||||
s.reserve(128);
|
||||
utils::CString s;
|
||||
|
||||
uint32_t const id = getId();
|
||||
const char* const nodeName = getName();
|
||||
VirtualResource* const pResource = mFrameGraph.getResource(resourceHandle);
|
||||
VirtualResource const* const pResource = mFrameGraph.getResource(resourceHandle);
|
||||
FrameGraph::ResourceSlot const& slot = mFrameGraph.getResourceSlot(resourceHandle);
|
||||
|
||||
s.append("[label=\"");
|
||||
s.append(nodeName);
|
||||
s.append("\\nrefs: ");
|
||||
s.append(std::to_string(pResource->refcount));
|
||||
s.append(utils::to_string(pResource->refcount));
|
||||
s.append(", id: ");
|
||||
s.append(std::to_string(id));
|
||||
s.append(utils::to_string(id));
|
||||
s.append("\\nversion: ");
|
||||
s.append(std::to_string(resourceHandle.version));
|
||||
s.append(utils::to_string(resourceHandle.version));
|
||||
s.append("/");
|
||||
s.append(std::to_string(slot.version));
|
||||
s.append(utils::to_string(slot.version));
|
||||
if (pResource->isImported()) {
|
||||
s.append(", imported");
|
||||
}
|
||||
@@ -160,9 +170,8 @@ utils::CString ResourceNode::graphvizify() const noexcept {
|
||||
s.append("style=filled, fillcolor=");
|
||||
s.append(pResource->refcount ? "skyblue" : "skyblue4");
|
||||
s.append("]");
|
||||
s.shrink_to_fit();
|
||||
|
||||
return utils::CString{ s.c_str() };
|
||||
return s;
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <utils/compiler.h>
|
||||
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <assert.h>
|
||||
@@ -51,6 +52,10 @@ struct hashCStrings {
|
||||
template <size_t N>
|
||||
using StringLiteral = const char[N];
|
||||
|
||||
namespace details {
|
||||
template<typename T>
|
||||
constexpr bool is_char_pointer_v = std::is_pointer_v<T> && std::is_same_v<char, std::remove_cv_t<std::remove_pointer_t<T>>>;
|
||||
} // namespace details
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -127,8 +132,7 @@ public:
|
||||
|
||||
// replace
|
||||
template<size_t N>
|
||||
CString& replace(size_type const pos,
|
||||
size_type const len, const StringLiteral<N>& str) & noexcept {
|
||||
CString& replace(size_type const pos, size_type const len, const StringLiteral<N>& str) & noexcept {
|
||||
return replace(pos, len, str, N - 1);
|
||||
}
|
||||
|
||||
@@ -136,36 +140,83 @@ public:
|
||||
return replace(pos, len, str.c_str_safe(), str.size());
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<details::is_char_pointer_v<T>>>
|
||||
CString& replace(size_type pos, size_type len, T str) & noexcept {
|
||||
if (str) {
|
||||
return replace(pos, len, str, strlen(str));
|
||||
}
|
||||
return replace(pos, len, "", 0);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
CString&& replace(size_type const pos,
|
||||
size_type const len, const StringLiteral<N>& str) && noexcept {
|
||||
return std::move(replace(pos, len, str));
|
||||
CString&& replace(size_type pos, size_type len, const StringLiteral<N>& str) && noexcept {
|
||||
this->replace(pos, len, str);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
CString&& replace(size_type const pos, size_type const len, const CString& str) && noexcept {
|
||||
return std::move(replace(pos, len, str));
|
||||
this->replace(pos, len, str);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<details::is_char_pointer_v<T>>>
|
||||
CString&& replace(size_type pos, size_type len, T str) && noexcept {
|
||||
this->replace(pos, len, str);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
|
||||
// insert
|
||||
CString& insert(size_type pos, char c) & noexcept {
|
||||
const char s[1] = { c };
|
||||
return replace(pos, 0, s, 1);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
CString& insert(size_type const pos, const StringLiteral<N>& str) & noexcept {
|
||||
return replace(pos, 0, str);
|
||||
return replace(pos, 0, str, N - 1);
|
||||
}
|
||||
|
||||
CString& insert(size_type const pos, const CString& str) & noexcept {
|
||||
return replace(pos, 0, str);
|
||||
return replace(pos, 0, str.c_str_safe(), str.size());
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<details::is_char_pointer_v<T>>>
|
||||
CString& insert(size_type pos, T str) & noexcept {
|
||||
if (str) {
|
||||
return replace(pos, 0, str, strlen(str));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CString&& insert(size_type pos, char c) && noexcept {
|
||||
this->insert(pos, c);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
CString&& insert(size_type const pos, const StringLiteral<N>& str) && noexcept {
|
||||
return std::move(*this).replace(pos, 0, str);
|
||||
CString&& insert(size_type pos, const StringLiteral<N>& str) && noexcept {
|
||||
this->insert(pos, str);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
CString&& insert(size_type const pos, const CString& str) && noexcept {
|
||||
return std::move(*this).replace(pos, 0, str);
|
||||
this->insert(pos, str);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<details::is_char_pointer_v<T>>>
|
||||
CString&& insert(size_type pos, T str) && noexcept {
|
||||
this->insert(pos, str);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
|
||||
// append
|
||||
CString& append(char c) & noexcept {
|
||||
return insert(length(), c);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
CString& append(const StringLiteral<N>& str) & noexcept {
|
||||
return insert(length(), str);
|
||||
@@ -175,15 +226,49 @@ public:
|
||||
return insert(length(), str);
|
||||
}
|
||||
|
||||
template<typename T, typename = std::enable_if_t<details::is_char_pointer_v<T>>>
|
||||
CString& append(T str) & noexcept {
|
||||
return insert(length(), str);
|
||||
}
|
||||
|
||||
CString&& append(char c) && noexcept {
|
||||
this->append(c);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
CString&& append(const StringLiteral<N>& str) && noexcept {
|
||||
return std::move(*this).insert(length(), str);
|
||||
this->append(str);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
CString&& append(const CString& str) && noexcept {
|
||||
return std::move(*this).insert(length(), str);
|
||||
this->append(str);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
template<typename T, typename = std::enable_if_t<details::is_char_pointer_v<T>>>
|
||||
CString&& append(T str) && noexcept {
|
||||
this->append(str);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
// operator+=
|
||||
CString& operator+=(char c) & noexcept {
|
||||
return append(c);
|
||||
}
|
||||
|
||||
CString& operator+=(const CString& str) & noexcept {
|
||||
return append(str);
|
||||
}
|
||||
template<size_t N>
|
||||
CString& operator+=(const StringLiteral<N>& str) & noexcept {
|
||||
return append(str);
|
||||
}
|
||||
template <typename T, typename = std::enable_if_t<details::is_char_pointer_v<T>>>
|
||||
CString& operator+=(T str) & noexcept {
|
||||
return append(str);
|
||||
}
|
||||
|
||||
const_reference operator[](size_type const pos) const noexcept {
|
||||
assert(pos < size());
|
||||
@@ -282,6 +367,32 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
// operator+
|
||||
inline CString operator+(CString lhs, const CString& rhs) {
|
||||
lhs += rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
inline CString operator+(CString lhs, const char* rhs) {
|
||||
lhs += rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
inline CString operator+(const char* lhs, CString rhs) {
|
||||
rhs.insert(0, lhs);
|
||||
return rhs;
|
||||
}
|
||||
|
||||
inline CString operator+(CString lhs, char rhs) {
|
||||
lhs += rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
inline CString operator+(char lhs, CString rhs) {
|
||||
rhs.insert(0, lhs);
|
||||
return rhs;
|
||||
}
|
||||
|
||||
// Implement this for your type for automatic conversion to CString. Failing to do so leads
|
||||
// to a compile-time failure.
|
||||
template<typename T>
|
||||
|
||||
@@ -377,7 +377,8 @@ public:
|
||||
* @param file the file where the above function in implemented
|
||||
* @param line the line in the above file where the error was detected
|
||||
* @param literal a literal version of the error message
|
||||
* @param format printf style string describing the error
|
||||
* @param format printf style format string describing the error
|
||||
* @param ... printf style arguments
|
||||
* @see ASSERT_PRECONDITION, ASSERT_POSTCONDITION, ASSERT_ARITHMETIC
|
||||
* @see PANIC_PRECONDITION, PANIC_POSTCONDITION, PANIC_ARITHMETIC
|
||||
* @see setMode()
|
||||
@@ -448,8 +449,8 @@ void panicLog(
|
||||
class UTILS_PUBLIC PreconditionPanic final : public TPanic<PreconditionPanic> {
|
||||
// Programming error, can be avoided
|
||||
// e.g.: invalid arguments
|
||||
using TPanic<PreconditionPanic>::TPanic;
|
||||
friend class TPanic<PreconditionPanic>;
|
||||
using TPanic::TPanic;
|
||||
friend class TPanic;
|
||||
constexpr static auto type = "Precondition";
|
||||
};
|
||||
|
||||
@@ -462,8 +463,8 @@ class UTILS_PUBLIC PreconditionPanic final : public TPanic<PreconditionPanic> {
|
||||
class UTILS_PUBLIC PostconditionPanic final : public TPanic<PostconditionPanic> {
|
||||
// Usually only detectable at runtime
|
||||
// e.g.: deadlock would occur, arithmetic errors
|
||||
using TPanic<PostconditionPanic>::TPanic;
|
||||
friend class TPanic<PostconditionPanic>;
|
||||
using TPanic::TPanic;
|
||||
friend class TPanic;
|
||||
constexpr static auto type = "Postcondition";
|
||||
};
|
||||
|
||||
@@ -476,8 +477,8 @@ class UTILS_PUBLIC PostconditionPanic final : public TPanic<PostconditionPanic>
|
||||
class UTILS_PUBLIC ArithmeticPanic final : public TPanic<ArithmeticPanic> {
|
||||
// A common case of post-condition error
|
||||
// e.g.: underflow, overflow, internal computations errors
|
||||
using TPanic<ArithmeticPanic>::TPanic;
|
||||
friend class TPanic<ArithmeticPanic>;
|
||||
using TPanic::TPanic;
|
||||
friend class TPanic;
|
||||
constexpr static auto type = "Arithmetic";
|
||||
};
|
||||
|
||||
@@ -547,7 +548,7 @@ public:
|
||||
template<typename PanicType>
|
||||
class FlagGuardedStream : public PanicStream {
|
||||
public:
|
||||
FlagGuardedStream(bool enable, char const* function, char const* file, int line,
|
||||
FlagGuardedStream(bool const enable, char const* function, char const* file, int const line,
|
||||
char const* condition)
|
||||
: PanicStream(function, file, line, condition),
|
||||
mEnablePanic(enable) {}
|
||||
|
||||
@@ -20,7 +20,11 @@
|
||||
#include <utils/ostream.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
|
||||
@@ -113,5 +117,73 @@ io::ostream& operator<<(io::ostream& out, const CString& rhs) {
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace utils
|
||||
namespace {
|
||||
|
||||
// use a C-style variadic function to avoid code bloat from templates
|
||||
UTILS_NOINLINE
|
||||
CString to_string_impl(const char* format, ...) noexcept {
|
||||
va_list args1;
|
||||
va_start(args1, format);
|
||||
va_list args2;
|
||||
va_copy(args2, args1);
|
||||
int const len = vsnprintf(nullptr, 0, format, args1);
|
||||
va_end(args1);
|
||||
if (len >= 0) {
|
||||
CString s(len);
|
||||
vsnprintf(s.data(), len + 1, format, args2);
|
||||
va_end(args2);
|
||||
return s;
|
||||
}
|
||||
va_end(args2);
|
||||
return {};
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
template<>
|
||||
CString to_string<int>(int const value) noexcept {
|
||||
return to_string_impl("%d", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
CString to_string<unsigned int>(unsigned int const value) noexcept {
|
||||
return to_string_impl("%u", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
CString to_string<short>(short const value) noexcept {
|
||||
return to_string_impl("%hd", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
CString to_string<unsigned short>(unsigned short const value) noexcept {
|
||||
return to_string_impl("%hu", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
CString to_string<long>(long const value) noexcept {
|
||||
return to_string_impl("%ld", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
CString to_string<unsigned long>(unsigned long const value) noexcept {
|
||||
return to_string_impl("%lu", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
CString to_string<long long>(long long const value) noexcept {
|
||||
return to_string_impl("%lld", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
CString to_string<unsigned long long>(unsigned long long const value) noexcept {
|
||||
return to_string_impl("%llu", value);
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
CString to_string<float>(float const value) noexcept {
|
||||
return to_string_impl("%f", value);
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
||||
@@ -18,53 +18,416 @@
|
||||
|
||||
#include <utils/CString.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <utility>
|
||||
|
||||
using namespace utils;
|
||||
|
||||
TEST(CString, EmptyString) {
|
||||
CString emptyString("");
|
||||
CString const emptyString("");
|
||||
EXPECT_STREQ("", emptyString.c_str_safe());
|
||||
EXPECT_EQ(0, emptyString.length());
|
||||
EXPECT_TRUE(emptyString.empty());
|
||||
}
|
||||
|
||||
TEST(CString, Constructors) {
|
||||
// CString()
|
||||
{
|
||||
CString str;
|
||||
EXPECT_EQ(nullptr, str.c_str());
|
||||
EXPECT_STREQ("", str.c_str_safe());
|
||||
EXPECT_EQ(0, str.length());
|
||||
EXPECT_TRUE(str.empty());
|
||||
}
|
||||
// CString(const char* cstr, size_t length)
|
||||
{
|
||||
CString str("foobar", 3);
|
||||
EXPECT_STREQ("foo", str.c_str());
|
||||
EXPECT_EQ(3, str.length());
|
||||
}
|
||||
// CString(size_t length)
|
||||
{
|
||||
CString str(5);
|
||||
EXPECT_EQ(5, str.length());
|
||||
// The memory is zero-initialized
|
||||
EXPECT_EQ(0, str.c_str()[0]);
|
||||
EXPECT_EQ(0, str.c_str()[4]);
|
||||
}
|
||||
// CString(const char* cstr)
|
||||
{
|
||||
CString str("hello");
|
||||
EXPECT_STREQ("hello", str.c_str());
|
||||
EXPECT_EQ(5, str.length());
|
||||
}
|
||||
// CString(StringLiteral<N>)
|
||||
{
|
||||
CString str("literal"); // this uses the template constructor
|
||||
EXPECT_STREQ("literal", str.c_str());
|
||||
EXPECT_EQ(7, str.length());
|
||||
}
|
||||
// Copy constructor
|
||||
{
|
||||
CString s1("copy me");
|
||||
CString s2(s1);
|
||||
EXPECT_STREQ("copy me", s2.c_str());
|
||||
EXPECT_NE(s1.c_str(), s2.c_str()); // should be a deep copy
|
||||
}
|
||||
// Move constructor
|
||||
{
|
||||
CString s1("move me");
|
||||
const char* original_cstr = s1.c_str();
|
||||
CString s2(std::move(s1));
|
||||
EXPECT_STREQ("move me", s2.c_str());
|
||||
EXPECT_EQ(original_cstr, s2.c_str()); // pointer should be moved
|
||||
EXPECT_EQ(nullptr, s1.c_str()); // original should be empty
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CString, Assignment) {
|
||||
// Copy assignment
|
||||
{
|
||||
CString s1("copy");
|
||||
CString s2;
|
||||
s2 = s1;
|
||||
EXPECT_STREQ("copy", s2.c_str());
|
||||
EXPECT_NE(s1.c_str(), s2.c_str());
|
||||
}
|
||||
// Move assignment
|
||||
{
|
||||
CString s1("move");
|
||||
const char* original_cstr = s1.c_str();
|
||||
CString s2;
|
||||
s2 = std::move(s1);
|
||||
EXPECT_STREQ("move", s2.c_str());
|
||||
EXPECT_EQ(original_cstr, s2.c_str());
|
||||
EXPECT_EQ(nullptr, s1.c_str());
|
||||
}
|
||||
// self-assignment
|
||||
{
|
||||
CString s1("self");
|
||||
const char* original_cstr = s1.c_str();
|
||||
s1 = s1;
|
||||
EXPECT_STREQ("self", s1.c_str());
|
||||
EXPECT_EQ(original_cstr, s1.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CString, Swap) {
|
||||
CString s1("first");
|
||||
CString s2("second");
|
||||
|
||||
const char* p1 = s1.c_str();
|
||||
const char* p2 = s2.c_str();
|
||||
size_t l1 = s1.length();
|
||||
size_t l2 = s2.length();
|
||||
|
||||
s1.swap(s2);
|
||||
|
||||
EXPECT_STREQ("second", s1.c_str());
|
||||
EXPECT_STREQ("first", s2.c_str());
|
||||
EXPECT_EQ(p2, s1.c_str());
|
||||
EXPECT_EQ(p1, s2.c_str());
|
||||
EXPECT_EQ(l2, s1.length());
|
||||
EXPECT_EQ(l1, s2.length());
|
||||
}
|
||||
|
||||
TEST(CString, Concatenation) {
|
||||
// operator+=
|
||||
{
|
||||
CString s("hello");
|
||||
s += CString(" world");
|
||||
EXPECT_STREQ("hello world", s.c_str());
|
||||
}
|
||||
{
|
||||
CString s("hello");
|
||||
s += " world";
|
||||
EXPECT_STREQ("hello world", s.c_str());
|
||||
}
|
||||
{
|
||||
CString s("hello");
|
||||
const char* world = " world";
|
||||
s += world;
|
||||
EXPECT_STREQ("hello world", s.c_str());
|
||||
}
|
||||
{
|
||||
CString s("hello");
|
||||
s += "";
|
||||
EXPECT_STREQ("hello", s.c_str());
|
||||
}
|
||||
{
|
||||
CString s;
|
||||
s += "world";
|
||||
EXPECT_STREQ("world", s.c_str());
|
||||
}
|
||||
|
||||
// operator+
|
||||
{
|
||||
CString s1("hello");
|
||||
CString s2(" world");
|
||||
CString s3 = s1 + s2;
|
||||
EXPECT_STREQ("hello world", s3.c_str());
|
||||
}
|
||||
{
|
||||
CString s1("hello");
|
||||
CString s2 = s1 + " world";
|
||||
EXPECT_STREQ("hello world", s2.c_str());
|
||||
}
|
||||
{
|
||||
CString s1(" world");
|
||||
CString s2 = "hello" + s1;
|
||||
EXPECT_STREQ("hello world", s2.c_str());
|
||||
}
|
||||
{
|
||||
CString s1("hello");
|
||||
const char* world = " world";
|
||||
CString s2 = s1 + world;
|
||||
EXPECT_STREQ("hello world", s2.c_str());
|
||||
}
|
||||
{
|
||||
CString s1(" world");
|
||||
const char* hello = "hello";
|
||||
CString s2 = hello + s1;
|
||||
EXPECT_STREQ("hello world", s2.c_str());
|
||||
}
|
||||
{
|
||||
CString s = CString("a") + CString("b") + "c" + "d";
|
||||
EXPECT_STREQ("abcd", s.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CString, Comparison) {
|
||||
CString s1("abc");
|
||||
CString s2("abc");
|
||||
CString s3("def");
|
||||
CString s4("ab");
|
||||
|
||||
EXPECT_TRUE(s1 == s2);
|
||||
EXPECT_FALSE(s1 == s3);
|
||||
|
||||
EXPECT_TRUE(s1 != s3);
|
||||
EXPECT_FALSE(s1 != s2);
|
||||
|
||||
EXPECT_TRUE(s1 < s3);
|
||||
EXPECT_FALSE(s3 < s1);
|
||||
|
||||
EXPECT_TRUE(s3 > s1);
|
||||
EXPECT_FALSE(s1 > s3);
|
||||
|
||||
EXPECT_TRUE(s1 <= s2);
|
||||
EXPECT_TRUE(s1 <= s3);
|
||||
EXPECT_FALSE(s3 <= s1);
|
||||
|
||||
EXPECT_TRUE(s2 >= s1);
|
||||
EXPECT_TRUE(s3 >= s1);
|
||||
EXPECT_FALSE(s1 >= s3);
|
||||
|
||||
EXPECT_TRUE(s4 < s1);
|
||||
EXPECT_TRUE(s1 > s4);
|
||||
}
|
||||
|
||||
TEST(CString, ElementAccess) {
|
||||
CString str("01234");
|
||||
const CString cstr("const");
|
||||
|
||||
EXPECT_EQ('0', str.front());
|
||||
EXPECT_EQ('4', str.back());
|
||||
EXPECT_EQ('c', cstr.front());
|
||||
EXPECT_EQ('t', cstr.back());
|
||||
|
||||
EXPECT_EQ('2', str[2]);
|
||||
EXPECT_EQ('n', cstr[2]);
|
||||
|
||||
str[0] = 'A';
|
||||
EXPECT_STREQ("A1234", str.c_str());
|
||||
|
||||
EXPECT_EQ('3', str.at(3));
|
||||
EXPECT_EQ('t', cstr.at(4));
|
||||
|
||||
// iterators
|
||||
std::string s(str.begin(), str.end());
|
||||
EXPECT_EQ("A1234", s);
|
||||
|
||||
EXPECT_TRUE(std::equal(cstr.begin(), cstr.end(), "const"));
|
||||
}
|
||||
|
||||
TEST(CString, Append) {
|
||||
// Append CString
|
||||
{
|
||||
CString str("foo");
|
||||
str.append(CString("bar"));
|
||||
EXPECT_STREQ("foobar", str.c_str());
|
||||
}
|
||||
// Append string literal
|
||||
{
|
||||
CString str("foo");
|
||||
str.append("bar");
|
||||
EXPECT_STREQ("foobar", str.c_str());
|
||||
}
|
||||
// Append const char*
|
||||
{
|
||||
CString str("foo");
|
||||
const char* bar = "bar";
|
||||
str.append(bar);
|
||||
EXPECT_STREQ("foobar", str.c_str());
|
||||
}
|
||||
// Append nullptr
|
||||
{
|
||||
CString str("foo");
|
||||
const char* bar = nullptr;
|
||||
str.append(bar);
|
||||
EXPECT_STREQ("foo", str.c_str());
|
||||
}
|
||||
// Append to empty
|
||||
{
|
||||
CString str;
|
||||
str.append("foo");
|
||||
EXPECT_STREQ("foo", str.c_str());
|
||||
}
|
||||
{
|
||||
CString str;
|
||||
str.append(CString("foo"));
|
||||
EXPECT_STREQ("foo", str.c_str());
|
||||
}
|
||||
{
|
||||
CString str;
|
||||
const char* foo = "foo";
|
||||
str.append(foo);
|
||||
EXPECT_STREQ("foo", str.c_str());
|
||||
}
|
||||
// Append empty
|
||||
{
|
||||
CString str("foo");
|
||||
str.append("");
|
||||
EXPECT_STREQ("foo", str.c_str());
|
||||
}
|
||||
{
|
||||
CString str("foo");
|
||||
str.append(CString(""));
|
||||
EXPECT_STREQ("foo", str.c_str());
|
||||
}
|
||||
{
|
||||
CString str("foo");
|
||||
const char* empty = "";
|
||||
str.append(empty);
|
||||
EXPECT_STREQ("foo", str.c_str());
|
||||
}
|
||||
// Chaining
|
||||
{
|
||||
CString str;
|
||||
str.append("foo").append("bar").append(CString("baz"));
|
||||
EXPECT_STREQ("foobarbaz", str.c_str());
|
||||
}
|
||||
// r-value appends
|
||||
{
|
||||
CString str = CString("foo").append("bar");
|
||||
EXPECT_STREQ("foobar", str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CString, Insert) {
|
||||
// with CString
|
||||
{
|
||||
CString str("foobaz");
|
||||
str.insert(3, CString("bar"));
|
||||
EXPECT_STREQ("foobarbaz", str.c_str());
|
||||
}
|
||||
// with string literal
|
||||
{
|
||||
CString str("world");
|
||||
str.insert(0, "hello ");
|
||||
EXPECT_STREQ("hello world", str.c_str());
|
||||
}
|
||||
// with const char*
|
||||
{
|
||||
CString str("foo");
|
||||
const char* bar = "bar";
|
||||
str.insert(3, bar);
|
||||
EXPECT_STREQ("foobar", str.c_str());
|
||||
}
|
||||
// with nullptr
|
||||
{
|
||||
CString str("foo");
|
||||
const char* bar = nullptr;
|
||||
str.insert(1, bar);
|
||||
EXPECT_STREQ("foo", str.c_str());
|
||||
}
|
||||
// r-value insert
|
||||
{
|
||||
const char* bar = "bar";
|
||||
CString str = CString("foo").insert(3, bar);
|
||||
EXPECT_STREQ("foobar", str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CString, Replace) {
|
||||
{
|
||||
CString str("foo bar baz");
|
||||
str.replace(0, 0, CString("lkj"));
|
||||
EXPECT_STREQ("lkjfoo bar baz", str.c_str());
|
||||
}
|
||||
// with CString
|
||||
{
|
||||
CString str("foo bar baz");
|
||||
str.replace(4, 3, CString("dpa"));
|
||||
EXPECT_STREQ("foo dpa baz", str.c_str());
|
||||
}
|
||||
// with string literal
|
||||
{
|
||||
CString str("foo bar baz");
|
||||
str.replace(4, 3, CString(""));
|
||||
str.replace(4, 3, "dpa");
|
||||
EXPECT_STREQ("foo dpa baz", str.c_str());
|
||||
}
|
||||
// with const char*
|
||||
{
|
||||
CString str("foo bar baz");
|
||||
const char* dpa = "dpa";
|
||||
str.replace(4, 3, dpa);
|
||||
EXPECT_STREQ("foo dpa baz", str.c_str());
|
||||
}
|
||||
// with nullptr
|
||||
{
|
||||
CString str("foo bar baz");
|
||||
const char* dpa = nullptr;
|
||||
str.replace(4, 3, dpa);
|
||||
EXPECT_STREQ("foo baz", str.c_str());
|
||||
}
|
||||
// with empty string
|
||||
{
|
||||
CString str("foo bar baz");
|
||||
str.replace(4, 3, CString("a"));
|
||||
EXPECT_STREQ("foo a baz", str.c_str());
|
||||
str.replace(4, 3, "");
|
||||
EXPECT_STREQ("foo baz", str.c_str());
|
||||
}
|
||||
// replace that grows the string
|
||||
{
|
||||
CString str("foo bar baz");
|
||||
str.replace(4, 3, CString("abcdef"));
|
||||
str.replace(4, 3, "abcdef");
|
||||
EXPECT_STREQ("foo abcdef baz", str.c_str());
|
||||
}
|
||||
// replace that shrinks the string
|
||||
{
|
||||
CString str("foo bar baz");
|
||||
str.replace(0, 3, CString("abcdef"));
|
||||
EXPECT_STREQ("abcdef bar baz", str.c_str());
|
||||
str.replace(4, 3, "a");
|
||||
EXPECT_STREQ("foo a baz", str.c_str());
|
||||
}
|
||||
// replace at the beginning
|
||||
{
|
||||
CString str("foo bar baz");
|
||||
str.replace(8, 3, CString("abcdef"));
|
||||
EXPECT_STREQ("foo bar abcdef", str.c_str());
|
||||
str.replace(0, 3, "lkj");
|
||||
EXPECT_STREQ("lkj bar baz", str.c_str());
|
||||
}
|
||||
// replace at the end
|
||||
{
|
||||
CString str("foo bar baz");
|
||||
str.replace(0, 11, CString("abcdef"));
|
||||
EXPECT_STREQ("abcdef", str.c_str());
|
||||
str.replace(8, 3, "lkj");
|
||||
EXPECT_STREQ("foo bar lkj", str.c_str());
|
||||
}
|
||||
// replace all
|
||||
{
|
||||
CString str("foo bar baz");
|
||||
str.replace(0, 11, "lkj");
|
||||
EXPECT_STREQ("lkj", str.c_str());
|
||||
}
|
||||
// r-value replace
|
||||
{
|
||||
const char* dpa = "dpa";
|
||||
CString str = CString("foo bar baz").replace(4, 3, dpa);
|
||||
EXPECT_STREQ("foo dpa baz", str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +457,42 @@ TEST(CString, ReplacePastEndOfString) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CString, ToString) {
|
||||
EXPECT_STREQ("0", to_string(0).c_str());
|
||||
EXPECT_STREQ("123", to_string(123).c_str());
|
||||
EXPECT_STREQ("-456", to_string(-456).c_str());
|
||||
EXPECT_STREQ("2147483647", to_string(INT_MAX).c_str());
|
||||
EXPECT_STREQ("-2147483648", to_string(INT_MIN).c_str());
|
||||
|
||||
EXPECT_STREQ("0", to_string(0u).c_str());
|
||||
EXPECT_STREQ("4294967295", to_string(UINT_MAX).c_str());
|
||||
|
||||
EXPECT_STREQ("0", to_string((short)0).c_str());
|
||||
EXPECT_STREQ("32767", to_string(SHRT_MAX).c_str());
|
||||
EXPECT_STREQ("-32768", to_string(SHRT_MIN).c_str());
|
||||
|
||||
EXPECT_STREQ("0", to_string((unsigned short)0).c_str());
|
||||
EXPECT_STREQ("65535", to_string(USHRT_MAX).c_str());
|
||||
|
||||
#if LONG_MAX == 2147483647
|
||||
EXPECT_STREQ("2147483647", to_string(LONG_MAX).c_str());
|
||||
EXPECT_STREQ("-2147483648", to_string(LONG_MIN).c_str());
|
||||
EXPECT_STREQ("4294967295", to_string(ULONG_MAX).c_str());
|
||||
#else
|
||||
EXPECT_STREQ("9223372036854775807", to_string(LONG_MAX).c_str());
|
||||
EXPECT_STREQ("-9223372036854775808", to_string(LONG_MIN).c_str());
|
||||
EXPECT_STREQ("18446744073709551615", to_string(ULONG_MAX).c_str());
|
||||
#endif
|
||||
|
||||
EXPECT_STREQ("9223372036854775807", to_string(LLONG_MAX).c_str());
|
||||
EXPECT_STREQ("-9223372036854775808", to_string(LLONG_MIN).c_str());
|
||||
EXPECT_STREQ("18446744073709551615", to_string(ULLONG_MAX).c_str());
|
||||
|
||||
EXPECT_STREQ("0.000000", to_string(0.0f).c_str());
|
||||
EXPECT_STREQ("1.500000", to_string(1.5f).c_str());
|
||||
EXPECT_STREQ("-3.140000", to_string(-3.14f).c_str());
|
||||
}
|
||||
|
||||
TEST(FixedSizeString, EmptyString) {
|
||||
{
|
||||
FixedSizeString<32> str;
|
||||
|
||||
Reference in New Issue
Block a user