1//===-- flang/unittests/Runtime/BufferTest.cpp ------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "../../runtime/buffer.h"
10#include "CrashHandlerFixture.h"
11#include "gtest/gtest.h"
12#include <algorithm>
13#include <cstdint>
14#include <cstring>
15#include <memory>
16
17static constexpr std::size_t tinyBufferSize{32};
18using FileOffset = std::int64_t;
19using namespace Fortran::runtime;
20using namespace Fortran::runtime::io;
21
22class Store : public FileFrame<Store, tinyBufferSize> {
23public:
24 explicit Store(std::size_t bytes = 65536) : bytes_{bytes} {
25 data_.reset(p: new char[bytes]);
26 std::memset(s: &data_[0], c: 0, n: bytes);
27 }
28 std::size_t bytes() const { return bytes_; }
29 void set_enforceSequence(bool yes = true) { enforceSequence_ = yes; }
30 void set_expect(FileOffset to) { expect_ = to; }
31
32 std::size_t Read(FileOffset at, char *to, std::size_t minBytes,
33 std::size_t maxBytes, IoErrorHandler &handler) {
34 if (enforceSequence_ && at != expect_) {
35 handler.SignalError("Read(%d,%d,%d) not at expected %d",
36 static_cast<int>(at), static_cast<int>(minBytes),
37 static_cast<int>(maxBytes), static_cast<int>(expect_));
38 } else if (at < 0 || at + minBytes > bytes_) {
39 handler.SignalError("Read(%d,%d,%d) is out of bounds",
40 static_cast<int>(at), static_cast<int>(minBytes),
41 static_cast<int>(maxBytes));
42 }
43 auto result{std::min<std::size_t>(a: maxBytes, b: bytes_ - at)};
44 std::memcpy(dest: to, src: &data_[at], n: result);
45 expect_ = at + result;
46 return result;
47 }
48 std::size_t Write(FileOffset at, const char *from, std::size_t bytes,
49 IoErrorHandler &handler) {
50 if (enforceSequence_ && at != expect_) {
51 handler.SignalError("Write(%d,%d) not at expected %d",
52 static_cast<int>(at), static_cast<int>(bytes),
53 static_cast<int>(expect_));
54 } else if (at < 0 || at + bytes > bytes_) {
55 handler.SignalError("Write(%d,%d) is out of bounds", static_cast<int>(at),
56 static_cast<int>(bytes));
57 }
58 std::memcpy(dest: &data_[at], src: from, n: bytes);
59 expect_ = at + bytes;
60 return bytes;
61 }
62
63private:
64 std::size_t bytes_;
65 std::unique_ptr<char[]> data_;
66 bool enforceSequence_{false};
67 FileOffset expect_{0};
68};
69
70inline int ChunkSize(int j, int most) {
71 // 31, 1, 29, 3, 27, ...
72 j %= tinyBufferSize;
73 auto chunk{static_cast<int>(
74 ((j % 2) ? j : (tinyBufferSize - 1 - j)) % tinyBufferSize)};
75 return std::min(a: chunk, b: most);
76}
77
78inline int ValueFor(int at) { return (at ^ (at >> 8)) & 0xff; }
79
80struct BufferTests : CrashHandlerFixture {};
81
82TEST(BufferTests, TestFrameBufferReadAndWrite) {
83 Terminator terminator{__FILE__, __LINE__};
84 IoErrorHandler handler{terminator};
85 Store store;
86 store.set_enforceSequence(true);
87 const auto bytes{static_cast<FileOffset>(store.bytes())};
88 // Fill with an assortment of chunks
89 int at{0}, j{0};
90 while (at < bytes) {
91 auto chunk{ChunkSize(j, most: static_cast<int>(bytes - at))};
92 store.WriteFrame(at, chunk, handler);
93 char *to{store.Frame()};
94 for (int k{0}; k < chunk; ++k) {
95 to[k] = ValueFor(at: at + k);
96 }
97 at += chunk;
98 ++j;
99 }
100 store.Flush(handler);
101 // Validate
102 store.set_expect(0);
103 at = 0;
104 while (at < bytes) {
105 auto chunk{ChunkSize(j, most: static_cast<int>(bytes - at))};
106 std::size_t frame{store.ReadFrame(at, chunk, handler)};
107 ASSERT_GE(frame, static_cast<std::size_t>(chunk))
108 << "Badly-sized ReadFrame at " << at << ", chunk=" << chunk << ", got "
109 << frame << '\n';
110
111 const char *from{store.Frame()};
112 for (int k{0}; k < chunk; ++k) {
113 auto expect{static_cast<char>(ValueFor(at: at + k))};
114 ASSERT_EQ(from[k], expect)
115 << "At " << at << '+' << k << '(' << (at + k) << "), read "
116 << (from[k] & 0xff) << ", expected " << static_cast<int>(expect)
117 << '\n';
118 }
119 at += chunk;
120 ++j;
121 }
122}
123

source code of flang/unittests/Runtime/BufferTest.cpp