array-view.hpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #pragma once
  2. #include <nall/iterator.hpp>
  3. #include <nall/range.hpp>
  4. #include <nall/traits.hpp>
  5. namespace nall {
  6. template<typename T> struct array_view {
  7. using type = array_view;
  8. array_view() {
  9. _data = nullptr;
  10. _size = 0;
  11. }
  12. array_view(nullptr_t) {
  13. _data = nullptr;
  14. _size = 0;
  15. }
  16. array_view(const void* data, uint64_t size) {
  17. _data = (const T*)data;
  18. _size = (int)size;
  19. }
  20. explicit operator bool() const { return _data && _size > 0; }
  21. operator const T*() const {
  22. #ifdef DEBUG
  23. struct out_of_bounds {};
  24. if(_size < 0) throw out_of_bounds{};
  25. #endif
  26. return _data;
  27. }
  28. auto operator++() -> type& { _data++; _size--; return *this; }
  29. auto operator--() -> type& { _data--; _size++; return *this; }
  30. auto operator++(int) -> type { auto copy = *this; ++(*this); return copy; }
  31. auto operator--(int) -> type { auto copy = *this; --(*this); return copy; }
  32. auto operator-=(int distance) -> type& { _data -= distance; _size += distance; return *this; }
  33. auto operator+=(int distance) -> type& { _data += distance; _size -= distance; return *this; }
  34. auto operator[](uint index) const -> const T& {
  35. #ifdef DEBUG
  36. struct out_of_bounds {};
  37. if(index >= _size) throw out_of_bounds{};
  38. #endif
  39. return _data[index];
  40. }
  41. auto operator()(uint index, const T& fallback = {}) const -> T {
  42. if(index >= _size) return fallback;
  43. return _data[index];
  44. }
  45. template<typename U = T> auto data() const -> const U* { return (const U*)_data; }
  46. template<typename U = T> auto size() const -> uint64_t { return _size * sizeof(T) / sizeof(U); }
  47. auto begin() const -> iterator_const<T> { return {_data, (uint)0}; }
  48. auto end() const -> iterator_const<T> { return {_data, (uint)_size}; }
  49. auto rbegin() const -> reverse_iterator_const<T> { return {_data, (uint)_size - 1}; }
  50. auto rend() const -> reverse_iterator_const<T> { return {_data, (uint)-1}; }
  51. auto read() -> T {
  52. auto value = operator[](0);
  53. _data++;
  54. _size--;
  55. return value;
  56. }
  57. auto view(uint offset, uint length) const -> type {
  58. #ifdef DEBUG
  59. struct out_of_bounds {};
  60. if(offset + length >= _size) throw out_of_bounds{};
  61. #endif
  62. return {_data + offset, length};
  63. }
  64. //array_view<uint8_t> specializations
  65. template<typename U> auto readl(U& value, uint size) -> U;
  66. template<typename U> auto readm(U& value, uint size) -> U;
  67. template<typename U> auto readvn(U& value, uint size) -> U;
  68. template<typename U> auto readvi(U& value, uint size) -> U;
  69. template<typename U> auto readl(U& value, uint offset, uint size) -> U { return view(offset, size).readl(value, size); }
  70. template<typename U = uint64_t> auto readl(uint size) -> U { U value; return readl(value, size); }
  71. template<typename U = uint64_t> auto readm(uint size) -> U { U value; return readm(value, size); }
  72. template<typename U = uint64_t> auto readvn(uint size) -> U { U value; return readvn(value, size); }
  73. template<typename U = int64_t> auto readvi(uint size) -> U { U value; return readvi(value, size); }
  74. template<typename U = uint64_t> auto readl(uint offset, uint size) -> U { U value; return readl(value, offset, size); }
  75. protected:
  76. const T* _data;
  77. int _size;
  78. };
  79. //array_view<uint8_t>
  80. template<> template<typename U> inline auto array_view<uint8_t>::readl(U& value, uint size) -> U {
  81. value = 0;
  82. for(uint byte : range(size)) value |= (U)read() << byte * 8;
  83. return value;
  84. }
  85. template<> template<typename U> inline auto array_view<uint8_t>::readm(U& value, uint size) -> U {
  86. value = 0;
  87. for(uint byte : reverse(range(size))) value |= (U)read() << byte * 8;
  88. return value;
  89. }
  90. template<> template<typename U> inline auto array_view<uint8_t>::readvn(U& value, uint size) -> U {
  91. value = 0;
  92. uint shift = 1;
  93. while(true) {
  94. auto byte = read();
  95. value += (byte & 0x7f) * shift;
  96. if(byte & 0x80) break;
  97. shift <<= 7;
  98. value += shift;
  99. }
  100. return value;
  101. }
  102. template<> template<typename U> inline auto array_view<uint8_t>::readvi(U& value, uint size) -> U {
  103. value = readvn<U>();
  104. bool negate = value & 1;
  105. value >>= 1;
  106. if(negate) value = ~value;
  107. return value;
  108. }
  109. }