1 //===--- DraftStore.cpp - File contents container ---------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "DraftStore.h"
10 #include "support/Logger.h"
11 #include "llvm/ADT/StringExtras.h"
12 #include "llvm/Support/VirtualFileSystem.h"
19 std::optional
<DraftStore::Draft
> DraftStore::getDraft(PathRef File
) const {
20 std::lock_guard
<std::mutex
> Lock(Mutex
);
22 auto It
= Drafts
.find(File
);
23 if (It
== Drafts
.end())
29 std::vector
<Path
> DraftStore::getActiveFiles() const {
30 std::lock_guard
<std::mutex
> Lock(Mutex
);
31 std::vector
<Path
> ResultVector
;
33 for (auto DraftIt
= Drafts
.begin(); DraftIt
!= Drafts
.end(); DraftIt
++)
34 ResultVector
.push_back(std::string(DraftIt
->getKey()));
39 static void increment(std::string
&S
) {
40 // Ensure there is a numeric suffix.
41 if (S
.empty() || !llvm::isDigit(S
.back())) {
45 // Increment the numeric suffix.
46 auto I
= S
.rbegin(), E
= S
.rend();
48 if (I
== E
|| !llvm::isDigit(*I
)) {
49 // Reached start of numeric section, it was all 9s.
50 S
.insert(I
.base(), '1');
54 // Found a digit we can increment, we're done.
58 *I
= '0'; // and keep incrementing to the left.
62 static void updateVersion(DraftStore::Draft
&D
,
63 llvm::StringRef SpecifiedVersion
) {
64 if (!SpecifiedVersion
.empty()) {
65 // We treat versions as opaque, but the protocol says they increase.
66 if (SpecifiedVersion
.compare_numeric(D
.Version
) <= 0)
67 log("File version went from {0} to {1}", D
.Version
, SpecifiedVersion
);
68 D
.Version
= SpecifiedVersion
.str();
70 // Note that if D was newly-created, this will bump D.Version from "" to 1.
75 std::string
DraftStore::addDraft(PathRef File
, llvm::StringRef Version
,
76 llvm::StringRef Contents
) {
77 std::lock_guard
<std::mutex
> Lock(Mutex
);
79 auto &D
= Drafts
[File
];
80 updateVersion(D
.D
, Version
);
82 D
.D
.Contents
= std::make_shared
<std::string
>(Contents
);
86 void DraftStore::removeDraft(PathRef File
) {
87 std::lock_guard
<std::mutex
> Lock(Mutex
);
94 /// A read only MemoryBuffer shares ownership of a ref counted string. The
95 /// shared string object must not be modified while an owned by this buffer.
96 class SharedStringBuffer
: public llvm::MemoryBuffer
{
97 const std::shared_ptr
<const std::string
> BufferContents
;
98 const std::string Name
;
101 BufferKind
getBufferKind() const override
{
102 return MemoryBuffer::MemoryBuffer_Malloc
;
105 StringRef
getBufferIdentifier() const override
{ return Name
; }
107 SharedStringBuffer(std::shared_ptr
<const std::string
> Data
, StringRef Name
)
108 : BufferContents(std::move(Data
)), Name(Name
) {
109 assert(BufferContents
&& "Can't create from empty shared_ptr");
110 MemoryBuffer::init(BufferContents
->c_str(),
111 BufferContents
->c_str() + BufferContents
->size(),
112 /*RequiresNullTerminator=*/true);
117 llvm::IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> DraftStore::asVFS() const {
118 auto MemFS
= llvm::makeIntrusiveRefCnt
<llvm::vfs::InMemoryFileSystem
>();
119 std::lock_guard
<std::mutex
> Guard(Mutex
);
120 for (const auto &Draft
: Drafts
)
121 MemFS
->addFile(Draft
.getKey(), Draft
.getValue().MTime
,
122 std::make_unique
<SharedStringBuffer
>(
123 Draft
.getValue().D
.Contents
, Draft
.getKey()));
126 } // namespace clangd