| //===--- SourceLoc.h - ReST source location and source manager classes ----===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| |
| #ifndef SWIFT_MARKUP_SOURCELOC_H |
| #define SWIFT_MARKUP_SOURCELOC_H |
| |
| #include "llvm/ADT/StringRef.h" |
| #include <algorithm> |
| #include <cassert> |
| #include <utility> |
| #include <vector> |
| |
| namespace swift { |
| namespace markup { |
| |
| class SourceLoc { |
| friend class SourceManagerBase; |
| |
| template<typename ExternalSourceLocTy> |
| friend class SourceManager; |
| |
| unsigned Value; |
| |
| static const unsigned InvalidValue = 0; |
| |
| public: |
| SourceLoc() : Value(InvalidValue) {} |
| SourceLoc(const SourceLoc &) = default; |
| |
| bool isValid() const { return !isInvalid(); } |
| bool isInvalid() const { return Value == InvalidValue; } |
| |
| bool operator==(SourceLoc RHS) const { return Value == RHS.Value; } |
| bool operator!=(SourceLoc RHS) const { return !(*this == RHS); } |
| |
| /// Return a source location advanced a specified number of bytes. |
| SourceLoc getAdvancedLoc(int ByteOffset) const { |
| assert(isValid() && "Can't advance an invalid location"); |
| SourceLoc Result = *this; |
| Result.Value += ByteOffset; |
| return Result; |
| } |
| }; |
| |
| class SourceRange { |
| public: |
| /// The source range is a half-open byte range [Start; End). |
| SourceLoc Start, End; |
| |
| SourceRange() {} |
| SourceRange(SourceLoc Loc) : Start(Loc), End(Loc) { } |
| SourceRange(SourceLoc Start, SourceLoc End) : Start(Start), End(End) { |
| assert(Start.isValid() == End.isValid() && |
| "Start and end should either both be valid or both be invalid!"); |
| } |
| |
| bool isValid() const { return Start.isValid(); } |
| bool isInvalid() const { return Start.isInvalid(); } |
| }; |
| |
| class SourceManagerBase { |
| protected: |
| SourceLoc NextUnassignedLoc; |
| |
| /// All source pieces, in order of increasing source location. |
| std::vector<SourceRange> RegisteredRanges; |
| |
| public: |
| SourceManagerBase() : NextUnassignedLoc() { |
| NextUnassignedLoc.Value = 1; |
| } |
| SourceManagerBase(const SourceManagerBase &) = delete; |
| |
| void operator=(const SourceManagerBase &) = delete; |
| |
| bool isBeforeInBuffer(SourceLoc LHS, SourceLoc RHS) const { |
| // When we support multiple buffers, assert that locations come from the |
| // same buffer. |
| return LHS.Value < RHS.Value; |
| } |
| |
| /// Returns true if range \c R contains the location \c Loc. |
| bool containsLoc(SourceRange R, SourceLoc Loc) const { |
| return Loc == R.Start || |
| (isBeforeInBuffer(R.Start, Loc) && isBeforeInBuffer(Loc, R.End)); |
| } |
| }; |
| |
| template <typename ExternalSourceLocTy> |
| class SourceManager : public SourceManagerBase { |
| std::vector<ExternalSourceLocTy> ExternalLocs; |
| |
| public: |
| SourceManager() = default; |
| SourceManager(const SourceManager &) = delete; |
| |
| void operator=(const SourceManager &) = delete; |
| |
| SourceRange registerLine(StringRef Line, ExternalSourceLocTy ExternalLoc); |
| |
| /// Returns the external source range and a byte offset inside it. |
| std::pair<ExternalSourceLocTy, unsigned> |
| toExternalSourceLoc(SourceLoc Loc) const; |
| }; |
| |
| template <typename ExternalSourceLocTy> |
| SourceRange SourceManager<ExternalSourceLocTy>::registerLine( |
| StringRef Line, ExternalSourceLocTy ExternalLoc) { |
| if (Line.size() > 4095) |
| return SourceRange(); |
| |
| SourceLoc Start = NextUnassignedLoc; |
| SourceLoc End = Start.getAdvancedLoc(Line.size()); |
| RegisteredRanges.push_back(SourceRange(Start, End)); |
| ExternalLocs.push_back(ExternalLoc); |
| NextUnassignedLoc = End.getAdvancedLoc(2); |
| #ifndef NDEBUG |
| // To make debugging easier, make each line start at offset that is equal to |
| // 1 mod 1000. |
| NextUnassignedLoc.Value = ((NextUnassignedLoc.Value + 999) / 1000) * 1000 + 1; |
| #endif |
| return SourceRange(Start, End); |
| } |
| |
| template <typename ExternalSourceLocTy> |
| std::pair<ExternalSourceLocTy, unsigned> |
| SourceManager<ExternalSourceLocTy>::toExternalSourceLoc(SourceLoc Loc) const { |
| auto I = std::lower_bound(RegisteredRanges.begin(), RegisteredRanges.end(), |
| Loc, [this](const SourceRange &LHS, SourceLoc Loc) { |
| return this->isBeforeInBuffer(LHS.Start, Loc); |
| }); |
| assert(I != RegisteredRanges.end() && "unknown source location"); |
| const auto &InternalRange = *I; |
| assert(containsLoc(InternalRange, Loc) && "unknown source location"); |
| const auto &ExternalLoc = ExternalLocs[I - RegisteredRanges.begin()]; |
| return { ExternalLoc, Loc.Value - InternalRange.Start.Value }; |
| } |
| |
| } // namespace markup |
| } // namespace swift |
| |
| #endif // SWIFT_MARKUP_SOURCELOC_H |
| |