зеркало из https://github.com/SixLabors/Core.git
Use shared source MathF and HashCode
This commit is contained in:
Родитель
2db3a31981
Коммит
570bad0ff2
|
@ -1 +1 @@
|
||||||
Subproject commit 9b5a5b70b46bc23b9d8d8645cd691d5bc5a2d84f
|
Subproject commit faf84e44ec90e8a42a7271bcd04fea76279efb08
|
|
@ -1,448 +0,0 @@
|
||||||
#pragma warning disable SA1636, SA1600, SA1503, SA1202, SA1101, SA1132, SA1309, SA1520, SA1108, SA1203, SA1028, SA1512, SA1308
|
|
||||||
|
|
||||||
// SOURCE: https://github.com/dotnet/corefx/blob/master/src/Common/src/CoreLib/System/HashCode.cs
|
|
||||||
|
|
||||||
// Licensed to the .NET Foundation under one or more agreements.
|
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
|
||||||
// See the LICENSE file in the project root for more information.
|
|
||||||
|
|
||||||
/*
|
|
||||||
The xxHash32 implementation is based on the code published by Yann Collet:
|
|
||||||
https://raw.githubusercontent.com/Cyan4973/xxHash/5c174cfa4e45a42f94082dc0d4539b39696afea1/xxhash.c
|
|
||||||
xxHash - Fast Hash algorithm
|
|
||||||
Copyright (C) 2012-2016, Yann Collet
|
|
||||||
|
|
||||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
You can contact the author at :
|
|
||||||
- xxHash homepage: http://www.xxhash.com
|
|
||||||
- xxHash source repository : https://github.com/Cyan4973/xxHash
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if SUPPORTS_HASHCODE
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
[assembly: TypeForwardedTo(typeof(System.HashCode))]
|
|
||||||
#else
|
|
||||||
using System.Buffers.Binary;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace System
|
|
||||||
{
|
|
||||||
// xxHash32 is used for the hash code.
|
|
||||||
// https://github.com/Cyan4973/xxHash
|
|
||||||
internal struct HashCode
|
|
||||||
{
|
|
||||||
#pragma warning disable SA1311 // Static readonly fields should begin with upper-case letter
|
|
||||||
private static readonly uint s_seed = GenerateGlobalSeed();
|
|
||||||
#pragma warning restore SA1311 // Static readonly fields should begin with upper-case letter
|
|
||||||
|
|
||||||
private const uint Prime1 = 2654435761U;
|
|
||||||
private const uint Prime2 = 2246822519U;
|
|
||||||
private const uint Prime3 = 3266489917U;
|
|
||||||
private const uint Prime4 = 668265263U;
|
|
||||||
private const uint Prime5 = 374761393U;
|
|
||||||
|
|
||||||
private uint _v1, _v2, _v3, _v4;
|
|
||||||
private uint _queue1, _queue2, _queue3;
|
|
||||||
private uint _length;
|
|
||||||
|
|
||||||
private static uint GenerateGlobalSeed()
|
|
||||||
{
|
|
||||||
byte[] data = new byte[4];
|
|
||||||
|
|
||||||
using (var rng = RandomNumberGenerator.Create())
|
|
||||||
{
|
|
||||||
rng.GetBytes(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return BinaryPrimitives.ReadUInt32LittleEndian(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int Combine<T1>(T1 value1)
|
|
||||||
{
|
|
||||||
// Provide a way of diffusing bits from something with a limited
|
|
||||||
// input hash space. For example, many enums only have a few
|
|
||||||
// possible hashes, only using the bottom few bits of the code. Some
|
|
||||||
// collections are built on the assumption that hashes are spread
|
|
||||||
// over a larger space, so diffusing the bits may help the
|
|
||||||
// collection work more efficiently.
|
|
||||||
|
|
||||||
var hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
|
||||||
|
|
||||||
uint hash = MixEmptyState();
|
|
||||||
hash += 4;
|
|
||||||
|
|
||||||
hash = QueueRound(hash, hc1);
|
|
||||||
|
|
||||||
hash = MixFinal(hash);
|
|
||||||
return (int)hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int Combine<T1, T2>(T1 value1, T2 value2)
|
|
||||||
{
|
|
||||||
var hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
|
||||||
var hc2 = (uint)(value2?.GetHashCode() ?? 0);
|
|
||||||
|
|
||||||
uint hash = MixEmptyState();
|
|
||||||
hash += 8;
|
|
||||||
|
|
||||||
hash = QueueRound(hash, hc1);
|
|
||||||
hash = QueueRound(hash, hc2);
|
|
||||||
|
|
||||||
hash = MixFinal(hash);
|
|
||||||
return (int)hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int Combine<T1, T2, T3>(T1 value1, T2 value2, T3 value3)
|
|
||||||
{
|
|
||||||
var hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
|
||||||
var hc2 = (uint)(value2?.GetHashCode() ?? 0);
|
|
||||||
var hc3 = (uint)(value3?.GetHashCode() ?? 0);
|
|
||||||
|
|
||||||
uint hash = MixEmptyState();
|
|
||||||
hash += 12;
|
|
||||||
|
|
||||||
hash = QueueRound(hash, hc1);
|
|
||||||
hash = QueueRound(hash, hc2);
|
|
||||||
hash = QueueRound(hash, hc3);
|
|
||||||
|
|
||||||
hash = MixFinal(hash);
|
|
||||||
return (int)hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int Combine<T1, T2, T3, T4>(T1 value1, T2 value2, T3 value3, T4 value4)
|
|
||||||
{
|
|
||||||
var hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
|
||||||
var hc2 = (uint)(value2?.GetHashCode() ?? 0);
|
|
||||||
var hc3 = (uint)(value3?.GetHashCode() ?? 0);
|
|
||||||
var hc4 = (uint)(value4?.GetHashCode() ?? 0);
|
|
||||||
|
|
||||||
Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
|
|
||||||
|
|
||||||
v1 = Round(v1, hc1);
|
|
||||||
v2 = Round(v2, hc2);
|
|
||||||
v3 = Round(v3, hc3);
|
|
||||||
v4 = Round(v4, hc4);
|
|
||||||
|
|
||||||
uint hash = MixState(v1, v2, v3, v4);
|
|
||||||
hash += 16;
|
|
||||||
|
|
||||||
hash = MixFinal(hash);
|
|
||||||
return (int)hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int Combine<T1, T2, T3, T4, T5>(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5)
|
|
||||||
{
|
|
||||||
var hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
|
||||||
var hc2 = (uint)(value2?.GetHashCode() ?? 0);
|
|
||||||
var hc3 = (uint)(value3?.GetHashCode() ?? 0);
|
|
||||||
var hc4 = (uint)(value4?.GetHashCode() ?? 0);
|
|
||||||
var hc5 = (uint)(value5?.GetHashCode() ?? 0);
|
|
||||||
|
|
||||||
Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
|
|
||||||
|
|
||||||
v1 = Round(v1, hc1);
|
|
||||||
v2 = Round(v2, hc2);
|
|
||||||
v3 = Round(v3, hc3);
|
|
||||||
v4 = Round(v4, hc4);
|
|
||||||
|
|
||||||
uint hash = MixState(v1, v2, v3, v4);
|
|
||||||
hash += 20;
|
|
||||||
|
|
||||||
hash = QueueRound(hash, hc5);
|
|
||||||
|
|
||||||
hash = MixFinal(hash);
|
|
||||||
return (int)hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int Combine<T1, T2, T3, T4, T5, T6>(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6)
|
|
||||||
{
|
|
||||||
var hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
|
||||||
var hc2 = (uint)(value2?.GetHashCode() ?? 0);
|
|
||||||
var hc3 = (uint)(value3?.GetHashCode() ?? 0);
|
|
||||||
var hc4 = (uint)(value4?.GetHashCode() ?? 0);
|
|
||||||
var hc5 = (uint)(value5?.GetHashCode() ?? 0);
|
|
||||||
var hc6 = (uint)(value6?.GetHashCode() ?? 0);
|
|
||||||
|
|
||||||
Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
|
|
||||||
|
|
||||||
v1 = Round(v1, hc1);
|
|
||||||
v2 = Round(v2, hc2);
|
|
||||||
v3 = Round(v3, hc3);
|
|
||||||
v4 = Round(v4, hc4);
|
|
||||||
|
|
||||||
uint hash = MixState(v1, v2, v3, v4);
|
|
||||||
hash += 24;
|
|
||||||
|
|
||||||
hash = QueueRound(hash, hc5);
|
|
||||||
hash = QueueRound(hash, hc6);
|
|
||||||
|
|
||||||
hash = MixFinal(hash);
|
|
||||||
return (int)hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int Combine<T1, T2, T3, T4, T5, T6, T7>(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7)
|
|
||||||
{
|
|
||||||
var hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
|
||||||
var hc2 = (uint)(value2?.GetHashCode() ?? 0);
|
|
||||||
var hc3 = (uint)(value3?.GetHashCode() ?? 0);
|
|
||||||
var hc4 = (uint)(value4?.GetHashCode() ?? 0);
|
|
||||||
var hc5 = (uint)(value5?.GetHashCode() ?? 0);
|
|
||||||
var hc6 = (uint)(value6?.GetHashCode() ?? 0);
|
|
||||||
var hc7 = (uint)(value7?.GetHashCode() ?? 0);
|
|
||||||
|
|
||||||
Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
|
|
||||||
|
|
||||||
v1 = Round(v1, hc1);
|
|
||||||
v2 = Round(v2, hc2);
|
|
||||||
v3 = Round(v3, hc3);
|
|
||||||
v4 = Round(v4, hc4);
|
|
||||||
|
|
||||||
uint hash = MixState(v1, v2, v3, v4);
|
|
||||||
hash += 28;
|
|
||||||
|
|
||||||
hash = QueueRound(hash, hc5);
|
|
||||||
hash = QueueRound(hash, hc6);
|
|
||||||
hash = QueueRound(hash, hc7);
|
|
||||||
|
|
||||||
hash = MixFinal(hash);
|
|
||||||
return (int)hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int Combine<T1, T2, T3, T4, T5, T6, T7, T8>(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7, T8 value8)
|
|
||||||
{
|
|
||||||
var hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
|
||||||
var hc2 = (uint)(value2?.GetHashCode() ?? 0);
|
|
||||||
var hc3 = (uint)(value3?.GetHashCode() ?? 0);
|
|
||||||
var hc4 = (uint)(value4?.GetHashCode() ?? 0);
|
|
||||||
var hc5 = (uint)(value5?.GetHashCode() ?? 0);
|
|
||||||
var hc6 = (uint)(value6?.GetHashCode() ?? 0);
|
|
||||||
var hc7 = (uint)(value7?.GetHashCode() ?? 0);
|
|
||||||
var hc8 = (uint)(value8?.GetHashCode() ?? 0);
|
|
||||||
|
|
||||||
Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
|
|
||||||
|
|
||||||
v1 = Round(v1, hc1);
|
|
||||||
v2 = Round(v2, hc2);
|
|
||||||
v3 = Round(v3, hc3);
|
|
||||||
v4 = Round(v4, hc4);
|
|
||||||
|
|
||||||
v1 = Round(v1, hc5);
|
|
||||||
v2 = Round(v2, hc6);
|
|
||||||
v3 = Round(v3, hc7);
|
|
||||||
v4 = Round(v4, hc8);
|
|
||||||
|
|
||||||
uint hash = MixState(v1, v2, v3, v4);
|
|
||||||
hash += 32;
|
|
||||||
|
|
||||||
hash = MixFinal(hash);
|
|
||||||
return (int)hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static uint Rol(uint value, int count)
|
|
||||||
=> (value << count) | (value >> (32 - count));
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static void Initialize(out uint v1, out uint v2, out uint v3, out uint v4)
|
|
||||||
{
|
|
||||||
v1 = s_seed + Prime1 + Prime2;
|
|
||||||
v2 = s_seed + Prime2;
|
|
||||||
v3 = s_seed;
|
|
||||||
v4 = s_seed - Prime1;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static uint Round(uint hash, uint input)
|
|
||||||
{
|
|
||||||
hash += input * Prime2;
|
|
||||||
hash = Rol(hash, 13);
|
|
||||||
hash *= Prime1;
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static uint QueueRound(uint hash, uint queuedValue)
|
|
||||||
{
|
|
||||||
hash += queuedValue * Prime3;
|
|
||||||
return Rol(hash, 17) * Prime4;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static uint MixState(uint v1, uint v2, uint v3, uint v4)
|
|
||||||
{
|
|
||||||
return Rol(v1, 1) + Rol(v2, 7) + Rol(v3, 12) + Rol(v4, 18);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static uint MixEmptyState()
|
|
||||||
{
|
|
||||||
return s_seed + Prime5;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static uint MixFinal(uint hash)
|
|
||||||
{
|
|
||||||
hash ^= hash >> 15;
|
|
||||||
hash *= Prime2;
|
|
||||||
hash ^= hash >> 13;
|
|
||||||
hash *= Prime3;
|
|
||||||
hash ^= hash >> 16;
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add<T>(T value)
|
|
||||||
{
|
|
||||||
Add(value?.GetHashCode() ?? 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add<T>(T value, IEqualityComparer<T> comparer)
|
|
||||||
{
|
|
||||||
Add(comparer != null ? comparer.GetHashCode(value) : (value?.GetHashCode() ?? 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Add(int value)
|
|
||||||
{
|
|
||||||
// The original xxHash works as follows:
|
|
||||||
// 0. Initialize immediately. We can't do this in a struct (no
|
|
||||||
// default ctor).
|
|
||||||
// 1. Accumulate blocks of length 16 (4 uints) into 4 accumulators.
|
|
||||||
// 2. Accumulate remaining blocks of length 4 (1 uint) into the
|
|
||||||
// hash.
|
|
||||||
// 3. Accumulate remaining blocks of length 1 into the hash.
|
|
||||||
|
|
||||||
// There is no need for #3 as this type only accepts ints. _queue1,
|
|
||||||
// _queue2 and _queue3 are basically a buffer so that when
|
|
||||||
// ToHashCode is called we can execute #2 correctly.
|
|
||||||
|
|
||||||
// We need to initialize the xxHash32 state (_v1 to _v4) lazily (see
|
|
||||||
// #0) nd the last place that can be done if you look at the
|
|
||||||
// original code is just before the first block of 16 bytes is mixed
|
|
||||||
// in. The xxHash32 state is never used for streams containing fewer
|
|
||||||
// than 16 bytes.
|
|
||||||
|
|
||||||
// To see what's really going on here, have a look at the Combine
|
|
||||||
// methods.
|
|
||||||
|
|
||||||
var val = (uint)value;
|
|
||||||
|
|
||||||
// Storing the value of _length locally shaves of quite a few bytes
|
|
||||||
// in the resulting machine code.
|
|
||||||
uint previousLength = _length++;
|
|
||||||
uint position = previousLength % 4;
|
|
||||||
|
|
||||||
// Switch can't be inlined.
|
|
||||||
|
|
||||||
if (position == 0)
|
|
||||||
_queue1 = val;
|
|
||||||
else if (position == 1)
|
|
||||||
_queue2 = val;
|
|
||||||
else if (position == 2)
|
|
||||||
_queue3 = val;
|
|
||||||
else // position == 3
|
|
||||||
{
|
|
||||||
if (previousLength == 3)
|
|
||||||
Initialize(out _v1, out _v2, out _v3, out _v4);
|
|
||||||
|
|
||||||
_v1 = Round(_v1, _queue1);
|
|
||||||
_v2 = Round(_v2, _queue2);
|
|
||||||
_v3 = Round(_v3, _queue3);
|
|
||||||
_v4 = Round(_v4, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ToHashCode()
|
|
||||||
{
|
|
||||||
// Storing the value of _length locally shaves of quite a few bytes
|
|
||||||
// in the resulting machine code.
|
|
||||||
uint length = _length;
|
|
||||||
|
|
||||||
// position refers to the *next* queue position in this method, so
|
|
||||||
// position == 1 means that _queue1 is populated; _queue2 would have
|
|
||||||
// been populated on the next call to Add.
|
|
||||||
uint position = length % 4;
|
|
||||||
|
|
||||||
// If the length is less than 4, _v1 to _v4 don't contain anything
|
|
||||||
// yet. xxHash32 treats this differently.
|
|
||||||
|
|
||||||
uint hash = length < 4 ? MixEmptyState() : MixState(_v1, _v2, _v3, _v4);
|
|
||||||
|
|
||||||
// _length is incremented once per Add(Int32) and is therefore 4
|
|
||||||
// times too small (xxHash length is in bytes, not ints).
|
|
||||||
|
|
||||||
hash += length * 4;
|
|
||||||
|
|
||||||
// Mix what remains in the queue
|
|
||||||
|
|
||||||
// Switch can't be inlined right now, so use as few branches as
|
|
||||||
// possible by manually excluding impossible scenarios (position > 1
|
|
||||||
// is always false if position is not > 0).
|
|
||||||
if (position > 0)
|
|
||||||
{
|
|
||||||
hash = QueueRound(hash, _queue1);
|
|
||||||
if (position > 1)
|
|
||||||
{
|
|
||||||
hash = QueueRound(hash, _queue2);
|
|
||||||
if (position > 2)
|
|
||||||
hash = QueueRound(hash, _queue3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hash = MixFinal(hash);
|
|
||||||
return (int)hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning disable 0809
|
|
||||||
|
|
||||||
// Obsolete member 'memberA' overrides non-obsolete member 'memberB'.
|
|
||||||
// Disallowing GetHashCode and Equals is by design
|
|
||||||
|
|
||||||
// * We decided to not override GetHashCode() to produce the hash code
|
|
||||||
// as this would be weird, both naming-wise as well as from a
|
|
||||||
// behavioral standpoint (GetHashCode() should return the object's
|
|
||||||
// hash code, not the one being computed).
|
|
||||||
|
|
||||||
// * Even though ToHashCode() can be called safely multiple times on
|
|
||||||
// this implementation, it is not part of the contract. If the
|
|
||||||
// implementation has to change in the future we don't want to worry
|
|
||||||
// about people who might have incorrectly used this type.
|
|
||||||
|
|
||||||
[Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes. Use ToHashCode to retrieve the computed hash code.", error: true)]
|
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
||||||
public override int GetHashCode() => throw new NotSupportedException("Equality not supported");
|
|
||||||
|
|
||||||
[Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes.", error: true)]
|
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
||||||
public override bool Equals(object obj) => throw new NotSupportedException("Equality not supported");
|
|
||||||
#pragma warning restore 0809
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#pragma warning restore SA1636, SA1600, SA1503, SA1202, SA1101, SA1132, SA1309, SA1520, SA1108, SA1203, SA1028, SA1512, SA1308
|
|
|
@ -1,231 +0,0 @@
|
||||||
// Copyright (c) Six Labors and contributors.
|
|
||||||
// Licensed under the Apache License, Version 2.0.
|
|
||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
#if SUPPORTS_MATHF
|
|
||||||
[assembly: TypeForwardedTo(typeof(System.MathF))]
|
|
||||||
#else
|
|
||||||
namespace System
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Provides single-precision floating point constants and static methods for trigonometric, logarithmic, and other common mathematical functions.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>MathF emulation on platforms that don't support it natively.</remarks>
|
|
||||||
// ReSharper disable InconsistentNaming
|
|
||||||
internal static class MathF
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Represents the ratio of the circumference of a circle to its diameter, specified by the constant, π.
|
|
||||||
/// </summary>
|
|
||||||
public const float PI = (float)Math.PI;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the absolute value of a single-precision floating-point number.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="f">
|
|
||||||
/// A number that is greater than or equal to <see cref="F:System.Single.MinValue" />, but less than or equal to <see cref="F:System.Single.MaxValue" />.
|
|
||||||
/// </param>
|
|
||||||
/// <returns>
|
|
||||||
/// A single-precision floating-point number, x, such that 0 ≤ x ≤<see cref="F:System.Single.MaxValue" />.
|
|
||||||
/// </returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Abs(float f)
|
|
||||||
{
|
|
||||||
return Math.Abs(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the angle whose tangent is the quotient of two specified numbers.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="y">The y coordinate of a point.</param>
|
|
||||||
/// <param name="x">The x coordinate of a point.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// An angle, θ, measured in radians, such that -π≤θ≤π, and tan(θ) = y / x, where
|
|
||||||
/// (x, y) is a point in the Cartesian plane. Observe the following: For (x, y) in
|
|
||||||
/// quadrant 1, 0 < θ < π/2.For (x, y) in quadrant 2, π/2 < θ≤π.For (x, y) in quadrant
|
|
||||||
/// 3, -π < θ < -π/2.For (x, y) in quadrant 4, -π/2 < θ < 0.For points on the boundaries
|
|
||||||
/// of the quadrants, the return value is the following:If y is 0 and x is not negative,
|
|
||||||
/// θ = 0.If y is 0 and x is negative, θ = π.If y is positive and x is 0, θ = π/2.If
|
|
||||||
/// y is negative and x is 0, θ = -π/2.If y is 0 and x is 0, θ = 0. If x or y is
|
|
||||||
/// <see cref="F:System.Single.NaN"/>, or if x and y are either <see cref="F:System.Single.PositiveInfinity"/> or
|
|
||||||
/// <see cref="F:System.Single.NegativeInfinity"/>, the method returns <see cref="F:System.Single.NaN"/>.
|
|
||||||
/// </returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Atan2(float y, float x)
|
|
||||||
{
|
|
||||||
return (float)Math.Atan2(y, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the smallest integral value that is greater than or equal to the specified single-precision floating-point number.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="f">A single-precision floating-point number.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The smallest integral value that is greater than or equal to <paramref name="f" />.
|
|
||||||
/// If <paramref name="f" /> is equal to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NegativeInfinity" />,
|
|
||||||
/// or <see cref="F:System.Single.PositiveInfinity" />, that value is returned.
|
|
||||||
/// Note that this method returns a <see cref="T:System.Single" /> instead of an integral type.
|
|
||||||
/// </returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Ceiling(float f)
|
|
||||||
{
|
|
||||||
return (float)Math.Ceiling(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the cosine of the specified angle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="f">An angle, measured in radians.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The cosine of <paramref name="f"/>. If <paramref name="f"/> is equal to <see cref="F:System.Float.NaN"/>, <see cref="F:System.Float.NegativeInfinity"/>,
|
|
||||||
/// or <see cref="F:System.Float.PositiveInfinity"/>, this method returns <see cref="F:System.Float.NaN"/>.
|
|
||||||
/// </returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Cos(float f)
|
|
||||||
{
|
|
||||||
return (float)Math.Cos(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns e raised to the specified power.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="f">A number specifying a power.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The number e raised to the power <paramref name="f" />.
|
|
||||||
/// If <paramref name="f" /> equals <see cref="F:System.Single.NaN" /> or <see cref="F:System.Single.PositiveInfinity" />, that value is returned.
|
|
||||||
/// If <paramref name="f" /> equals <see cref="F:System.Single.NegativeInfinity" />, 0 is returned.
|
|
||||||
/// </returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Exp(float f)
|
|
||||||
{
|
|
||||||
return (float)Math.Exp(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the largest integer less than or equal to the specified single-precision floating-point number.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="f">A single-precision floating-point number. </param>
|
|
||||||
/// <returns>
|
|
||||||
/// The largest integer less than or equal to <paramref name="f" />.
|
|
||||||
/// If <paramref name="f" /> is equal to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NegativeInfinity" />,
|
|
||||||
/// or <see cref="F:System.Single.PositiveInfinity" />, that value is returned.
|
|
||||||
/// </returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Floor(float f)
|
|
||||||
{
|
|
||||||
return (float)Math.Floor(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the larger of two single-precision floating-point numbers.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="val1">The first of two single-precision floating-point numbers to compare. </param>
|
|
||||||
/// <param name="val2">The second of two single-precision floating-point numbers to compare. </param>
|
|
||||||
/// <returns>
|
|
||||||
/// Parameter <paramref name="val1" /> or <paramref name="val2" />, whichever is larger.
|
|
||||||
/// If <paramref name="val1" />, or <paramref name="val2" />, or both <paramref name="val1" /> and <paramref name="val2" /> are
|
|
||||||
/// equal to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NaN" /> is returned.
|
|
||||||
/// </returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Max(float val1, float val2)
|
|
||||||
{
|
|
||||||
return Math.Max(val1, val2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the smaller of two single-precision floating-point numbers.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="val1">The first of two single-precision floating-point numbers to compare. </param>
|
|
||||||
/// <param name="val2">The second of two single-precision floating-point numbers to compare. </param>
|
|
||||||
/// <returns>
|
|
||||||
/// Parameter <paramref name="val1" /> or <paramref name="val2" />, whichever is smaller.
|
|
||||||
/// If <paramref name="val1" />, <paramref name="val2" />, or both <paramref name="val1" /> and <paramref name="val2" /> are equal
|
|
||||||
/// to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NaN" /> is returned.
|
|
||||||
/// </returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Min(float val1, float val2)
|
|
||||||
{
|
|
||||||
return Math.Min(val1, val2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a specified number raised to the specified power.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">A single-precision floating-point number to be raised to a power. </param>
|
|
||||||
/// <param name="y">A single-precision floating-point number that specifies a power. </param>
|
|
||||||
/// <returns>The number <paramref name="x" /> raised to the power <paramref name="y" />.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Pow(float x, float y)
|
|
||||||
{
|
|
||||||
return (float)Math.Pow(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Rounds a single-precision floating-point value to the nearest integral value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="f">A single-precision floating-point number to be rounded.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The integer nearest <paramref name="f" />.
|
|
||||||
/// If the fractional component of <paramref name="f" /> is halfway between two integers, one of which is even and the other odd, then the even number is returned.
|
|
||||||
/// Note that this method returns a <see cref="T:System.Single" /> instead of an integral type.
|
|
||||||
/// </returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Round(float f)
|
|
||||||
{
|
|
||||||
return (float)Math.Round(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Rounds a single-precision floating-point value to the nearest integer.
|
|
||||||
/// A parameter specifies how to round the value if it is midway between two numbers.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="f">A single-precision floating-point number to be rounded. </param>
|
|
||||||
/// <param name="mode">Specification for how to round <paramref name="f" /> if it is midway between two other numbers.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The integer nearest <paramref name="f" />. If <paramref name="f" /> is halfway between two integers, one of which is even
|
|
||||||
/// and the other odd, then <paramref name="mode" /> determines which of the two is returned.
|
|
||||||
/// Note that this method returns a <see cref="T:System.Single" /> instead of an integral type.
|
|
||||||
/// </returns>
|
|
||||||
/// <exception cref="T:System.ArgumentException">
|
|
||||||
/// <paramref name="mode" /> is not a valid value of <see cref="T:System.MidpointRounding" />.</exception>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Round(float f, MidpointRounding mode)
|
|
||||||
{
|
|
||||||
return (float)Math.Round(f, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the sine of the specified angle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="f">An angle, measured in radians.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The sine of <paramref name="f" />.
|
|
||||||
/// If <paramref name="f" /> is equal to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NegativeInfinity" />,
|
|
||||||
/// or <see cref="F:System.Single.PositiveInfinity" />, this method returns <see cref="F:System.Single.NaN" />.
|
|
||||||
/// </returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Sin(float f)
|
|
||||||
{
|
|
||||||
return (float)Math.Sin(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the square root of a specified number.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="f">The number whose square root is to be found.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// One of the values in the following table.
|
|
||||||
/// <paramref name="f" /> parameter Return value Zero or positive The positive square root of <paramref name="f" />.
|
|
||||||
/// Negative <see cref="F:System.Single.NaN" />Equals <see cref="F:System.Single.NaN" />
|
|
||||||
/// <see cref="F:System.Single.NaN" />Equals <see cref="F:System.Single.PositiveInfinity" />
|
|
||||||
/// <see cref="F:System.Single.PositiveInfinity" />.
|
|
||||||
/// </returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float Sqrt(float f)
|
|
||||||
{
|
|
||||||
return (float)Math.Sqrt(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
Загрузка…
Ссылка в новой задаче