| //===--- CompactArray.cpp -------------------------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "sourcekitd/CompactArray.h" |
| #include "SourceKit/Core/LLVM.h" |
| #include "SourceKit/Support/UIdent.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include <limits.h> |
| |
| using namespace SourceKit; |
| using namespace sourcekitd; |
| |
| template <typename T> |
| static void addScalar(T Val, SmallVectorImpl<uint8_t> &Buf) { |
| const uint8_t *ValPtr = reinterpret_cast<const uint8_t *>(&Val); |
| Buf.append(ValPtr, ValPtr + sizeof(Val)); |
| } |
| |
| CompactArrayBuilderImpl::CompactArrayBuilderImpl() { |
| // Offset 0 is used for empty strings. |
| StringBuffer += '\0'; |
| } |
| |
| void CompactArrayBuilderImpl::addImpl(uint8_t Val) { |
| addScalar(Val, EntriesBuffer); |
| } |
| |
| void CompactArrayBuilderImpl::addImpl(unsigned Val) { |
| addScalar(Val, EntriesBuffer); |
| } |
| |
| void CompactArrayBuilderImpl::addImpl(StringRef Val) { |
| addScalar(getOffsetForString(Val), EntriesBuffer); |
| } |
| |
| void CompactArrayBuilderImpl::addImpl(UIdent Val) { |
| if (Val.isValid()) { |
| sourcekitd_uid_t uid = SKDUIDFromUIdent(Val); |
| addScalar(uid, EntriesBuffer); |
| } else { |
| addScalar(sourcekitd_uid_t(nullptr), EntriesBuffer); |
| } |
| } |
| |
| void CompactArrayBuilderImpl::addImpl(Optional<llvm::StringRef> Val) { |
| if (Val.hasValue()) { |
| addImpl(Val.getValue()); |
| } else { |
| addImpl(unsigned(-1)); |
| } |
| } |
| |
| unsigned CompactArrayBuilderImpl::getOffsetForString(StringRef Str) { |
| if (Str.empty()) |
| return 0; |
| |
| unsigned Offset = StringBuffer.size(); |
| StringBuffer += Str; |
| StringBuffer += '\0'; |
| return Offset; |
| } |
| |
| std::unique_ptr<llvm::MemoryBuffer> |
| CompactArrayBuilderImpl::createBuffer() const { |
| std::unique_ptr<llvm::MemoryBuffer> Buf; |
| Buf = llvm::MemoryBuffer::getNewUninitMemBuffer(sizeInBytes()); |
| copyInto(const_cast<char *>(Buf->getBufferStart()), Buf->getBufferSize()); |
| return Buf; |
| } |
| |
| void CompactArrayBuilderImpl::appendTo(SmallVectorImpl<char> &Buf) const { |
| size_t OrigSize = Buf.size(); |
| size_t NewSize = OrigSize + sizeInBytes(); |
| Buf.resize(NewSize); |
| copyInto(Buf.data() + OrigSize, NewSize - OrigSize); |
| } |
| |
| void CompactArrayBuilderImpl::copyInto(char *BufPtr, size_t Length) const { |
| uint64_t EntriesBufSize = EntriesBuffer.size(); |
| assert(Length >= sizeInBytes()); |
| memcpy(BufPtr, &EntriesBufSize, sizeof(EntriesBufSize)); |
| BufPtr += sizeof(EntriesBufSize); |
| memcpy(BufPtr, EntriesBuffer.data(), EntriesBufSize); |
| BufPtr += EntriesBufSize; |
| memcpy(BufPtr, StringBuffer.data(), StringBuffer.size()); |
| } |
| |
| bool CompactArrayBuilderImpl::empty() const { |
| return EntriesBuffer.empty(); |
| } |
| |
| size_t CompactArrayBuilderImpl::sizeInBytes() const { |
| return sizeof(uint64_t) + EntriesBuffer.size() + StringBuffer.size(); |
| } |
| |
| template <typename T> |
| static void readScalar(const uint8_t *Buf, T &Val) { |
| memcpy(&Val, Buf, sizeof(Val)); |
| } |
| |
| void CompactArrayReaderImpl::readImpl(size_t Offset, uint8_t &Val) { |
| readScalar(getEntriesBufStart() + Offset, Val); |
| } |
| |
| void CompactArrayReaderImpl::readImpl(size_t Offset, unsigned &Val) { |
| readScalar(getEntriesBufStart() + Offset, Val); |
| } |
| |
| void CompactArrayReaderImpl::readImpl(size_t Offset, const char * &Val) { |
| unsigned StrOffset; |
| readScalar(getEntriesBufStart() + Offset, StrOffset); |
| if (StrOffset == unsigned(-1)) { |
| Val = nullptr; |
| return; |
| } |
| Val = getStringBufStart() + StrOffset; |
| } |
| |
| void CompactArrayReaderImpl::readImpl(size_t Offset, sourcekitd_uid_t &Val) { |
| readScalar(getEntriesBufStart() + Offset, Val); |
| } |