diff --git a/src/main/native/cpp/llvm/Path.cpp b/src/main/native/cpp/llvm/Path.cpp new file mode 100644 index 0000000000..3f7b578ce0 --- /dev/null +++ b/src/main/native/cpp/llvm/Path.cpp @@ -0,0 +1,684 @@ +//===-- Path.cpp - Implement OS Path Concept ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the operating system Path API. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Path.h" + +#include +#include + +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include +#else +#include +#endif + +#include "llvm/SmallString.h" + +using namespace llvm; + +namespace { + using llvm::StringRef; + using llvm::sys::path::is_separator; + +#ifdef _WIN32 + const char *separators = "\\/"; + const char preferred_separator = '\\'; +#else + const char separators = '/'; + const char preferred_separator = '/'; +#endif + + StringRef find_first_component(StringRef path) { + // Look for this first component in the following order. + // * empty (in this case we return an empty string) + // * either C: or {//,\\}net. + // * {/,\} + // * {file,directory}name + + if (path.empty()) + return path; + +#ifdef _WIN32 + // C: + if (path.size() >= 2 && std::isalpha(static_cast(path[0])) && + path[1] == ':') + return path.substr(0, 2); +#endif + + // //net + if ((path.size() > 2) && + is_separator(path[0]) && + path[0] == path[1] && + !is_separator(path[2])) { + // Find the next directory separator. + size_t end = path.find_first_of(separators, 2); + return path.substr(0, end); + } + + // {/,\} + if (is_separator(path[0])) + return path.substr(0, 1); + + // * {file,directory}name + size_t end = path.find_first_of(separators); + return path.substr(0, end); + } + + size_t filename_pos(StringRef str) { + if (str.size() == 2 && + is_separator(str[0]) && + str[0] == str[1]) + return 0; + + if (str.size() > 0 && is_separator(str[str.size() - 1])) + return str.size() - 1; + + size_t pos = str.find_last_of(separators, str.size() - 1); + +#ifdef _WIN32 + if (pos == StringRef::npos) + pos = str.find_last_of(':', str.size() - 2); +#endif + + if (pos == StringRef::npos || + (pos == 1 && is_separator(str[0]))) + return 0; + + return pos + 1; + } + + size_t root_dir_start(StringRef str) { + // case "c:/" +#ifdef _WIN32 + if (str.size() > 2 && + str[1] == ':' && + is_separator(str[2])) + return 2; +#endif + + // case "//" + if (str.size() == 2 && + is_separator(str[0]) && + str[0] == str[1]) + return StringRef::npos; + + // case "//net" + if (str.size() > 3 && + is_separator(str[0]) && + str[0] == str[1] && + !is_separator(str[2])) { + return str.find_first_of(separators, 2); + } + + // case "/" + if (str.size() > 0 && is_separator(str[0])) + return 0; + + return StringRef::npos; + } + + size_t parent_path_end(StringRef path) { + size_t end_pos = filename_pos(path); + + bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]); + + // Skip separators except for root dir. + size_t root_dir_pos = root_dir_start(path.substr(0, end_pos)); + + while(end_pos > 0 && + (end_pos - 1) != root_dir_pos && + is_separator(path[end_pos - 1])) + --end_pos; + + if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) + return StringRef::npos; + + return end_pos; + } +} // end unnamed namespace + +namespace llvm { +namespace sys { +namespace path { + +const_iterator begin(StringRef path) { + const_iterator i; + i.Path = path; + i.Component = find_first_component(path); + i.Position = 0; + return i; +} + +const_iterator end(StringRef path) { + const_iterator i; + i.Path = path; + i.Position = path.size(); + return i; +} + +const_iterator &const_iterator::operator++() { + assert(Position < Path.size() && "Tried to increment past end!"); + + // Increment Position to past the current component + Position += Component.size(); + + // Check for end. + if (Position == Path.size()) { + Component = StringRef(); + return *this; + } + + // Both POSIX and Windows treat paths that begin with exactly two separators + // specially. + bool was_net = Component.size() > 2 && + is_separator(Component[0]) && + Component[1] == Component[0] && + !is_separator(Component[2]); + + // Handle separators. + if (is_separator(Path[Position])) { + // Root dir. + if (was_net +#ifdef _WIN32 + // c:/ + || Component.endswith(":") +#endif + ) { + Component = Path.substr(Position, 1); + return *this; + } + + // Skip extra separators. + while (Position != Path.size() && + is_separator(Path[Position])) { + ++Position; + } + + // Treat trailing '/' as a '.'. + if (Position == Path.size()) { + --Position; + Component = "."; + return *this; + } + } + + // Find next component. + size_t end_pos = Path.find_first_of(separators, Position); + Component = Path.slice(Position, end_pos); + + return *this; +} + +bool const_iterator::operator==(const const_iterator &RHS) const { + return Path.begin() == RHS.Path.begin() && Position == RHS.Position; +} + +ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const { + return Position - RHS.Position; +} + +reverse_iterator rbegin(StringRef Path) { + reverse_iterator I; + I.Path = Path; + I.Position = Path.size(); + return ++I; +} + +reverse_iterator rend(StringRef Path) { + reverse_iterator I; + I.Path = Path; + I.Component = Path.substr(0, 0); + I.Position = 0; + return I; +} + +reverse_iterator &reverse_iterator::operator++() { + // If we're at the end and the previous char was a '/', return '.' unless + // we are the root path. + size_t root_dir_pos = root_dir_start(Path); + if (Position == Path.size() && + Path.size() > root_dir_pos + 1 && + is_separator(Path[Position - 1])) { + --Position; + Component = "."; + return *this; + } + + // Skip separators unless it's the root directory. + size_t end_pos = Position; + + while(end_pos > 0 && + (end_pos - 1) != root_dir_pos && + is_separator(Path[end_pos - 1])) + --end_pos; + + // Find next separator. + size_t start_pos = filename_pos(Path.substr(0, end_pos)); + Component = Path.slice(start_pos, end_pos); + Position = start_pos; + return *this; +} + +bool reverse_iterator::operator==(const reverse_iterator &RHS) const { + return Path.begin() == RHS.Path.begin() && Component == RHS.Component && + Position == RHS.Position; +} + +ptrdiff_t reverse_iterator::operator-(const reverse_iterator &RHS) const { + return Position - RHS.Position; +} + +StringRef root_path(StringRef path) { + const_iterator b = begin(path), + pos = b, + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef _WIN32 + b->endswith(":"); +#else + false; +#endif + + if (has_net || has_drive) { + if ((++pos != e) && is_separator((*pos)[0])) { + // {C:/,//net/}, so get the first two components. + return path.substr(0, b->size() + pos->size()); + } else { + // just {C:,//net}, return the first component. + return *b; + } + } + + // POSIX style root directory. + if (is_separator((*b)[0])) { + return *b; + } + } + + return StringRef(); +} + +StringRef root_name(StringRef path) { + const_iterator b = begin(path), + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef _WIN32 + b->endswith(":"); +#else + false; +#endif + + if (has_net || has_drive) { + // just {C:,//net}, return the first component. + return *b; + } + } + + // No path or no name. + return StringRef(); +} + +StringRef root_directory(StringRef path) { + const_iterator b = begin(path), + pos = b, + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef _WIN32 + b->endswith(":"); +#else + false; +#endif + + if ((has_net || has_drive) && + // {C:,//net}, skip to the next component. + (++pos != e) && is_separator((*pos)[0])) { + return *pos; + } + + // POSIX style root directory. + if (!has_net && is_separator((*b)[0])) { + return *b; + } + } + + // No path or no root. + return StringRef(); +} + +StringRef relative_path(StringRef path) { + StringRef root = root_path(path); + return path.substr(root.size()); +} + +void append(SmallVectorImpl &path, const Twine &a, + const Twine &b, + const Twine &c, + const Twine &d) { + SmallString<32> a_storage; + SmallString<32> b_storage; + SmallString<32> c_storage; + SmallString<32> d_storage; + + SmallVector components; + if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage)); + if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage)); + if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage)); + if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage)); + + for (auto &component : components) { + bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]); + bool component_has_sep = !component.empty() && is_separator(component[0]); + bool is_root_name = has_root_name(component); + + if (path_has_sep) { + // Strip separators from beginning of component. + size_t loc = component.find_first_not_of(separators); + StringRef c = component.substr(loc); + + // Append it. + path.append(c.begin(), c.end()); + continue; + } + + if (!component_has_sep && !(path.empty() || is_root_name)) { + // Add a separator. + path.push_back(preferred_separator); + } + + path.append(component.begin(), component.end()); + } +} + +void append(SmallVectorImpl &path, + const_iterator begin, const_iterator end) { + for (; begin != end; ++begin) + path::append(path, *begin); +} + +StringRef parent_path(StringRef path) { + size_t end_pos = parent_path_end(path); + if (end_pos == StringRef::npos) + return StringRef(); + else + return path.substr(0, end_pos); +} + +void remove_filename(SmallVectorImpl &path) { + size_t end_pos = parent_path_end(StringRef(path.begin(), path.size())); + if (end_pos != StringRef::npos) + path.set_size(end_pos); +} + +void replace_extension(SmallVectorImpl &path, const Twine &extension) { + StringRef p(path.begin(), path.size()); + SmallString<32> ext_storage; + StringRef ext = extension.toStringRef(ext_storage); + + // Erase existing extension. + size_t pos = p.find_last_of('.'); + if (pos != StringRef::npos && pos >= filename_pos(p)) + path.set_size(pos); + + // Append '.' if needed. + if (ext.size() > 0 && ext[0] != '.') + path.push_back('.'); + + // Append extension. + path.append(ext.begin(), ext.end()); +} + +void replace_path_prefix(SmallVectorImpl &Path, + const StringRef &OldPrefix, + const StringRef &NewPrefix) { + if (OldPrefix.empty() && NewPrefix.empty()) + return; + + StringRef OrigPath(Path.begin(), Path.size()); + if (!OrigPath.startswith(OldPrefix)) + return; + + // If prefixes have the same size we can simply copy the new one over. + if (OldPrefix.size() == NewPrefix.size()) { + std::copy(NewPrefix.begin(), NewPrefix.end(), Path.begin()); + return; + } + + StringRef RelPath = OrigPath.substr(OldPrefix.size()); + SmallString<256> NewPath; + path::append(NewPath, NewPrefix); + path::append(NewPath, RelPath); + Path.swap(NewPath); +} + +void native(const Twine &path, SmallVectorImpl &result) { + assert((!path.isSingleStringRef() || + path.getSingleStringRef().data() != result.data()) && + "path and result are not allowed to overlap!"); + // Clear result. + result.clear(); + path.toVector(result); + native(result); +} + +void native(SmallVectorImpl &Path) { +#ifdef _WIN32 + std::replace(Path.begin(), Path.end(), '/', '\\'); +#else + for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) { + if (*PI == '\\') { + auto PN = PI + 1; + if (PN < PE && *PN == '\\') + ++PI; // increment once, the for loop will move over the escaped slash + else + *PI = '/'; + } + } +#endif +} + +StringRef filename(StringRef path) { + return *rbegin(path); +} + +StringRef stem(StringRef path) { + StringRef fname = filename(path); + size_t pos = fname.find_last_of('.'); + if (pos == StringRef::npos) + return fname; + else + if ((fname.size() == 1 && fname == ".") || + (fname.size() == 2 && fname == "..")) + return fname; + else + return fname.substr(0, pos); +} + +StringRef extension(StringRef path) { + StringRef fname = filename(path); + size_t pos = fname.find_last_of('.'); + if (pos == StringRef::npos) + return StringRef(); + else + if ((fname.size() == 1 && fname == ".") || + (fname.size() == 2 && fname == "..")) + return StringRef(); + else + return fname.substr(pos); +} + +bool is_separator(char value) { + switch(value) { +#ifdef _WIN32 + case '\\': // fall through +#endif + case '/': return true; + default: return false; + } +} + +static const char preferred_separator_string[] = { preferred_separator, '\0' }; + +StringRef get_separator() { + return preferred_separator_string; +} + +bool has_root_name(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_name(p).empty(); +} + +bool has_root_directory(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_directory(p).empty(); +} + +bool has_root_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_path(p).empty(); +} + +bool has_relative_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !relative_path(p).empty(); +} + +bool has_filename(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !filename(p).empty(); +} + +bool has_parent_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !parent_path(p).empty(); +} + +bool has_stem(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !stem(p).empty(); +} + +bool has_extension(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !extension(p).empty(); +} + +bool is_absolute(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + bool rootDir = has_root_directory(p), +#ifdef _WIN32 + rootName = has_root_name(p); +#else + rootName = true; +#endif + + return rootDir && rootName; +} + +bool is_relative(const Twine &path) { return !is_absolute(path); } + +StringRef remove_leading_dotslash(StringRef Path) { + // Remove leading "./" (or ".//" or "././" etc.) + while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1])) { + Path = Path.substr(2); + while (Path.size() > 0 && is_separator(Path[0])) + Path = Path.substr(1); + } + return Path; +} + +static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot) { + SmallVector components; + + // Skip the root path, then look for traversal in the components. + StringRef rel = path::relative_path(path); + for (StringRef C : llvm::make_range(path::begin(rel), path::end(rel))) { + if (C == ".") + continue; + if (remove_dot_dot) { + if (C == "..") { + if (!components.empty()) + components.pop_back(); + continue; + } + } + components.push_back(C); + } + + SmallString<256> buffer = path::root_path(path); + for (StringRef C : components) + path::append(buffer, C); + return buffer; +} + +bool remove_dots(SmallVectorImpl &path, bool remove_dot_dot) { + StringRef p(path.data(), path.size()); + + SmallString<256> result = remove_dots(p, remove_dot_dot); + if (result == path) + return false; + + path.swap(result); + return true; +} + +} // end namespace path +} // end namespace sys +} // end namespace llvm + +// Include the truly platform-specific parts. +#ifdef _WIN32 +#include "Windows/Path.inc" +#else +#include "Unix/Path.inc" +#endif + +namespace llvm { +namespace sys { +namespace path { + +bool user_cache_directory(SmallVectorImpl &Result, const Twine &Path1, + const Twine &Path2, const Twine &Path3) { + if (getUserCacheDir(Result)) { + append(Result, Path1, Path2, Path3); + return true; + } + return false; +} + +} // end namespace path +} // end namsspace sys +} // end namespace llvm diff --git a/src/main/native/cpp/llvm/Twine.cpp b/src/main/native/cpp/llvm/Twine.cpp new file mode 100644 index 0000000000..7d771d50a8 --- /dev/null +++ b/src/main/native/cpp/llvm/Twine.cpp @@ -0,0 +1,169 @@ +//===-- Twine.cpp - Fast Temporary String Concatenation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Twine.h" +#include "llvm/SmallString.h" +#include "llvm/raw_ostream.h" +using namespace llvm; + +std::string Twine::str() const { + // If we're storing only a std::string, just return it. + if (LHSKind == StdStringKind && RHSKind == EmptyKind) + return *LHS.stdString; + + // Otherwise, flatten and copy the contents first. + SmallString<256> Vec; + return toStringRef(Vec).str(); +} + +void Twine::toVector(SmallVectorImpl &Out) const { + raw_svector_ostream OS(Out); + print(OS); +} + +StringRef Twine::toNullTerminatedStringRef(SmallVectorImpl &Out) const { + if (isUnary()) { + switch (getLHSKind()) { + case CStringKind: + // Already null terminated, yay! + return StringRef(LHS.cString); + case StdStringKind: { + const std::string *str = LHS.stdString; + return StringRef(str->c_str(), str->size()); + } + default: + break; + } + } + toVector(Out); + Out.push_back(0); + Out.pop_back(); + return StringRef(Out.data(), Out.size()); +} + +void Twine::printOneChild(raw_ostream &OS, Child Ptr, + NodeKind Kind) const { + switch (Kind) { + case Twine::NullKind: break; + case Twine::EmptyKind: break; + case Twine::TwineKind: + Ptr.twine->print(OS); + break; + case Twine::CStringKind: + OS << Ptr.cString; + break; + case Twine::StdStringKind: + OS << *Ptr.stdString; + break; + case Twine::StringRefKind: + OS << *Ptr.stringRef; + break; + case Twine::SmallStringKind: + OS << *Ptr.smallString; + break; + case Twine::CharKind: + OS << Ptr.character; + break; + case Twine::DecUIKind: + OS << Ptr.decUI; + break; + case Twine::DecIKind: + OS << Ptr.decI; + break; + case Twine::DecULKind: + OS << *Ptr.decUL; + break; + case Twine::DecLKind: + OS << *Ptr.decL; + break; + case Twine::DecULLKind: + OS << *Ptr.decULL; + break; + case Twine::DecLLKind: + OS << *Ptr.decLL; + break; + case Twine::UHexKind: + OS.write_hex(*Ptr.uHex); + break; + } +} + +void Twine::printOneChildRepr(raw_ostream &OS, Child Ptr, + NodeKind Kind) const { + switch (Kind) { + case Twine::NullKind: + OS << "null"; break; + case Twine::EmptyKind: + OS << "empty"; break; + case Twine::TwineKind: + OS << "rope:"; + Ptr.twine->printRepr(OS); + break; + case Twine::CStringKind: + OS << "cstring:\"" + << Ptr.cString << "\""; + break; + case Twine::StdStringKind: + OS << "std::string:\"" + << Ptr.stdString << "\""; + break; + case Twine::StringRefKind: + OS << "stringref:\"" + << Ptr.stringRef << "\""; + break; + case Twine::SmallStringKind: + OS << "smallstring:\"" << *Ptr.smallString << "\""; + break; + case Twine::CharKind: + OS << "char:\"" << Ptr.character << "\""; + break; + case Twine::DecUIKind: + OS << "decUI:\"" << Ptr.decUI << "\""; + break; + case Twine::DecIKind: + OS << "decI:\"" << Ptr.decI << "\""; + break; + case Twine::DecULKind: + OS << "decUL:\"" << *Ptr.decUL << "\""; + break; + case Twine::DecLKind: + OS << "decL:\"" << *Ptr.decL << "\""; + break; + case Twine::DecULLKind: + OS << "decULL:\"" << *Ptr.decULL << "\""; + break; + case Twine::DecLLKind: + OS << "decLL:\"" << *Ptr.decLL << "\""; + break; + case Twine::UHexKind: + OS << "uhex:\"" << Ptr.uHex << "\""; + break; + } +} + +void Twine::print(raw_ostream &OS) const { + printOneChild(OS, LHS, getLHSKind()); + printOneChild(OS, RHS, getRHSKind()); +} + +void Twine::printRepr(raw_ostream &OS) const { + OS << "(Twine "; + printOneChildRepr(OS, LHS, getLHSKind()); + OS << " "; + printOneChildRepr(OS, RHS, getRHSKind()); + OS << ")"; +} + +void Twine::dump() const { + print(errs()); +} + +void Twine::dumpRepr() const { + printRepr(errs()); +} diff --git a/src/main/native/cpp/llvm/Unix/Path.inc b/src/main/native/cpp/llvm/Unix/Path.inc new file mode 100644 index 0000000000..436fb6efbb --- /dev/null +++ b/src/main/native/cpp/llvm/Unix/Path.inc @@ -0,0 +1,129 @@ +//===- llvm/Support/Unix/Path.inc - Unix Path Implementation ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific implementation of the Path API. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include + +namespace llvm { +namespace sys { +namespace path { + +bool home_directory(SmallVectorImpl &result) { + if (char *RequestedDir = std::getenv("HOME")) { + result.clear(); + result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); + return true; + } + + return false; +} + +static bool getDarwinConfDir(bool TempDir, SmallVectorImpl &Result) { + #if defined(_CS_DARWIN_USER_TEMP_DIR) && defined(_CS_DARWIN_USER_CACHE_DIR) + // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR. + // macros defined in on darwin >= 9 + int ConfName = TempDir ? _CS_DARWIN_USER_TEMP_DIR + : _CS_DARWIN_USER_CACHE_DIR; + size_t ConfLen = confstr(ConfName, nullptr, 0); + if (ConfLen > 0) { + do { + Result.resize(ConfLen); + ConfLen = confstr(ConfName, Result.data(), Result.size()); + } while (ConfLen > 0 && ConfLen != Result.size()); + + if (ConfLen > 0) { + assert(Result.back() == 0); + Result.pop_back(); + return true; + } + + Result.clear(); + } + #endif + return false; +} + +static bool getUserCacheDir(SmallVectorImpl &Result) { + // First try using XDG_CACHE_HOME env variable, + // as specified in XDG Base Directory Specification at + // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + if (const char *XdgCacheDir = std::getenv("XDG_CACHE_HOME")) { + Result.clear(); + Result.append(XdgCacheDir, XdgCacheDir + strlen(XdgCacheDir)); + return true; + } + + // Try Darwin configuration query + if (getDarwinConfDir(false, Result)) + return true; + + // Use "$HOME/.cache" if $HOME is available + if (home_directory(Result)) { + append(Result, ".cache"); + return true; + } + + return false; +} + +static const char *getEnvTempDir() { + // Check whether the temporary directory is specified by an environment + // variable. + const char *EnvironmentVariables[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"}; + for (const char *Env : EnvironmentVariables) { + if (const char *Dir = std::getenv(Env)) + return Dir; + } + + return nullptr; +} + +static const char *getDefaultTempDir(bool ErasedOnReboot) { +#ifdef P_tmpdir + if ((bool)P_tmpdir) + return P_tmpdir; +#endif + + if (ErasedOnReboot) + return "/tmp"; + return "/var/tmp"; +} + +void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl &Result) { + Result.clear(); + + if (ErasedOnReboot) { + // There is no env variable for the cache directory. + if (const char *RequestedDir = getEnvTempDir()) { + Result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); + return; + } + } + + if (getDarwinConfDir(ErasedOnReboot, Result)) + return; + + const char *RequestedDir = getDefaultTempDir(ErasedOnReboot); + Result.append(RequestedDir, RequestedDir + strlen(RequestedDir)); +} + +} // end namespace path +} // end namespace sys +} // end namespace llvm diff --git a/src/main/native/cpp/llvm/Windows/Path.inc b/src/main/native/cpp/llvm/Windows/Path.inc new file mode 100644 index 0000000000..1dd7d67dd3 --- /dev/null +++ b/src/main/native/cpp/llvm/Windows/Path.inc @@ -0,0 +1,175 @@ +//===- llvm/Support/Windows/Path.inc - Windows Path Impl --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Windows specific implementation of the Path API. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Windows code that +//=== is guaranteed to work on *all* Windows variants. +//===----------------------------------------------------------------------===// + +#include "llvm/STLExtras.h" +#include +#include +#include +#include +#include +#include + +#include "llvm/WindowsError.h" + +#ifdef _MSC_VER +# pragma comment(lib, "shell32.lib") +# pragma comment(lib, "ole32.lib") +#endif + +namespace llvm { +namespace sys { +namespace windows { +std::error_code UTF8ToUTF16(llvm::StringRef utf8, + llvm::SmallVectorImpl &utf16) { + if (!utf8.empty()) { + int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), + utf8.size(), utf16.begin(), 0); + + if (len == 0) + return mapWindowsError(::GetLastError()); + + utf16.reserve(len + 1); + utf16.set_size(len); + + len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), + utf8.size(), utf16.begin(), utf16.size()); + + if (len == 0) + return mapWindowsError(::GetLastError()); + } + + // Make utf16 null terminated. + utf16.push_back(0); + utf16.pop_back(); + + return std::error_code(); +} + +static +std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16, + size_t utf16_len, + llvm::SmallVectorImpl &utf8) { + if (utf16_len) { + // Get length. + int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.begin(), + 0, NULL, NULL); + + if (len == 0) + return mapWindowsError(::GetLastError()); + + utf8.reserve(len); + utf8.set_size(len); + + // Now do the actual conversion. + len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.data(), + utf8.size(), NULL, NULL); + + if (len == 0) + return mapWindowsError(::GetLastError()); + } + + // Make utf8 null terminated. + utf8.push_back(0); + utf8.pop_back(); + + return std::error_code(); +} + +std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, + llvm::SmallVectorImpl &utf8) { + return UTF16ToCodePage(CP_UTF8, utf16, utf16_len, utf8); +} + +std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, + llvm::SmallVectorImpl &utf8) { + return UTF16ToCodePage(CP_ACP, utf16, utf16_len, utf8); +} + +} // end namespace windows + +using llvm::sys::windows::UTF8ToUTF16; +using llvm::sys::windows::UTF16ToUTF8; + +namespace path { + +static bool getKnownFolderPath(KNOWNFOLDERID folderId, + SmallVectorImpl &result) { + wchar_t *path = nullptr; + if (::SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, nullptr, &path) != S_OK) + return false; + + bool ok = !UTF16ToUTF8(path, ::wcslen(path), result); + ::CoTaskMemFree(path); + return ok; +} + +bool getUserCacheDir(SmallVectorImpl &Result) { + return getKnownFolderPath(FOLDERID_LocalAppData, Result); +} + +bool home_directory(SmallVectorImpl &result) { + return getKnownFolderPath(FOLDERID_Profile, result); +} + +static bool getTempDirEnvVar(const wchar_t *Var, SmallVectorImpl &Res) { + SmallVector Buf; + size_t Size = 1024; + do { + Buf.reserve(Size); + Size = GetEnvironmentVariableW(Var, Buf.data(), Buf.capacity()); + if (Size == 0) + return false; + + // Try again with larger buffer. + } while (Size > Buf.capacity()); + Buf.set_size(Size); + + return !windows::UTF16ToUTF8(Buf.data(), Size, Res); +} + +static bool getTempDirEnvVar(SmallVectorImpl &Res) { + const wchar_t *EnvironmentVariables[] = {L"TMP", L"TEMP", L"USERPROFILE"}; + for (auto *Env : EnvironmentVariables) { + if (getTempDirEnvVar(Env, Res)) + return true; + } + return false; +} + +void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl &Result) { + (void)ErasedOnReboot; + Result.clear(); + + // Check whether the temporary directory is specified by an environment var. + // This matches GetTempPath logic to some degree. GetTempPath is not used + // directly as it cannot handle evn var longer than 130 chars on Windows 7 + // (fixed on Windows 8). + if (getTempDirEnvVar(Result)) { + assert(!Result.empty() && "Unexpected empty path"); + native(Result); // Some Unix-like shells use Unix path separator in $TMP. + //fs::make_absolute(Result); // Make it absolute if not already. + return; + } + + // Fall back to a system default. + const char *DefaultResult = "C:\\Temp"; + Result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); +} +} // end namespace path +} // end namespace sys +} // end namespace llvm diff --git a/src/main/native/include/llvm/Path.h b/src/main/native/include/llvm/Path.h new file mode 100644 index 0000000000..1431c47b15 --- /dev/null +++ b/src/main/native/include/llvm/Path.h @@ -0,0 +1,457 @@ +//===- llvm/Support/Path.h - Path Operating System Concept ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::path namespace. It is designed after +// TR2/boost filesystem (v3), but modified to remove exception handling and the +// path class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_PATH_H +#define LLVM_SUPPORT_PATH_H + +#include "llvm/Twine.h" +#include + +#include + +namespace llvm { +namespace sys { +namespace path { + +/// @name Lexical Component Iterator +/// @{ + +/// @brief Path iterator. +/// +/// This is an input iterator that iterates over the individual components in +/// \a path. The traversal order is as follows: +/// * The root-name element, if present. +/// * The root-directory element, if present. +/// * Each successive filename element, if present. +/// * Dot, if one or more trailing non-root slash characters are present. +/// Traversing backwards is possible with \a reverse_iterator +/// +/// Iteration examples. Each component is separated by ',': +/// @code +/// / => / +/// /foo => /,foo +/// foo/ => foo,. +/// /foo/bar => /,foo,bar +/// ../ => ..,. +/// C:\foo\bar => C:,/,foo,bar +/// @endcode +class const_iterator + : public std::iterator { + StringRef Path; ///< The entire path. + StringRef Component; ///< The current component. Not necessarily in Path. + size_t Position; ///< The iterators current position within Path. + + // An end iterator has Position = Path.size() + 1. + friend const_iterator begin(StringRef path); + friend const_iterator end(StringRef path); + +public: + reference operator*() const { return Component; } + pointer operator->() const { return &Component; } + const_iterator &operator++(); // preincrement + bool operator==(const const_iterator &RHS) const; + bool operator!=(const const_iterator &RHS) const { return !(*this == RHS); } + + /// @brief Difference in bytes between this and RHS. + ptrdiff_t operator-(const const_iterator &RHS) const; +}; + +/// @brief Reverse path iterator. +/// +/// This is an input iterator that iterates over the individual components in +/// \a path in reverse order. The traversal order is exactly reversed from that +/// of \a const_iterator +class reverse_iterator + : public std::iterator { + StringRef Path; ///< The entire path. + StringRef Component; ///< The current component. Not necessarily in Path. + size_t Position; ///< The iterators current position within Path. + + friend reverse_iterator rbegin(StringRef path); + friend reverse_iterator rend(StringRef path); + +public: + reference operator*() const { return Component; } + pointer operator->() const { return &Component; } + reverse_iterator &operator++(); // preincrement + bool operator==(const reverse_iterator &RHS) const; + bool operator!=(const reverse_iterator &RHS) const { return !(*this == RHS); } + + /// @brief Difference in bytes between this and RHS. + ptrdiff_t operator-(const reverse_iterator &RHS) const; +}; + +/// @brief Get begin iterator over \a path. +/// @param path Input path. +/// @returns Iterator initialized with the first component of \a path. +const_iterator begin(StringRef path); + +/// @brief Get end iterator over \a path. +/// @param path Input path. +/// @returns Iterator initialized to the end of \a path. +const_iterator end(StringRef path); + +/// @brief Get reverse begin iterator over \a path. +/// @param path Input path. +/// @returns Iterator initialized with the first reverse component of \a path. +reverse_iterator rbegin(StringRef path); + +/// @brief Get reverse end iterator over \a path. +/// @param path Input path. +/// @returns Iterator initialized to the reverse end of \a path. +reverse_iterator rend(StringRef path); + +/// @} +/// @name Lexical Modifiers +/// @{ + +/// @brief Remove the last component from \a path unless it is the root dir. +/// +/// @code +/// directory/filename.cpp => directory/ +/// directory/ => directory +/// filename.cpp => +/// / => / +/// @endcode +/// +/// @param path A path that is modified to not have a file component. +void remove_filename(SmallVectorImpl &path); + +/// @brief Replace the file extension of \a path with \a extension. +/// +/// @code +/// ./filename.cpp => ./filename.extension +/// ./filename => ./filename.extension +/// ./ => ./.extension +/// @endcode +/// +/// @param path A path that has its extension replaced with \a extension. +/// @param extension The extension to be added. It may be empty. It may also +/// optionally start with a '.', if it does not, one will be +/// prepended. +void replace_extension(SmallVectorImpl &path, const Twine &extension); + +/// @brief Replace matching path prefix with another path. +/// +/// @code +/// /foo, /old, /new => /foo +/// /old/foo, /old, /new => /new/foo +/// /foo, , /new => /new/foo +/// /old/foo, /old, => /foo +/// @endcode +/// +/// @param Path If \a Path starts with \a OldPrefix modify to instead +/// start with \a NewPrefix. +/// @param OldPrefix The path prefix to strip from \a Path. +/// @param NewPrefix The path prefix to replace \a NewPrefix with. +void replace_path_prefix(SmallVectorImpl &Path, + const StringRef &OldPrefix, + const StringRef &NewPrefix); + +/// @brief Append to path. +/// +/// @code +/// /foo + bar/f => /foo/bar/f +/// /foo/ + bar/f => /foo/bar/f +/// foo + bar/f => foo/bar/f +/// @endcode +/// +/// @param path Set to \a path + \a component. +/// @param a The component to be appended to \a path. +void append(SmallVectorImpl &path, const Twine &a, + const Twine &b = "", + const Twine &c = "", + const Twine &d = ""); + +/// @brief Append to path. +/// +/// @code +/// /foo + [bar,f] => /foo/bar/f +/// /foo/ + [bar,f] => /foo/bar/f +/// foo + [bar,f] => foo/bar/f +/// @endcode +/// +/// @param path Set to \a path + [\a begin, \a end). +/// @param begin Start of components to append. +/// @param end One past the end of components to append. +void append(SmallVectorImpl &path, + const_iterator begin, const_iterator end); + +/// @} +/// @name Transforms (or some other better name) +/// @{ + +/// Convert path to the native form. This is used to give paths to users and +/// operating system calls in the platform's normal way. For example, on Windows +/// all '/' are converted to '\'. +/// +/// @param path A path that is transformed to native format. +/// @param result Holds the result of the transformation. +void native(const Twine &path, SmallVectorImpl &result); + +/// Convert path to the native form in place. This is used to give paths to +/// users and operating system calls in the platform's normal way. For example, +/// on Windows all '/' are converted to '\'. +/// +/// @param path A path that is transformed to native format. +void native(SmallVectorImpl &path); + +/// @} +/// @name Lexical Observers +/// @{ + +/// @brief Get root name. +/// +/// @code +/// //net/hello => //net +/// c:/hello => c: (on Windows, on other platforms nothing) +/// /hello => +/// @endcode +/// +/// @param path Input path. +/// @result The root name of \a path if it has one, otherwise "". +StringRef root_name(StringRef path); + +/// @brief Get root directory. +/// +/// @code +/// /goo/hello => / +/// c:/hello => / +/// d/file.txt => +/// @endcode +/// +/// @param path Input path. +/// @result The root directory of \a path if it has one, otherwise +/// "". +StringRef root_directory(StringRef path); + +/// @brief Get root path. +/// +/// Equivalent to root_name + root_directory. +/// +/// @param path Input path. +/// @result The root path of \a path if it has one, otherwise "". +StringRef root_path(StringRef path); + +/// @brief Get relative path. +/// +/// @code +/// C:\hello\world => hello\world +/// foo/bar => foo/bar +/// /foo/bar => foo/bar +/// @endcode +/// +/// @param path Input path. +/// @result The path starting after root_path if one exists, otherwise "". +StringRef relative_path(StringRef path); + +/// @brief Get parent path. +/// +/// @code +/// / => +/// /foo => / +/// foo/../bar => foo/.. +/// @endcode +/// +/// @param path Input path. +/// @result The parent path of \a path if one exists, otherwise "". +StringRef parent_path(StringRef path); + +/// @brief Get filename. +/// +/// @code +/// /foo.txt => foo.txt +/// . => . +/// .. => .. +/// / => / +/// @endcode +/// +/// @param path Input path. +/// @result The filename part of \a path. This is defined as the last component +/// of \a path. +StringRef filename(StringRef path); + +/// @brief Get stem. +/// +/// If filename contains a dot but not solely one or two dots, result is the +/// substring of filename ending at (but not including) the last dot. Otherwise +/// it is filename. +/// +/// @code +/// /foo/bar.txt => bar +/// /foo/bar => bar +/// /foo/.txt => +/// /foo/. => . +/// /foo/.. => .. +/// @endcode +/// +/// @param path Input path. +/// @result The stem of \a path. +StringRef stem(StringRef path); + +/// @brief Get extension. +/// +/// If filename contains a dot but not solely one or two dots, result is the +/// substring of filename starting at (and including) the last dot, and ending +/// at the end of \a path. Otherwise "". +/// +/// @code +/// /foo/bar.txt => .txt +/// /foo/bar => +/// /foo/.txt => .txt +/// @endcode +/// +/// @param path Input path. +/// @result The extension of \a path. +StringRef extension(StringRef path); + +/// @brief Check whether the given char is a path separator on the host OS. +/// +/// @param value a character +/// @result true if \a value is a path separator character on the host OS +bool is_separator(char value); + +/// @brief Return the preferred separator for this platform. +/// +/// @result StringRef of the preferred separator, null-terminated. +StringRef get_separator(); + +/// @brief Get the typical temporary directory for the system, e.g., +/// "/var/tmp" or "C:/TEMP" +/// +/// @param erasedOnReboot Whether to favor a path that is erased on reboot +/// rather than one that potentially persists longer. This parameter will be +/// ignored if the user or system has set the typical environment variable +/// (e.g., TEMP on Windows, TMPDIR on *nix) to specify a temporary directory. +/// +/// @param result Holds the resulting path name. +void system_temp_directory(bool erasedOnReboot, SmallVectorImpl &result); + +/// @brief Get the user's home directory. +/// +/// @param result Holds the resulting path name. +/// @result True if a home directory is set, false otherwise. +bool home_directory(SmallVectorImpl &result); + +/// @brief Get the user's cache directory. +/// +/// Expect the resulting path to be a directory shared with other +/// applications/services used by the user. Params \p Path1 to \p Path3 can be +/// used to append additional directory names to the resulting path. Recommended +/// pattern is //. +/// +/// @param Result Holds the resulting path. +/// @param Path1 Additional path to be appended to the user's cache directory +/// path. "" can be used to append nothing. +/// @param Path2 Second additional path to be appended. +/// @param Path3 Third additional path to be appended. +/// @result True if a cache directory path is set, false otherwise. +bool user_cache_directory(SmallVectorImpl &Result, const Twine &Path1, + const Twine &Path2 = "", const Twine &Path3 = ""); + +/// @brief Has root name? +/// +/// root_name != "" +/// +/// @param path Input path. +/// @result True if the path has a root name, false otherwise. +bool has_root_name(const Twine &path); + +/// @brief Has root directory? +/// +/// root_directory != "" +/// +/// @param path Input path. +/// @result True if the path has a root directory, false otherwise. +bool has_root_directory(const Twine &path); + +/// @brief Has root path? +/// +/// root_path != "" +/// +/// @param path Input path. +/// @result True if the path has a root path, false otherwise. +bool has_root_path(const Twine &path); + +/// @brief Has relative path? +/// +/// relative_path != "" +/// +/// @param path Input path. +/// @result True if the path has a relative path, false otherwise. +bool has_relative_path(const Twine &path); + +/// @brief Has parent path? +/// +/// parent_path != "" +/// +/// @param path Input path. +/// @result True if the path has a parent path, false otherwise. +bool has_parent_path(const Twine &path); + +/// @brief Has filename? +/// +/// filename != "" +/// +/// @param path Input path. +/// @result True if the path has a filename, false otherwise. +bool has_filename(const Twine &path); + +/// @brief Has stem? +/// +/// stem != "" +/// +/// @param path Input path. +/// @result True if the path has a stem, false otherwise. +bool has_stem(const Twine &path); + +/// @brief Has extension? +/// +/// extension != "" +/// +/// @param path Input path. +/// @result True if the path has a extension, false otherwise. +bool has_extension(const Twine &path); + +/// @brief Is path absolute? +/// +/// @param path Input path. +/// @result True if the path is absolute, false if it is not. +bool is_absolute(const Twine &path); + +/// @brief Is path relative? +/// +/// @param path Input path. +/// @result True if the path is relative, false if it is not. +bool is_relative(const Twine &path); + +/// @brief Remove redundant leading "./" pieces and consecutive separators. +/// +/// @param path Input path. +/// @result The cleaned-up \a path. +StringRef remove_leading_dotslash(StringRef path); + +/// @brief In-place remove any './' and optionally '../' components from a path. +/// +/// @param path processed path +/// @param remove_dot_dot specify if '../' should be removed +/// @result True if path was changed +bool remove_dots(SmallVectorImpl &path, bool remove_dot_dot = false); + +} // end namespace path +} // end namespace sys +} // end namespace llvm + +#endif diff --git a/src/main/native/include/llvm/Twine.h b/src/main/native/include/llvm/Twine.h new file mode 100644 index 0000000000..9cac658f76 --- /dev/null +++ b/src/main/native/include/llvm/Twine.h @@ -0,0 +1,542 @@ +//===-- Twine.h - Fast Temporary String Concatenation -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_TWINE_H +#define LLVM_ADT_TWINE_H + +#include "llvm/SmallVector.h" +#include "llvm/StringRef.h" +#include +#include + +#include + +namespace llvm { + class raw_ostream; + + /// Twine - A lightweight data structure for efficiently representing the + /// concatenation of temporary values as strings. + /// + /// A Twine is a kind of rope, it represents a concatenated string using a + /// binary-tree, where the string is the preorder of the nodes. Since the + /// Twine can be efficiently rendered into a buffer when its result is used, + /// it avoids the cost of generating temporary values for intermediate string + /// results -- particularly in cases when the Twine result is never + /// required. By explicitly tracking the type of leaf nodes, we can also avoid + /// the creation of temporary strings for conversions operations (such as + /// appending an integer to a string). + /// + /// A Twine is not intended for use directly and should not be stored, its + /// implementation relies on the ability to store pointers to temporary stack + /// objects which may be deallocated at the end of a statement. Twines should + /// only be used accepted as const references in arguments, when an API wishes + /// to accept possibly-concatenated strings. + /// + /// Twines support a special 'null' value, which always concatenates to form + /// itself, and renders as an empty string. This can be returned from APIs to + /// effectively nullify any concatenations performed on the result. + /// + /// \b Implementation + /// + /// Given the nature of a Twine, it is not possible for the Twine's + /// concatenation method to construct interior nodes; the result must be + /// represented inside the returned value. For this reason a Twine object + /// actually holds two values, the left- and right-hand sides of a + /// concatenation. We also have nullary Twine objects, which are effectively + /// sentinel values that represent empty strings. + /// + /// Thus, a Twine can effectively have zero, one, or two children. The \see + /// isNullary(), \see isUnary(), and \see isBinary() predicates exist for + /// testing the number of children. + /// + /// We maintain a number of invariants on Twine objects (FIXME: Why): + /// - Nullary twines are always represented with their Kind on the left-hand + /// side, and the Empty kind on the right-hand side. + /// - Unary twines are always represented with the value on the left-hand + /// side, and the Empty kind on the right-hand side. + /// - If a Twine has another Twine as a child, that child should always be + /// binary (otherwise it could have been folded into the parent). + /// + /// These invariants are check by \see isValid(). + /// + /// \b Efficiency Considerations + /// + /// The Twine is designed to yield efficient and small code for common + /// situations. For this reason, the concat() method is inlined so that + /// concatenations of leaf nodes can be optimized into stores directly into a + /// single stack allocated object. + /// + /// In practice, not all compilers can be trusted to optimize concat() fully, + /// so we provide two additional methods (and accompanying operator+ + /// overloads) to guarantee that particularly important cases (cstring plus + /// StringRef) codegen as desired. + class Twine { + /// NodeKind - Represent the type of an argument. + enum NodeKind : unsigned char { + /// An empty string; the result of concatenating anything with it is also + /// empty. + NullKind, + + /// The empty string. + EmptyKind, + + /// A pointer to a Twine instance. + TwineKind, + + /// A pointer to a C string instance. + CStringKind, + + /// A pointer to an std::string instance. + StdStringKind, + + /// A pointer to a StringRef instance. + StringRefKind, + + /// A pointer to a SmallString instance. + SmallStringKind, + + /// A char value, to render as a character. + CharKind, + + /// An unsigned int value, to render as an unsigned decimal integer. + DecUIKind, + + /// An int value, to render as a signed decimal integer. + DecIKind, + + /// A pointer to an unsigned long value, to render as an unsigned decimal + /// integer. + DecULKind, + + /// A pointer to a long value, to render as a signed decimal integer. + DecLKind, + + /// A pointer to an unsigned long long value, to render as an unsigned + /// decimal integer. + DecULLKind, + + /// A pointer to a long long value, to render as a signed decimal integer. + DecLLKind, + + /// A pointer to a uint64_t value, to render as an unsigned hexadecimal + /// integer. + UHexKind + }; + + union Child + { + const Twine *twine; + const char *cString; + const std::string *stdString; + const StringRef *stringRef; + const SmallVectorImpl *smallString; + char character; + unsigned int decUI; + int decI; + const unsigned long *decUL; + const long *decL; + const unsigned long long *decULL; + const long long *decLL; + const uint64_t *uHex; + }; + + private: + /// LHS - The prefix in the concatenation, which may be uninitialized for + /// Null or Empty kinds. + Child LHS; + /// RHS - The suffix in the concatenation, which may be uninitialized for + /// Null or Empty kinds. + Child RHS; + /// LHSKind - The NodeKind of the left hand side, \see getLHSKind(). + NodeKind LHSKind; + /// RHSKind - The NodeKind of the right hand side, \see getRHSKind(). + NodeKind RHSKind; + + private: + /// Construct a nullary twine; the kind must be NullKind or EmptyKind. + explicit Twine(NodeKind Kind) + : LHSKind(Kind), RHSKind(EmptyKind) { + assert(isNullary() && "Invalid kind!"); + } + + /// Construct a binary twine. + explicit Twine(const Twine &LHS, const Twine &RHS) + : LHSKind(TwineKind), RHSKind(TwineKind) { + this->LHS.twine = &LHS; + this->RHS.twine = &RHS; + assert(isValid() && "Invalid twine!"); + } + + /// Construct a twine from explicit values. + explicit Twine(Child LHS, NodeKind LHSKind, Child RHS, NodeKind RHSKind) + : LHS(LHS), RHS(RHS), LHSKind(LHSKind), RHSKind(RHSKind) { + assert(isValid() && "Invalid twine!"); + } + + /// Since the intended use of twines is as temporary objects, assignments + /// when concatenating might cause undefined behavior or stack corruptions + Twine &operator=(const Twine &Other) = delete; + + /// Check for the null twine. + bool isNull() const { + return getLHSKind() == NullKind; + } + + /// Check for the empty twine. + bool isEmpty() const { + return getLHSKind() == EmptyKind; + } + + /// Check if this is a nullary twine (null or empty). + bool isNullary() const { + return isNull() || isEmpty(); + } + + /// Check if this is a unary twine. + bool isUnary() const { + return getRHSKind() == EmptyKind && !isNullary(); + } + + /// Check if this is a binary twine. + bool isBinary() const { + return getLHSKind() != NullKind && getRHSKind() != EmptyKind; + } + + /// Check if this is a valid twine (satisfying the invariants on + /// order and number of arguments). + bool isValid() const { + // Nullary twines always have Empty on the RHS. + if (isNullary() && getRHSKind() != EmptyKind) + return false; + + // Null should never appear on the RHS. + if (getRHSKind() == NullKind) + return false; + + // The RHS cannot be non-empty if the LHS is empty. + if (getRHSKind() != EmptyKind && getLHSKind() == EmptyKind) + return false; + + // A twine child should always be binary. + if (getLHSKind() == TwineKind && + !LHS.twine->isBinary()) + return false; + if (getRHSKind() == TwineKind && + !RHS.twine->isBinary()) + return false; + + return true; + } + + /// Get the NodeKind of the left-hand side. + NodeKind getLHSKind() const { return LHSKind; } + + /// Get the NodeKind of the right-hand side. + NodeKind getRHSKind() const { return RHSKind; } + + /// Print one child from a twine. + void printOneChild(raw_ostream &OS, Child Ptr, NodeKind Kind) const; + + /// Print the representation of one child from a twine. + void printOneChildRepr(raw_ostream &OS, Child Ptr, + NodeKind Kind) const; + + public: + /// @name Constructors + /// @{ + + /// Construct from an empty string. + /*implicit*/ Twine() : LHSKind(EmptyKind), RHSKind(EmptyKind) { + assert(isValid() && "Invalid twine!"); + } + + Twine(const Twine &) = default; + + /// Construct from a C string. + /// + /// We take care here to optimize "" into the empty twine -- this will be + /// optimized out for string constants. This allows Twine arguments have + /// default "" values, without introducing unnecessary string constants. + /*implicit*/ Twine(const char *Str) + : RHSKind(EmptyKind) { + if (Str[0] != '\0') { + LHS.cString = Str; + LHSKind = CStringKind; + } else + LHSKind = EmptyKind; + + assert(isValid() && "Invalid twine!"); + } + + /// Construct from an std::string. + /*implicit*/ Twine(const std::string &Str) + : LHSKind(StdStringKind), RHSKind(EmptyKind) { + LHS.stdString = &Str; + assert(isValid() && "Invalid twine!"); + } + + /// Construct from a StringRef. + /*implicit*/ Twine(const StringRef &Str) + : LHSKind(StringRefKind), RHSKind(EmptyKind) { + LHS.stringRef = &Str; + assert(isValid() && "Invalid twine!"); + } + + /// Construct from a SmallString. + /*implicit*/ Twine(const SmallVectorImpl &Str) + : LHSKind(SmallStringKind), RHSKind(EmptyKind) { + LHS.smallString = &Str; + assert(isValid() && "Invalid twine!"); + } + + /// Construct from a char. + explicit Twine(char Val) + : LHSKind(CharKind), RHSKind(EmptyKind) { + LHS.character = Val; + } + + /// Construct from a signed char. + explicit Twine(signed char Val) + : LHSKind(CharKind), RHSKind(EmptyKind) { + LHS.character = static_cast(Val); + } + + /// Construct from an unsigned char. + explicit Twine(unsigned char Val) + : LHSKind(CharKind), RHSKind(EmptyKind) { + LHS.character = static_cast(Val); + } + + /// Construct a twine to print \p Val as an unsigned decimal integer. + explicit Twine(unsigned Val) + : LHSKind(DecUIKind), RHSKind(EmptyKind) { + LHS.decUI = Val; + } + + /// Construct a twine to print \p Val as a signed decimal integer. + explicit Twine(int Val) + : LHSKind(DecIKind), RHSKind(EmptyKind) { + LHS.decI = Val; + } + + /// Construct a twine to print \p Val as an unsigned decimal integer. + explicit Twine(const unsigned long &Val) + : LHSKind(DecULKind), RHSKind(EmptyKind) { + LHS.decUL = &Val; + } + + /// Construct a twine to print \p Val as a signed decimal integer. + explicit Twine(const long &Val) + : LHSKind(DecLKind), RHSKind(EmptyKind) { + LHS.decL = &Val; + } + + /// Construct a twine to print \p Val as an unsigned decimal integer. + explicit Twine(const unsigned long long &Val) + : LHSKind(DecULLKind), RHSKind(EmptyKind) { + LHS.decULL = &Val; + } + + /// Construct a twine to print \p Val as a signed decimal integer. + explicit Twine(const long long &Val) + : LHSKind(DecLLKind), RHSKind(EmptyKind) { + LHS.decLL = &Val; + } + + // FIXME: Unfortunately, to make sure this is as efficient as possible we + // need extra binary constructors from particular types. We can't rely on + // the compiler to be smart enough to fold operator+()/concat() down to the + // right thing. Yet. + + /// Construct as the concatenation of a C string and a StringRef. + /*implicit*/ Twine(const char *LHS, const StringRef &RHS) + : LHSKind(CStringKind), RHSKind(StringRefKind) { + this->LHS.cString = LHS; + this->RHS.stringRef = &RHS; + assert(isValid() && "Invalid twine!"); + } + + /// Construct as the concatenation of a StringRef and a C string. + /*implicit*/ Twine(const StringRef &LHS, const char *RHS) + : LHSKind(StringRefKind), RHSKind(CStringKind) { + this->LHS.stringRef = &LHS; + this->RHS.cString = RHS; + assert(isValid() && "Invalid twine!"); + } + + /// Create a 'null' string, which is an empty string that always + /// concatenates to form another empty string. + static Twine createNull() { + return Twine(NullKind); + } + + /// @} + /// @name Numeric Conversions + /// @{ + + // Construct a twine to print \p Val as an unsigned hexadecimal integer. + static Twine utohexstr(const uint64_t &Val) { + Child LHS, RHS; + LHS.uHex = &Val; + RHS.twine = nullptr; + return Twine(LHS, UHexKind, RHS, EmptyKind); + } + + /// @} + /// @name Predicate Operations + /// @{ + + /// Check if this twine is trivially empty; a false return value does not + /// necessarily mean the twine is empty. + bool isTriviallyEmpty() const { + return isNullary(); + } + + /// Return true if this twine can be dynamically accessed as a single + /// StringRef value with getSingleStringRef(). + bool isSingleStringRef() const { + if (getRHSKind() != EmptyKind) return false; + + switch (getLHSKind()) { + case EmptyKind: + case CStringKind: + case StdStringKind: + case StringRefKind: + case SmallStringKind: + return true; + default: + return false; + } + } + + /// @} + /// @name String Operations + /// @{ + + Twine concat(const Twine &Suffix) const; + + /// @} + /// @name Output & Conversion. + /// @{ + + /// Return the twine contents as a std::string. + std::string str() const; + + /// Append the concatenated string into the given SmallString or SmallVector. + void toVector(SmallVectorImpl &Out) const; + + /// This returns the twine as a single StringRef. This method is only valid + /// if isSingleStringRef() is true. + StringRef getSingleStringRef() const { + assert(isSingleStringRef() &&"This cannot be had as a single stringref!"); + switch (getLHSKind()) { + default: + // unreachable("Out of sync with isSingleStringRef"); + return StringRef(); + case EmptyKind: return StringRef(); + case CStringKind: return StringRef(LHS.cString); + case StdStringKind: return StringRef(*LHS.stdString); + case StringRefKind: return *LHS.stringRef; + case SmallStringKind: + return StringRef(LHS.smallString->data(), LHS.smallString->size()); + } + } + + /// This returns the twine as a single StringRef if it can be + /// represented as such. Otherwise the twine is written into the given + /// SmallVector and a StringRef to the SmallVector's data is returned. + StringRef toStringRef(SmallVectorImpl &Out) const { + if (isSingleStringRef()) + return getSingleStringRef(); + toVector(Out); + return StringRef(Out.data(), Out.size()); + } + + /// This returns the twine as a single null terminated StringRef if it + /// can be represented as such. Otherwise the twine is written into the + /// given SmallVector and a StringRef to the SmallVector's data is returned. + /// + /// The returned StringRef's size does not include the null terminator. + StringRef toNullTerminatedStringRef(SmallVectorImpl &Out) const; + + /// Write the concatenated string represented by this twine to the + /// stream \p OS. + void print(raw_ostream &OS) const; + + /// Dump the concatenated string represented by this twine to stderr. + void dump() const; + + /// Write the representation of this twine to the stream \p OS. + void printRepr(raw_ostream &OS) const; + + /// Dump the representation of this twine to stderr. + void dumpRepr() const; + + /// @} + }; + + /// @name Twine Inline Implementations + /// @{ + + inline Twine Twine::concat(const Twine &Suffix) const { + // Concatenation with null is null. + if (isNull() || Suffix.isNull()) + return Twine(NullKind); + + // Concatenation with empty yields the other side. + if (isEmpty()) + return Suffix; + if (Suffix.isEmpty()) + return *this; + + // Otherwise we need to create a new node, taking care to fold in unary + // twines. + Child NewLHS, NewRHS; + NewLHS.twine = this; + NewRHS.twine = &Suffix; + NodeKind NewLHSKind = TwineKind, NewRHSKind = TwineKind; + if (isUnary()) { + NewLHS = LHS; + NewLHSKind = getLHSKind(); + } + if (Suffix.isUnary()) { + NewRHS = Suffix.LHS; + NewRHSKind = Suffix.getLHSKind(); + } + + return Twine(NewLHS, NewLHSKind, NewRHS, NewRHSKind); + } + + inline Twine operator+(const Twine &LHS, const Twine &RHS) { + return LHS.concat(RHS); + } + + /// Additional overload to guarantee simplified codegen; this is equivalent to + /// concat(). + + inline Twine operator+(const char *LHS, const StringRef &RHS) { + return Twine(LHS, RHS); + } + + /// Additional overload to guarantee simplified codegen; this is equivalent to + /// concat(). + + inline Twine operator+(const StringRef &LHS, const char *RHS) { + return Twine(LHS, RHS); + } + + inline raw_ostream &operator<<(raw_ostream &OS, const Twine &RHS) { + RHS.print(OS); + return OS; + } + + /// @} +} + +#endif