blob: 2f1eb74251002f2601f3b279cb5a573427d368b8 [file] [log] [blame] [edit]
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Antlr4.Runtime.Sharpen;
namespace Antlr4.Runtime.Dfa
{
/// <author>Sam Harwell</author>
public sealed class SparseEdgeMap<T> : AbstractEdgeMap<T>
where T : class
{
private const int DefaultMaxSize = 5;
private readonly int[] keys;
private readonly List<T> values;
public SparseEdgeMap(int minIndex, int maxIndex)
: this(minIndex, maxIndex, DefaultMaxSize)
{
}
public SparseEdgeMap(int minIndex, int maxIndex, int maxSparseSize)
: base(minIndex, maxIndex)
{
this.keys = new int[maxSparseSize];
this.values = new List<T>(maxSparseSize);
}
private SparseEdgeMap(Antlr4.Runtime.Dfa.SparseEdgeMap<T> map, int maxSparseSize)
: base(map.minIndex, map.maxIndex)
{
lock (map)
{
if (maxSparseSize < map.values.Count)
{
throw new ArgumentException();
}
keys = Arrays.CopyOf(map.keys, maxSparseSize);
values = new List<T>(maxSparseSize);
values.AddRange(map.Values);
}
}
public int[] Keys
{
get
{
return keys;
}
}
public IList<T> Values
{
get
{
return values;
}
}
public int MaxSparseSize
{
get
{
return keys.Length;
}
}
public override int Count
{
get
{
return values.Count;
}
}
public override bool IsEmpty
{
get
{
return values.Count == 0;
}
}
public override bool ContainsKey(int key)
{
return this[key] != null;
}
public override T this[int key]
{
get
{
// Special property of this collection: values are only even added to
// the end, else a new object is returned from put(). Therefore no lock
// is required in this method.
int index = System.Array.BinarySearch(keys, 0, Count, key);
if (index < 0)
{
return null;
}
return values[index];
}
}
public override AbstractEdgeMap<T> Put(int key, T value)
{
if (key < minIndex || key > maxIndex)
{
return this;
}
if (value == null)
{
return Remove(key);
}
lock (this)
{
int index = System.Array.BinarySearch(keys, 0, Count, key);
if (index >= 0)
{
// replace existing entry
values[index] = value;
return this;
}
System.Diagnostics.Debug.Assert(index < 0 && value != null);
int insertIndex = -index - 1;
if (Count < MaxSparseSize && insertIndex == Count)
{
// stay sparse and add new entry
keys[insertIndex] = key;
values.Add(value);
return this;
}
int desiredSize = Count >= MaxSparseSize ? MaxSparseSize * 2 : MaxSparseSize;
int space = maxIndex - minIndex + 1;
// SparseEdgeMap only uses less memory than ArrayEdgeMap up to half the size of the symbol space
if (desiredSize >= space / 2)
{
ArrayEdgeMap<T> arrayMap = new ArrayEdgeMap<T>(minIndex, maxIndex);
arrayMap = ((ArrayEdgeMap<T>)arrayMap.PutAll(this));
arrayMap.Put(key, value);
return arrayMap;
}
else
{
Antlr4.Runtime.Dfa.SparseEdgeMap<T> resized = new Antlr4.Runtime.Dfa.SparseEdgeMap<T>(this, desiredSize);
System.Array.Copy(resized.keys, insertIndex, resized.keys, insertIndex + 1, Count - insertIndex);
resized.keys[insertIndex] = key;
resized.values.Insert(insertIndex, value);
return resized;
}
}
}
public override AbstractEdgeMap<T> Remove(int key)
{
lock (this)
{
int index = System.Array.BinarySearch(keys, 0, Count, key);
if (index < 0)
{
return this;
}
Antlr4.Runtime.Dfa.SparseEdgeMap<T> result = new Antlr4.Runtime.Dfa.SparseEdgeMap<T>(this, MaxSparseSize);
System.Array.Copy(result.keys, index + 1, result.keys, index, Count - index - 1);
result.values.RemoveAt(index);
return result;
}
}
public override AbstractEdgeMap<T> Clear()
{
if (IsEmpty)
{
return this;
}
return new EmptyEdgeMap<T>(minIndex, maxIndex);
}
public override IReadOnlyDictionary<int, T> ToMap()
{
if (IsEmpty)
{
return Sharpen.Collections.EmptyMap<int, T>();
}
lock (this)
{
IDictionary<int, T> result = new SortedDictionary<int, T>();
for (int i = 0; i < Count; i++)
{
result[keys[i]] = values[i];
}
return new ReadOnlyDictionary<int, T>(result);
}
}
}
}