blob: 307001946f19d430658d29d80690e5bfb41f4689 [file] [log] [blame]
/* 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