//===--- SourceLoc.h - ReST source location and source manager classes ----===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://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 #include #include #include namespace swift { namespace markup { class SourceLoc { friend class SourceManagerBase; template 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 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 class SourceManager : public SourceManagerBase { std::vector 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 toExternalSourceLoc(SourceLoc Loc) const; }; template SourceRange SourceManager::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 std::pair SourceManager::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