Statistics
| Branch: | Revision:

root / trunk / Pithos.Core / Agents / CollectionExtensions.cs @ 8f44fd3a

History | View | Annotate | Download (11 kB)

1 255f5f86 Panagiotis Kanavos
#region
2 255f5f86 Panagiotis Kanavos
/* -----------------------------------------------------------------------
3 255f5f86 Panagiotis Kanavos
 * <copyright file="CollectionExtensions.cs" company="GRNet">
4 255f5f86 Panagiotis Kanavos
 * 
5 255f5f86 Panagiotis Kanavos
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6 255f5f86 Panagiotis Kanavos
 *
7 255f5f86 Panagiotis Kanavos
 * Redistribution and use in source and binary forms, with or
8 255f5f86 Panagiotis Kanavos
 * without modification, are permitted provided that the following
9 255f5f86 Panagiotis Kanavos
 * conditions are met:
10 255f5f86 Panagiotis Kanavos
 *
11 255f5f86 Panagiotis Kanavos
 *   1. Redistributions of source code must retain the above
12 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
13 255f5f86 Panagiotis Kanavos
 *      disclaimer.
14 255f5f86 Panagiotis Kanavos
 *
15 255f5f86 Panagiotis Kanavos
 *   2. Redistributions in binary form must reproduce the above
16 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
17 255f5f86 Panagiotis Kanavos
 *      disclaimer in the documentation and/or other materials
18 255f5f86 Panagiotis Kanavos
 *      provided with the distribution.
19 255f5f86 Panagiotis Kanavos
 *
20 255f5f86 Panagiotis Kanavos
 *
21 255f5f86 Panagiotis Kanavos
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22 255f5f86 Panagiotis Kanavos
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 255f5f86 Panagiotis Kanavos
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 255f5f86 Panagiotis Kanavos
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25 255f5f86 Panagiotis Kanavos
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 255f5f86 Panagiotis Kanavos
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 255f5f86 Panagiotis Kanavos
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 255f5f86 Panagiotis Kanavos
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 255f5f86 Panagiotis Kanavos
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 255f5f86 Panagiotis Kanavos
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 255f5f86 Panagiotis Kanavos
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 255f5f86 Panagiotis Kanavos
 * POSSIBILITY OF SUCH DAMAGE.
33 255f5f86 Panagiotis Kanavos
 *
34 255f5f86 Panagiotis Kanavos
 * The views and conclusions contained in the software and
35 255f5f86 Panagiotis Kanavos
 * documentation are those of the authors and should not be
36 255f5f86 Panagiotis Kanavos
 * interpreted as representing official policies, either expressed
37 255f5f86 Panagiotis Kanavos
 * or implied, of GRNET S.A.
38 255f5f86 Panagiotis Kanavos
 * </copyright>
39 255f5f86 Panagiotis Kanavos
 * -----------------------------------------------------------------------
40 255f5f86 Panagiotis Kanavos
 */
41 255f5f86 Panagiotis Kanavos
#endregion
42 b9f5b594 Panagiotis Kanavos
using System.Collections.Concurrent;
43 fec5da06 Panagiotis Kanavos
using System.Diagnostics.Contracts;
44 759bd3c4 Panagiotis Kanavos
using Pithos.Interfaces;
45 d78d765c pkanavos
using System;
46 d78d765c pkanavos
using System.Collections.Generic;
47 d78d765c pkanavos
using System.Linq;
48 b9f5b594 Panagiotis Kanavos
49 b9f5b594 Panagiotis Kanavos
namespace Pithos.Core.Agents
50 b9f5b594 Panagiotis Kanavos
{
51 b9f5b594 Panagiotis Kanavos
52 b9f5b594 Panagiotis Kanavos
    /// <summary>
53 b9f5b594 Panagiotis Kanavos
    /// Extension methods for collections
54 b9f5b594 Panagiotis Kanavos
    /// </summary>
55 b9f5b594 Panagiotis Kanavos
    public static class CollectionExtensions
56 b9f5b594 Panagiotis Kanavos
    {
57 92f18b56 Panagiotis Kanavos
        public static IEnumerable<T> Replace<T>(this IEnumerable<T> list,Func<T,bool> match, Func<T,IEnumerable<T>> generate)
58 99e6329f Panagiotis Kanavos
        {
59 99e6329f Panagiotis Kanavos
            foreach (var item in list)
60 99e6329f Panagiotis Kanavos
            {
61 99e6329f Panagiotis Kanavos
                if (match(item))
62 92f18b56 Panagiotis Kanavos
                    foreach (var newItem in generate(item))
63 99e6329f Panagiotis Kanavos
                    {
64 99e6329f Panagiotis Kanavos
                        yield return newItem;
65 99e6329f Panagiotis Kanavos
                    }
66 99e6329f Panagiotis Kanavos
                else
67 99e6329f Panagiotis Kanavos
                    yield return item;
68 99e6329f Panagiotis Kanavos
            }
69 99e6329f Panagiotis Kanavos
        }
70 99e6329f Panagiotis Kanavos
71 99e6329f Panagiotis Kanavos
72 b9f5b594 Panagiotis Kanavos
        /// <summary>
73 b9f5b594 Panagiotis Kanavos
        /// Remove the first message in a queue that matches the predicate
74 b9f5b594 Panagiotis Kanavos
        /// </summary>
75 d78d765c pkanavos
        /// <param name="queue">The queue</param>
76 b9f5b594 Panagiotis Kanavos
        /// <param name="predicate">The condition to match</param>
77 b9f5b594 Panagiotis Kanavos
        /// <remarks>Removes the first message that matches the predicate by dequeing all 
78 b9f5b594 Panagiotis Kanavos
        /// messages and re-enqueing all except the first matching message</remarks>
79 b9f5b594 Panagiotis Kanavos
        public static void RemoveFirst<TMessage>(this ConcurrentQueue<TMessage> queue, Func<TMessage, bool> predicate)
80 b9f5b594 Panagiotis Kanavos
        {
81 b9f5b594 Panagiotis Kanavos
            //Can this work? Dequeue all items 
82 b9f5b594 Panagiotis Kanavos
            //and then enqueue everything except the filtered items
83 b9f5b594 Panagiotis Kanavos
84 b9f5b594 Panagiotis Kanavos
            //Possible problems: 
85 b9f5b594 Panagiotis Kanavos
            //* A matching item may be dequeued between one TryDequeue and the next
86 b9f5b594 Panagiotis Kanavos
            var temp = new Queue<TMessage>();
87 b9f5b594 Panagiotis Kanavos
            TMessage message;
88 b9f5b594 Panagiotis Kanavos
            var alreadyFound = false;
89 b9f5b594 Panagiotis Kanavos
            while (queue.TryDequeue(out message))
90 b9f5b594 Panagiotis Kanavos
            {
91 b9f5b594 Panagiotis Kanavos
                if (!predicate(message) || alreadyFound)
92 b9f5b594 Panagiotis Kanavos
                    temp.Enqueue(message);
93 b9f5b594 Panagiotis Kanavos
                else
94 b9f5b594 Panagiotis Kanavos
                {
95 b9f5b594 Panagiotis Kanavos
                    alreadyFound = true;
96 b9f5b594 Panagiotis Kanavos
                }
97 b9f5b594 Panagiotis Kanavos
            }
98 b9f5b594 Panagiotis Kanavos
99 b9f5b594 Panagiotis Kanavos
            queue.AddFromEnumerable(temp);
100 b9f5b594 Panagiotis Kanavos
        }
101 759bd3c4 Panagiotis Kanavos
102 759bd3c4 Panagiotis Kanavos
103 99e6329f Panagiotis Kanavos
        /// <summary>
104 99e6329f Panagiotis Kanavos
        /// Return only the info objects that are below one of the filter Uris
105 99e6329f Panagiotis Kanavos
        /// </summary>
106 99e6329f Panagiotis Kanavos
        /// <param name="infos">ObjectInfo items to filter</param>
107 99e6329f Panagiotis Kanavos
        /// <param name="filterUris">List of filter Uris</param>
108 99e6329f Panagiotis Kanavos
        /// <returns>An enumerable of ObjectInfo items. If the list of filter Uris is empty or null, the original list is returned</returns>
109 759bd3c4 Panagiotis Kanavos
        public static IEnumerable<ObjectInfo> FilterBelow(this IEnumerable<ObjectInfo> infos,List<Uri> filterUris  )
110 759bd3c4 Panagiotis Kanavos
        {
111 759bd3c4 Panagiotis Kanavos
            if (filterUris == null)
112 759bd3c4 Panagiotis Kanavos
                return infos;
113 759bd3c4 Panagiotis Kanavos
            if (filterUris.Count == 0)
114 759bd3c4 Panagiotis Kanavos
                return infos;
115 fec5da06 Panagiotis Kanavos
            //Allow all objects whose Uris start with any of the filters            
116 759bd3c4 Panagiotis Kanavos
            var filteredUris = from info in infos
117 fec5da06 Panagiotis Kanavos
                                  where filterUris.Any(f => info.Uri.IsAtOrBelow(f)) 
118 fec5da06 Panagiotis Kanavos
                                  select info;            
119 759bd3c4 Panagiotis Kanavos
            return filteredUris;
120 759bd3c4 Panagiotis Kanavos
        }
121 fec5da06 Panagiotis Kanavos
122 99e6329f Panagiotis Kanavos
        /// <summary>
123 99e6329f Panagiotis Kanavos
        /// Return only the info objects that are directly below one of the filter Uris
124 99e6329f Panagiotis Kanavos
        /// </summary>
125 99e6329f Panagiotis Kanavos
        /// <param name="infos">ObjectInfo items to filter</param>
126 99e6329f Panagiotis Kanavos
        /// <param name="filterUris">List of filter Uris</param>
127 99e6329f Panagiotis Kanavos
        /// <returns>An enumerable of ObjectInfo items. If the list of filter Uris is empty or null, the original list is returned</returns>
128 99e6329f Panagiotis Kanavos
        public static IEnumerable<ObjectInfo> FilterDirectlyBelow(this IEnumerable<ObjectInfo> infos, List<Uri> filterUris)
129 fec5da06 Panagiotis Kanavos
        {
130 fec5da06 Panagiotis Kanavos
            if (filterUris == null)
131 fec5da06 Panagiotis Kanavos
                return infos;
132 fec5da06 Panagiotis Kanavos
            if (filterUris.Count == 0)
133 fec5da06 Panagiotis Kanavos
                return infos;
134 fec5da06 Panagiotis Kanavos
            //Allow all objects whose Uris start with any of the filters            
135 fec5da06 Panagiotis Kanavos
            var filteredUris = from info in infos
136 fec5da06 Panagiotis Kanavos
                                  where filterUris.Any(f => info.Uri.IsAtOrDirectlyBelow(f)) 
137 fec5da06 Panagiotis Kanavos
                                  select info;            
138 fec5da06 Panagiotis Kanavos
            return filteredUris;
139 fec5da06 Panagiotis Kanavos
        }
140 fec5da06 Panagiotis Kanavos
141 99e6329f Panagiotis Kanavos
        /// <summary>
142 99e6329f Panagiotis Kanavos
        /// Checkes whether a Uri is below a root Uri
143 99e6329f Panagiotis Kanavos
        /// </summary>
144 99e6329f Panagiotis Kanavos
        /// <param name="target"></param>
145 99e6329f Panagiotis Kanavos
        /// <param name="root"></param>
146 99e6329f Panagiotis Kanavos
        /// <returns></returns>
147 fec5da06 Panagiotis Kanavos
        public static bool IsAtOrBelow(this Uri target,Uri root)
148 fec5da06 Panagiotis Kanavos
        {
149 d78d765c pkanavos
            if(root == null)
150 d78d765c pkanavos
                throw new ArgumentNullException("root");
151 d78d765c pkanavos
            if(target == null)
152 d78d765c pkanavos
                throw new ArgumentNullException("target");
153 d78d765c pkanavos
            Contract.EndContractBlock();
154 fec5da06 Panagiotis Kanavos
155 fec5da06 Panagiotis Kanavos
            var targetSegments = target.Segments;
156 fec5da06 Panagiotis Kanavos
            var rootSegments = root.Segments;
157 fec5da06 Panagiotis Kanavos
158 fec5da06 Panagiotis Kanavos
            return InnerAtOrBelow(targetSegments, rootSegments);
159 fec5da06 Panagiotis Kanavos
        }
160 fec5da06 Panagiotis Kanavos
161 fec5da06 Panagiotis Kanavos
        private static bool InnerAtOrBelow(string[] targetSegments, string[] rootSegments)
162 fec5da06 Panagiotis Kanavos
        {
163 fec5da06 Panagiotis Kanavos
            //If the uri is shorter than the root, no point in comparing
164 fec5da06 Panagiotis Kanavos
            if (targetSegments.Length < rootSegments.Length)
165 fec5da06 Panagiotis Kanavos
                return false;
166 fec5da06 Panagiotis Kanavos
            //If the uri is below the root, it should match the root's segments one by one
167 fec5da06 Panagiotis Kanavos
            //If there is any root segment that doesn't match its corresponding target segment,
168 fec5da06 Panagiotis Kanavos
            //the target is not below the root
169 1a41e9ec pkanavos
            //DON'T FORGET that Uri segments include the slashes. Must remove them to ensure proper checks
170 fec5da06 Panagiotis Kanavos
            var mismatch = rootSegments
171 8f44fd3a pkanavos
                .Where((t, i) => !String.Equals(targetSegments[i].TrimEnd('/'), t.TrimEnd('/'),StringComparison.InvariantCultureIgnoreCase))
172 fec5da06 Panagiotis Kanavos
                .Any();
173 fec5da06 Panagiotis Kanavos
            return !mismatch;
174 fec5da06 Panagiotis Kanavos
        }
175 fec5da06 Panagiotis Kanavos
176 fec5da06 Panagiotis Kanavos
177 99e6329f Panagiotis Kanavos
        /// <summary>
178 99e6329f Panagiotis Kanavos
        /// Checks whether a Uri is directly below a root Uri
179 99e6329f Panagiotis Kanavos
        /// </summary>
180 99e6329f Panagiotis Kanavos
        /// <param name="target"></param>
181 99e6329f Panagiotis Kanavos
        /// <param name="root"></param>
182 99e6329f Panagiotis Kanavos
        /// <returns></returns>
183 fec5da06 Panagiotis Kanavos
        public static bool IsAtOrDirectlyBelow(this Uri target,Uri root)
184 fec5da06 Panagiotis Kanavos
        {
185 d78d765c pkanavos
            if (root==null)
186 d78d765c pkanavos
                throw new ArgumentNullException("root");
187 d78d765c pkanavos
            if (target==null)
188 d78d765c pkanavos
                throw new ArgumentNullException("target");
189 d78d765c pkanavos
            Contract.EndContractBlock();
190 fec5da06 Panagiotis Kanavos
191 1a41e9ec pkanavos
            if (target.Equals(root))
192 1a41e9ec pkanavos
                return true;
193 fec5da06 Panagiotis Kanavos
            return
194 fec5da06 Panagiotis Kanavos
                //If the target is directly below the root, it will have exactly 
195 fec5da06 Panagiotis Kanavos
                //one segment more than the root            
196 fec5da06 Panagiotis Kanavos
                target.Segments.Length == root.Segments.Length + 1
197 fec5da06 Panagiotis Kanavos
                //Ensure that the candidate target is indeed below the root
198 fec5da06 Panagiotis Kanavos
                && target.IsAtOrBelow(root);
199 fec5da06 Panagiotis Kanavos
        }
200 fec5da06 Panagiotis Kanavos
201 99e6329f Panagiotis Kanavos
        /// <summary>
202 99e6329f Panagiotis Kanavos
        /// Checkes whether a file path is below a root path
203 99e6329f Panagiotis Kanavos
        /// </summary>
204 99e6329f Panagiotis Kanavos
        /// <param name="targetPath"></param>
205 99e6329f Panagiotis Kanavos
        /// <param name="rootPath"></param>
206 99e6329f Panagiotis Kanavos
        /// <returns></returns>
207 fec5da06 Panagiotis Kanavos
        public static bool IsAtOrBelow(this string targetPath, string rootPath)
208 fec5da06 Panagiotis Kanavos
        {
209 d78d765c pkanavos
            if(String.IsNullOrWhiteSpace(targetPath))
210 d78d765c pkanavos
                throw new ArgumentNullException("targetPath");
211 d78d765c pkanavos
            if(String.IsNullOrWhiteSpace(rootPath))
212 d78d765c pkanavos
                throw new ArgumentNullException("rootPath");
213 d78d765c pkanavos
            Contract.EndContractBlock();
214 fec5da06 Panagiotis Kanavos
215 fec5da06 Panagiotis Kanavos
            var targetSegments = targetPath.Split('\\');
216 fec5da06 Panagiotis Kanavos
            var rootSegments = rootPath.Split('\\');
217 fec5da06 Panagiotis Kanavos
218 fec5da06 Panagiotis Kanavos
            return InnerAtOrBelow(targetSegments, rootSegments);
219 fec5da06 Panagiotis Kanavos
        }
220 fec5da06 Panagiotis Kanavos
221 99e6329f Panagiotis Kanavos
        /// <summary>
222 99e6329f Panagiotis Kanavos
        /// Checks whether a file path is directly below a root path
223 99e6329f Panagiotis Kanavos
        /// </summary>
224 99e6329f Panagiotis Kanavos
        /// <param name="targetPath"></param>
225 99e6329f Panagiotis Kanavos
        /// <param name="rootPath"></param>
226 99e6329f Panagiotis Kanavos
        /// <returns></returns>
227 fec5da06 Panagiotis Kanavos
        public static bool IsAtOrDirectlyBelow(this string targetPath, string rootPath)
228 fec5da06 Panagiotis Kanavos
        {
229 d78d765c pkanavos
            if (String.IsNullOrWhiteSpace(targetPath))
230 d78d765c pkanavos
                throw new ArgumentNullException("targetPath");
231 d78d765c pkanavos
            if (String.IsNullOrWhiteSpace(rootPath))
232 d78d765c pkanavos
                throw new ArgumentNullException("rootPath");
233 d78d765c pkanavos
            Contract.EndContractBlock();
234 d78d765c pkanavos
235 1a41e9ec pkanavos
            if (targetPath==rootPath)
236 1a41e9ec pkanavos
                return true;
237 fec5da06 Panagiotis Kanavos
            var targetSegments = targetPath.Split('\\');
238 fec5da06 Panagiotis Kanavos
            var rootSegments = rootPath.Split('\\');
239 fec5da06 Panagiotis Kanavos
240 fec5da06 Panagiotis Kanavos
            return
241 fec5da06 Panagiotis Kanavos
                //If the target is directly below the root, it will have exactly 
242 fec5da06 Panagiotis Kanavos
                //one segment more than the root            
243 fec5da06 Panagiotis Kanavos
                targetSegments.Length == rootSegments.Length + 1
244 fec5da06 Panagiotis Kanavos
                //Ensure that the candidate target is indeed below the root
245 fec5da06 Panagiotis Kanavos
                && InnerAtOrBelow(targetSegments, rootSegments);
246 fec5da06 Panagiotis Kanavos
        }
247 62d5b25f Panagiotis Kanavos
248 62d5b25f Panagiotis Kanavos
        /// <summary>
249 62d5b25f Panagiotis Kanavos
        /// Returns the part of the target string that comes after the prefix string.
250 62d5b25f Panagiotis Kanavos
        /// The target is not modified if it doesn't start with the prefix string
251 62d5b25f Panagiotis Kanavos
        /// </summary>
252 62d5b25f Panagiotis Kanavos
        /// <param name="target"></param>
253 d78d765c pkanavos
        /// <param name="prefix"></param>
254 62d5b25f Panagiotis Kanavos
        /// <returns></returns>
255 62d5b25f Panagiotis Kanavos
        public static string After(this string target,string prefix)
256 62d5b25f Panagiotis Kanavos
        {            
257 62d5b25f Panagiotis Kanavos
            //If the prefix or the target are empty, return the target
258 62d5b25f Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(prefix) || String.IsNullOrWhiteSpace(target))
259 62d5b25f Panagiotis Kanavos
                return target;
260 62d5b25f Panagiotis Kanavos
            if (target.StartsWith(prefix))
261 62d5b25f Panagiotis Kanavos
                return target.Remove(0,prefix.Length);
262 62d5b25f Panagiotis Kanavos
            return target;
263 62d5b25f Panagiotis Kanavos
        }
264 b9f5b594 Panagiotis Kanavos
    }
265 62d5b25f Panagiotis Kanavos
266 62d5b25f Panagiotis Kanavos
267 b9f5b594 Panagiotis Kanavos
}