/* Copyright 2010-2014 MongoDB Inc. * * 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; using System.Linq; using System.Text; using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; using MongoDB.Shared; namespace MongoDB.Bson { /// /// Represents a BSON array. /// [Serializable] public class BsonArray : BsonValue, IComparable, IEquatable, IList { // private fields private List _values; // constructors /// /// Initializes a new instance of the BsonArray class. /// public BsonArray() : this(0) { } /// /// Initializes a new instance of the BsonArray class. /// /// A list of values to add to the array. public BsonArray(IEnumerable values) : this(0) { AddRange(values); } /// /// Initializes a new instance of the BsonArray class. /// /// A list of values to add to the array. public BsonArray(IEnumerable values) : this(0) { AddRange(values); } /// /// Initializes a new instance of the BsonArray class. /// /// A list of values to add to the array. public BsonArray(IEnumerable values) : this(0) { AddRange(values); } /// /// Initializes a new instance of the BsonArray class. /// /// A list of values to add to the array. public BsonArray(IEnumerable values) : this(0) { AddRange(values); } /// /// Initializes a new instance of the BsonArray class. /// /// A list of values to add to the array. public BsonArray(IEnumerable values) : this(0) { AddRange(values); } /// /// Initializes a new instance of the BsonArray class. /// /// A list of values to add to the array. public BsonArray(IEnumerable values) : this(0) { AddRange(values); } /// /// Initializes a new instance of the BsonArray class. /// /// A list of values to add to the array. public BsonArray(IEnumerable values) : this(0) { AddRange(values); } /// /// Initializes a new instance of the BsonArray class. /// /// A list of values to add to the array. public BsonArray(IEnumerable values) : this(0) { AddRange(values); } /// /// Initializes a new instance of the BsonArray class. /// /// A list of values to add to the array. public BsonArray(IEnumerable values) : this(0) { AddRange(values); } /// /// Initializes a new instance of the BsonArray class. /// /// The initial capacity of the array. public BsonArray(int capacity) : base(BsonType.Array) { _values = new List(capacity); } // public operators /// /// Compares two BsonArray values. /// /// The first BsonArray. /// The other BsonArray. /// True if the two BsonArray values are not equal according to ==. public static bool operator !=(BsonArray lhs, BsonArray rhs) { return !(lhs == rhs); } /// /// Compares two BsonArray values. /// /// The first BsonArray. /// The other BsonArray. /// True if the two BsonArray values are equal according to ==. public static bool operator ==(BsonArray lhs, BsonArray rhs) { return object.Equals(lhs, rhs); // handles lhs == null correctly } // public properties /// /// Gets or sets the total number of elements the internal data structure can hold without resizing. /// public virtual int Capacity { get { return _values.Capacity; } set { _values.Capacity = value; } } /// /// Gets the count of array elements. /// public virtual int Count { get { return _values.Count; } } /// /// Gets whether the array is read-only. /// public virtual bool IsReadOnly { get { return false; } } /// /// Gets the array elements as raw values (see BsonValue.RawValue). /// [Obsolete("Use ToArray to ToList instead.")] public virtual IEnumerable RawValues { get { return _values.Select(v => v.RawValue); } } /// /// Gets the array elements. /// public virtual IEnumerable Values { get { return _values; } } // public indexers /// /// Gets or sets a value by position. /// /// The position. /// The value. public override BsonValue this[int index] { get { return _values[index]; } set { if (value == null) { throw new ArgumentNullException("value"); } _values[index] = value; } } // public static methods /// /// Creates a new BsonArray. /// /// A list of values to add to the array. /// A BsonArray or null. [Obsolete("Use new BsonArray(IEnumerable values) instead.")] public static BsonArray Create(IEnumerable values) { if (values != null) { return new BsonArray(values); } else { return null; } } /// /// Creates a new BsonArray. /// /// A list of values to add to the array. /// A BsonArray or null. [Obsolete("Use new BsonArray(IEnumerable values) instead.")] public static BsonArray Create(IEnumerable values) { if (values != null) { return new BsonArray(values); } else { return null; } } /// /// Creates a new BsonArray. /// /// A list of values to add to the array. /// A BsonArray or null. [Obsolete("Use new BsonArray(IEnumerable values) instead.")] public static BsonArray Create(IEnumerable values) { if (values != null) { return new BsonArray(values); } else { return null; } } /// /// Creates a new BsonArray. /// /// A list of values to add to the array. /// A BsonArray or null. [Obsolete("Use new BsonArray(IEnumerable values) instead.")] public static BsonArray Create(IEnumerable values) { if (values != null) { return new BsonArray(values); } else { return null; } } /// /// Creates a new BsonArray. /// /// A list of values to add to the array. /// A BsonArray or null. [Obsolete("Use new BsonArray(IEnumerable values) instead.")] public static BsonArray Create(IEnumerable values) { if (values != null) { return new BsonArray(values); } else { return null; } } /// /// Creates a new BsonArray. /// /// A list of values to add to the array. /// A BsonArray or null. [Obsolete("Use new BsonArray(IEnumerable values) instead.")] public static BsonArray Create(IEnumerable values) { if (values != null) { return new BsonArray(values); } else { return null; } } /// /// Creates a new BsonArray. /// /// A list of values to add to the array. /// A BsonArray or null. [Obsolete("Use new BsonArray(IEnumerable values) instead.")] public static BsonArray Create(IEnumerable values) { if (values != null) { return new BsonArray(values); } else { return null; } } /// /// Creates a new BsonArray. /// /// A list of values to add to the array. /// A BsonArray or null. [Obsolete("Use new BsonArray(IEnumerable values) instead.")] public static BsonArray Create(IEnumerable values) { if (values != null) { return new BsonArray(values); } else { return null; } } /// /// Creates a new BsonArray. /// /// A list of values to add to the array. /// A BsonArray or null. [Obsolete("Use new BsonArray(IEnumerable values) instead.")] public static BsonArray Create(IEnumerable values) { if (values != null) { return new BsonArray(values); } else { return null; } } /// /// Creates a new BsonArray. /// /// A value to be mapped to a BsonArray. /// A BsonArray or null. public new static BsonArray Create(object value) { if (value != null) { return (BsonArray)BsonTypeMapper.MapToBsonValue(value, BsonType.Array); } else { return null; } } /// /// Reads a BsonArray from a BsonReader. /// /// The reader. /// A BsonArray. [Obsolete("Use BsonSerializer.Deserialize instead.")] public static new BsonArray ReadFrom(BsonReader bsonReader) { return BsonSerializer.Deserialize(bsonReader); } // public methods /// /// Adds an element to the array. /// /// The value to add to the array. /// The array (so method calls can be chained). public virtual BsonArray Add(BsonValue value) { if (value != null) { _values.Add(value); } return this; } /// /// Adds multiple elements to the array. /// /// A list of values to add to the array. /// The array (so method calls can be chained). public virtual BsonArray AddRange(IEnumerable values) { if (values != null) { foreach (var value in values) { Add((BsonBoolean)value); } } return this; } /// /// Adds multiple elements to the array. /// /// A list of values to add to the array. /// The array (so method calls can be chained). public virtual BsonArray AddRange(IEnumerable values) { if (values != null) { foreach (var value in values) { if (value != null) { _values.Add(value); } } } return this; } /// /// Adds multiple elements to the array. /// /// A list of values to add to the array. /// The array (so method calls can be chained). public virtual BsonArray AddRange(IEnumerable values) { if (values != null) { foreach (var value in values) { Add(new BsonDateTime(value)); } } return this; } /// /// Adds multiple elements to the array. /// /// A list of values to add to the array. /// The array (so method calls can be chained). public virtual BsonArray AddRange(IEnumerable values) { if (values != null) { foreach (var value in values) { Add(new BsonDouble(value)); } } return this; } /// /// Adds multiple elements to the array. /// /// A list of values to add to the array. /// The array (so method calls can be chained). public virtual BsonArray AddRange(IEnumerable values) { if (values != null) { foreach (var value in values) { Add(new BsonInt32(value)); } } return this; } /// /// Adds multiple elements to the array. /// /// A list of values to add to the array. /// The array (so method calls can be chained). public virtual BsonArray AddRange(IEnumerable values) { if (values != null) { foreach (var value in values) { Add(new BsonInt64(value)); } } return this; } /// /// Adds multiple elements to the array. /// /// A list of values to add to the array. /// The array (so method calls can be chained). public virtual BsonArray AddRange(IEnumerable values) { if (values != null) { foreach (var value in values) { Add(new BsonObjectId(value)); } } return this; } /// /// Adds multiple elements to the array. /// /// A list of values to add to the array. /// The array (so method calls can be chained). public virtual BsonArray AddRange(IEnumerable values) { if (values != null) { foreach (var value in values) { _values.Add((value == null) ? (BsonValue)BsonNull.Value : new BsonString(value)); } } return this; } /// /// Adds multiple elements to the array. /// /// A list of values to add to the array. /// The array (so method calls can be chained). public virtual BsonArray AddRange(IEnumerable values) { if (values != null) { foreach (var value in values) { Add(BsonTypeMapper.MapToBsonValue(value)); } } return this; } /// /// Creates a shallow clone of the array (see also DeepClone). /// /// A shallow clone of the array. public override BsonValue Clone() { var clone = new BsonArray(_values.Capacity); foreach (var value in _values) { clone.Add(value); } return clone; } /// /// Clears the array. /// public virtual void Clear() { _values.Clear(); } /// /// Compares the array to another array. /// /// The other array. /// A 32-bit signed integer that indicates whether this array is less than, equal to, or greather than the other. public virtual int CompareTo(BsonArray rhs) { if (rhs == null) { return 1; } // lhs and rhs might be subclasses of BsonArray using (var lhsEnumerator = GetEnumerator()) using (var rhsEnumerator = rhs.GetEnumerator()) { while (true) { var lhsHasNext = lhsEnumerator.MoveNext(); var rhsHasNext = rhsEnumerator.MoveNext(); if (!lhsHasNext && !rhsHasNext) { return 0; } if (!lhsHasNext) { return -1; } if (!rhsHasNext) { return 1; } var lhsValue = lhsEnumerator.Current; var rhsValue = rhsEnumerator.Current; var result = lhsValue.CompareTo(rhsValue); if (result != 0) { return result; } } } } /// /// Compares the array to another BsonValue. /// /// The other BsonValue. /// A 32-bit signed integer that indicates whether this array is less than, equal to, or greather than the other BsonValue. public override int CompareTo(BsonValue other) { if (other == null) { return 1; } var otherArray = other as BsonArray; if (otherArray != null) { return CompareTo(otherArray); } return CompareTypeTo(other); } /// /// Tests whether the array contains a value. /// /// The value to test for. /// True if the array contains the value. public virtual bool Contains(BsonValue value) { // don't throw ArgumentNullException if value is null // just let _values.Contains return false return _values.Contains(value); } /// /// Copies elements from this array to another array. /// /// The other array. /// The zero based index of the other array at which to start copying. public virtual void CopyTo(BsonValue[] array, int arrayIndex) { for (int i = 0, j = arrayIndex; i < _values.Count; i++, j++) { array[j] = _values[i]; } } /// /// Copies elements from this array to another array as raw values (see BsonValue.RawValue). /// /// The other array. /// The zero based index of the other array at which to start copying. [Obsolete("Use ToArray or ToList instead.")] public virtual void CopyTo(object[] array, int arrayIndex) { for (int i = 0, j = arrayIndex; i < _values.Count; i++, j++) { array[j] = _values[i].RawValue; } } /// /// Creates a deep clone of the array (see also Clone). /// /// A deep clone of the array. public override BsonValue DeepClone() { var clone = new BsonArray(_values.Capacity); foreach (var value in _values) { clone.Add(value.DeepClone()); } return clone; } /// /// Compares this array to another array. /// /// The other array. /// True if the two arrays are equal. public bool Equals(BsonArray obj) { return Equals((object)obj); // handles obj == null correctly } /// /// Compares this BsonArray to another object. /// /// The other object. /// True if the other object is a BsonArray and equal to this one. public override bool Equals(object obj) { if (object.ReferenceEquals(obj, null) || !(obj is BsonArray)) { return false; } // lhs and rhs might be subclasses of BsonArray var rhs = (BsonArray)obj; return Values.SequenceEqual(rhs.Values); } /// /// Gets an enumerator that can enumerate the elements of the array. /// /// An enumerator. public virtual IEnumerator GetEnumerator() { return _values.GetEnumerator(); } /// /// Gets the hash code. /// /// The hash code. public override int GetHashCode() { return new Hasher() .Hash(BsonType) .HashElements(Values) .GetHashCode(); } /// /// Gets the index of a value in the array. /// /// The value to search for. /// The zero based index of the value (or -1 if not found). public virtual int IndexOf(BsonValue value) { if (value == null) { throw new ArgumentNullException("value"); } return _values.IndexOf(value); } /// /// Gets the index of a value in the array. /// /// The value to search for. /// The zero based index at which to start the search. /// The zero based index of the value (or -1 if not found). public virtual int IndexOf(BsonValue value, int index) { if (value == null) { throw new ArgumentNullException("value"); } return _values.IndexOf(value, index); } /// /// Gets the index of a value in the array. /// /// The value to search for. /// The zero based index at which to start the search. /// The number of elements to search. /// The zero based index of the value (or -1 if not found). public virtual int IndexOf(BsonValue value, int index, int count) { if (value == null) { throw new ArgumentNullException("value"); } return _values.IndexOf(value, index, count); } /// /// Inserts a new value into the array. /// /// The zero based index at which to insert the new value. /// The new value. public virtual void Insert(int index, BsonValue value) { if (value == null) { throw new ArgumentNullException("value"); } _values.Insert(index, value); } /// /// Removes the first occurrence of a value from the array. /// /// The value to remove. /// True if the value was removed. public virtual bool Remove(BsonValue value) { if (value == null) { throw new ArgumentNullException("value"); } return _values.Remove(value); } /// /// Removes an element from the array. /// /// The zero based index of the element to remove. public virtual void RemoveAt(int index) { _values.RemoveAt(index); } /// /// Converts the BsonArray to an array of BsonValues. /// /// An array of BsonValues. public virtual BsonValue[] ToArray() { return _values.ToArray(); } /// /// Converts the BsonArray to a list of BsonValues. /// /// A list of BsonValues. public virtual List ToList() { return _values.ToList(); } /// /// Returns a string representation of the array. /// /// A string representation of the array. public override string ToString() { var sb = new StringBuilder(); sb.Append("["); for (int i = 0; i < _values.Count; i++) { if (i > 0) { sb.Append(", "); } sb.Append(_values[i].ToString()); } sb.Append("]"); return sb.ToString(); } /// /// Writes the array to a BsonWriter. /// /// The writer. [Obsolete("Use BsonSerializer.Serialize instead.")] public new void WriteTo(BsonWriter bsonWriter) { BsonSerializer.Serialize(bsonWriter, this); } // explicit interface implementations // our version of Add returns BsonArray void ICollection.Add(BsonValue value) { Add(value); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }