OutpostUniverse / OP2Utility

C++ library for working with Outpost 2 related files and tasks.
MIT License
4 stars 0 forks source link

Improve StreamReader/Writer static checks #135

Open DanRStevens opened 5 years ago

DanRStevens commented 5 years ago

We can improve the static checks for the StreamReader and StreamWriter template methods. In particular, the length prefixed data types can use some bounds checking on the length. The checks depend on Read/Write, as well as the relative data sizes between the chosen type and std::size_t.

For reading: With signed length values, negative values should result in an exception. For positive values (either signed or unsigned types), exceeding the bounds of a std::size_t should result in an exception.

For writing: No bounds checking is needed for negative values, as an object can never have negative size. If the size of the object (bounded by the range of std::size_t) exceeds the range of the chosen length type, an exception should be raised.

Depending on the type parameter, either case may be impossible. It is desirable to not incur any runtime cost for these checks when the condition is impossible. For instance, a uint32_t can never be negative, and can never overflow the bounds of a std::size_t.

It may be possible to implement this with template specialization using some combination of the following methods:

From <type_traits>: std::integral_constant std::is_signed std::is_unsigned

From <numeric_limits>: std::numeric_limits::is_integer std::numeric_limits::is_signed

DanRStevens commented 5 years ago

Saw this article about if constexpr(expression) in C++17: https://www.codingame.com/playgrounds/2205/7-features-of-c17-that-will-simplify-your-code/constexpr-if

This could be used to ensure a zero-cost runtime check when SizeType parameters are set such that overflow is impossible, or such that negative values are impossible.

This could be used to wrap the existing runtime checks, such that they are only present in the compiled code if some SizeType range check determines a runtime check is necessary.

if constexpr(compileTimeSizeTypeRangeCheck) {
  if (existingRuntimeOverflowCheck) {
    throw std::runtime_error("Overflow ...");
  }
}

Here's some additional update info detailing if constexpr(...): https://en.cppreference.com/w/cpp/language/if