Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 1 | //===- MappedBlockStream.cpp - Reads stream data from an MSF file ---------===// |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 10 | #include "llvm/DebugInfo/Msf/MappedBlockStream.h" |
| 11 | #include "llvm/DebugInfo/Msf/DirectoryStreamData.h" |
| 12 | #include "llvm/DebugInfo/Msf/IMsfStreamData.h" |
| 13 | #include "llvm/DebugInfo/Msf/IndexedStreamData.h" |
| 14 | #include "llvm/DebugInfo/Msf/MsfError.h" |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 15 | |
| 16 | using namespace llvm; |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 17 | using namespace llvm::msf; |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 18 | |
Zachary Turner | a1657a9 | 2016-06-08 17:26:39 +0000 | [diff] [blame] | 19 | namespace { |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 20 | // This exists so that we can use make_unique (which requires a public default |
| 21 | // constructor, while still keeping the constructor of MappedBlockStream |
| 22 | // protected, forcing users to go through the `create` interface. |
Zachary Turner | a1657a9 | 2016-06-08 17:26:39 +0000 | [diff] [blame] | 23 | class MappedBlockStreamImpl : public MappedBlockStream { |
| 24 | public: |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 25 | MappedBlockStreamImpl(std::unique_ptr<IMsfStreamData> Data, |
| 26 | const IMsfFile &File) |
Zachary Turner | a1657a9 | 2016-06-08 17:26:39 +0000 | [diff] [blame] | 27 | : MappedBlockStream(std::move(Data), File) {} |
| 28 | }; |
| 29 | } |
| 30 | |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 31 | typedef std::pair<uint32_t, uint32_t> Interval; |
| 32 | static Interval intersect(const Interval &I1, const Interval &I2) { |
| 33 | return std::make_pair(std::max(I1.first, I2.first), |
| 34 | std::min(I1.second, I2.second)); |
| 35 | } |
| 36 | |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 37 | MappedBlockStream::MappedBlockStream(std::unique_ptr<IMsfStreamData> Data, |
| 38 | const IMsfFile &File) |
| 39 | : Msf(File), Data(std::move(Data)) {} |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 40 | |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 41 | Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, |
| 42 | ArrayRef<uint8_t> &Buffer) const { |
| 43 | // Make sure we aren't trying to read beyond the end of the stream. |
Zachary Turner | d844799 | 2016-06-07 05:28:55 +0000 | [diff] [blame] | 44 | if (Size > Data->getLength()) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 45 | return make_error<MsfError>(msf_error_code::insufficient_buffer); |
Zachary Turner | d844799 | 2016-06-07 05:28:55 +0000 | [diff] [blame] | 46 | if (Offset > Data->getLength() - Size) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 47 | return make_error<MsfError>(msf_error_code::insufficient_buffer); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 48 | |
| 49 | if (tryReadContiguously(Offset, Size, Buffer)) |
| 50 | return Error::success(); |
| 51 | |
| 52 | auto CacheIter = CacheMap.find(Offset); |
| 53 | if (CacheIter != CacheMap.end()) { |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 54 | // Try to find an alloc that was large enough for this request. |
| 55 | for (auto &Entry : CacheIter->second) { |
| 56 | if (Entry.size() >= Size) { |
| 57 | Buffer = Entry.slice(0, Size); |
| 58 | return Error::success(); |
| 59 | } |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | // We couldn't find a buffer that started at the correct offset (the most |
| 64 | // common scenario). Try to see if there is a buffer that starts at some |
| 65 | // other offset but overlaps the desired range. |
| 66 | for (auto &CacheItem : CacheMap) { |
| 67 | Interval RequestExtent = std::make_pair(Offset, Offset + Size); |
| 68 | |
| 69 | // We already checked this one on the fast path above. |
| 70 | if (CacheItem.first == Offset) |
| 71 | continue; |
| 72 | // If the initial extent of the cached item is beyond the ending extent |
| 73 | // of the request, there is no overlap. |
| 74 | if (CacheItem.first >= Offset + Size) |
| 75 | continue; |
| 76 | |
| 77 | // We really only have to check the last item in the list, since we append |
| 78 | // in order of increasing length. |
| 79 | if (CacheItem.second.empty()) |
| 80 | continue; |
| 81 | |
| 82 | auto CachedAlloc = CacheItem.second.back(); |
| 83 | // If the initial extent of the request is beyond the ending extent of |
| 84 | // the cached item, there is no overlap. |
| 85 | Interval CachedExtent = |
| 86 | std::make_pair(CacheItem.first, CacheItem.first + CachedAlloc.size()); |
| 87 | if (RequestExtent.first >= CachedExtent.first + CachedExtent.second) |
| 88 | continue; |
| 89 | |
| 90 | Interval Intersection = intersect(CachedExtent, RequestExtent); |
| 91 | // Only use this if the entire request extent is contained in the cached |
| 92 | // extent. |
| 93 | if (Intersection != RequestExtent) |
| 94 | continue; |
| 95 | |
| 96 | uint32_t CacheRangeOffset = |
| 97 | AbsoluteDifference(CachedExtent.first, Intersection.first); |
| 98 | Buffer = CachedAlloc.slice(CacheRangeOffset, Size); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 99 | return Error::success(); |
| 100 | } |
| 101 | |
| 102 | // Otherwise allocate a large enough buffer in the pool, memcpy the data |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 103 | // into it, and return an ArrayRef to that. Do not touch existing pool |
| 104 | // allocations, as existing clients may be holding a pointer which must |
| 105 | // not be invalidated. |
Zachary Turner | 97609bb | 2016-06-10 21:47:26 +0000 | [diff] [blame] | 106 | uint8_t *WriteBuffer = static_cast<uint8_t *>(Pool.Allocate(Size, 8)); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 107 | if (auto EC = readBytes(Offset, MutableArrayRef<uint8_t>(WriteBuffer, Size))) |
| 108 | return EC; |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 109 | |
| 110 | if (CacheIter != CacheMap.end()) { |
| 111 | CacheIter->second.emplace_back(WriteBuffer, Size); |
| 112 | } else { |
| 113 | std::vector<CacheEntry> List; |
| 114 | List.emplace_back(WriteBuffer, Size); |
| 115 | CacheMap.insert(std::make_pair(Offset, List)); |
| 116 | } |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 117 | Buffer = ArrayRef<uint8_t>(WriteBuffer, Size); |
| 118 | return Error::success(); |
| 119 | } |
| 120 | |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 121 | Error MappedBlockStream::readLongestContiguousChunk( |
| 122 | uint32_t Offset, ArrayRef<uint8_t> &Buffer) const { |
| 123 | // Make sure we aren't trying to read beyond the end of the stream. |
| 124 | if (Offset >= Data->getLength()) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 125 | return make_error<MsfError>(msf_error_code::insufficient_buffer); |
| 126 | uint32_t First = Offset / Msf.getBlockSize(); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 127 | uint32_t Last = First; |
| 128 | |
| 129 | auto BlockList = Data->getStreamBlocks(); |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 130 | while (Last < Msf.getBlockCount() - 1) { |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 131 | if (BlockList[Last] != BlockList[Last + 1] - 1) |
| 132 | break; |
| 133 | ++Last; |
| 134 | } |
| 135 | |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 136 | uint32_t OffsetInFirstBlock = Offset % Msf.getBlockSize(); |
| 137 | uint32_t BytesFromFirstBlock = Msf.getBlockSize() - OffsetInFirstBlock; |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 138 | uint32_t BlockSpan = Last - First + 1; |
| 139 | uint32_t ByteSpan = |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 140 | BytesFromFirstBlock + (BlockSpan - 1) * Msf.getBlockSize(); |
| 141 | auto Result = Msf.getBlockData(BlockList[First], Msf.getBlockSize()); |
David Majnemer | 6211b1f | 2016-07-10 03:34:47 +0000 | [diff] [blame] | 142 | if (!Result) |
| 143 | return Result.takeError(); |
| 144 | Buffer = Result->drop_front(OffsetInFirstBlock); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 145 | Buffer = ArrayRef<uint8_t>(Buffer.data(), ByteSpan); |
| 146 | return Error::success(); |
| 147 | } |
| 148 | |
Zachary Turner | d844799 | 2016-06-07 05:28:55 +0000 | [diff] [blame] | 149 | uint32_t MappedBlockStream::getLength() const { return Data->getLength(); } |
| 150 | |
Zachary Turner | ab58ae8 | 2016-06-30 17:43:00 +0000 | [diff] [blame] | 151 | Error MappedBlockStream::commit() const { return Error::success(); } |
| 152 | |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 153 | bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, |
| 154 | ArrayRef<uint8_t> &Buffer) const { |
| 155 | // Attempt to fulfill the request with a reference directly into the stream. |
| 156 | // This can work even if the request crosses a block boundary, provided that |
| 157 | // all subsequent blocks are contiguous. For example, a 10k read with a 4k |
| 158 | // block size can be filled with a reference if, from the starting offset, |
| 159 | // 3 blocks in a row are contiguous. |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 160 | uint32_t BlockNum = Offset / Msf.getBlockSize(); |
| 161 | uint32_t OffsetInBlock = Offset % Msf.getBlockSize(); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 162 | uint32_t BytesFromFirstBlock = |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 163 | std::min(Size, Msf.getBlockSize() - OffsetInBlock); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 164 | uint32_t NumAdditionalBlocks = |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 165 | llvm::alignTo(Size - BytesFromFirstBlock, Msf.getBlockSize()) / |
| 166 | Msf.getBlockSize(); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 167 | |
Zachary Turner | d844799 | 2016-06-07 05:28:55 +0000 | [diff] [blame] | 168 | auto BlockList = Data->getStreamBlocks(); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 169 | uint32_t RequiredContiguousBlocks = NumAdditionalBlocks + 1; |
| 170 | uint32_t E = BlockList[BlockNum]; |
| 171 | for (uint32_t I = 0; I < RequiredContiguousBlocks; ++I, ++E) { |
| 172 | if (BlockList[I + BlockNum] != E) |
| 173 | return false; |
| 174 | } |
| 175 | |
| 176 | uint32_t FirstBlockAddr = BlockList[BlockNum]; |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 177 | auto Result = Msf.getBlockData(FirstBlockAddr, Msf.getBlockSize()); |
David Majnemer | 6211b1f | 2016-07-10 03:34:47 +0000 | [diff] [blame] | 178 | if (!Result) { |
| 179 | consumeError(Result.takeError()); |
| 180 | return false; |
| 181 | } |
| 182 | auto Data = Result->drop_front(OffsetInBlock); |
Zachary Turner | e6fee88 | 2016-06-07 20:38:37 +0000 | [diff] [blame] | 183 | Buffer = ArrayRef<uint8_t>(Data.data(), Size); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 184 | return true; |
| 185 | } |
| 186 | |
Zachary Turner | 819e77d | 2016-05-06 20:51:57 +0000 | [diff] [blame] | 187 | Error MappedBlockStream::readBytes(uint32_t Offset, |
| 188 | MutableArrayRef<uint8_t> Buffer) const { |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 189 | uint32_t BlockNum = Offset / Msf.getBlockSize(); |
| 190 | uint32_t OffsetInBlock = Offset % Msf.getBlockSize(); |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 191 | |
| 192 | // Make sure we aren't trying to read beyond the end of the stream. |
Zachary Turner | d844799 | 2016-06-07 05:28:55 +0000 | [diff] [blame] | 193 | if (Buffer.size() > Data->getLength()) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 194 | return make_error<MsfError>(msf_error_code::insufficient_buffer); |
Zachary Turner | d844799 | 2016-06-07 05:28:55 +0000 | [diff] [blame] | 195 | if (Offset > Data->getLength() - Buffer.size()) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 196 | return make_error<MsfError>(msf_error_code::insufficient_buffer); |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 197 | |
| 198 | uint32_t BytesLeft = Buffer.size(); |
| 199 | uint32_t BytesWritten = 0; |
| 200 | uint8_t *WriteBuffer = Buffer.data(); |
Zachary Turner | d844799 | 2016-06-07 05:28:55 +0000 | [diff] [blame] | 201 | auto BlockList = Data->getStreamBlocks(); |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 202 | while (BytesLeft > 0) { |
| 203 | uint32_t StreamBlockAddr = BlockList[BlockNum]; |
| 204 | |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 205 | auto Result = Msf.getBlockData(StreamBlockAddr, Msf.getBlockSize()); |
David Majnemer | 6211b1f | 2016-07-10 03:34:47 +0000 | [diff] [blame] | 206 | if (!Result) |
| 207 | return Result.takeError(); |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 208 | |
David Majnemer | 6211b1f | 2016-07-10 03:34:47 +0000 | [diff] [blame] | 209 | auto Data = *Result; |
Zachary Turner | e6fee88 | 2016-06-07 20:38:37 +0000 | [diff] [blame] | 210 | const uint8_t *ChunkStart = Data.data() + OffsetInBlock; |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 211 | uint32_t BytesInChunk = |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 212 | std::min(BytesLeft, Msf.getBlockSize() - OffsetInBlock); |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 213 | ::memcpy(WriteBuffer + BytesWritten, ChunkStart, BytesInChunk); |
| 214 | |
| 215 | BytesWritten += BytesInChunk; |
| 216 | BytesLeft -= BytesInChunk; |
| 217 | ++BlockNum; |
| 218 | OffsetInBlock = 0; |
| 219 | } |
| 220 | |
Zachary Turner | 819e77d | 2016-05-06 20:51:57 +0000 | [diff] [blame] | 221 | return Error::success(); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 222 | } |
Zachary Turner | f5c5965 | 2016-05-03 00:28:21 +0000 | [diff] [blame] | 223 | |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 224 | Error MappedBlockStream::writeBytes(uint32_t Offset, |
| 225 | ArrayRef<uint8_t> Buffer) const { |
| 226 | // Make sure we aren't trying to write beyond the end of the stream. |
| 227 | if (Buffer.size() > Data->getLength()) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 228 | return make_error<MsfError>(msf_error_code::insufficient_buffer); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 229 | |
| 230 | if (Offset > Data->getLength() - Buffer.size()) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 231 | return make_error<MsfError>(msf_error_code::insufficient_buffer); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 232 | |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 233 | uint32_t BlockNum = Offset / Msf.getBlockSize(); |
| 234 | uint32_t OffsetInBlock = Offset % Msf.getBlockSize(); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 235 | |
| 236 | uint32_t BytesLeft = Buffer.size(); |
| 237 | auto BlockList = Data->getStreamBlocks(); |
| 238 | uint32_t BytesWritten = 0; |
| 239 | while (BytesLeft > 0) { |
| 240 | uint32_t StreamBlockAddr = BlockList[BlockNum]; |
| 241 | uint32_t BytesToWriteInChunk = |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 242 | std::min(BytesLeft, Msf.getBlockSize() - OffsetInBlock); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 243 | |
| 244 | const uint8_t *Chunk = Buffer.data() + BytesWritten; |
| 245 | ArrayRef<uint8_t> ChunkData(Chunk, BytesToWriteInChunk); |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 246 | if (auto EC = Msf.setBlockData(StreamBlockAddr, OffsetInBlock, ChunkData)) |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 247 | return EC; |
| 248 | |
| 249 | BytesLeft -= BytesToWriteInChunk; |
| 250 | BytesWritten += BytesToWriteInChunk; |
| 251 | ++BlockNum; |
| 252 | OffsetInBlock = 0; |
| 253 | } |
| 254 | |
| 255 | // If this write overlapped a read which previously came from the pool, |
| 256 | // someone may still be holding a pointer to that alloc which is now invalid. |
| 257 | // Compute the overlapping range and update the cache entry, so any |
| 258 | // outstanding buffers are automatically updated. |
| 259 | for (const auto &MapEntry : CacheMap) { |
| 260 | // If the end of the written extent precedes the beginning of the cached |
| 261 | // extent, ignore this map entry. |
| 262 | if (Offset + BytesWritten < MapEntry.first) |
| 263 | continue; |
| 264 | for (const auto &Alloc : MapEntry.second) { |
| 265 | // If the end of the cached extent precedes the beginning of the written |
| 266 | // extent, ignore this alloc. |
| 267 | if (MapEntry.first + Alloc.size() < Offset) |
| 268 | continue; |
| 269 | |
| 270 | // If we get here, they are guaranteed to overlap. |
| 271 | Interval WriteInterval = std::make_pair(Offset, Offset + BytesWritten); |
| 272 | Interval CachedInterval = |
| 273 | std::make_pair(MapEntry.first, MapEntry.first + Alloc.size()); |
| 274 | // If they overlap, we need to write the new data into the overlapping |
| 275 | // range. |
| 276 | auto Intersection = intersect(WriteInterval, CachedInterval); |
| 277 | assert(Intersection.first <= Intersection.second); |
| 278 | |
| 279 | uint32_t Length = Intersection.second - Intersection.first; |
| 280 | uint32_t SrcOffset = |
| 281 | AbsoluteDifference(WriteInterval.first, Intersection.first); |
| 282 | uint32_t DestOffset = |
| 283 | AbsoluteDifference(CachedInterval.first, Intersection.first); |
| 284 | ::memcpy(Alloc.data() + DestOffset, Buffer.data() + SrcOffset, Length); |
| 285 | } |
| 286 | } |
| 287 | |
| 288 | return Error::success(); |
Zachary Turner | f5c5965 | 2016-05-03 00:28:21 +0000 | [diff] [blame] | 289 | } |
Zachary Turner | 90b8b8d | 2016-05-31 22:41:52 +0000 | [diff] [blame] | 290 | |
| 291 | uint32_t MappedBlockStream::getNumBytesCopied() const { |
| 292 | return static_cast<uint32_t>(Pool.getBytesAllocated()); |
| 293 | } |
Zachary Turner | a1657a9 | 2016-06-08 17:26:39 +0000 | [diff] [blame] | 294 | |
| 295 | Expected<std::unique_ptr<MappedBlockStream>> |
| 296 | MappedBlockStream::createIndexedStream(uint32_t StreamIdx, |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 297 | const IMsfFile &File) { |
Zachary Turner | a1657a9 | 2016-06-08 17:26:39 +0000 | [diff] [blame] | 298 | if (StreamIdx >= File.getNumStreams()) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 299 | return make_error<MsfError>(msf_error_code::no_stream); |
Zachary Turner | a1657a9 | 2016-06-08 17:26:39 +0000 | [diff] [blame] | 300 | |
| 301 | auto Data = llvm::make_unique<IndexedStreamData>(StreamIdx, File); |
| 302 | return llvm::make_unique<MappedBlockStreamImpl>(std::move(Data), File); |
| 303 | } |
| 304 | |
| 305 | Expected<std::unique_ptr<MappedBlockStream>> |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 306 | MappedBlockStream::createDirectoryStream(uint32_t Length, |
| 307 | ArrayRef<support::ulittle32_t> Blocks, |
| 308 | const IMsfFile &File) { |
| 309 | auto Data = llvm::make_unique<DirectoryStreamData>(Length, Blocks); |
Zachary Turner | a1657a9 | 2016-06-08 17:26:39 +0000 | [diff] [blame] | 310 | return llvm::make_unique<MappedBlockStreamImpl>(std::move(Data), File); |
| 311 | } |