mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
* libSyntax: Parse member access expression. This patch uses createNodeInPlace from syntax parsing context API to merge an expression with its suffix to create recursive nodes such as member access expression. Meanwhile, this patch breaks down a signed integer or float literal to a prefix operator expression. This expression consists of two parts: an operator and the following expression. This makes literals like "+1" or "-1" no different from other prefix unary expressions such as "!true".
107 lines
2.8 KiB
C++
107 lines
2.8 KiB
C++
#include "swift/Syntax/SyntaxFactory.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <future>
|
|
#include <thread>
|
|
#include <queue>
|
|
|
|
using namespace swift;
|
|
using namespace swift::syntax;
|
|
|
|
static uintptr_t getExpressionFrom(ReturnStmtSyntax Return) {
|
|
auto Expression = Return.getExpression().getValue();
|
|
return reinterpret_cast<uintptr_t>(Expression.getDataPointer());
|
|
}
|
|
|
|
class Pool {
|
|
static constexpr size_t NumThreads = 2;
|
|
using FuncTy = std::function<uintptr_t(ReturnStmtSyntax)>;
|
|
std::vector<std::thread> Workers;
|
|
std::queue<std::function<void()>> Tasks;
|
|
std::mutex QueueLock;
|
|
std::condition_variable Condition;
|
|
bool Stop;
|
|
|
|
public:
|
|
Pool() : Stop(false) {
|
|
for (size_t i = 0; i < NumThreads; ++i)
|
|
Workers.emplace_back([this] {
|
|
while (true) {
|
|
std::function<void()> Task;
|
|
{
|
|
std::unique_lock<std::mutex> L(QueueLock);
|
|
|
|
Condition.wait(L, [this]{
|
|
return Stop || !Tasks.empty();
|
|
});
|
|
|
|
if (Stop && Tasks.empty()) {
|
|
return;
|
|
}
|
|
|
|
Task = std::move(Tasks.front());
|
|
Tasks.pop();
|
|
}
|
|
|
|
Task();
|
|
}
|
|
});
|
|
}
|
|
|
|
std::future<uintptr_t> run(FuncTy Func, ReturnStmtSyntax Return) {
|
|
auto Task = std::make_shared<std::packaged_task<uintptr_t()>>(
|
|
std::bind(Func, Return));
|
|
|
|
auto Future = Task->get_future();
|
|
{
|
|
std::unique_lock<std::mutex> L(QueueLock);
|
|
Tasks.emplace([Task](){ (*Task)(); });
|
|
}
|
|
Condition.notify_one();
|
|
return Future;
|
|
}
|
|
|
|
~Pool() {
|
|
{
|
|
std::lock_guard<std::mutex> L(QueueLock);
|
|
Stop = true;
|
|
}
|
|
Condition.notify_all();
|
|
for (auto &Worker : Workers) {
|
|
Worker.join();
|
|
}
|
|
}
|
|
};
|
|
|
|
// Tests that, when multiple threads ask for a child node of the same syntax
|
|
// node:
|
|
// - Only one thread inserts the realized child into the parent
|
|
// - Both threads get the exact same child (by identity)
|
|
TEST(ThreadSafeCachingTests, ReturnGetExpression) {
|
|
auto ReturnKW = SyntaxFactory::makeReturnKeyword({}, Trivia::spaces(1));
|
|
auto Minus = SyntaxFactory::makePrefixOperator("-", {}, {});
|
|
auto One = SyntaxFactory::makeIntegerLiteral("1", {}, {});
|
|
auto MinusOne = SyntaxFactory::makePrefixOperatorExpr(Minus,
|
|
SyntaxFactory::makeIntegerLiteralExpr(One));
|
|
|
|
Pool P;
|
|
|
|
for (unsigned i = 0; i < 10000; ++i) {
|
|
auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne, None);
|
|
|
|
auto Future1 = P.run(getExpressionFrom, Return);
|
|
auto Future2 = P.run(getExpressionFrom, Return);
|
|
|
|
auto FirstDataPointer = Future1.get();
|
|
auto SecondDataPointer = Future2.get();
|
|
|
|
auto DataPointer = reinterpret_cast<uintptr_t>(
|
|
Return.getExpression().getValue().getDataPointer());
|
|
|
|
ASSERT_EQ(FirstDataPointer, SecondDataPointer);
|
|
ASSERT_EQ(FirstDataPointer, DataPointer);
|
|
}
|
|
}
|
|
|