diff --git a/src/MongoDB.Bson/ObjectModel/ObjectId.cs b/src/MongoDB.Bson/ObjectModel/ObjectId.cs
index d249e6cf1b2..9e3430e78e9 100644
--- a/src/MongoDB.Bson/ObjectModel/ObjectId.cs
+++ b/src/MongoDB.Bson/ObjectModel/ObjectId.cs
@@ -41,6 +41,17 @@ public struct ObjectId : IComparable, IEquatable, IConvertib
private readonly int _c;
// constructors
+ ///
+ /// Initializes a new instance of the ObjectId class.
+ ///
+ /// First 32 bits
+ /// Second 32 bits
+ /// Third 32 bits
+ private ObjectId(int a, int b, int c)
+ {
+ _a = a; _b = b; _c = c;
+ }
+
///
/// Initializes a new instance of the ObjectId class.
///
@@ -49,11 +60,11 @@ public ObjectId(byte[] bytes)
{
if (bytes == null)
{
- throw new ArgumentNullException("bytes");
+ throw new ArgumentNullException(nameof(bytes));
}
if (bytes.Length != 12)
{
- throw new ArgumentException("Byte array must be 12 bytes long", "bytes");
+ throw new ArgumentException("Byte array must be 12 bytes long", nameof(bytes));
}
FromByteArray(bytes, 0, out _a, out _b, out _c);
@@ -92,16 +103,16 @@ public ObjectId(int timestamp, int machine, short pid, int increment)
{
if ((machine & 0xff000000) != 0)
{
- throw new ArgumentOutOfRangeException("machine", "The machine value must be between 0 and 16777215 (it must fit in 3 bytes).");
+ throw new ArgumentOutOfRangeException(nameof(machine), "The machine value must be between 0 and 16777215 (it must fit in 3 bytes).");
}
if ((increment & 0xff000000) != 0)
{
- throw new ArgumentOutOfRangeException("increment", "The increment value must be between 0 and 16777215 (it must fit in 3 bytes).");
+ throw new ArgumentOutOfRangeException(nameof(increment), "The increment value must be between 0 and 16777215 (it must fit in 3 bytes).");
}
_a = timestamp;
- _b = (machine << 8) | (((int)pid>> 8) & 0xff);
- _c = ((int)pid << 24) | increment; + _b = (machine << 8) | ((pid>> 8) & 0xff);
+ _c = (pid << 24) | increment; } ///
@@ -112,11 +123,13 @@ public ObjectId(string value)
{
if (value == null)
{
- throw new ArgumentNullException("value");
+ throw new ArgumentNullException(nameof(value));
}
- var bytes = BsonUtils.ParseHexString(value);
- FromByteArray(bytes, 0, out _a, out _b, out _c);
+ if (!TryParse(value, out _a, out _b, out _c))
+ {
+ throw new ArgumentException("String value is not valid.", nameof(value));
+ }
}
// public static properties
@@ -279,11 +292,11 @@ public static byte[] Pack(int timestamp, int machine, short pid, int increment)
{
if ((machine & 0xff000000) != 0)
{
- throw new ArgumentOutOfRangeException("machine", "The machine value must be between 0 and 16777215 (it must fit in 3 bytes).");
+ throw new ArgumentOutOfRangeException(nameof(machine), "The machine value must be between 0 and 16777215 (it must fit in 3 bytes).");
}
if ((increment & 0xff000000) != 0)
{
- throw new ArgumentOutOfRangeException("increment", "The increment value must be between 0 and 16777215 (it must fit in 3 bytes).");
+ throw new ArgumentOutOfRangeException(nameof(increment), "The increment value must be between 0 and 16777215 (it must fit in 3 bytes).");
}
byte[] bytes = new byte[12];
@@ -311,7 +324,7 @@ public static ObjectId Parse(string s)
{
if (s == null)
{
- throw new ArgumentNullException("s");
+ throw new ArgumentNullException(nameof(s));
}
ObjectId objectId;
@@ -335,14 +348,11 @@ public static ObjectId Parse(string s)
public static bool TryParse(string s, out ObjectId objectId)
{
// don't throw ArgumentNullException if s is null
- if (s != null && s.Length == 24)
+ int a, b, c;
+ if (TryParse(s, out a, out b, out c))
{
- byte[] bytes;
- if (BsonUtils.TryParseHexString(s, out bytes))
- {
- objectId = new ObjectId(bytes);
- return true;
- }
+ objectId = new ObjectId(a, b, c);
+ return true;
}
objectId = default(ObjectId);
@@ -361,11 +371,11 @@ public static void Unpack(byte[] bytes, out int timestamp, out int machine, out
{
if (bytes == null)
{
- throw new ArgumentNullException("bytes");
+ throw new ArgumentNullException(nameof(bytes));
}
if (bytes.Length != 12)
{
- throw new ArgumentOutOfRangeException("bytes", "Byte array must be 12 bytes long.");
+ throw new ArgumentOutOfRangeException(nameof(bytes), "Byte array must be 12 bytes long.");
}
timestamp = (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3]; @@ -429,6 +439,38 @@ private static int GetTimestampFromDateTime(DateTime timestamp) return (int)secondsSinceEpoch; } + private static bool TryParse(string value, out int a, out int b, out int c) + { + a = 0; b = 0; c = 0; + + if (value == null || value.Length != 24) + { + return false; + } + + var err = 0; + + for (int i = 0; i < 8 && err == 0; i++) + { + var ch = value[i] | 0x20; + var r = (ch>= '0' && ch <= '9') ? (ch - '0') : (ch>= 'a' && ch <= 'f') ? (ch - 'a' + 10) : 16; + a = (a << 4) | (r & 0x0F); + err |= (r & 0xF0); + + ch = value[i + 8] | 0x20; + r = (ch>= '0' && ch <= '9') ? (ch - '0') : (ch>= 'a' && ch <= 'f') ? (ch - 'a' + 10) : 16; + b = (b << 4) | (r & 0x0F); + err |= (r & 0xF0); + + ch = value[i + 16] | 0x20; + r = (ch>= '0' && ch <= '9') ? (ch - '0') : (ch>= 'a' && ch <= 'f') ? (ch - 'a' + 10) : 16; + c = (c << 4) | (r & 0x0F); + err |= (r & 0xF0); + } + + return err == 0; + } + private static void FromByteArray(byte[] bytes, int offset, out int a, out int b, out int c) { a = (bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3]; @@ -471,14 +513,7 @@ public bool Equals(ObjectId rhs) /// True if the other object is an ObjectId and equal to this one.
public override bool Equals(object obj)
{
- if (obj is ObjectId)
- {
- return Equals((ObjectId)obj);
- }
- else
- {
- return false;
- }
+ return obj is ObjectId && Equals((ObjectId)obj);
}
///
@@ -514,11 +549,11 @@ public void ToByteArray(byte[] destination, int offset)
{
if (destination == null)
{
- throw new ArgumentNullException("destination");
+ throw new ArgumentNullException(nameof(destination));
}
if (offset + 12> destination.Length)
{
- throw new ArgumentException("Not enough room in destination buffer.", "offset");
+ throw new ArgumentException("Not enough room in destination buffer.", nameof(offset));
}
destination[offset + 0] = (byte)(_a>> 24);
@@ -541,7 +576,24 @@ public void ToByteArray(byte[] destination, int offset)
/// A string representation of the value.
public override string ToString()
{
- return BsonUtils.ToHexString(ToByteArray());
+ var buffer = new char[24];
+
+ for (int i = 7, a = _a, b = _b, c = _c; i>= 0; i--)
+ {
+ var r = (a & 0x0F);
+ buffer[i] = (char)(r < 10 ? (r + '0') : (r - 10 + 'a')); + a>>= 4;
+
+ r = (b & 0x0F);
+ buffer[i + 8] = (char)(r < 10 ? (r + '0') : (r - 10 + 'a')); + b>>= 4;
+
+ r = (c & 0x0F);
+ buffer[i + 16] = (char)(r < 10 ? (r + '0') : (r - 10 + 'a')); + c>>= 4;
+ }
+
+ return new string(buffer);
}
// explicit IConvertible implementation
diff --git a/tests/MongoDB.Bson.Tests/ObjectModel/Decimal128Tests.cs b/tests/MongoDB.Bson.Tests/ObjectModel/Decimal128Tests.cs
index 541e461b111..554f499c727 100644
--- a/tests/MongoDB.Bson.Tests/ObjectModel/Decimal128Tests.cs
+++ b/tests/MongoDB.Bson.Tests/ObjectModel/Decimal128Tests.cs
@@ -46,7 +46,7 @@ public void Default_value()
[InlineData("-79228162514264337593543950335", "-79228162514264337593543950335")]
public void Decimal(string valueString, string s)
{
- var value = decimal.Parse(valueString);
+ var value = decimal.Parse(valueString, CultureInfo.InvariantCulture);
var subject = new Decimal128(value);
subject.ToString().Should().Be(s);