unaligned_mem.h 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. #pragma once
  2. #include "defaults.h"
  3. #include "yassert.h"
  4. #include <string.h>
  5. #include <type_traits>
  6. // The following code used to have smart tricks assuming that unaligned reads and writes are OK on x86. This assumption
  7. // is wrong because compiler may emit alignment-sensitive x86 instructions e.g. movaps. See IGNIETFERRO-735.
  8. template <class T>
  9. inline T ReadUnaligned(const void* from) noexcept {
  10. T ret;
  11. memcpy(&ret, from, sizeof(T));
  12. return ret;
  13. }
  14. // std::remove_reference_t for non-deduced context to prevent such code to blow below:
  15. // ui8 first = f(); ui8 second = g();
  16. // WriteUnaligned(to, first - second) (int will be deduced)
  17. template <class T>
  18. inline void WriteUnaligned(void* to, const std::remove_reference_t<T>& t) noexcept {
  19. memcpy(to, &t, sizeof(T));
  20. }
  21. template <class T, unsigned Align = sizeof(T)>
  22. class TUnalignedMemoryIterator {
  23. public:
  24. inline TUnalignedMemoryIterator(const void* buf, size_t len)
  25. : Current_((const unsigned char*)buf)
  26. , End_(Current_ + len)
  27. , AlignedEnd_(End_ - (len % Align))
  28. {
  29. Y_FAKE_READ(buf);
  30. }
  31. inline bool AtEnd() const noexcept {
  32. return Current_ == AlignedEnd_;
  33. }
  34. inline T Cur() const noexcept {
  35. Y_ASSERT(Current_ < AlignedEnd_ || sizeof(T) < Align);
  36. return ::ReadUnaligned<T>(Current_);
  37. }
  38. inline T Next() noexcept {
  39. T ret(Cur());
  40. Current_ += sizeof(T);
  41. return ret;
  42. }
  43. inline const unsigned char* Last() const noexcept {
  44. return Current_;
  45. }
  46. inline size_t Left() const noexcept {
  47. return End_ - Current_;
  48. }
  49. private:
  50. const unsigned char* Current_;
  51. const unsigned char* End_;
  52. const unsigned char* AlignedEnd_;
  53. };