File: integer.hpp

package info (click to toggle)
ares 126-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 32,600 kB
  • sloc: cpp: 356,508; ansic: 20,394; makefile: 16; sh: 2
file content (137 lines) | stat: -rw-r--r-- 6,104 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#pragma once

namespace nall {

template<u32 Precision> struct IntegerPrimitive {
  static_assert(Precision >= 1 && Precision <= 64);
  using stype =
    conditional_t<Precision <=  8, s8,
    conditional_t<Precision <= 16, s16,
    conditional_t<Precision <= 32, s32,
    conditional_t<Precision <= 64, s64,
    void>>>>;
  using utype = typename Natural<Precision>::utype;

  IntegerPrimitive() = default;
  template<u32 Bits> IntegerPrimitive(IntegerPrimitive<Bits> value) { data = cast(value); }
  template<typename T> IntegerPrimitive(const T& value) { data = cast(value); }
  explicit IntegerPrimitive(const char* value) { data = cast(toInteger(value)); }

  operator stype() const { return data; }

  auto operator++(s32) { auto value = *this; data = cast(data + 1); return value; }
  auto operator--(s32) { auto value = *this; data = cast(data - 1); return value; }

  auto& operator++() { data = cast(data + 1); return *this; }
  auto& operator--() { data = cast(data - 1); return *this; }

  template<typename T> auto& operator  =(const T& value) { data = cast(        value); return *this; }
  template<typename T> auto& operator *=(const T& value) { data = cast(data  * value); return *this; }
  template<typename T> auto& operator /=(const T& value) { data = cast(data  / value); return *this; }
  template<typename T> auto& operator %=(const T& value) { data = cast(data  % value); return *this; }
  template<typename T> auto& operator +=(const T& value) { data = cast(data  + value); return *this; }
  template<typename T> auto& operator -=(const T& value) { data = cast(data  - value); return *this; }
  template<typename T> auto& operator<<=(const T& value) { data = cast(data << value); return *this; }
  template<typename T> auto& operator>>=(const T& value) { data = cast(data >> value); return *this; }
  template<typename T> auto& operator &=(const T& value) { data = cast(data  & value); return *this; }
  template<typename T> auto& operator ^=(const T& value) { data = cast(data  ^ value); return *this; }
  template<typename T> auto& operator |=(const T& value) { data = cast(data  | value); return *this; }

private:
  static constexpr auto mask() -> utype {
    return ~0ull >> 64 - Precision;
  }

  static constexpr auto sign() -> utype {
    return 1ull << Precision - 1;
  }

  auto cast(stype value) const -> stype {
    return (value & mask() ^ sign()) - sign();
  }

  stype data;
};

template<u32 Precision> struct Integer {
  static_assert(Precision >= 1 && Precision <= 64);
  static constexpr auto bits() -> u32 { return Precision; }
  using stype =
    conditional_t<Precision <=  8, s8,
    conditional_t<Precision <= 16, s16,
    conditional_t<Precision <= 32, s32,
    conditional_t<Precision <= 64, s64,
    void>>>>;
  using utype = typename Natural<Precision>::utype;
  static constexpr auto mask() -> utype { return ~0ull >> 64 - Precision; }
  static constexpr auto sign() -> utype { return 1ull << Precision - 1; }

  Integer() : data(0) {}
  template<u32 Bits> Integer(Integer<Bits> value) { data = cast(value); }
  template<typename T> Integer(const T& value) { data = cast(value); }
  explicit Integer(const char* value) { data = cast(toInteger(value)); }

  operator stype() const { return data; }

  auto operator++(s32) { auto value = *this; data = cast(data + 1); return value; }
  auto operator--(s32) { auto value = *this; data = cast(data - 1); return value; }

  auto& operator++() { data = cast(data + 1); return *this; }
  auto& operator--() { data = cast(data - 1); return *this; }

  template<typename T> auto& operator  =(const T& value) { data = cast(        value); return *this; }
  template<typename T> auto& operator *=(const T& value) { data = cast(data  * value); return *this; }
  template<typename T> auto& operator /=(const T& value) { data = cast(data  / value); return *this; }
  template<typename T> auto& operator %=(const T& value) { data = cast(data  % value); return *this; }
  template<typename T> auto& operator +=(const T& value) { data = cast(data  + value); return *this; }
  template<typename T> auto& operator -=(const T& value) { data = cast(data  - value); return *this; }
  template<typename T> auto& operator<<=(const T& value) { data = cast(data << value); return *this; }
  template<typename T> auto& operator>>=(const T& value) { data = cast(data >> value); return *this; }
  template<typename T> auto& operator &=(const T& value) { data = cast(data  & value); return *this; }
  template<typename T> auto& operator ^=(const T& value) { data = cast(data  ^ value); return *this; }
  template<typename T> auto& operator |=(const T& value) { data = cast(data  | value); return *this; }

  auto bit(s32 index) -> DynamicBitRange<Integer> { return {*this, index}; }
  auto bit(s32 index) const -> const DynamicBitRange<Integer> { return {(Integer&)*this, index}; }

  auto bit(s32 lo, s32 hi) -> DynamicBitRange<Integer> { return {*this, lo, hi}; }
  auto bit(s32 lo, s32 hi) const -> const DynamicBitRange<Integer> { return {(Integer&)*this, lo, hi}; }

  auto byte(s32 index) -> DynamicBitRange<Integer> { return {*this, index * 8 + 0, index * 8 + 7}; }
  auto byte(s32 index) const -> const DynamicBitRange<Integer> { return {(Integer&)*this, index * 8 + 0, index * 8 + 7}; }

  auto mask(s32 index) const -> utype {
    return data & 1 << index;
  }

  auto mask(s32 lo, s32 hi) const -> utype {
    return data & (~0ull >> 64 - (hi - lo + 1) << lo);
  }

  auto slice(s32 index) const { return Natural<>{bit(index)}; }
  auto slice(s32 lo, s32 hi) const { return Natural<>{bit(lo, hi)}; }

  static auto clamp(s64 value) -> stype {
    constexpr s64 b = 1ull << bits() - 1;
    constexpr s64 m = b - 1;
    return value > m ? m : value < -b ? -b : value;
  }

  auto clip(u32 bits) -> stype {
    const u64 b = 1ull << bits - 1;
    const u64 m = b * 2 - 1;
    return (data & m ^ b) - b;
  }

  auto serialize(serializer& s) { s(data); }
  auto natural() const -> Natural<Precision>;

private:
  auto cast(stype value) const -> stype {
    return (value & mask() ^ sign()) - sign();
  }

  stype data;
};

}