File: ItemCollection.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (515 lines) | stat: -rw-r--r-- 25,343 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
//---------------------------------------------------------------------
// <copyright file="ItemCollection.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// @owner       Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------

namespace System.Data.Metadata.Edm
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data.Common.Utils;
    using System.Diagnostics;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Threading;

    /// <summary>
    /// Class for representing a collection of items.
    /// Most of the implemetation for actual maintainance of the collection is
    /// done by MetadataCollection
    /// </summary>
    [CLSCompliant(false)]
    public abstract class ItemCollection : ReadOnlyMetadataCollection<GlobalItem>
    {
        #region Constructors
        /// <summary>
        /// The default constructor for ItemCollection
        /// </summary>
        internal ItemCollection(DataSpace dataspace)
            : base(new MetadataCollection<GlobalItem>())
        {
            _space = dataspace;
        }
        #endregion

        #region Fields
        private readonly DataSpace _space;
        private Dictionary<string, System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction>> _functionLookUpTable;
        private Memoizer<Type, ICollection> _itemsCache;
        private int _itemCount;
        #endregion

        #region Properties
        /// <summary>
        /// Dataspace associated with ItemCollection
        /// </summary>
        public DataSpace DataSpace
        {
            get
            {
                return this._space;
            }
        }

        /// <summary>
        /// Return the function lookUpTable
        /// </summary>
        internal Dictionary<string, System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction>> FunctionLookUpTable
        {
            get
            {
                if (_functionLookUpTable == null)
                {
                    Dictionary<string, System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction>> functionLookUpTable = PopulateFunctionLookUpTable(this);
                    Interlocked.CompareExchange(ref _functionLookUpTable, functionLookUpTable, null);
                }

                return _functionLookUpTable;
            }
        }

        #endregion

        #region Methods
        /// <summary>
        /// Adds an item to the collection 
        /// </summary>
        /// <param name="item">The item to add to the list</param>
        /// <exception cref="System.ArgumentNullException">Thrown if item argument is null</exception>
        /// <exception cref="System.InvalidOperationException">Thrown if the item passed in or the collection itself instance is in ReadOnly state</exception>
        /// <exception cref="System.ArgumentException">Thrown if the item that is being added already belongs to another ItemCollection</exception>
        /// <exception cref="System.ArgumentException">Thrown if the ItemCollection already contains an item with the same identity</exception>
        internal void AddInternal(GlobalItem item)
        {
            Debug.Assert(item.IsReadOnly, "The item is not readonly, it should be by the time it is added to the item collection");
            Debug.Assert(item.DataSpace == this.DataSpace);
            base.Source.Add(item);
        }

        /// <summary>
        /// Adds a collection of items to the collection 
        /// </summary>
        /// <param name="items">The items to add to the list</param>
        /// <exception cref="System.ArgumentNullException">Thrown if item argument is null</exception>
        /// <exception cref="System.InvalidOperationException">Thrown if the item passed in or the collection itself instance is in ReadOnly state</exception>
        /// <exception cref="System.ArgumentException">Thrown if the item that is being added already belongs to another ItemCollection</exception>
        /// <exception cref="System.ArgumentException">Thrown if the ItemCollection already contains an item with the same identity</exception>
        internal bool AtomicAddRange(List<GlobalItem> items)
        {
#if DEBUG
            // We failed to add, so undo the setting of the ItemCollection reference
            foreach (GlobalItem item in items)
            {
                Debug.Assert(item.IsReadOnly, "The item is not readonly, it should be by the time it is added to the item collection");
                Debug.Assert(item.DataSpace == this.DataSpace);
            }

#endif
            if (base.Source.AtomicAddRange(items))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Returns strongly typed MetadataItem from the collection that has
        /// the passed in identity.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="identity">Identity of the item to look up for</param>
        /// <returns>returns the item if a match is found, otherwise throwns an exception</returns>
        /// <exception cref="System.ArgumentNullException">Thrown if identity argument passed in is null</exception>
        /// <exception cref="System.ArgumentException">Thrown if the Collection does not have an item with the given identity</exception>
        public T GetItem<T>(string identity) where T : GlobalItem
        {
            return this.GetItem<T>(identity, false /*ignoreCase*/);
        }

        /// <summary>
        /// Returns strongly typed MetadataItem from the collection that has
        /// the passed in identity.
        /// Returns null if the item is not found.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="identity"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentNullException">if identity argument is null</exception>
        public bool TryGetItem<T>(string identity, out T item) where T : GlobalItem
        {
            return this.TryGetItem<T>(identity, false /*ignorecase*/, out item);
        }

        /// <summary>
        /// Returns strongly typed MetadataItem from the collection that has
        /// the passed in identity.
        /// Returns null if the item is not found.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="identity">identity of the type to look up for</param>
        /// <param name="ignoreCase">true for case-insensitive lookup</param>
        /// <param name="item">item with the given identity if a match is found, otherwise returns null</param>
        /// <returns>returns true if a match is found, otherwise returns false</returns>
        /// <exception cref="System.ArgumentNullException">if identity argument is null</exception>
        public bool TryGetItem<T>(string identity, bool ignoreCase, out T item) where T : GlobalItem
        {
            GlobalItem outItem = null;
            TryGetValue(identity, ignoreCase, out outItem);
            item = outItem as T;
            return item != null;
        }

        /// <summary>
        /// Returns strongly typed MetadataItem from the collection that has
        /// the passed in identity with either case sensitive or case insensitive search
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="identity">identity of the type to look up for</param>
        /// <param name="ignoreCase">true for case-insensitive lookup</param>
        /// <returns>returns item if a match is found, otherwise returns throws an argument exception</returns>
        /// <exception cref="System.ArgumentNullException">Thrown if identity argument passed in is null</exception>
        /// <exception cref="System.ArgumentException">Thrown if no item is found with the given identity</exception>
        public T GetItem<T>(string identity, bool ignoreCase) where T : GlobalItem
        {
            T item;
            if (TryGetItem<T>(identity, ignoreCase, out item))
            {
                return item;
            }
            throw EntityUtil.ItemInvalidIdentity(identity, "identity");
        }

        /// <summary>
        /// Returns ReadOnlyCollection of the Items of the given type 
        /// in the item collection.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public virtual System.Collections.ObjectModel.ReadOnlyCollection<T> GetItems<T>() where T : GlobalItem
        {
            Memoizer<Type, ICollection> currentValueForItemCache = _itemsCache;
            // initialize the memoizer, update the _itemCache and _itemCount
            if (_itemsCache == null || this._itemCount != this.Count)
            {
                Memoizer<Type, ICollection> itemsCache =
                               new Memoizer<Type, ICollection>(InternalGetItems, null);
                Interlocked.CompareExchange(ref _itemsCache, itemsCache, currentValueForItemCache);
                
                this._itemCount = this.Count;
            }

            Debug.Assert(_itemsCache != null, "check the initialization of the Memoizer");

            // use memoizer so that it won't create a new list every time this method get called
            ICollection items = this._itemsCache.Evaluate(typeof(T));
            System.Collections.ObjectModel.ReadOnlyCollection<T> returnItems = items as System.Collections.ObjectModel.ReadOnlyCollection<T>;

            return returnItems;
        }

        [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
        internal ICollection InternalGetItems(Type type)
        {
            MethodInfo mi = typeof(ItemCollection).GetMethod("GenericGetItems", BindingFlags.NonPublic | BindingFlags.Static);
            MethodInfo genericMi = mi.MakeGenericMethod(type);

            return genericMi.Invoke(null, new object[] { this }) as ICollection;
        }

        private static System.Collections.ObjectModel.ReadOnlyCollection<TItem> GenericGetItems<TItem>(ItemCollection collection) where TItem : GlobalItem
        {
            List<TItem> list = new List<TItem>();
            foreach (GlobalItem item in collection)
            {
                TItem stronglyTypedItem = item as TItem;
                if (stronglyTypedItem != null)
                {
                    list.Add(stronglyTypedItem);
                }
            }
            return list.AsReadOnly();
        }


        /// <summary>
        /// Search for a type metadata with the specified name and namespace name in the given space.
        /// </summary>
        /// <param name="name">name of the type</param>
        /// <param name="namespaceName">namespace of the type</param>
        /// <returns>Returns null if no match found.</returns>
        /// <exception cref="System.ArgumentNullException">Thrown if name or namespaceName arguments passed in are null</exception>
        /// <exception cref="System.ArgumentException">Thrown if the ItemCollection for this space does not have a type with the given name and namespaceName</exception>
        public EdmType GetType(string name, string namespaceName)
        {
            return this.GetType(name, namespaceName, false /*ignoreCase*/);
        }

        /// <summary>
        /// Search for a type metadata with the specified name and namespace name in the given space.
        /// </summary>
        /// <param name="name">name of the type</param>
        /// <param name="namespaceName">namespace of the type</param>
        /// <param name="type">The type that needs to be filled with the return value</param>
        /// <returns>Returns null if no match found.</returns>
        /// <exception cref="System.ArgumentNullException">if name or namespaceName argument is null</exception>
        public bool TryGetType(string name, string namespaceName, out EdmType type)
        {
            return this.TryGetType(name, namespaceName, false /*ignoreCase*/, out type);
        }

        /// <summary>
        /// Search for a type metadata with the specified key.
        /// </summary>
        /// <param name="name">name of the type</param>
        /// <param name="namespaceName">namespace of the type</param>
        /// <param name="ignoreCase">true for case-insensitive lookup</param>
        /// <returns>Returns null if no match found.</returns>
        /// <exception cref="System.ArgumentNullException">Thrown if name or namespaceName arguments passed in are null</exception>
        public EdmType GetType(string name, string namespaceName, bool ignoreCase)
        {
            EntityUtil.GenericCheckArgumentNull(name, "name");
            EntityUtil.GenericCheckArgumentNull(namespaceName, "namespaceName");
            return GetItem<EdmType>(EdmType.CreateEdmTypeIdentity(namespaceName, name), ignoreCase);
        }

        /// <summary>
        /// Search for a type metadata with the specified name and namespace name in the given space.
        /// </summary>
        /// <param name="name">name of the type</param>
        /// <param name="namespaceName">namespace of the type</param>
        /// <param name="ignoreCase">true for case-insensitive lookup</param>
        /// <param name="type">The type that needs to be filled with the return value</param>
        /// <returns>Returns null if no match found.</returns>
        /// <exception cref="System.ArgumentNullException">if name or namespaceName argument is null</exception>
        public bool TryGetType(string name, string namespaceName, bool ignoreCase, out EdmType type)
        {
            EntityUtil.GenericCheckArgumentNull(name, "name");
            EntityUtil.GenericCheckArgumentNull(namespaceName, "namespaceName");
            GlobalItem item = null;
            TryGetValue(EdmType.CreateEdmTypeIdentity(namespaceName, name), ignoreCase, out item);
            type = item as EdmType;
            return type != null;
        }

        /// <summary>
        /// Get all the overloads of the function with the given name
        /// </summary>
        /// <param name="functionName">The full name of the function</param>
        /// <returns>A collection of all the functions with the given name in the given data space</returns>
        /// <exception cref="System.ArgumentNullException">Thrown if functionaName argument passed in is null</exception>
        public System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction> GetFunctions(string functionName)
        {
            return this.GetFunctions(functionName, false /*ignoreCase*/);
        }

        /// <summary>
        /// Get all the overloads of the function with the given name
        /// </summary>
        /// <param name="functionName">The full name of the function</param>
        /// <param name="ignoreCase">true for case-insensitive lookup</param>
        /// <returns>A collection of all the functions with the given name in the given data space</returns>
        /// <exception cref="System.ArgumentNullException">Thrown if functionaName argument passed in is null</exception>
        public System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction> GetFunctions(string functionName, bool ignoreCase)
        {
            return GetFunctions(this.FunctionLookUpTable, functionName, ignoreCase);
        }

        /// <summary>
        /// Look for the functions in the given collection and 
        /// returns all the functions with the given name
        /// </summary>
        /// <param name="functionCollection"></param>
        /// <param name="functionName"></param>
        /// <param name="ignoreCase"></param>
        /// <returns></returns>
        protected static System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction> GetFunctions(
            Dictionary<string, System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction>> functionCollection,
            string functionName, bool ignoreCase)
        {
            System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction> functionOverloads;

            if (functionCollection.TryGetValue(functionName, out functionOverloads))
            {
                if (ignoreCase)
                {
                    return functionOverloads;
                }

                return GetCaseSensitiveFunctions(functionOverloads, functionName);
            }

            return Helper.EmptyEdmFunctionReadOnlyCollection;
        }

        internal static System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction> GetCaseSensitiveFunctions(
            System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction> functionOverloads,
            string functionName)
        {
            // For case-sensitive match, first check if there are anything with a different case
            // its very rare to have functions with different case. So optimizing the case where all
            // functions are of same case
            // Else create a new list with the functions with the exact name
            List<EdmFunction> caseSensitiveFunctionOverloads = new List<EdmFunction>(functionOverloads.Count);

            for (int i = 0; i < functionOverloads.Count; i++)
            {
                if (functionOverloads[i].FullName == functionName)
                {
                    caseSensitiveFunctionOverloads.Add(functionOverloads[i]);
                }
            }

            // If there are no functions with different case, just return the collection
            if (caseSensitiveFunctionOverloads.Count != functionOverloads.Count)
            {
                functionOverloads = caseSensitiveFunctionOverloads.AsReadOnly();
            }
            return functionOverloads;
        }

        /// <summary>
        /// Gets the function as specified by the function key.
        /// All parameters are assumed to be <see cref="ParameterMode.In"/>.
        /// </summary>
        /// <param name="functionName">Name of the function</param>
        /// <param name="parameterTypes">types of the parameters</param>
        /// <param name="ignoreCase">true for case-insensitive lookup</param>
        /// <param name="function">The function that needs to be returned</param>
        /// <returns> The function as specified in the function key or null</returns>
        /// <exception cref="System.ArgumentNullException">if functionName or parameterTypes argument is null</exception>
        /// <exception cref="System.ArgumentException">if no function is found with the given name or with given input parameters</exception>
        internal bool TryGetFunction(string functionName, TypeUsage[] parameterTypes, bool ignoreCase, out EdmFunction function)
        {
            EntityUtil.GenericCheckArgumentNull(functionName, "functionName");
            EntityUtil.GenericCheckArgumentNull(parameterTypes, "parameterTypes");
            string functionIdentity = EdmFunction.BuildIdentity(functionName, parameterTypes);
            GlobalItem item = null;
            function = null;
            if (TryGetValue(functionIdentity, ignoreCase, out item) && Helper.IsEdmFunction(item))
            {
                function = (EdmFunction)item;
                return true;
            }
            return false;
        }

        /// <summary>
        /// Get an entity container based upon the strong name of the container
        /// If no entity container is found, returns null, else returns the first one/// </summary>
        /// <param name="name">name of the entity container</param>
        /// <returns>The EntityContainer</returns>
        /// <exception cref="System.ArgumentNullException">Thrown if name argument passed in is null</exception>
        public EntityContainer GetEntityContainer(string name)
        {
            EntityUtil.GenericCheckArgumentNull(name, "name");
            return this.GetEntityContainer(name, false /*ignoreCase*/);
        }

        /// <summary>
        /// Get an entity container based upon the strong name of the container
        /// If no entity container is found, returns null, else returns the first one/// </summary>
        /// <param name="name">name of the entity container</param>
        /// <param name="entityContainer"></param>
        /// <exception cref="System.ArgumentNullException">if name argument is null</exception>
        public bool TryGetEntityContainer(string name, out EntityContainer entityContainer)
        {
            EntityUtil.GenericCheckArgumentNull(name, "name");
            return this.TryGetEntityContainer(name, false /*ignoreCase*/, out entityContainer);
        }

        /// <summary>
        /// Get an entity container based upon the strong name of the container
        /// If no entity container is found, returns null, else returns the first one/// </summary>
        /// <param name="name">name of the entity container</param>
        /// <param name="ignoreCase">true for case-insensitive lookup</param>
        /// <returns>The EntityContainer</returns>
        /// <exception cref="System.ArgumentNullException">Thrown if name argument passed in is null</exception>
        /// <exception cref="System.ArgumentException">Thrown if no entity container with the given name is found</exception>
        public EntityContainer GetEntityContainer(string name, bool ignoreCase)
        {
            EntityContainer container = GetValue(name, ignoreCase) as EntityContainer;
            if (null != container)
            {
                return container;
            }
            throw EntityUtil.ItemInvalidIdentity(name, "name");
        }

        /// <summary>
        /// Get an entity container based upon the strong name of the container
        /// If no entity container is found, returns null, else returns the first one/// </summary>
        /// <param name="name">name of the entity container</param>
        /// <param name="ignoreCase">true for case-insensitive lookup</param>
        /// <param name="entityContainer"></param>
        /// <exception cref="System.ArgumentNullException">if name argument is null</exception>
        public bool TryGetEntityContainer(string name, bool ignoreCase, out EntityContainer entityContainer)
        {
            EntityUtil.GenericCheckArgumentNull(name, "name");
            GlobalItem item = null;
            if (TryGetValue(name, ignoreCase, out item) && Helper.IsEntityContainer(item))
            {
                entityContainer = (EntityContainer)item;
                return true;
            }
            entityContainer = null;
            return false;
        }

        /// <summary>
        /// Given the canonical primitive type, get the mapping primitive type in the given dataspace
        /// </summary>
        /// <param name="primitiveTypeKind">canonical primitive type</param>
        /// <returns>The mapped scalar type</returns>
        internal virtual PrimitiveType GetMappedPrimitiveType(PrimitiveTypeKind primitiveTypeKind)
        {
            //The method needs to be overloaded on methods that support this
            throw System.Data.Entity.Error.NotSupported();
        }

        /// <summary>
        /// Determines whether this item collection is equivalent to another. At present, we look only
        /// at object reference equivalence. This is a somewhat reasonable approximation when caching
        /// is enabled, because collections are identical when their source resources (including 
        /// provider) are known to be identical.
        /// </summary>
        /// <param name="other">Collection to compare.</param>
        /// <returns>true if the collections are equivalent; false otherwise</returns>
        internal virtual bool MetadataEquals(ItemCollection other)
        {
            return Object.ReferenceEquals(this, other);
        }

        static private Dictionary<string, System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction>> PopulateFunctionLookUpTable(ItemCollection itemCollection)
        {
            var tempFunctionLookUpTable = new Dictionary<string, List<EdmFunction>>(StringComparer.OrdinalIgnoreCase);

            foreach (EdmFunction function in itemCollection.GetItems<EdmFunction>())
            {
                List<EdmFunction> functionList;
                if (!tempFunctionLookUpTable.TryGetValue(function.FullName, out functionList))
                {
                    functionList = new List<EdmFunction>();
                    tempFunctionLookUpTable[function.FullName] = functionList;
                }
                functionList.Add(function);
            }

            var functionLookUpTable = new Dictionary<string, System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction>>(StringComparer.OrdinalIgnoreCase);
            foreach (List<EdmFunction> functionList in tempFunctionLookUpTable.Values)
            {
                functionLookUpTable.Add(functionList[0].FullName, new System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction>(functionList.ToArray()));
            }

            return functionLookUpTable;
        }

        #endregion
    }//---- ItemCollection
}//----