diff --git a/docs/dyn_array.md b/docs/dyn_array.md new file mode 100644 index 000000000..2ea87b42d --- /dev/null +++ b/docs/dyn_array.md @@ -0,0 +1,109 @@ + + +# `gsl::dyn_array` + +`gsl::dyn_array` is a dynamic array that is intended to be a replacement for slinging +around raw pointers and sizes. Notably, it _owns_ all of its elements. It should replace +the following idioms: + +* Replace `new T[n]` with `gsl::dyn_array(n)`. +* Replace both `foo(T*, size_t)` and `foo(unique_ptr&, size_t)` with +`foo(gsl::dyn_array&)`. + +It can be thought of like a... + +* `std::array` except the size is specified at runtime. +* `std::vector` except it can neither shrink nor grow. + +By design, `gsl::dyn_array` is not a `Container` as defined by the C++ Named +Requirements because we want to avoid the invalidation of iterators or references to +`gsl::dyn_array` objects. + +### Construction +`gsl::dyn_array`s can be constructed in the following ways: + +* Default construct a `dyn_array` with no elements: +```c++ +constexpr dyn_array(); +``` + +* Move construct a `dyn_array` from `other`: +```c++ +constexpr dyn_array(dyn_array&& other) noexcept; +``` + +* Construct a `dyn_array` with `n` default constructed elements: +```c++ +constexpr explicit dyn_array(size_t n, const Allocator & alloc = Allocator()); +``` + +* Construct a `dyn_array` with `n` elements, each copy constructed from `arg`: +```c++ +constexpr dyn_array(size_t n, const T& arg, const Allocator & alloc = Allocator()); +``` + +* Construct a `dyn_array` with elements from the range `[first, last)`: +```c++ +template +#ifdef __cpp_lib_concepts + requires(std::input_iterator) +#endif /* __cpp_lib_concepts */ +constexpr dyn_array(InputIt first, InputIt last, const Allocator & alloc = Allocator()); +``` + +* Construct a `dyn_array` from a range: +```c++ +#ifdef __cpp_lib_containers_range +template + requires(std::ranges::range) +constexpr dyn_array(std::from_range_t, R&& r, const Allocator & alloc = Allocator()); +#endif /* __cpp_lib_containers_range */ +``` + +* Construct a `dyn_array` with elements from the initializer list: +```c++ +constexpr dyn_array(std::initializer_list, const Allocator & alloc = Allocator()); +``` + +### Operations +In addition to the operations required by the named requirements, `gsl::dyn_array` will +support the following operations: + +* Access the specified element **_with bounds checking_**: +```c++ +constexpr T& operator[](size_t); +constexpr const T& operator[](size_t) const; +``` + +* Access the underlying array: +```c++ +constexpr T* data() noexcept; +constexpr const T* data() const noexcept; +``` + +* Return the number of elements in the `dyn_array`: +```c++ +constexpr size_t size() const noexcept; +``` + +### FAQ + +#### Why no push_back (and friends)? +`gsl::dyn_array` is intended to be a fixed-size array and all objects should be +constructed at creation. + +#### Why does `gsl::dyn_array` not conform to the `Container` Named Requirements? +`gsl::dyn_array` is intended to be a safer replacement for raw pointers and sizes. We +don't want users to accidentally use it in a way that would be unsafe. For example, +`gsl::dyn_array` does not have copy or move assignment operators. This is because it +would be possible to invalidate existing iterators and references. + +### Bounds Checking Semantics +If an out-of-bounds access (read or write) is attempted, `gsl::dyn_array` should follow +the contract violation strategy outlined in [GSL.assert: Assertions](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#gslassert-assertions). + +### References +* [C++ Named Requirements](https://en.cppreference.com/w/cpp/named_req) +* [Microsoft/GSL #1169](https://github.com/microsoft/GSL/issues/1169) +* [isocpp/CppCoreGuidelines #2244](https://github.com/isocpp/CppCoreGuidelines/issues/2244) +* [n3662](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3662.html)