/* 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();
}
}
}