/* 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 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 toMap(const std::vector &keys) { std::map 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 += "ยท"; 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 &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 split(const std::string &s, const std::string &sep, int count) { std::vector 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 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 std::exception_ptr get_nested(const T &/*e*/) { try { return nullptr; } catch (const std::bad_cast &) { return nullptr; } } #else template std::exception_ptr get_nested(const T &e) { try { auto nested = dynamic_cast(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; } //----------------- FinallyAction ------------------------------------------------------------------------------------ FinalAction finally(std::function f) { return FinalAction(f); } //----------------- SingleWriteMultipleRead -------------------------------------------------------------------------- void SingleWriteMultipleReadLock::readLock() { std::unique_lock lock(_mutex); while (_waitingWriters != 0) _readerGate.wait(lock); ++_activeReaders; lock.unlock(); } void SingleWriteMultipleReadLock::readUnlock() { std::unique_lock lock(_mutex); --_activeReaders; lock.unlock(); _writerGate.notify_one(); } void SingleWriteMultipleReadLock::writeLock() { std::unique_lock lock(_mutex); ++_waitingWriters; while (_activeReaders != 0 || _activeWriters != 0) _writerGate.wait(lock); ++_activeWriters; lock.unlock(); } void SingleWriteMultipleReadLock::writeUnlock() { std::unique_lock lock(_mutex); --_waitingWriters; --_activeWriters; if (_waitingWriters > 0) _writerGate.notify_one(); else _readerGate.notify_all(); lock.unlock(); } } // namespace antlrcpp