aboutsummaryrefslogtreecommitdiff
path: root/src/ProtocolBuffers/Collections
diff options
context:
space:
mode:
authorJon Skeet <skeet@pobox.com>2008-10-22 13:30:34 +0100
committerJon Skeet <skeet@pobox.com>2008-10-22 13:30:34 +0100
commit6803686bc06c4d96afd9bd2637f7b37a58596699 (patch)
tree4b21c563f4cd4e399fbc0b253bc2f15e822eae88 /src/ProtocolBuffers/Collections
parentf0589506c96600dcd01319b9d1929d87505f3daa (diff)
downloadprotobuf-6803686bc06c4d96afd9bd2637f7b37a58596699.tar.gz
protobuf-6803686bc06c4d96afd9bd2637f7b37a58596699.tar.bz2
protobuf-6803686bc06c4d96afd9bd2637f7b37a58596699.zip
First cut at new layout
Diffstat (limited to 'src/ProtocolBuffers/Collections')
-rw-r--r--src/ProtocolBuffers/Collections/Dictionaries.cs108
-rw-r--r--src/ProtocolBuffers/Collections/Lists.cs56
-rw-r--r--src/ProtocolBuffers/Collections/PopsicleList.cs95
-rw-r--r--src/ProtocolBuffers/Collections/ReadOnlyDictionary.cs112
4 files changed, 371 insertions, 0 deletions
diff --git a/src/ProtocolBuffers/Collections/Dictionaries.cs b/src/ProtocolBuffers/Collections/Dictionaries.cs
new file mode 100644
index 00000000..5ba02664
--- /dev/null
+++ b/src/ProtocolBuffers/Collections/Dictionaries.cs
@@ -0,0 +1,108 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Google.ProtocolBuffers.Collections {
+
+ /// <summary>
+ /// Non-generic class with generic methods which proxy to the non-generic methods
+ /// in the generic class.
+ /// </summary>
+ public static class Dictionaries {
+
+ /// <summary>
+ /// Compares two dictionaries for equality. Each value is compared with equality using Equals
+ /// for non-IEnumerable implementations, and using EnumerableEquals otherwise.
+ /// TODO(jonskeet): This is clearly pretty slow, and involves lots of boxing/unboxing...
+ /// </summary>
+ public static bool Equals<TKey, TValue>(IDictionary<TKey, TValue> left, IDictionary<TKey, TValue> right) {
+ if (left.Count != right.Count) {
+ return false;
+ }
+ foreach (KeyValuePair<TKey,TValue> leftEntry in left)
+ {
+ TValue rightValue;
+ if (!right.TryGetValue(leftEntry.Key, out rightValue)) {
+ return false;
+ }
+
+ IEnumerable leftEnumerable = leftEntry.Value as IEnumerable;
+ IEnumerable rightEnumerable = rightValue as IEnumerable;
+ if (leftEnumerable == null || rightEnumerable == null) {
+ if (!object.Equals(leftEntry.Value, rightValue)) {
+ return false;
+ }
+ } else {
+ IEnumerator leftEnumerator = leftEnumerable.GetEnumerator();
+ try {
+ foreach (object rightObject in rightEnumerable) {
+ if (!leftEnumerator.MoveNext()) {
+ return false;
+ }
+ if (!object.Equals(leftEnumerator.Current, rightObject)) {
+ return false;
+ }
+ }
+ if (leftEnumerator.MoveNext()) {
+ return false;
+ }
+ } finally {
+ if (leftEnumerator is IDisposable) {
+ ((IDisposable)leftEnumerator).Dispose();
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ public static IDictionary<TKey, TValue> AsReadOnly<TKey, TValue> (IDictionary<TKey, TValue> dictionary) {
+ return dictionary.IsReadOnly ? dictionary : new ReadOnlyDictionary<TKey, TValue>(dictionary);
+ }
+
+ /// <summary>
+ /// Creates a hashcode for a dictionary by XORing the hashcodes of all the fields
+ /// and values. (By XORing, we avoid ordering issues.)
+ /// TODO(jonskeet): Currently XORs other stuff too, and assumes non-null values.
+ /// </summary>
+ public static int GetHashCode<TKey, TValue>(IDictionary<TKey, TValue> dictionary) {
+ int ret = 31;
+ foreach (KeyValuePair<TKey, TValue> entry in dictionary) {
+ int hash = entry.Key.GetHashCode() ^ GetDeepHashCode(entry.Value);
+ ret ^= hash;
+ }
+ return ret;
+ }
+
+ /// <summary>
+ /// Determines the hash of a value by either taking it directly or hashing all the elements
+ /// for IEnumerable implementations.
+ /// </summary>
+ private static int GetDeepHashCode(object value) {
+ IEnumerable iterable = value as IEnumerable;
+ if (iterable == null) {
+ return value.GetHashCode();
+ }
+ int hash = 29;
+ foreach (object element in iterable) {
+ hash = hash * 37 + element.GetHashCode();
+ }
+ return hash;
+ }
+ }
+}
diff --git a/src/ProtocolBuffers/Collections/Lists.cs b/src/ProtocolBuffers/Collections/Lists.cs
new file mode 100644
index 00000000..b1b6b122
--- /dev/null
+++ b/src/ProtocolBuffers/Collections/Lists.cs
@@ -0,0 +1,56 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace Google.ProtocolBuffers.Collections {
+
+ /// <summary>
+ /// Utility non-generic class for calling into Lists{T} using type inference.
+ /// </summary>
+ public static class Lists {
+
+ /// <summary>
+ /// Returns a read-only view of the specified list.
+ /// </summary>
+ public static IList<T> AsReadOnly<T>(IList<T> list) {
+ return Lists<T>.AsReadOnly(list);
+ }
+ }
+
+ /// <summary>
+ /// Utility class for dealing with lists.
+ /// </summary>
+ public static class Lists<T> {
+
+ static readonly ReadOnlyCollection<T> empty = new ReadOnlyCollection<T>(new T[0]);
+
+ /// <summary>
+ /// Returns an immutable empty list.
+ /// </summary>
+ public static ReadOnlyCollection<T> Empty {
+ get { return empty; }
+ }
+
+ /// <summary>
+ /// Returns either the original reference if it's already read-only,
+ /// or a new ReadOnlyCollection wrapping the original list.
+ /// </summary>
+ public static IList<T> AsReadOnly(IList<T> list) {
+ return list.IsReadOnly ? list : new ReadOnlyCollection<T>(list);
+ }
+ }
+}
diff --git a/src/ProtocolBuffers/Collections/PopsicleList.cs b/src/ProtocolBuffers/Collections/PopsicleList.cs
new file mode 100644
index 00000000..4efe13d0
--- /dev/null
+++ b/src/ProtocolBuffers/Collections/PopsicleList.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Collections;
+
+namespace Google.ProtocolBuffers.Collections {
+ /// <summary>
+ /// Proxies calls to a <see cref="List{T}" />, but allows the list
+ /// to be made read-only (with the <see cref="MakeReadOnly" /> method),
+ /// after which any modifying methods throw <see cref="NotSupportedException" />.
+ /// </summary>
+ public sealed class PopsicleList<T> : IList<T> {
+
+ private readonly List<T> items = new List<T>();
+ private bool readOnly = false;
+
+ /// <summary>
+ /// Makes this list read-only ("freezes the popsicle"). From this
+ /// point on, mutating methods (Clear, Add etc) will throw a
+ /// NotSupportedException. There is no way of "defrosting" the list afterwards.
+ /// </summary>
+ public void MakeReadOnly() {
+ readOnly = true;
+ }
+
+ public int IndexOf(T item) {
+ return items.IndexOf(item);
+ }
+
+ public void Insert(int index, T item) {
+ ValidateModification();
+ items.Insert(index, item);
+ }
+
+ public void RemoveAt(int index) {
+ ValidateModification();
+ items.RemoveAt(index);
+ }
+
+ public T this[int index] {
+ get {
+ return items[index];
+ }
+ set {
+ ValidateModification();
+ items[index] = value;
+ }
+ }
+
+ public void Add(T item) {
+ ValidateModification();
+ items.Add(item);
+ }
+
+ public void Clear() {
+ ValidateModification();
+ items.Clear();
+ }
+
+ public bool Contains(T item) {
+ return items.Contains(item);
+ }
+
+ public void CopyTo(T[] array, int arrayIndex) {
+ items.CopyTo(array, arrayIndex);
+ }
+
+ public int Count {
+ get { return items.Count; }
+ }
+
+ public bool IsReadOnly {
+ get { return readOnly; }
+ }
+
+ public bool Remove(T item) {
+ ValidateModification();
+ return items.Remove(item);
+ }
+
+ public IEnumerator<T> GetEnumerator() {
+ return items.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() {
+ return GetEnumerator();
+ }
+
+ private void ValidateModification() {
+ if (readOnly) {
+ throw new NotSupportedException("List is read-only");
+ }
+ }
+ }
+}
diff --git a/src/ProtocolBuffers/Collections/ReadOnlyDictionary.cs b/src/ProtocolBuffers/Collections/ReadOnlyDictionary.cs
new file mode 100644
index 00000000..cd4b1898
--- /dev/null
+++ b/src/ProtocolBuffers/Collections/ReadOnlyDictionary.cs
@@ -0,0 +1,112 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.
+// http://code.google.com/p/protobuf/
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Google.ProtocolBuffers.Collections {
+ /// <summary>
+ /// Read-only wrapper around another dictionary.
+ /// </summary>
+ public sealed class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue> {
+ readonly IDictionary<TKey, TValue> wrapped;
+
+ public ReadOnlyDictionary(IDictionary<TKey, TValue> wrapped) {
+ this.wrapped = wrapped;
+ }
+
+ public void Add(TKey key, TValue value) {
+ throw new InvalidOperationException();
+ }
+
+ public bool ContainsKey(TKey key) {
+ return wrapped.ContainsKey(key);
+ }
+
+ public ICollection<TKey> Keys {
+ get { return wrapped.Keys; }
+ }
+
+ public bool Remove(TKey key) {
+ throw new InvalidOperationException();
+ }
+
+ public bool TryGetValue(TKey key, out TValue value) {
+ return wrapped.TryGetValue(key, out value);
+ }
+
+ public ICollection<TValue> Values {
+ get { return wrapped.Values; }
+ }
+
+ public TValue this[TKey key] {
+ get {
+ return wrapped[key];
+ }
+ set {
+ throw new InvalidOperationException();
+ }
+ }
+
+ public void Add(KeyValuePair<TKey, TValue> item) {
+ throw new InvalidOperationException();
+ }
+
+ public void Clear() {
+ throw new InvalidOperationException();
+ }
+
+ public bool Contains(KeyValuePair<TKey, TValue> item) {
+ return wrapped.Contains(item);
+ }
+
+ public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
+ wrapped.CopyTo(array, arrayIndex);
+ }
+
+ public int Count {
+ get { return wrapped.Count; }
+ }
+
+ public bool IsReadOnly {
+ get { return true; }
+ }
+
+ public bool Remove(KeyValuePair<TKey, TValue> item) {
+ throw new InvalidOperationException();
+ }
+
+ public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
+ return wrapped.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() {
+ return ((IEnumerable) wrapped).GetEnumerator();
+ }
+
+ public override bool Equals(object obj) {
+ return wrapped.Equals(obj);
+ }
+
+ public override int GetHashCode() {
+ return wrapped.GetHashCode();
+ }
+
+ public override string ToString() {
+ return wrapped.ToString();
+ }
+ }
+}