Skip to content

Commit

Permalink
Eliminate allocations.
Browse files Browse the repository at this point in the history
  • Loading branch information
tmds committed Nov 14, 2024
1 parent 33a8de9 commit 3b8cbeb
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 105 deletions.
3 changes: 3 additions & 0 deletions docs/protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,3 +323,6 @@ VariantValue v7 = new Dict<byte, VariantValue>()
};
VariantValue v8 = new Array<int>() { 1, 2 };
```

`VariantValue` avoids copies when possible. You should not modify the data used to construct a `VariantValue` until that value was written.
The data returned by some methods (like `GetArray`) may return the underlying data. If you modify it, other users of the object may observe the changes.
77 changes: 57 additions & 20 deletions src/Tmds.DBus.Protocol/Array.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public sealed class Array<T> : IDBusWritable, IList<T>, IVariantValueConvertable
where T : notnull
{
private readonly List<T> _values;
private bool _isReadOnly;

public Array() :
this(new List<T>())
Expand All @@ -29,20 +30,30 @@ private Array(List<T> values)
}

public void Add(T item)
=> _values.Add(item);
{
ThrowIfReadOnly();
_values.Add(item);
}

public void Clear()
=> _values.Clear();
{
ThrowIfReadOnly();
_values.Clear();
}

public int Count => _values.Count;

bool ICollection<T>.IsReadOnly
=> false;
=> _isReadOnly;

public T this[int index]
{
get => _values[index];
set => _values[index] = value;
set
{
ThrowIfReadOnly();
_values[index] = value;
}
}

IEnumerator<T> IEnumerable<T>.GetEnumerator()
Expand All @@ -55,10 +66,16 @@ public int IndexOf(T item)
=> _values.IndexOf(item);

public void Insert(int index, T item)
=> _values.Insert(index, item);
{
ThrowIfReadOnly();
_values.Insert(index, item);
}

public void RemoveAt(int index)
=> _values.RemoveAt(index);
{
ThrowIfReadOnly();
_values.RemoveAt(index);
}

public bool Contains(T item)
=> _values.Contains(item);
Expand All @@ -67,7 +84,10 @@ public void CopyTo(T[] array, int arrayIndex)
=> _values.CopyTo(array, arrayIndex);

public bool Remove(T item)
=> _values.Remove(item);
{
ThrowIfReadOnly();
return _values.Remove(item);
}

public Variant AsVariant()
=> Variant.FromArray(this);
Expand All @@ -78,59 +98,76 @@ public static implicit operator Variant(Array<T> value)
public static implicit operator VariantValue(Array<T> value)
=> value.AsVariantValue();

private void ThrowIfReadOnly()
{
if (_isReadOnly)
{
ThrowReadOnlyException();
}
}

private void ThrowReadOnlyException()
{
throw new InvalidOperationException($"Can not modify {nameof(Array)} after calling {nameof(AsVariantValue)}.");
}
public VariantValue AsVariantValue()
{
_isReadOnly = true;
if (typeof(T) == typeof(byte))
{
return VariantValue.Array((byte[])(object)_values.ToArray());
return VariantValue.Array((List<byte>)(object)_values);
}
else if (typeof(T) == typeof(bool))
{
return VariantValue.Array((bool[])(object)_values.ToArray());
return VariantValue.Array((List<bool>)(object)_values);
}
else if (typeof(T) == typeof(short))
{
return VariantValue.Array((short[])(object)_values.ToArray());
return VariantValue.Array((List<short>)(object)_values);
}
else if (typeof(T) == typeof(ushort))
{
return VariantValue.Array((ushort[])(object)_values.ToArray());
return VariantValue.Array((List<ushort>)(object)_values);
}
else if (typeof(T) == typeof(int))
{
return VariantValue.Array((int[])(object)_values.ToArray());
return VariantValue.Array((List<int>)(object)_values);
}
else if (typeof(T) == typeof(uint))
{
return VariantValue.Array((uint[])(object)_values.ToArray());
return VariantValue.Array((List<uint>)(object)_values);
}
else if (typeof(T) == typeof(long))
{
return VariantValue.Array((long[])(object)_values.ToArray());
return VariantValue.Array((List<long>)(object)_values);
}
else if (typeof(T) == typeof(ulong))
{
return VariantValue.Array((ulong[])(object)_values.ToArray());
return VariantValue.Array((List<ulong>)(object)_values);
}
else if (typeof(T) == typeof(double))
{
return VariantValue.Array((double[])(object)_values.ToArray());
return VariantValue.Array((List<double>)(object)_values);
}
else if (typeof(T) == typeof(string))
{
return VariantValue.Array((string[])(object)_values.ToArray());
return VariantValue.Array((List<string>)(object)_values);
}
else if (typeof(T) == typeof(ObjectPath))
{
return VariantValue.Array((ObjectPath[])(object)_values.ToArray());
return VariantValue.Array((List<ObjectPath>)(object)_values);
}
else if (typeof(T) == typeof(Signature))
{
return VariantValue.Array((Signature[])(object)_values.ToArray());
return VariantValue.Array((List<Signature>)(object)_values);
}
else if (typeof(T) == typeof(SafeHandle))
{
return VariantValue.Array((SafeHandle[])(object)_values.ToArray());
return VariantValue.Array((List<SafeHandle>)(object)_values);
}
else if (typeof(T) == typeof(VariantValue))
{
return VariantValue.ArrayOfVariant((List<VariantValue>)(object)_values);
}
else if (typeof(T).IsAssignableTo(typeof(IVariantValueConvertable)))
{
Expand Down
Loading

0 comments on commit 3b8cbeb

Please sign in to comment.