| /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
| * Use of this file is governed by the BSD 3-clause license that |
| * can be found in the LICENSE.txt file in the project root. |
| */ |
| |
| #include "support/CPPUtils.h" |
| |
| namespace antlrcpp { |
| |
| std::string join(std::vector<std::string> strings, const std::string &separator) { |
| std::string str; |
| bool firstItem = true; |
| for (std::string s : strings) { |
| if (!firstItem) { |
| str.append(separator); |
| } |
| firstItem = false; |
| str.append(s); |
| } |
| return str; |
| } |
| |
| std::map<std::string, size_t> toMap(const std::vector<std::string> &keys) { |
| std::map<std::string, size_t> result; |
| for (size_t i = 0; i < keys.size(); ++i) { |
| result.insert({ keys[i], i }); |
| } |
| return result; |
| } |
| |
| std::string escapeWhitespace(std::string str, bool escapeSpaces) { |
| std::string result; |
| for (auto c : str) { |
| switch (c) { |
| case '\n': |
| result += "\\n"; |
| break; |
| |
| case '\r': |
| result += "\\r"; |
| break; |
| |
| case '\t': |
| result += "\\t"; |
| break; |
| |
| case ' ': |
| if (escapeSpaces) { |
| result += "\u00B7"; |
| break; |
| } else { |
| result += c; |
| break; |
| } |
| // else fall through |
| #ifndef _MSC_VER |
| #if __has_cpp_attribute(clang::fallthrough) |
| [[clang::fallthrough]]; |
| #endif |
| #endif |
| |
| default: |
| result += c; |
| } |
| } |
| |
| return result; |
| } |
| |
| std::string toHexString(const int t) { |
| std::stringstream stream; |
| stream << std::uppercase << std::hex << t; |
| return stream.str(); |
| } |
| |
| std::string arrayToString(const std::vector<std::string> &data) { |
| std::string answer; |
| for (auto sub: data) { |
| answer += sub; |
| } |
| return answer; |
| } |
| |
| std::string replaceString(const std::string &s, const std::string &from, const std::string &to) { |
| std::string::size_type p; |
| std::string ss, res; |
| |
| ss = s; |
| p = ss.find(from); |
| while (p != std::string::npos) { |
| if (p > 0) |
| res.append(ss.substr(0, p)).append(to); |
| else |
| res.append(to); |
| ss = ss.substr(p + from.size()); |
| p = ss.find(from); |
| } |
| res.append(ss); |
| |
| return res; |
| } |
| |
| std::vector<std::string> split(const std::string &s, const std::string &sep, int count) { |
| std::vector<std::string> parts; |
| std::string ss = s; |
| |
| std::string::size_type p; |
| |
| if (s.empty()) |
| return parts; |
| |
| if (count == 0) |
| count= -1; |
| |
| p = ss.find(sep); |
| while (!ss.empty() && p != std::string::npos && (count < 0 || count > 0)) { |
| parts.push_back(ss.substr(0, p)); |
| ss = ss.substr(p+sep.size()); |
| |
| --count; |
| p = ss.find(sep); |
| } |
| parts.push_back(ss); |
| |
| return parts; |
| } |
| |
| //-------------------------------------------------------------------------------------------------- |
| |
| // Debugging helper. Adds indentation to all lines in the given string. |
| std::string indent(const std::string &s, const std::string &indentation, bool includingFirst) { |
| std::vector<std::string> parts = split(s, "\n", -1); |
| for (size_t i = 0; i < parts.size(); ++i) { |
| if (i == 0 && !includingFirst) |
| continue; |
| parts[i].insert(0, indentation); |
| } |
| |
| return join(parts, "\n"); |
| } |
| |
| //-------------------------------------------------------------------------------------------------- |
| |
| // Recursively get the error from a, possibly nested, exception. |
| #if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023026 |
| // No nested exceptions before VS 2015. |
| template <typename T> |
| std::exception_ptr get_nested(const T &/*e*/) { |
| try { |
| return nullptr; |
| } |
| catch (const std::bad_cast &) { |
| return nullptr; |
| } |
| } |
| #else |
| template <typename T> |
| std::exception_ptr get_nested(const T &e) { |
| try { |
| auto nested = dynamic_cast<const std::nested_exception&>(e); |
| return nested.nested_ptr(); |
| } |
| catch (const std::bad_cast &) { |
| return nullptr; |
| } |
| } |
| #endif |
| |
| std::string what(std::exception_ptr eptr) { |
| if (!eptr) { |
| throw std::bad_exception(); |
| } |
| |
| std::string result; |
| std::size_t nestCount = 0; |
| |
| next: { |
| try { |
| std::exception_ptr yeptr; |
| std::swap(eptr, yeptr); |
| std::rethrow_exception(yeptr); |
| } |
| catch (const std::exception &e) { |
| result += e.what(); |
| eptr = get_nested(e); |
| } |
| catch (const std::string &e) { |
| result += e; |
| } |
| catch (const char *e) { |
| result += e; |
| } |
| catch (...) { |
| result += "cannot be determined"; |
| } |
| |
| if (eptr) { |
| result += " ("; |
| ++nestCount; |
| goto next; |
| } |
| } |
| |
| result += std::string(nestCount, ')'); |
| return result; |
| } |
| |
| //----------------- SingleWriteMultipleRead -------------------------------------------------------------------------- |
| |
| void SingleWriteMultipleReadLock::readLock() { |
| std::unique_lock<std::mutex> lock(_mutex); |
| while (_waitingWriters != 0) |
| _readerGate.wait(lock); |
| ++_activeReaders; |
| lock.unlock(); |
| } |
| |
| void SingleWriteMultipleReadLock::readUnlock() { |
| std::unique_lock<std::mutex> lock(_mutex); |
| --_activeReaders; |
| lock.unlock(); |
| _writerGate.notify_one(); |
| } |
| |
| void SingleWriteMultipleReadLock::writeLock() { |
| std::unique_lock<std::mutex> lock(_mutex); |
| ++_waitingWriters; |
| while (_activeReaders != 0 || _activeWriters != 0) |
| _writerGate.wait(lock); |
| ++_activeWriters; |
| lock.unlock(); |
| } |
| |
| void SingleWriteMultipleReadLock::writeUnlock() { |
| std::unique_lock<std::mutex> lock(_mutex); |
| --_waitingWriters; |
| --_activeWriters; |
| if (_waitingWriters > 0) |
| _writerGate.notify_one(); |
| else |
| _readerGate.notify_all(); |
| lock.unlock(); |
| } |
| |
| } // namespace antlrcpp |