scratch_buffer.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <algorithm>
  4. #include <array>
  5. #include <cstring>
  6. #include <span>
  7. #include <catch2/catch_test_macros.hpp>
  8. #include "common/common_types.h"
  9. #include "common/scratch_buffer.h"
  10. namespace Common {
  11. TEST_CASE("ScratchBuffer: Basic Test", "[common]") {
  12. ScratchBuffer<u8> buf;
  13. REQUIRE(buf.size() == 0U);
  14. REQUIRE(buf.capacity() == 0U);
  15. std::array<u8, 10> payload;
  16. payload.fill(66);
  17. buf.resize(payload.size());
  18. REQUIRE(buf.size() == payload.size());
  19. REQUIRE(buf.capacity() == payload.size());
  20. std::memcpy(buf.data(), payload.data(), payload.size());
  21. for (size_t i = 0; i < payload.size(); ++i) {
  22. REQUIRE(buf[i] == payload[i]);
  23. }
  24. }
  25. TEST_CASE("ScratchBuffer: resize_destructive Grow", "[common]") {
  26. std::array<u8, 10> payload;
  27. payload.fill(66);
  28. ScratchBuffer<u8> buf(payload.size());
  29. REQUIRE(buf.size() == payload.size());
  30. REQUIRE(buf.capacity() == payload.size());
  31. // Increasing the size should reallocate the buffer
  32. buf.resize_destructive(payload.size() * 2);
  33. REQUIRE(buf.size() == payload.size() * 2);
  34. REQUIRE(buf.capacity() == payload.size() * 2);
  35. // Since the buffer is not value initialized, reading its data will be garbage
  36. }
  37. TEST_CASE("ScratchBuffer: resize_destructive Shrink", "[common]") {
  38. std::array<u8, 10> payload;
  39. payload.fill(66);
  40. ScratchBuffer<u8> buf(payload.size());
  41. REQUIRE(buf.size() == payload.size());
  42. REQUIRE(buf.capacity() == payload.size());
  43. std::memcpy(buf.data(), payload.data(), payload.size());
  44. for (size_t i = 0; i < payload.size(); ++i) {
  45. REQUIRE(buf[i] == payload[i]);
  46. }
  47. // Decreasing the size should not cause a buffer reallocation
  48. // This can be tested by ensuring the buffer capacity and data has not changed,
  49. buf.resize_destructive(1U);
  50. REQUIRE(buf.size() == 1U);
  51. REQUIRE(buf.capacity() == payload.size());
  52. for (size_t i = 0; i < payload.size(); ++i) {
  53. REQUIRE(buf[i] == payload[i]);
  54. }
  55. }
  56. TEST_CASE("ScratchBuffer: resize Grow u8", "[common]") {
  57. std::array<u8, 10> payload;
  58. payload.fill(66);
  59. ScratchBuffer<u8> buf(payload.size());
  60. REQUIRE(buf.size() == payload.size());
  61. REQUIRE(buf.capacity() == payload.size());
  62. std::memcpy(buf.data(), payload.data(), payload.size());
  63. for (size_t i = 0; i < payload.size(); ++i) {
  64. REQUIRE(buf[i] == payload[i]);
  65. }
  66. // Increasing the size should reallocate the buffer
  67. buf.resize(payload.size() * 2);
  68. REQUIRE(buf.size() == payload.size() * 2);
  69. REQUIRE(buf.capacity() == payload.size() * 2);
  70. // resize() keeps the previous data intact
  71. for (size_t i = 0; i < payload.size(); ++i) {
  72. REQUIRE(buf[i] == payload[i]);
  73. }
  74. }
  75. TEST_CASE("ScratchBuffer: resize Grow u64", "[common]") {
  76. std::array<u64, 10> payload;
  77. payload.fill(6666);
  78. ScratchBuffer<u64> buf(payload.size());
  79. REQUIRE(buf.size() == payload.size());
  80. REQUIRE(buf.capacity() == payload.size());
  81. std::memcpy(buf.data(), payload.data(), payload.size() * sizeof(u64));
  82. for (size_t i = 0; i < payload.size(); ++i) {
  83. REQUIRE(buf[i] == payload[i]);
  84. }
  85. // Increasing the size should reallocate the buffer
  86. buf.resize(payload.size() * 2);
  87. REQUIRE(buf.size() == payload.size() * 2);
  88. REQUIRE(buf.capacity() == payload.size() * 2);
  89. // resize() keeps the previous data intact
  90. for (size_t i = 0; i < payload.size(); ++i) {
  91. REQUIRE(buf[i] == payload[i]);
  92. }
  93. }
  94. TEST_CASE("ScratchBuffer: resize Shrink", "[common]") {
  95. std::array<u8, 10> payload;
  96. payload.fill(66);
  97. ScratchBuffer<u8> buf(payload.size());
  98. REQUIRE(buf.size() == payload.size());
  99. REQUIRE(buf.capacity() == payload.size());
  100. std::memcpy(buf.data(), payload.data(), payload.size());
  101. for (size_t i = 0; i < payload.size(); ++i) {
  102. REQUIRE(buf[i] == payload[i]);
  103. }
  104. // Decreasing the size should not cause a buffer reallocation
  105. // This can be tested by ensuring the buffer capacity and data has not changed,
  106. buf.resize(1U);
  107. REQUIRE(buf.size() == 1U);
  108. REQUIRE(buf.capacity() == payload.size());
  109. for (size_t i = 0; i < payload.size(); ++i) {
  110. REQUIRE(buf[i] == payload[i]);
  111. }
  112. }
  113. TEST_CASE("ScratchBuffer: Span Size", "[common]") {
  114. std::array<u8, 10> payload;
  115. payload.fill(66);
  116. ScratchBuffer<u8> buf(payload.size());
  117. REQUIRE(buf.size() == payload.size());
  118. REQUIRE(buf.capacity() == payload.size());
  119. std::memcpy(buf.data(), payload.data(), payload.size());
  120. for (size_t i = 0; i < payload.size(); ++i) {
  121. REQUIRE(buf[i] == payload[i]);
  122. }
  123. buf.resize(3U);
  124. REQUIRE(buf.size() == 3U);
  125. REQUIRE(buf.capacity() == payload.size());
  126. const auto buf_span = std::span<u8>(buf);
  127. // The span size is the last requested size of the buffer, not its capacity
  128. REQUIRE(buf_span.size() == buf.size());
  129. for (size_t i = 0; i < buf_span.size(); ++i) {
  130. REQUIRE(buf_span[i] == buf[i]);
  131. REQUIRE(buf_span[i] == payload[i]);
  132. }
  133. }
  134. TEST_CASE("ScratchBuffer: Span Writes", "[common]") {
  135. std::array<u8, 10> payload;
  136. payload.fill(66);
  137. ScratchBuffer<u8> buf(payload.size());
  138. REQUIRE(buf.size() == payload.size());
  139. REQUIRE(buf.capacity() == payload.size());
  140. std::memcpy(buf.data(), payload.data(), payload.size());
  141. for (size_t i = 0; i < payload.size(); ++i) {
  142. REQUIRE(buf[i] == payload[i]);
  143. }
  144. buf.resize(3U);
  145. REQUIRE(buf.size() == 3U);
  146. REQUIRE(buf.capacity() == payload.size());
  147. const auto buf_span = std::span<u8>(buf);
  148. REQUIRE(buf_span.size() == buf.size());
  149. for (size_t i = 0; i < buf_span.size(); ++i) {
  150. const auto new_value = static_cast<u8>(i + 1U);
  151. // Writes to a span of the scratch buffer will propagate to the buffer itself
  152. buf_span[i] = new_value;
  153. REQUIRE(buf[i] == new_value);
  154. }
  155. }
  156. } // namespace Common