Last active
November 7, 2019 17:11
-
-
Save Enichan/9babeb439d20c003bb7bc0f1b75a6f90 to your computer and use it in GitHub Desktop.
Serves long identifiers in a threadsafe manner.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Runtime.InteropServices; | |
using System.Text; | |
using System.Threading; | |
namespace Franca { | |
[StructLayout(LayoutKind.Explicit)] | |
public struct IncrementalID : IEquatable<IncrementalID>, IComparable<IncrementalID> { | |
[FieldOffset(0)] | |
public readonly long Value; | |
public IncrementalID(long value) { | |
this.Value = value; | |
} | |
public IncrementalID(double value) { | |
this.Value = (long)value; | |
} | |
public static implicit operator long(IncrementalID id) { | |
return id.Value; | |
} | |
public static implicit operator double(IncrementalID id) { | |
return id.Value; | |
} | |
public static implicit operator IncrementalID(byte id) { | |
return new IncrementalID(id); | |
} | |
public static implicit operator IncrementalID(sbyte id) { | |
return new IncrementalID(id); | |
} | |
public static implicit operator IncrementalID(short id) { | |
return new IncrementalID(id); | |
} | |
public static implicit operator IncrementalID(ushort id) { | |
return new IncrementalID(id); | |
} | |
public static implicit operator IncrementalID(int id) { | |
return new IncrementalID(id); | |
} | |
public static implicit operator IncrementalID(uint id) { | |
return new IncrementalID(id); | |
} | |
public override string ToString() { | |
return Value.ToString(System.Globalization.CultureInfo.InvariantCulture); | |
} | |
#region Equality | |
public override bool Equals(object obj) { | |
if (obj == null) { | |
return false; | |
} | |
IncrementalID? b = obj as IncrementalID?; | |
if ((System.Object)b == null) { | |
return false; | |
} | |
return b.Value == Value; | |
} | |
public bool Equals(IncrementalID b) { | |
return b.Value == Value; | |
} | |
public override int GetHashCode() { | |
return Value.GetHashCode(); | |
} | |
public static bool operator ==(IncrementalID lhs, IncrementalID rhs) { | |
return lhs.Equals(rhs); | |
} | |
public static bool operator !=(IncrementalID lhs, IncrementalID rhs) { | |
return !(lhs.Equals(rhs)); | |
} | |
#endregion | |
#region Comparison | |
public static bool operator <(IncrementalID lhs, IncrementalID rhs) { | |
return lhs.Value < rhs.Value; | |
} | |
public static bool operator <=(IncrementalID lhs, IncrementalID rhs) { | |
return lhs.Value <= rhs.Value; | |
} | |
public static bool operator >(IncrementalID lhs, IncrementalID rhs) { | |
return lhs.Value > rhs.Value; | |
} | |
public static bool operator >=(IncrementalID lhs, IncrementalID rhs) { | |
return lhs.Value >= rhs.Value; | |
} | |
public int CompareTo(IncrementalID other) { | |
return Value.CompareTo(other.Value); | |
} | |
#endregion | |
} | |
/// <summary> | |
/// Serves long identifiers in a threadsafe manner. | |
/// </summary> | |
public class IDGenerator { | |
private long curID = 0; | |
public IDGenerator() { | |
} | |
public IDGenerator(long minimumID) { | |
SetMinimumID(minimumID); | |
} | |
/// <summary> | |
/// Sets the largest unused object ID value. Threadsafe. Will throw ArgumentOutOfRangeException if | |
/// the provided ID is less than or equal to the current ID. | |
/// </summary> | |
public void SetMinimumID(long id) { | |
if (!ExchangeIfGreaterThan(id)) { | |
throw new ArgumentOutOfRangeException("id", "Value was not greater than current ID value"); | |
} | |
} | |
private bool ExchangeIfGreaterThan(long newValue) { | |
long currentValue; | |
do { | |
currentValue = Interlocked.Read(ref curID); | |
if (newValue <= currentValue) { | |
return false; | |
} | |
} | |
while (Interlocked.CompareExchange(ref curID, newValue, currentValue) != currentValue); | |
return true; | |
} | |
/// <summary> | |
/// Gets the last used object ID value. Threadsafe. | |
/// </summary> | |
/// <returns>ID value</returns> | |
public IncrementalID GetCurrentID() { | |
return new IncrementalID(Interlocked.Read(ref curID)); | |
} | |
/// <summary> | |
/// Increments the last used object ID value and returns the new value. Threadsafe. | |
/// </summary> | |
/// <returns>ID value</returns> | |
public IncrementalID GetID() { | |
return new IncrementalID(Interlocked.Increment(ref curID)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment