2018-11-17 04:00:12 +08:00
|
|
|
|
namespace UglyToad.PdfPig.Tokens
|
2017-11-13 01:06:19 +08:00
|
|
|
|
{
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
2018-11-25 03:02:06 +08:00
|
|
|
|
/// <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>>
|
2017-11-13 01:06:19 +08:00
|
|
|
|
{
|
2018-11-25 03:02:06 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// The key value pairs in this dictionary.
|
|
|
|
|
/// </summary>
|
2018-01-14 18:53:01 +08:00
|
|
|
|
public IReadOnlyDictionary<string, IToken> Data { get; }
|
2017-11-13 01:06:19 +08:00
|
|
|
|
|
2018-11-25 03:02:06 +08:00
|
|
|
|
/// <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)
|
2017-11-13 01:06:19 +08:00
|
|
|
|
{
|
2018-01-14 18:53:01 +08:00
|
|
|
|
if (data == null)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentNullException(nameof(data));
|
|
|
|
|
}
|
2018-12-08 22:38:27 +08:00
|
|
|
|
|
2018-01-14 18:53:01 +08:00
|
|
|
|
var result = new Dictionary<string, IToken>(data.Count);
|
|
|
|
|
|
|
|
|
|
foreach (var keyValuePair in data)
|
|
|
|
|
{
|
2018-12-08 22:38:27 +08:00
|
|
|
|
result[keyValuePair.Key.Data] = keyValuePair.Value;
|
2018-01-14 18:53:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Data = result;
|
2017-11-13 01:06:19 +08:00
|
|
|
|
}
|
2018-01-19 08:35:04 +08:00
|
|
|
|
|
|
|
|
|
private DictionaryToken(IReadOnlyDictionary<string, IToken> data)
|
|
|
|
|
{
|
|
|
|
|
Data = data;
|
|
|
|
|
}
|
2018-04-13 05:34:38 +08:00
|
|
|
|
|
2018-11-25 03:02:06 +08:00
|
|
|
|
/// <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>
|
2018-01-19 08:35:04 +08:00
|
|
|
|
public bool TryGet(NameToken name, out IToken token)
|
2017-11-14 07:48:25 +08:00
|
|
|
|
{
|
|
|
|
|
if (name == null)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentNullException(nameof(name));
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-19 08:35:04 +08:00
|
|
|
|
return Data.TryGetValue(name.Data, out token);
|
2017-11-14 07:48:25 +08:00
|
|
|
|
}
|
2017-11-13 01:06:19 +08:00
|
|
|
|
|
2018-11-25 03:02:06 +08:00
|
|
|
|
/// <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>
|
2018-04-28 20:00:43 +08:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-25 03:02:06 +08:00
|
|
|
|
/// <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>
|
2018-01-19 08:35:04 +08:00
|
|
|
|
public bool ContainsKey(NameToken name)
|
|
|
|
|
{
|
|
|
|
|
return Data.ContainsKey(name.Data);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-25 03:02:06 +08:00
|
|
|
|
/// <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>
|
2018-01-19 08:35:04 +08:00
|
|
|
|
public DictionaryToken With(NameToken key, IToken value) => With(key.Data, value);
|
2018-11-25 03:02:06 +08:00
|
|
|
|
|
|
|
|
|
/// <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>
|
2018-01-19 08:35:04 +08:00
|
|
|
|
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);
|
|
|
|
|
}
|
2018-11-25 03:02:06 +08:00
|
|
|
|
|
2020-03-07 23:25:56 +08:00
|
|
|
|
|
|
|
|
|
/// <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));
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-25 03:02:06 +08:00
|
|
|
|
/// <inheritdoc />
|
2017-11-13 01:06:19 +08:00
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return string.Join(", ", Data.Select(x => $"<{x.Key}, {x.Value}>"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|