Gamedev Framework (gf)  0.19.0
A C++17 framework for 2D games
Span.h
1 /*
2  * Gamedev Framework (gf)
3  * Copyright (C) 2016-2021 Julien Bernard
4  *
5  * This software is provided 'as-is', without any express or implied
6  * warranty. In no event will the authors be held liable for any damages
7  * arising from the use of this software.
8  *
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  *
13  * 1. The origin of this software must not be misrepresented; you must not
14  * claim that you wrote the original software. If you use this software
15  * in a product, an acknowledgment in the product documentation would be
16  * appreciated but is not required.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  * misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  */
21 #ifndef GF_SPAN_H
22 #define GF_SPAN_H
23 
24 #include <cassert>
25 #include <array>
26 #include <vector>
27 
28 #include "Unused.h"
29 
30 namespace gf {
31 #ifndef DOXYGEN_SHOULD_SKIP_THIS
32 inline namespace v1 {
33 #endif
34 
35  template<typename T>
36  class Span;
37 
50  template<typename T, std::size_t N>
51  class StaticSpan {
52  public:
56  static constexpr std::size_t Size = N;
57 
58 
64  constexpr
65  StaticSpan() noexcept
66  : m_data(nullptr)
67  {
68  }
69 
75  constexpr
76  StaticSpan(std::nullptr_t) noexcept
77  : m_data(nullptr)
78  {
79  }
80 
89  constexpr
90  StaticSpan(T *data, std::size_t size) noexcept
91  : m_data(data)
92  {
93  assert(size == Size);
94  gf::unused(size);
95  }
96 
104  template<typename U, typename = std::enable_if_t<std::is_convertible<U(*)[], T(*)[]>::value>>
105  constexpr
106  StaticSpan(U (&data)[N]) noexcept
107  : m_data(data)
108  {
109  }
110 
118  template<typename U, typename = std::enable_if_t<std::is_convertible<U(*)[], T(*)[]>::value>>
119  constexpr
120  StaticSpan(std::array<U, N>& array) noexcept
121  : m_data(array.data())
122  {
123  }
124 
130  template<typename U, typename = std::enable_if_t<std::is_convertible<U(*)[], T(*)[]>::value>>
131  constexpr
132  StaticSpan(StaticSpan<U, N> other) noexcept
133  : m_data(other.getData())
134  {
135  }
136 
142  constexpr
143  T *getData() noexcept {
144  return m_data;
145  }
146 
152  constexpr
153  const T *getData() const noexcept {
154  return m_data;
155  }
156 
162  constexpr
163  std::size_t getSize() const noexcept {
164  return Size;
165  }
166 
172  constexpr
173  bool isEmpty() const noexcept {
174  return m_data == nullptr || Size == 0;
175  }
176 
184  constexpr
185  T *begin() noexcept {
186  return m_data;
187  }
188 
196  constexpr
197  T *end() noexcept {
198  return m_data == nullptr ? nullptr : m_data + Size;
199  }
200 
208  constexpr
209  const T *begin() const noexcept {
210  return m_data;
211  }
212 
220  constexpr
221  const T *end() const noexcept {
222  return m_data == nullptr ? nullptr : m_data + Size;
223  }
224 
231  constexpr
232  T& operator[](std::size_t index) noexcept {
233  assert(m_data != nullptr && index < Size);
234  return m_data[index];
235  }
236 
243  constexpr
244  const T& operator[](std::size_t index) const noexcept {
245  assert(m_data != nullptr && index < Size);
246  return m_data[index];
247  }
248 
254  template<std::size_t I>
255  constexpr
256  T& get() noexcept {
257  static_assert(I < N, "Out of bounds.");
258  assert(m_data != nullptr);
259  return m_data[I];
260  }
261 
267  template<std::size_t I>
268  constexpr
269  const T& get() const noexcept {
270  static_assert(I < N, "Out of bounds.");
271  assert(m_data != nullptr);
272  return m_data[I];
273  }
274 
282  constexpr
283  Span<T> slice(std::size_t b, std::size_t e) const noexcept {
284  assert(b <= e && e <= Size);
285  return Span<T>(m_data + b, e - b);
286  }
287 
295  template<std::size_t B, std::size_t E>
296  constexpr
297  StaticSpan<T, E - B> slice() const noexcept {
298  static_assert(B <= E && E <= Size, "Out of bounds.");
299  return StaticSpan<T, E - B>(m_data + B);
300  }
301 
308  constexpr
309  Span<T> first(std::size_t count) const noexcept {
310  return slice(0, count);
311  }
312 
319  template<std::size_t C>
320  constexpr
321  StaticSpan<T, C> first() const noexcept {
322  static_assert(C <= Size, "Out of bounds.");
323  return slice<0, C>();
324  }
325 
332  constexpr
333  Span<T> last(std::size_t count) const noexcept {
334  assert(count <= Size);
335  return slice(Size - count, Size);
336  }
337 
344  template<std::size_t C>
345  constexpr
346  StaticSpan<T, C> last() const noexcept {
347  static_assert(C <= Size, "Out of bounds.");
348  return slice<Size - C, Size>();
349  }
350 
357  constexpr
358  Span<T> firstExcept(std::size_t count) const noexcept {
359  assert(count <= Size);
360  return slice(0, Size - count);
361  }
362 
369  template<std::size_t C>
370  constexpr
371  StaticSpan<T, Size - C> firstExcept() const noexcept {
372  static_assert(C <= Size, "Out of bounds.");
373  return slice<0, Size - C>();
374  }
375 
382  constexpr
383  Span<T> lastExcept(std::size_t count) const noexcept {
384  return slice(count, Size);
385  }
386 
393  template<std::size_t C>
394  constexpr
395  StaticSpan<T, Size - C> lastExcept() const noexcept {
396  static_assert(C <= Size, "Out of bounds.");
397  return slice<C, Size>();
398  }
399 
400  private:
401  T *m_data;
402  };
403 
404 
416  template<typename T>
417  class Span {
418  public:
419 
420 
426  constexpr
428  : m_data(nullptr)
429  , m_size(0)
430  {
431  }
432 
438  constexpr
439  Span(std::nullptr_t)
440  : m_data(nullptr)
441  , m_size(0)
442  {
443  }
444 
451  constexpr
452  Span(T *data, std::size_t size)
453  : m_data(data)
454  , m_size(size)
455  {
456  }
457 
463  template<typename U, typename = std::enable_if_t<std::is_convertible<U(*)[], T(*)[]>::value>>
464  Span(std::vector<U>& values)
465  : m_data(values.data())
466  , m_size(values.size())
467  {
468  }
469 
475  template<typename U, typename = std::enable_if_t<std::is_convertible<U(*)[], T(*)[]>::value && std::is_const<T>::value>>
476  Span(const std::vector<U>& values)
477  : m_data(values.data())
478  , m_size(values.size())
479  {
480  }
481 
487  template<typename U, std::size_t N, typename = std::enable_if_t<std::is_convertible<U(*)[], T(*)[]>::value>>
488  Span(std::array<U,N>& values)
489  : m_data(values.data())
490  , m_size(values.size())
491  {
492  }
493 
501  template<typename U, std::size_t N, typename = std::enable_if_t<std::is_convertible<U(*)[], T(*)[]>::value>>
502  constexpr Span(U (&data)[N])
503  : m_data(data)
504  , m_size(N)
505  {
506  }
507 
513  template<typename U, typename = std::enable_if_t<std::is_convertible<U(*)[], T(*)[]>::value>>
514  constexpr Span(Span<U> other)
515  : m_data(other.getData())
516  , m_size(other.getSize())
517  {
518  }
519 
525  template<typename U, std::size_t N, typename = std::enable_if_t<std::is_convertible<U(*)[], T(*)[]>::value>>
526  constexpr Span(StaticSpan<U, N> other)
527  : m_data(other.getData())
528  , m_size(other.getSize())
529  {
530  }
531 
537  constexpr T *getData() noexcept {
538  return m_data;
539  }
540 
546  constexpr const T *getData() const noexcept {
547  return m_data;
548  }
549 
555  constexpr std::size_t getSize() const noexcept {
556  return m_size;
557  }
558 
564  constexpr bool isEmpty() const noexcept {
565  return m_size == 0;
566  }
567 
575  constexpr T *begin() noexcept {
576  return m_data;
577  }
578 
586  constexpr T *end() noexcept {
587  return m_data + m_size;
588  }
589 
597  constexpr const T *begin() const noexcept {
598  return m_data;
599  }
600 
608  constexpr const T *end() const noexcept {
609  return m_data + m_size;
610  }
611 
620  constexpr T& operator[](std::size_t index) {
621  return m_data[index];
622  }
623 
632  constexpr const T& operator[](std::size_t index) const {
633  return m_data[index];
634  }
635 
643  constexpr
644  Span<T> slice(std::size_t b, std::size_t e) const noexcept {
645  assert(b <= e && e <= m_size);
646  return Span<T>(m_data + b, e - b);
647  }
648 
656  template<std::size_t B, std::size_t E>
657  constexpr
658  StaticSpan<T, E - B> slice() const noexcept {
659  static_assert(B <= E, "Out of bounds.");
660  assert(E <= m_size);
661  return StaticSpan<T, E - B>(m_data + B);
662  }
663 
670  constexpr
671  Span<T> first(std::size_t count) const noexcept {
672  return slice(0, count);
673  }
674 
681  template<std::size_t C>
682  constexpr
683  StaticSpan<T, C> first() const noexcept {
684  assert(C <= m_size);
685  return StaticSpan<T, C>(m_data, C);
686  }
687 
694  constexpr
695  Span<T> last(std::size_t count) const noexcept {
696  assert(count <= m_size);
697  return slice(m_size - count, m_size);
698  }
699 
706  template<std::size_t C>
707  constexpr
708  StaticSpan<T, C> last() const noexcept {
709  assert(C <= m_size);
710  return StaticSpan<T, C>(m_data + m_size - C, C);
711  }
712 
719  constexpr
720  Span<T> firstExcept(std::size_t count) const noexcept {
721  assert(count <= m_size);
722  return slice(0, m_size - count);
723  }
724 
731  template<std::size_t C>
732  constexpr
733  Span<T> firstExcept() const noexcept {
734  assert(C <= m_size);
735  return slice(0, m_size - C);
736  }
737 
744  constexpr
745  Span<T> lastExcept(std::size_t count) const noexcept {
746  return slice(count, m_size);
747  }
748 
755  template<std::size_t C>
756  constexpr
757  Span<T> lastExcept() const noexcept {
758  assert(C <= m_size);
759  return slice(C, m_size);
760  }
761 
762  private:
763  T *m_data;
764  std::size_t m_size;
765  };
766 
767 
768  template<typename T>
769  constexpr
770  Span<T> span(T *data, std::size_t size) {
771  return Span<T>(data, size);
772  }
773 
774  template<typename T, std::size_t N>
775  constexpr
776  StaticSpan<T, N> span(T (&data)[N]) {
777  return StaticSpan<T, N>(data);
778  }
779 
780 #ifndef DOXYGEN_SHOULD_SKIP_THIS
781 }
782 #endif
783 }
784 
785 #endif // GF_SPAN_H
constexpr Span< T > first(std::size_t count) const noexcept
Take a span on the first objects.
Definition: Span.h:309
constexpr T * begin() noexcept
Get an iterator to the first element.
Definition: Span.h:185
constexpr Span< T > lastExcept(std::size_t count) const noexcept
Take a span on the last objects.
Definition: Span.h:383
constexpr T * end() noexcept
Get an iterator past the last element.
Definition: Span.h:586
constexpr StaticSpan(T *data, std::size_t size) noexcept
Constructor from a pointer and a size.
Definition: Span.h:90
constexpr Span< T > firstExcept(std::size_t count) const noexcept
Take a span on the first objects.
Definition: Span.h:358
constexpr StaticSpan< T, C > first() const noexcept
Take a constant span on the first objects.
Definition: Span.h:321
constexpr StaticSpan< T, E - B > slice() const noexcept
Take a constant sub-span.
Definition: Span.h:658
constexpr const T * begin() const noexcept
Get an iterator to the first element.
Definition: Span.h:209
constexpr T * end() noexcept
Get an iterator past the last element.
Definition: Span.h:197
Span(const std::vector< U > &values)
Constructor from a std::vector
Definition: Span.h:476
constexpr Span< T > firstExcept() const noexcept
Take a span on the first objects.
Definition: Span.h:733
Span(std::array< U, N > &values)
Constructor from a std::array
Definition: Span.h:488
constexpr Span< T > first(std::size_t count) const noexcept
Take a span on the first objects.
Definition: Span.h:671
constexpr T & operator[](std::size_t index) noexcept
Get an element at a given index.
Definition: Span.h:232
constexpr Span< T > slice(std::size_t b, std::size_t e) const noexcept
Take a sub-span.
Definition: Span.h:283
A span.
Definition: Span.h:36
constexpr StaticSpan< T, C > last() const noexcept
Take a constant span on the last objects.
Definition: Span.h:346
constexpr T & operator[](std::size_t index)
Get an element at a given index.
Definition: Span.h:620
constexpr const T * begin() const noexcept
Get an iterator to the first element.
Definition: Span.h:597
A static span.
Definition: Span.h:51
constexpr StaticSpan< T, Size - C > firstExcept() const noexcept
Take a constant span on the first objects.
Definition: Span.h:371
constexpr Span< T > span(T *data, std::size_t size)
Definition: Span.h:770
constexpr const T * end() const noexcept
Get an iterator past the last element.
Definition: Span.h:221
constexpr bool isEmpty() const noexcept
Check if the array is empty.
Definition: Span.h:564
constexpr T * begin() noexcept
Get an iterator to the first element.
Definition: Span.h:575
constexpr StaticSpan(U(&data)[N]) noexcept
Constructor from a static array.
Definition: Span.h:106
constexpr Span< T > last(std::size_t count) const noexcept
Take a span on the last objects.
Definition: Span.h:695
constexpr std::size_t getSize() const noexcept
Get the number of elements.
Definition: Span.h:555
constexpr T * getData() noexcept
Get a pointer to the elements.
Definition: Span.h:143
constexpr bool isEmpty() const noexcept
Check if the array is empty.
Definition: Span.h:173
constexpr Span(std::nullptr_t)
Null constructor.
Definition: Span.h:439
constexpr const T * getData() const noexcept
Get a pointer to the elements.
Definition: Span.h:153
constexpr StaticSpan(std::nullptr_t) noexcept
Null constructor.
Definition: Span.h:76
The namespace for gf classes.
Definition: Action.h:35
constexpr const T * getData() const noexcept
Get a pointer to the elements.
Definition: Span.h:546
constexpr StaticSpan(StaticSpan< U, N > other) noexcept
Constructor from another span.
Definition: Span.h:132
constexpr Span< T > lastExcept(std::size_t count) const noexcept
Take a span on the last objects.
Definition: Span.h:745
constexpr Span(U(&data)[N])
Constructor from a static array.
Definition: Span.h:502
Span(std::vector< U > &values)
Constructor from a std::vector
Definition: Span.h:464
constexpr const T & operator[](std::size_t index) const
Get an element at a given index.
Definition: Span.h:632
constexpr StaticSpan< T, E - B > slice() const noexcept
Take a constant sub-span.
Definition: Span.h:297
constexpr StaticSpan() noexcept
Default constructor.
Definition: Span.h:65
constexpr std::size_t getSize() const noexcept
Get the number of elements.
Definition: Span.h:163
constexpr Span< T > slice(std::size_t b, std::size_t e) const noexcept
Take a sub-span.
Definition: Span.h:644
constexpr const T & operator[](std::size_t index) const noexcept
Get an element at a given index.
Definition: Span.h:244
constexpr Span< T > lastExcept() const noexcept
Take a span on the last objects.
Definition: Span.h:757
constexpr Span< T > firstExcept(std::size_t count) const noexcept
Take a span on the first objects.
Definition: Span.h:720
constexpr Span(StaticSpan< U, N > other)
Constructor from another static span.
Definition: Span.h:526
constexpr void unused(Args &&...)
A simple way to avoid warnings about unused variables.
Definition: Unused.h:35
constexpr T * getData() noexcept
Get a pointer to the elements.
Definition: Span.h:537
constexpr Span(Span< U > other)
Constructor from another span.
Definition: Span.h:514
constexpr const T * end() const noexcept
Get an iterator past the last element.
Definition: Span.h:608
The B button.
constexpr StaticSpan< T, C > first() const noexcept
Take a constant span on the first objects.
Definition: Span.h:683
constexpr StaticSpan(std::array< U, N > &array) noexcept
Constructor from a std::array
Definition: Span.h:120
constexpr StaticSpan< T, Size - C > lastExcept() const noexcept
Take a constant span on the last objects.
Definition: Span.h:395
constexpr Span(T *data, std::size_t size)
Constructor from a pointer and a size.
Definition: Span.h:452
constexpr Span< T > last(std::size_t count) const noexcept
Take a span on the last objects.
Definition: Span.h:333
constexpr Span()
Default constructor.
Definition: Span.h:427
constexpr StaticSpan< T, C > last() const noexcept
Take a constant span on the last objects.
Definition: Span.h:708