00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "comma/basic/TextProvider.h"
00010 #include <ostream>
00011 #include <cstdlib>
00012 #include <cstring>
00013 #include <cassert>
00014
00015 using namespace comma;
00016
00017 TextProvider::TextProvider(const llvm::sys::Path &path)
00018 {
00019 memBuffer = llvm::MemoryBuffer::getFile(path.c_str());
00020
00021
00022
00023 if (!memBuffer) abort();
00024
00025 buffer = memBuffer->getBufferStart();
00026 identity = path.getLast();
00027 initializeLinevec();
00028 }
00029
00030 TextProvider::TextProvider(const char *raw, size_t length)
00031 {
00032 memBuffer = llvm::MemoryBuffer::getMemBufferCopy(raw, raw + length);
00033 buffer = memBuffer->getBufferStart();
00034 initializeLinevec();
00035 }
00036
00037 TextProvider::TextProvider(const std::string &str)
00038 {
00039 const char *start = str.c_str();
00040 const char *end = start + str.size();
00041 memBuffer = llvm::MemoryBuffer::getMemBufferCopy(start, end);
00042 buffer = memBuffer->getBufferStart();
00043 initializeLinevec();
00044 }
00045
00046 TextProvider::~TextProvider()
00047 {
00048 delete memBuffer;
00049 }
00050
00051 Location TextProvider::getLocation(const TextIterator &ti) const
00052 {
00053 return indexOf(ti.cursor);
00054 }
00055
00056 SourceLocation TextProvider::getSourceLocation(const TextIterator &ti) const
00057 {
00058 unsigned line = getLine(ti);
00059 unsigned column = getColumn(ti);
00060 return SourceLocation(line, column, identity);
00061 }
00062
00063 SourceLocation TextProvider::getSourceLocation(const Location loc) const
00064 {
00065 unsigned line = getLine(loc);
00066 unsigned column = getColumn(loc);
00067 return SourceLocation(line, column, identity);
00068 }
00069
00070 TextIterator TextProvider::begin() const
00071 {
00072 return TextIterator(buffer);
00073 }
00074
00075
00076 TextIterator TextProvider::end() const
00077 {
00078 return TextIterator(memBuffer->getBufferEnd());
00079 }
00080
00081 std::string TextProvider::extract(Location start, Location end) const
00082 {
00083 std::string str;
00084 unsigned x = start.getOffset();
00085 unsigned y = end.getOffset();
00086 assert(x <= y && "Inconsistent Location range!");
00087 assert(y < indexOf(memBuffer->getBufferEnd()) && "Locations out of range!");
00088 str.insert(0, &buffer[x], y - x + 1);
00089 return str;
00090 }
00091
00092
00093 std::string TextProvider::extract(const TextIterator &s,
00094 const TextIterator &e) const
00095 {
00096 std::string str;
00097 unsigned length = e.cursor - s.cursor;
00098 str.insert(0, s.cursor, length);
00099 return str;
00100 }
00101
00102 unsigned TextProvider::extract(const TextIterator &s,
00103 const TextIterator &e,
00104 char *buff, size_t size) const
00105 {
00106 unsigned length = e.cursor - s.cursor;
00107
00108 if (buff == 0) return length;
00109
00110 if (length >= size) {
00111 ::memcpy(buff, s.cursor, size);
00112 return size;
00113 }
00114
00115 ::memcpy(buff, s.cursor, length);
00116 buff[length] = 0;
00117 return length;
00118 }
00119
00120 void TextProvider::initializeLinevec()
00121 {
00122 lines.push_back(0);
00123 maxLineIndex = 0;
00124 }
00125
00126 unsigned TextProvider::getLine(Location loc) const
00127 {
00128 assert(loc < indexOf(memBuffer->getBufferEnd()));
00129
00130
00131
00132 if (loc > maxLineIndex) {
00133 unsigned line;
00134 const char* cursor = &buffer[lines.back()];
00135 while (cursor != &buffer[loc]) {
00136 switch (*cursor++) {
00137 case '\r':
00138 if (*cursor == '\n')
00139 cursor++;
00140 case '\n':
00141 case '\f':
00142 lines.push_back(indexOf(cursor));
00143 }
00144 }
00145
00146
00147 line = lines.size();
00148
00149
00150 while (cursor != memBuffer->getBufferEnd()) {
00151 switch (*cursor++) {
00152 case '\r':
00153 if (*cursor == '\n')
00154 cursor++;
00155 case '\n':
00156 case '\f':
00157 lines.push_back(indexOf(cursor));
00158 maxLineIndex = indexOf(cursor);
00159 return line;
00160 }
00161 }
00162
00163 lines.push_back(indexOf(cursor));
00164 maxLineIndex = indexOf(cursor);
00165 return line;
00166 }
00167
00168
00169 int max = lines.size();
00170 int start = 0;
00171 int end = max - 1;
00172 while (start <= end) {
00173 int mid = (start + end) >> 1;
00174 Location candidate = lines[mid];
00175 if (candidate <= loc) {
00176 if (mid + 1 < max) {
00177 if (lines[mid + 1] <= loc) {
00178 start = ++mid;
00179 continue;
00180 }
00181 }
00182 return ++mid;
00183 }
00184 end = --mid;
00185 }
00186 assert(false && "Bad offset into chunk map.");
00187 return 0;
00188 }
00189
00190 unsigned TextProvider::getColumn(Location loc) const
00191 {
00192 unsigned start = lines[getLine(loc) - 1];
00193 return loc - start;
00194 }
00195
00196 std::pair<unsigned, unsigned> TextProvider::getLineOf(Location loc) const
00197 {
00198 unsigned line = getLine(loc) - 1;
00199 unsigned start = lines[line];
00200 unsigned end = lines[line + 1];
00201
00202 return std::pair<unsigned, unsigned>(start, end);
00203 }
00204