PdfPig/src/UglyToad.PdfPig.Tokens/DictionaryToken.cs

144 lines
5.1 KiB
C#
Raw Normal View History

namespace UglyToad.PdfPig.Tokens
{
using System;
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// A dictionary object is an associative table containing pairs of objects, known as the dictionary's entries.
/// The key must be a <see cref="NameToken"/> and the value may be an kind of <see cref="IToken"/>.
/// </summary>
public class DictionaryToken : IDataToken<IReadOnlyDictionary<string, IToken>>
{
/// <summary>
/// The key value pairs in this dictionary.
/// </summary>
public IReadOnlyDictionary<string, IToken> Data { get; }
/// <summary>
/// Create a new <see cref="DictionaryToken"/>.
/// </summary>
/// <param name="data">The data this dictionary will contain.</param>
2020-01-05 18:07:01 +08:00
public DictionaryToken(IReadOnlyDictionary<NameToken, IToken> data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
var result = new Dictionary<string, IToken>(data.Count);
foreach (var keyValuePair in data)
{
result[keyValuePair.Key.Data] = keyValuePair.Value;
}
Data = result;
}
private DictionaryToken(IReadOnlyDictionary<string, IToken> data)
{
Data = data;
}
/// <summary>
/// Try and get the entry with a given name.
/// </summary>
/// <param name="name">The name of the entry to retrieve.</param>
/// <param name="token">The token, if it is found.</param>
/// <returns><see langword="true"/> if the token is found, <see langword="false"/> otherwise.</returns>
public bool TryGet(NameToken name, out IToken token)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
return Data.TryGetValue(name.Data, out token);
}
/// <summary>
/// Try and get the entry with a given name and a specific data type.
/// </summary>
/// <typeparam name="T">The expected data type of the dictionary value.</typeparam>
/// <param name="name">The name of the entry to retrieve.</param>
/// <param name="token">The token, if it is found.</param>
/// <returns><see langword="true"/> if the token is found with this type, <see langword="false"/> otherwise.</returns>
public bool TryGet<T>(NameToken name, out T token) where T : IToken
{
token = default(T);
if (!TryGet(name, out var t) || !(t is T typedToken))
{
return false;
}
token = typedToken;
return true;
}
/// <summary>
/// Whether the dictionary contains an entry with this name.
/// </summary>
/// <param name="name">The name to check.</param>
/// <returns><see langword="true"/> if the token is found, <see langword="false"/> otherwise.</returns>
public bool ContainsKey(NameToken name)
{
return Data.ContainsKey(name.Data);
}
/// <summary>
/// Create a copy of this dictionary with the additional entry (or override the value of the existing entry).
/// </summary>
/// <param name="key">The key of the entry to create or override.</param>
/// <param name="value">The value of the entry to create or override.</param>
/// <returns>A new <see cref="DictionaryToken"/> with the entry created or modified.</returns>
public DictionaryToken With(NameToken key, IToken value) => With(key.Data, value);
/// <summary>
/// Create a copy of this dictionary with the additional entry (or override the value of the existing entry).
/// </summary>
/// <param name="key">The key of the entry to create or override.</param>
/// <param name="value">The value of the entry to create or override.</param>
/// <returns>A new <see cref="DictionaryToken"/> with the entry created or modified.</returns>
public DictionaryToken With(string key, IToken value)
{
var result = new Dictionary<string, IToken>(Data.Count + 1);
foreach (var keyValuePair in Data)
{
result[keyValuePair.Key] = keyValuePair.Value;
}
result[key] = value;
return new DictionaryToken(result);
}
/// <inheritdoc />
public bool Equals(IToken obj)
{
if (this == obj)
return true;
if (!(obj is DictionaryToken other))
{
return false;
}
if (Data.Count != other.Data.Count)
return false;
// TODO: Maybe consider using a sorted dictionary?
return Data.OrderBy(kvp => kvp.Key)
.SequenceEqual(other.Data.OrderBy(kvp => kvp.Key));
}
/// <inheritdoc />
public override string ToString()
{
return string.Join(", ", Data.Select(x => $"<{x.Key}, {x.Value}>"));
}
}
}