Skip to content

Instantly share code, notes, and snippets.

@Enichan
Last active November 7, 2019 17:11
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Enichan/9babeb439d20c003bb7bc0f1b75a6f90 to your computer and use it in GitHub Desktop.
Save Enichan/9babeb439d20c003bb7bc0f1b75a6f90 to your computer and use it in GitHub Desktop.
Serves long identifiers in a threadsafe manner.
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