--- /dev/null
+/* 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 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;
+ }
+
+ //----------------- FinallyAction ------------------------------------------------------------------------------------
+
+ FinalAction finally(std::function<void ()> f) {
+ return FinalAction(f);
+ }
+
+ //----------------- 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