Skip to content
This repository has been archived by the owner on May 27, 2022. It is now read-only.

Commit

Permalink
csharp: Use value type wrapper containers
Browse files Browse the repository at this point in the history
  • Loading branch information
mattico committed Nov 24, 2020
1 parent 65d8eca commit 2e439fb
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 71 deletions.
5 changes: 2 additions & 3 deletions serde-generate/runtime/csharp/Serde/BinaryDeserializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0

using System;
using System.Collections.Immutable;
using System.IO;
using System.Numerics;
using System.Text;
Expand Down Expand Up @@ -66,7 +65,7 @@ public string deserialize_str()
return utf8.GetString(content);
}

public ImmutableArray<byte> deserialize_bytes()
public ValueArray<byte> deserialize_bytes()
{
long len = deserialize_len();
if (len < 0 || len > int.MaxValue)
Expand All @@ -76,7 +75,7 @@ public ImmutableArray<byte> deserialize_bytes()
byte[] content = reader.ReadBytes((int)len);
if (content.Length < len)
throw new DeserializationException($"Need {len - content.Length} more bytes for byte array");
return ImmutableArray.CreateRange<byte>(content);
return new ValueArray<byte>(content);
}

public bool deserialize_bool()
Expand Down
11 changes: 5 additions & 6 deletions serde-generate/runtime/csharp/Serde/BinarySerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
// SPDX-License-Identifier: MIT OR Apache-2.0

using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;

Expand Down Expand Up @@ -64,12 +62,13 @@ public void decrease_container_depth()

public byte[] get_bytes() => buffer.ToArray();

public void serialize_str(string value) => serialize_bytes(ImmutableArray.CreateRange<byte>(utf8.GetBytes(value)));
public void serialize_str(string value) => serialize_bytes(new ValueArray<byte>(utf8.GetBytes(value)));

public void serialize_bytes(ImmutableArray<byte> value)
public void serialize_bytes(ValueArray<byte> value)
{
serialize_len(value.Length);
output.Write(value.ToArray());
serialize_len(value.Count);
foreach (byte b in value)
output.Write(b);
}

public void serialize_bool(bool value) => output.Write(value);
Expand Down
3 changes: 1 addition & 2 deletions serde-generate/runtime/csharp/Serde/IDeserializer.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Facebook, Inc. and its affiliates
// SPDX-License-Identifier: MIT OR Apache-2.0

using System.Collections.Immutable;
using System.Numerics;

namespace Serde
Expand All @@ -10,7 +9,7 @@ public interface IDeserializer
{
string deserialize_str();

ImmutableArray<byte> deserialize_bytes();
ValueArray<byte> deserialize_bytes();

bool deserialize_bool();

Expand Down
3 changes: 1 addition & 2 deletions serde-generate/runtime/csharp/Serde/ISerializer.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Facebook, Inc. and its affiliates
// SPDX-License-Identifier: MIT OR Apache-2.0

using System.Collections.Immutable;
using System.Numerics;

namespace Serde
Expand All @@ -10,7 +9,7 @@ public interface ISerializer
{
void serialize_str(string value);

void serialize_bytes(ImmutableArray<byte> value);
void serialize_bytes(ValueArray<byte> value);

void serialize_bool(bool value);

Expand Down
1 change: 0 additions & 1 deletion serde-generate/runtime/csharp/Serde/Serde.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
</ItemGroup>
</Project>
15 changes: 7 additions & 8 deletions serde-generate/runtime/csharp/Serde/Unit.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@

using System;

namespace Serde
{
public sealed class Unit
public sealed class Unit : IEquatable<Unit>
{
public Unit() { }

public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;
return true;
}
public override bool Equals(object obj) => obj is Unit unit;

public bool Equals(Unit other) => other != null;

public override int GetHashCode() => 7;
public override int GetHashCode() => 793253941;
}
}
75 changes: 75 additions & 0 deletions serde-generate/runtime/csharp/Serde/ValueArray.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Serde
{
/// <summary>
/// Immutable wrapper class around T[]. Implements value semantics for
/// <see cref="object.Equals(object)"/> and <see cref="object.GetHashCode"/>.
/// </summary>
public class ValueArray<T> : IEquatable<ValueArray<T>>, IReadOnlyList<T>, IStructuralEquatable
where T: IEquatable<T>
{
private readonly T[] array;
private int? hashCode;

public int Count => array.Length;

public T this[int index] => array[index];

public ValueArray(T[] data) {
array = data ?? throw new ArgumentNullException(nameof(data));
hashCode = null;
}

public T[] ToArray() => array.ToArray();

public static implicit operator ReadOnlySpan<T>(ValueArray<T> bytes) => bytes.array;

public ReadOnlySpan<T> AsReadOnlySpan() => array;

public override bool Equals(object obj) => obj is ValueArray<T> bytes && Equals(bytes);

public bool Equals(ValueArray<T> other) {
if (other == null) return false;
if (ReferenceEquals(this, other)) return true;
if (Count != other.Count) return false;
for (int i = 0; i < Count; i++)
if (!array[i].Equals(other[i])) return false;
return true;
}

public static bool operator ==(ValueArray<T> left, ValueArray<T> right) => Equals(left, right);

public static bool operator !=(ValueArray<T> left, ValueArray<T> right) => !Equals(left, right);

public IEnumerator<T> GetEnumerator() => ((IEnumerable<T>)array).GetEnumerator();

IEnumerator IEnumerable.GetEnumerator() => array.GetEnumerator();

public override int GetHashCode()
{
unchecked
{
if (hashCode.HasValue) return hashCode.Value;
int code = 1849862467;
foreach (T elem in array)
code = code * 31 + elem.GetHashCode();
hashCode = code;
return code;
}
}

public bool Equals(object other, IEqualityComparer comparer)
{
return ((IStructuralEquatable)array).Equals(other, comparer);
}

public int GetHashCode(IEqualityComparer comparer)
{
return ((IStructuralEquatable)array).GetHashCode(comparer);
}
}
}
73 changes: 73 additions & 0 deletions serde-generate/runtime/csharp/Serde/ValueDictionary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System;
using System.Collections;
using System.Collections.Generic;

namespace Serde
{
/// <summary>
/// Immutable wrapper class around <see cref="Dictionary<K, V>"/>. Implements value semantics for
/// <see cref="object.Equals(object)"/> and <see cref="object.GetHashCode"/>.
/// </summary>
public class ValueDictionary<K, V> : IEquatable<ValueDictionary<K, V>>, IReadOnlyDictionary<K, V>
where K: IEquatable<K>
where V: IEquatable<V>
{
private readonly Dictionary<K, V> dict;
private int? hashCode;

public int Count => dict.Count;

public IEnumerable<K> Keys => dict.Keys;

public IEnumerable<V> Values => dict.Values;

public V this[K key] => dict[key];

public ValueDictionary(Dictionary<K, V> dictionary) {
dict = dictionary ?? throw new ArgumentNullException(nameof(dictionary));
hashCode = null;
}

public bool ContainsKey(K key) => dict.ContainsKey(key);

public bool TryGetValue(K key, out V value) => dict.TryGetValue(key, out value);

IEnumerator<KeyValuePair<K, V>> IEnumerable<KeyValuePair<K, V>>.GetEnumerator() => dict.GetEnumerator();

public IEnumerator GetEnumerator() => ((IEnumerable)dict).GetEnumerator();

public override bool Equals(object obj) => obj is ValueDictionary<K, V> bytes && Equals(bytes);

public bool Equals(ValueDictionary<K, V> other) {
if (other == null) return false;
if (Count != other.Count) return false;
foreach (var key in Keys)
{
if (!other.ContainsKey(key)) return false;
if (!dict[key].Equals(other[key])) return false;
}
return true;
}

public static bool operator ==(ValueDictionary<K, V> left, ValueDictionary<K, V> right) => Equals(left, right);

public static bool operator !=(ValueDictionary<K, V> left, ValueDictionary<K, V> right) => !Equals(left, right);


public override int GetHashCode()
{
unchecked
{
if (hashCode.HasValue) return hashCode.Value;
int code = 45053;
foreach (var pair in dict)
{
code = code * 31 + pair.Key.GetHashCode();
code = code * 31 + pair.Value.GetHashCode();
}
hashCode = code;
return code;
}
}
}
}
Loading

0 comments on commit 2e439fb

Please sign in to comment.