| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #ifndef SkNx_DEFINED | 8 #ifndef SkNx_DEFINED |
| 9 #define SkNx_DEFINED | 9 #define SkNx_DEFINED |
| 10 | 10 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 SkNi thenElse(const SkNi& t, const SkNi& e) const { | 74 SkNi thenElse(const SkNi& t, const SkNi& e) const { |
| 75 return SkNi(fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi)); | 75 return SkNi(fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi)); |
| 76 } | 76 } |
| 77 | 77 |
| 78 protected: | 78 protected: |
| 79 REQUIRE(0 == (N & (N-1))); | 79 REQUIRE(0 == (N & (N-1))); |
| 80 | 80 |
| 81 SkNi<N/2, T> fLo, fHi; | 81 SkNi<N/2, T> fLo, fHi; |
| 82 }; | 82 }; |
| 83 | 83 |
| 84 template <int N, typename T> | 84 template <int N> |
| 85 class SkNf { | 85 class SkNf { |
| 86 static int32_t MyNi(float); | |
| 87 static int64_t MyNi(double); | |
| 88 typedef decltype(MyNi(T())) I; | |
| 89 public: | 86 public: |
| 90 SkNf() {} | 87 SkNf() {} |
| 91 explicit SkNf(T val) : fLo(val), fHi(val) {} | 88 explicit SkNf(float val) : fLo(val), fHi(val) {} |
| 92 static SkNf Load(const T vals[N]) { | 89 static SkNf Load(const float vals[N]) { |
| 93 return SkNf(SkNf<N/2,T>::Load(vals), SkNf<N/2,T>::Load(vals+N/2)); | 90 return SkNf(SkNf<N/2>::Load(vals), SkNf<N/2>::Load(vals+N/2)); |
| 94 } | 91 } |
| 95 // FromBytes() and toBytes() specializations may assume their argument is N-
byte aligned. | 92 // FromBytes() and toBytes() specializations may assume their argument is N-
byte aligned. |
| 96 // E.g. Sk4f::FromBytes() may assume it's reading from a 4-byte-aligned poin
ter. | 93 // E.g. Sk4f::FromBytes() may assume it's reading from a 4-byte-aligned poin
ter. |
| 97 // Converts [0,255] bytes to [0.0, 255.0] floats. | 94 // Converts [0,255] bytes to [0.0, 255.0] floats. |
| 98 static SkNf FromBytes(const uint8_t bytes[N]) { | 95 static SkNf FromBytes(const uint8_t bytes[N]) { |
| 99 return SkNf(SkNf<N/2,T>::FromBytes(bytes), SkNf<N/2,T>::FromBytes(bytes+
N/2)); | 96 return SkNf(SkNf<N/2>::FromBytes(bytes), SkNf<N/2>::FromBytes(bytes+N/2)
); |
| 100 } | 97 } |
| 101 | 98 |
| 102 SkNf(T a, T b) : fLo(a), fHi(b) {
REQUIRE(N==2); } | 99 SkNf(float a, float b) : fLo(a), fHi(b) { REQUIRE(N==2
); } |
| 103 SkNf(T a, T b, T c, T d) : fLo(a,b), fHi(c,d) {
REQUIRE(N==4); } | 100 SkNf(float a, float b, float c, float d) : fLo(a,b), fHi(c,d) { REQUIRE(N==4
); } |
| 104 SkNf(T a, T b, T c, T d, T e, T f, T g, T h) : fLo(a,b,c,d), fHi(e,f,g,h) {
REQUIRE(N==8); } | 101 SkNf(float a, float b, float c, float d, float e, float f, float g, float h) |
| 102 : fLo(a,b,c,d) |
| 103 , fHi(e,f,g,h) { REQUIRE(N==8); } |
| 105 | 104 |
| 106 void store(T vals[N]) const { | 105 void store(float vals[N]) const { |
| 107 fLo.store(vals); | 106 fLo.store(vals); |
| 108 fHi.store(vals+N/2); | 107 fHi.store(vals+N/2); |
| 109 } | 108 } |
| 110 // Please see note on FromBytes(). | 109 // Please see note on FromBytes(). |
| 111 // Clamps to [0.0,255.0] floats and truncates to [0,255] bytes. | 110 // Clamps to [0.0,255.0] floats and truncates to [0,255] bytes. |
| 112 void toBytes(uint8_t bytes[N]) const { | 111 void toBytes(uint8_t bytes[N]) const { |
| 113 fLo.toBytes(bytes); | 112 fLo.toBytes(bytes); |
| 114 fHi.toBytes(bytes+N/2); | 113 fHi.toBytes(bytes+N/2); |
| 115 } | 114 } |
| 116 | 115 |
| 117 SkNi<N,I> castTrunc() const { return SkNi<N,I>(fLo.castTrunc(), fHi.castTrun
c()); } | |
| 118 | |
| 119 SkNf operator + (const SkNf& o) const { return SkNf(fLo + o.fLo, fHi + o.fHi
); } | 116 SkNf operator + (const SkNf& o) const { return SkNf(fLo + o.fLo, fHi + o.fHi
); } |
| 120 SkNf operator - (const SkNf& o) const { return SkNf(fLo - o.fLo, fHi - o.fHi
); } | 117 SkNf operator - (const SkNf& o) const { return SkNf(fLo - o.fLo, fHi - o.fHi
); } |
| 121 SkNf operator * (const SkNf& o) const { return SkNf(fLo * o.fLo, fHi * o.fHi
); } | 118 SkNf operator * (const SkNf& o) const { return SkNf(fLo * o.fLo, fHi * o.fHi
); } |
| 122 SkNf operator / (const SkNf& o) const { return SkNf(fLo / o.fLo, fHi / o.fHi
); } | 119 SkNf operator / (const SkNf& o) const { return SkNf(fLo / o.fLo, fHi / o.fHi
); } |
| 123 | 120 |
| 124 SkNf operator == (const SkNf& o) const { return SkNf(fLo == o.fLo, fHi == o.
fHi); } | 121 SkNf operator == (const SkNf& o) const { return SkNf(fLo == o.fLo, fHi == o.
fHi); } |
| 125 SkNf operator != (const SkNf& o) const { return SkNf(fLo != o.fLo, fHi != o.
fHi); } | 122 SkNf operator != (const SkNf& o) const { return SkNf(fLo != o.fLo, fHi != o.
fHi); } |
| 126 SkNf operator < (const SkNf& o) const { return SkNf(fLo < o.fLo, fHi < o.
fHi); } | 123 SkNf operator < (const SkNf& o) const { return SkNf(fLo < o.fLo, fHi < o.
fHi); } |
| 127 SkNf operator > (const SkNf& o) const { return SkNf(fLo > o.fLo, fHi > o.
fHi); } | 124 SkNf operator > (const SkNf& o) const { return SkNf(fLo > o.fLo, fHi > o.
fHi); } |
| 128 SkNf operator <= (const SkNf& o) const { return SkNf(fLo <= o.fLo, fHi <= o.
fHi); } | 125 SkNf operator <= (const SkNf& o) const { return SkNf(fLo <= o.fLo, fHi <= o.
fHi); } |
| 129 SkNf operator >= (const SkNf& o) const { return SkNf(fLo >= o.fLo, fHi >= o.
fHi); } | 126 SkNf operator >= (const SkNf& o) const { return SkNf(fLo >= o.fLo, fHi >= o.
fHi); } |
| 130 | 127 |
| 131 static SkNf Min(const SkNf& l, const SkNf& r) { | 128 static SkNf Min(const SkNf& l, const SkNf& r) { |
| 132 return SkNf(SkNf<N/2,T>::Min(l.fLo, r.fLo), SkNf<N/2,T>::Min(l.fHi, r.fH
i)); | 129 return SkNf(SkNf<N/2>::Min(l.fLo, r.fLo), SkNf<N/2>::Min(l.fHi, r.fHi)); |
| 133 } | 130 } |
| 134 static SkNf Max(const SkNf& l, const SkNf& r) { | 131 static SkNf Max(const SkNf& l, const SkNf& r) { |
| 135 return SkNf(SkNf<N/2,T>::Max(l.fLo, r.fLo), SkNf<N/2,T>::Max(l.fHi, r.fH
i)); | 132 return SkNf(SkNf<N/2>::Max(l.fLo, r.fLo), SkNf<N/2>::Max(l.fHi, r.fHi)); |
| 136 } | 133 } |
| 137 | 134 |
| 138 SkNf sqrt() const { return SkNf(fLo. sqrt(), fHi. sqrt()); } | 135 SkNf sqrt() const { return SkNf(fLo. sqrt(), fHi. sqrt()); } |
| 139 | 136 |
| 140 // Generally, increasing precision, increasing cost. | 137 // Generally, increasing precision, increasing cost. |
| 141 SkNf rsqrt0() const { return SkNf(fLo.rsqrt0(), fHi.rsqrt0()); } | 138 SkNf rsqrt0() const { return SkNf(fLo.rsqrt0(), fHi.rsqrt0()); } |
| 142 SkNf rsqrt1() const { return SkNf(fLo.rsqrt1(), fHi.rsqrt1()); } | 139 SkNf rsqrt1() const { return SkNf(fLo.rsqrt1(), fHi.rsqrt1()); } |
| 143 SkNf rsqrt2() const { return SkNf(fLo.rsqrt2(), fHi.rsqrt2()); } | 140 SkNf rsqrt2() const { return SkNf(fLo.rsqrt2(), fHi.rsqrt2()); } |
| 144 | 141 |
| 145 SkNf invert() const { return SkNf(fLo. invert(), fHi. invert
()); } | 142 SkNf invert() const { return SkNf(fLo. invert(), fHi. invert
()); } |
| 146 SkNf approxInvert() const { return SkNf(fLo.approxInvert(), fHi.approxInvert
()); } | 143 SkNf approxInvert() const { return SkNf(fLo.approxInvert(), fHi.approxInvert
()); } |
| 147 | 144 |
| 148 template <int k> T kth() const { | 145 template <int k> float kth() const { |
| 149 SkASSERT(0 <= k && k < N); | 146 SkASSERT(0 <= k && k < N); |
| 150 return k < N/2 ? fLo.template kth<k>() : fHi.template kth<k-N/2>(); | 147 return k < N/2 ? fLo.template kth<k>() : fHi.template kth<k-N/2>(); |
| 151 } | 148 } |
| 152 | 149 |
| 153 bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); } | 150 bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); } |
| 154 bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); } | 151 bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); } |
| 155 SkNf thenElse(const SkNf& t, const SkNf& e) const { | 152 SkNf thenElse(const SkNf& t, const SkNf& e) const { |
| 156 return SkNf(fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi)); | 153 return SkNf(fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi)); |
| 157 } | 154 } |
| 158 | 155 |
| 159 protected: | 156 protected: |
| 160 REQUIRE(0 == (N & (N-1))); | 157 REQUIRE(0 == (N & (N-1))); |
| 161 SkNf(const SkNf<N/2, T>& lo, const SkNf<N/2, T>& hi) : fLo(lo), fHi(hi) {} | 158 SkNf(const SkNf<N/2>& lo, const SkNf<N/2>& hi) : fLo(lo), fHi(hi) {} |
| 162 | 159 |
| 163 SkNf<N/2, T> fLo, fHi; | 160 SkNf<N/2> fLo, fHi; |
| 164 }; | 161 }; |
| 165 | 162 |
| 166 | 163 |
| 167 // Bottom out the default implementations with scalars when nothing's been speci
alized. | 164 // Bottom out the default implementations with scalars when nothing's been speci
alized. |
| 168 | 165 |
| 169 template <typename T> | 166 template <typename T> |
| 170 class SkNi<1,T> { | 167 class SkNi<1,T> { |
| 171 public: | 168 public: |
| 172 SkNi() {} | 169 SkNi() {} |
| 173 explicit SkNi(T val) : fVal(val) {} | 170 explicit SkNi(T val) : fVal(val) {} |
| (...skipping 23 matching lines...) Expand all Loading... |
| 197 } | 194 } |
| 198 | 195 |
| 199 bool allTrue() const { return fVal; } | 196 bool allTrue() const { return fVal; } |
| 200 bool anyTrue() const { return fVal; } | 197 bool anyTrue() const { return fVal; } |
| 201 SkNi thenElse(const SkNi& t, const SkNi& e) const { return fVal ? t : e; } | 198 SkNi thenElse(const SkNi& t, const SkNi& e) const { return fVal ? t : e; } |
| 202 | 199 |
| 203 protected: | 200 protected: |
| 204 T fVal; | 201 T fVal; |
| 205 }; | 202 }; |
| 206 | 203 |
| 207 template <typename T> | 204 template <> |
| 208 class SkNf<1,T> { | 205 class SkNf<1> { |
| 209 static int32_t MyNi(float); | |
| 210 static int64_t MyNi(double); | |
| 211 typedef decltype(MyNi(T())) I; | |
| 212 public: | 206 public: |
| 213 SkNf() {} | 207 SkNf() {} |
| 214 explicit SkNf(T val) : fVal(val) {} | 208 explicit SkNf(float val) : fVal(val) {} |
| 215 static SkNf Load(const T vals[1]) { return SkNf(vals[0]); } | 209 static SkNf Load(const float vals[1]) { return SkNf(vals[0]); } |
| 216 static SkNf FromBytes(const uint8_t bytes[1]) { return SkNf((T)bytes[0]); } | 210 static SkNf FromBytes(const uint8_t bytes[1]) { return SkNf((float)bytes[0])
; } |
| 217 | 211 |
| 218 void store(T vals[1]) const { vals[0] = fVal; } | 212 void store(float vals[1]) const { vals[0] = fVal; } |
| 219 void toBytes(uint8_t bytes[1]) const { bytes[0] = (uint8_t)(SkTMin(fVal, (T)
255.0)); } | 213 void toBytes(uint8_t bytes[1]) const { bytes[0] = (uint8_t)(SkTMin(fVal, 255
.0f)); } |
| 220 | |
| 221 SkNi<1,I> castTrunc() const { return SkNi<1,I>(fVal); } | |
| 222 | 214 |
| 223 SkNf operator + (const SkNf& o) const { return SkNf(fVal + o.fVal); } | 215 SkNf operator + (const SkNf& o) const { return SkNf(fVal + o.fVal); } |
| 224 SkNf operator - (const SkNf& o) const { return SkNf(fVal - o.fVal); } | 216 SkNf operator - (const SkNf& o) const { return SkNf(fVal - o.fVal); } |
| 225 SkNf operator * (const SkNf& o) const { return SkNf(fVal * o.fVal); } | 217 SkNf operator * (const SkNf& o) const { return SkNf(fVal * o.fVal); } |
| 226 SkNf operator / (const SkNf& o) const { return SkNf(fVal / o.fVal); } | 218 SkNf operator / (const SkNf& o) const { return SkNf(fVal / o.fVal); } |
| 227 | 219 |
| 228 SkNf operator == (const SkNf& o) const { return SkNf(fVal == o.fVal); } | 220 SkNf operator == (const SkNf& o) const { return SkNf(fVal == o.fVal); } |
| 229 SkNf operator != (const SkNf& o) const { return SkNf(fVal != o.fVal); } | 221 SkNf operator != (const SkNf& o) const { return SkNf(fVal != o.fVal); } |
| 230 SkNf operator < (const SkNf& o) const { return SkNf(fVal < o.fVal); } | 222 SkNf operator < (const SkNf& o) const { return SkNf(fVal < o.fVal); } |
| 231 SkNf operator > (const SkNf& o) const { return SkNf(fVal > o.fVal); } | 223 SkNf operator > (const SkNf& o) const { return SkNf(fVal > o.fVal); } |
| 232 SkNf operator <= (const SkNf& o) const { return SkNf(fVal <= o.fVal); } | 224 SkNf operator <= (const SkNf& o) const { return SkNf(fVal <= o.fVal); } |
| 233 SkNf operator >= (const SkNf& o) const { return SkNf(fVal >= o.fVal); } | 225 SkNf operator >= (const SkNf& o) const { return SkNf(fVal >= o.fVal); } |
| 234 | 226 |
| 235 static SkNf Min(const SkNf& l, const SkNf& r) { return SkNf(SkTMin(l.fVal, r
.fVal)); } | 227 static SkNf Min(const SkNf& l, const SkNf& r) { return SkNf(SkTMin(l.fVal, r
.fVal)); } |
| 236 static SkNf Max(const SkNf& l, const SkNf& r) { return SkNf(SkTMax(l.fVal, r
.fVal)); } | 228 static SkNf Max(const SkNf& l, const SkNf& r) { return SkNf(SkTMax(l.fVal, r
.fVal)); } |
| 237 | 229 |
| 238 SkNf sqrt() const { return SkNf(Sqrt(fVal)); } | 230 SkNf sqrt() const { return SkNf(sqrtf(fVal)); } |
| 239 SkNf rsqrt0() const { return SkNf((T)1 / Sqrt(fVal)); } | 231 SkNf rsqrt0() const { return SkNf(1.0f / sqrtf(fVal)); } |
| 240 SkNf rsqrt1() const { return this->rsqrt0(); } | 232 SkNf rsqrt1() const { return this->rsqrt0(); } |
| 241 SkNf rsqrt2() const { return this->rsqrt1(); } | 233 SkNf rsqrt2() const { return this->rsqrt1(); } |
| 242 | 234 |
| 243 SkNf invert() const { return SkNf((T)1 / fVal); } | 235 SkNf invert() const { return SkNf(1.0f / fVal); } |
| 244 SkNf approxInvert() const { return this->invert(); } | 236 SkNf approxInvert() const { return this->invert(); } |
| 245 | 237 |
| 246 template <int k> T kth() const { | 238 template <int k> float kth() const { |
| 247 SkASSERT(k == 0); | 239 SkASSERT(k == 0); |
| 248 return fVal; | 240 return fVal; |
| 249 } | 241 } |
| 250 | 242 |
| 251 bool allTrue() const { return this->pun(); } | 243 bool allTrue() const { return this->pun() != 0; } |
| 252 bool anyTrue() const { return this->pun(); } | 244 bool anyTrue() const { return this->pun() != 0; } |
| 253 SkNf thenElse(const SkNf& t, const SkNf& e) const { return this->pun() ? t :
e; } | 245 SkNf thenElse(const SkNf& t, const SkNf& e) const { return this->pun() ? t :
e; } |
| 254 | 246 |
| 255 protected: | 247 protected: |
| 256 // We do double sqrts natively, or via floats for any other type. | 248 uint32_t pun() const { |
| 257 template <typename U> | 249 union { float f; uint32_t i; } pun = { fVal }; |
| 258 static U Sqrt(U val) { return (U) ::sqrtf((float)val); } | |
| 259 static double Sqrt(double val) { return ::sqrt ( val); } | |
| 260 | |
| 261 I pun() const { | |
| 262 union { T f; I i; } pun = { fVal }; | |
| 263 return pun.i; | 250 return pun.i; |
| 264 } | 251 } |
| 265 | 252 |
| 266 T fVal; | 253 float fVal; |
| 267 }; | 254 }; |
| 268 | 255 |
| 269 // This default implementation can be specialized by ../opts/SkNx_foo.h | 256 // This default implementation can be specialized by ../opts/SkNx_foo.h |
| 270 // if there's a better platform-specific shuffle strategy. | 257 // if there's a better platform-specific shuffle strategy. |
| 271 template <typename SkNx, int... Ix> | 258 template <typename SkNx, int... Ix> |
| 272 inline SkNx SkNx_shuffle_impl(const SkNx& src) { return SkNx( src.template kth<I
x>()... ); } | 259 inline SkNx SkNx_shuffle_impl(const SkNx& src) { return SkNx( src.template kth<I
x>()... ); } |
| 273 | 260 |
| 274 // This generic shuffle can be called on either SkNi or SkNf with 1 or N indices
: | 261 // This generic shuffle can be called on either SkNi or SkNf with 1 or N indices
: |
| 275 // Sk4f f(a,b,c,d); | 262 // Sk4f f(a,b,c,d); |
| 276 // SkNx_shuffle<3>(f); // ~~~> Sk4f(d,d,d,d) | 263 // SkNx_shuffle<3>(f); // ~~~> Sk4f(d,d,d,d) |
| 277 // SkNx_shuffle<2,1,0,3>(f); // ~~~> Sk4f(c,b,a,d) | 264 // SkNx_shuffle<2,1,0,3>(f); // ~~~> Sk4f(c,b,a,d) |
| 278 template <int... Ix, typename SkNx> | 265 template <int... Ix, typename SkNx> |
| 279 inline SkNx SkNx_shuffle(const SkNx& src) { return SkNx_shuffle_impl<SkNx, Ix...
>(src); } | 266 inline SkNx SkNx_shuffle(const SkNx& src) { return SkNx_shuffle_impl<SkNx, Ix...
>(src); } |
| 280 | 267 |
| 281 // A reminder alias that shuffles can be used to duplicate a single index across
a vector. | 268 // A reminder alias that shuffles can be used to duplicate a single index across
a vector. |
| 282 template <int Ix, typename SkNx> | 269 template <int Ix, typename SkNx> |
| 283 inline SkNx SkNx_dup(const SkNx& src) { return SkNx_shuffle<Ix>(src); } | 270 inline SkNx SkNx_dup(const SkNx& src) { return SkNx_shuffle<Ix>(src); } |
| 284 | 271 |
| 285 } // namespace | 272 } // namespace |
| 286 | 273 |
| 287 | 274 |
| 288 | |
| 289 | |
| 290 // Include platform specific specializations if available. | 275 // Include platform specific specializations if available. |
| 291 #ifndef SKNX_NO_SIMD | 276 #ifndef SKNX_NO_SIMD |
| 292 #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 | 277 #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 |
| 293 #include "../opts/SkNx_sse.h" | 278 #include "../opts/SkNx_sse.h" |
| 294 #elif defined(SK_ARM_HAS_NEON) | 279 #elif defined(SK_ARM_HAS_NEON) |
| 295 #include "../opts/SkNx_neon.h" | 280 #include "../opts/SkNx_neon.h" |
| 296 #endif | 281 #endif |
| 297 #endif | 282 #endif |
| 298 | 283 |
| 299 #undef REQUIRE | 284 #undef REQUIRE |
| 300 | 285 |
| 301 typedef SkNf<2, float> Sk2f; | 286 typedef SkNf<2> Sk2f; |
| 302 typedef SkNf<2, double> Sk2d; | 287 typedef SkNf<2> Sk2s; |
| 303 typedef SkNf<2, SkScalar> Sk2s; | |
| 304 | 288 |
| 305 typedef SkNf<4, float> Sk4f; | 289 typedef SkNf<4> Sk4f; |
| 306 typedef SkNf<4, double> Sk4d; | 290 typedef SkNf<4> Sk4s; |
| 307 typedef SkNf<4, SkScalar> Sk4s; | |
| 308 | 291 |
| 309 typedef SkNi<4, uint16_t> Sk4h; | |
| 310 typedef SkNi<8, uint16_t> Sk8h; | 292 typedef SkNi<8, uint16_t> Sk8h; |
| 311 typedef SkNi<16, uint16_t> Sk16h; | 293 typedef SkNi<16, uint16_t> Sk16h; |
| 312 | 294 typedef SkNi<16, uint8_t> Sk16b; |
| 313 typedef SkNi<16, uint8_t> Sk16b; | |
| 314 | |
| 315 typedef SkNi<4, int32_t> Sk4i; | |
| 316 typedef SkNi<4, uint32_t> Sk4u; | |
| 317 | 295 |
| 318 #endif//SkNx_DEFINED | 296 #endif//SkNx_DEFINED |
| OLD | NEW |