forked from OSchip/llvm-project
123 lines
4.0 KiB
C++
123 lines
4.0 KiB
C++
//===-- flang/unittests/RuntimeGTest/BufferTest.cpp -------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "../../runtime/buffer.h"
|
|
#include "CrashHandlerFixture.h"
|
|
#include "gtest/gtest.h"
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <memory>
|
|
|
|
static constexpr std::size_t tinyBufferSize{32};
|
|
using FileOffset = std::int64_t;
|
|
using namespace Fortran::runtime;
|
|
using namespace Fortran::runtime::io;
|
|
|
|
class Store : public FileFrame<Store, tinyBufferSize> {
|
|
public:
|
|
explicit Store(std::size_t bytes = 65536) : bytes_{bytes} {
|
|
data_.reset(new char[bytes]);
|
|
std::memset(&data_[0], 0, bytes);
|
|
}
|
|
std::size_t bytes() const { return bytes_; }
|
|
void set_enforceSequence(bool yes = true) { enforceSequence_ = yes; }
|
|
void set_expect(FileOffset to) { expect_ = to; }
|
|
|
|
std::size_t Read(FileOffset at, char *to, std::size_t minBytes,
|
|
std::size_t maxBytes, IoErrorHandler &handler) {
|
|
if (enforceSequence_ && at != expect_) {
|
|
handler.SignalError("Read(%d,%d,%d) not at expected %d",
|
|
static_cast<int>(at), static_cast<int>(minBytes),
|
|
static_cast<int>(maxBytes), static_cast<int>(expect_));
|
|
} else if (at < 0 || at + minBytes > bytes_) {
|
|
handler.SignalError("Read(%d,%d,%d) is out of bounds",
|
|
static_cast<int>(at), static_cast<int>(minBytes),
|
|
static_cast<int>(maxBytes));
|
|
}
|
|
auto result{std::min<std::size_t>(maxBytes, bytes_ - at)};
|
|
std::memcpy(to, &data_[at], result);
|
|
expect_ = at + result;
|
|
return result;
|
|
}
|
|
std::size_t Write(FileOffset at, const char *from, std::size_t bytes,
|
|
IoErrorHandler &handler) {
|
|
if (enforceSequence_ && at != expect_) {
|
|
handler.SignalError("Write(%d,%d) not at expected %d",
|
|
static_cast<int>(at), static_cast<int>(bytes),
|
|
static_cast<int>(expect_));
|
|
} else if (at < 0 || at + bytes > bytes_) {
|
|
handler.SignalError("Write(%d,%d) is out of bounds", static_cast<int>(at),
|
|
static_cast<int>(bytes));
|
|
}
|
|
std::memcpy(&data_[at], from, bytes);
|
|
expect_ = at + bytes;
|
|
return bytes;
|
|
}
|
|
|
|
private:
|
|
std::size_t bytes_;
|
|
std::unique_ptr<char[]> data_;
|
|
bool enforceSequence_{false};
|
|
FileOffset expect_{0};
|
|
};
|
|
|
|
inline int ChunkSize(int j, int most) {
|
|
// 31, 1, 29, 3, 27, ...
|
|
j %= tinyBufferSize;
|
|
auto chunk{static_cast<int>(
|
|
((j % 2) ? j : (tinyBufferSize - 1 - j)) % tinyBufferSize)};
|
|
return std::min(chunk, most);
|
|
}
|
|
|
|
inline int ValueFor(int at) { return (at ^ (at >> 8)) & 0xff; }
|
|
|
|
struct BufferTests : CrashHandlerFixture {};
|
|
|
|
TEST(BufferTests, TestFrameBufferReadAndWrite) {
|
|
Terminator terminator{__FILE__, __LINE__};
|
|
IoErrorHandler handler{terminator};
|
|
Store store;
|
|
store.set_enforceSequence(true);
|
|
const auto bytes{static_cast<FileOffset>(store.bytes())};
|
|
// Fill with an assortment of chunks
|
|
int at{0}, j{0};
|
|
while (at < bytes) {
|
|
auto chunk{ChunkSize(j, static_cast<int>(bytes - at))};
|
|
store.WriteFrame(at, chunk, handler);
|
|
char *to{store.Frame()};
|
|
for (int k{0}; k < chunk; ++k) {
|
|
to[k] = ValueFor(at + k);
|
|
}
|
|
at += chunk;
|
|
++j;
|
|
}
|
|
store.Flush(handler);
|
|
// Validate
|
|
store.set_expect(0);
|
|
at = 0;
|
|
while (at < bytes) {
|
|
auto chunk{ChunkSize(j, static_cast<int>(bytes - at))};
|
|
std::size_t frame{store.ReadFrame(at, chunk, handler)};
|
|
ASSERT_GE(frame, static_cast<std::size_t>(chunk))
|
|
<< "Badly-sized ReadFrame at " << at << ", chunk=" << chunk << ", got "
|
|
<< frame << '\n';
|
|
|
|
const char *from{store.Frame()};
|
|
for (int k{0}; k < chunk; ++k) {
|
|
auto expect{static_cast<char>(ValueFor(at + k))};
|
|
ASSERT_EQ(from[k], expect)
|
|
<< "At " << at << '+' << k << '(' << (at + k) << "), read "
|
|
<< (from[k] & 0xff) << ", expected " << static_cast<int>(expect)
|
|
<< '\n';
|
|
}
|
|
at += chunk;
|
|
++j;
|
|
}
|
|
}
|