Free cookie consent management tool by TermsFeed Policy Generator

source: branches/CodeEditor/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory-5.5.0/IAnnotatable.cs @ 11700

Last change on this file since 11700 was 11700, checked in by jkarder, 9 years ago

#2077: created branch and added first version

File size: 7.5 KB
Line 
1// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4// software and associated documentation files (the "Software"), to deal in the Software
5// without restriction, including without limitation the rights to use, copy, modify, merge,
6// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7// to whom the Software is furnished to do so, subject to the following conditions:
8//
9// The above copyright notice and this permission notice shall be included in all copies or
10// substantial portions of the Software.
11//
12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17// DEALINGS IN THE SOFTWARE.
18
19using System;
20using System.Collections.Generic;
21using System.Linq;
22using System.Threading;
23
24namespace ICSharpCode.NRefactory
25{
26  /// <summary>
27  /// Provides an interface to handle annotations in an object.
28  /// </summary>
29  public interface IAnnotatable
30  {
31    /// <summary>
32    /// Gets all annotations stored on this IAnnotatable.
33    /// </summary>
34    IEnumerable<object> Annotations {
35      get;
36    }
37   
38    /// <summary>
39    /// Gets the first annotation of the specified type.
40    /// Returns null if no matching annotation exists.
41    /// </summary>
42    /// <typeparam name='T'>
43    /// The type of the annotation.
44    /// </typeparam>
45    T Annotation<T> () where T: class;
46   
47    /// <summary>
48    /// Gets the first annotation of the specified type.
49    /// Returns null if no matching annotation exists.
50    /// </summary>
51    /// <param name='type'>
52    /// The type of the annotation.
53    /// </param>
54    object Annotation (Type type);
55   
56    /// <summary>
57    /// Adds an annotation to this instance.
58    /// </summary>
59    /// <param name='annotation'>
60    /// The annotation to add.
61    /// </param>
62    void AddAnnotation (object annotation);
63   
64    /// <summary>
65    /// Removes all annotations of the specified type.
66    /// </summary>
67    /// <typeparam name='T'>
68    /// The type of the annotations to remove.
69    /// </typeparam>
70    void RemoveAnnotations<T> () where T : class;
71   
72    /// <summary>
73    /// Removes all annotations of the specified type.
74    /// </summary>
75    /// <param name='type'>
76    /// The type of the annotations to remove.
77    /// </param>
78    void RemoveAnnotations(Type type);
79  }
80 
81  /// <summary>
82  /// Base class used to implement the IAnnotatable interface.
83  /// This implementation is thread-safe.
84  /// </summary>
85  [Serializable]
86  public abstract class AbstractAnnotatable : IAnnotatable
87  {
88    // Annotations: points either null (no annotations), to the single annotation,
89    // or to an AnnotationList.
90    // Once it is pointed at an AnnotationList, it will never change (this allows thread-safety support by locking the list)
91   
92    object annotations;
93   
94    /// <summary>
95    /// Clones all annotations.
96    /// This method is intended to be called by Clone() implementations in derived classes.
97    /// <code>
98    /// AstNode copy = (AstNode)MemberwiseClone();
99    /// copy.CloneAnnotations();
100    /// </code>
101    /// </summary>
102    protected void CloneAnnotations()
103    {
104      ICloneable cloneable = annotations as ICloneable;
105      if (cloneable != null)
106        annotations = cloneable.Clone();
107    }
108
109    sealed class AnnotationList : List<object>, ICloneable
110    {
111      // There are two uses for this custom list type:
112      // 1) it's private, and thus (unlike List<object>) cannot be confused with real annotations
113      // 2) It allows us to simplify the cloning logic by making the list behave the same as a clonable annotation.
114      public AnnotationList (int initialCapacity) : base(initialCapacity)
115      {
116      }
117     
118      public object Clone ()
119      {
120        lock (this) {
121          AnnotationList copy = new AnnotationList (this.Count);
122          for (int i = 0; i < this.Count; i++) {
123            object obj = this [i];
124            ICloneable c = obj as ICloneable;
125            copy.Add (c != null ? c.Clone () : obj);
126          }
127          return copy;
128        }
129      }
130    }
131   
132    public virtual void AddAnnotation (object annotation)
133    {
134      if (annotation == null)
135        throw new ArgumentNullException ("annotation");
136    retry: // Retry until successful
137      object oldAnnotation = Interlocked.CompareExchange (ref this.annotations, annotation, null);
138      if (oldAnnotation == null) {
139        return; // we successfully added a single annotation
140      }
141      AnnotationList list = oldAnnotation as AnnotationList;
142      if (list == null) {
143        // we need to transform the old annotation into a list
144        list = new AnnotationList (4);
145        list.Add (oldAnnotation);
146        list.Add (annotation);
147        if (Interlocked.CompareExchange (ref this.annotations, list, oldAnnotation) != oldAnnotation) {
148          // the transformation failed (some other thread wrote to this.annotations first)
149          goto retry;
150        }
151      } else {
152        // once there's a list, use simple locking
153        lock (list) {
154          list.Add (annotation);
155        }
156      }
157    }
158   
159    public virtual void RemoveAnnotations<T> () where T : class
160    {
161    retry: // Retry until successful
162      object oldAnnotations = this.annotations;
163      AnnotationList list = oldAnnotations as AnnotationList;
164      if (list != null) {
165        lock (list)
166          list.RemoveAll (obj => obj is T);
167      } else if (oldAnnotations is T) {
168        if (Interlocked.CompareExchange (ref this.annotations, null, oldAnnotations) != oldAnnotations) {
169          // Operation failed (some other thread wrote to this.annotations first)
170          goto retry;
171        }
172      }
173    }
174   
175    public virtual void RemoveAnnotations (Type type)
176    {
177      if (type == null)
178        throw new ArgumentNullException ("type");
179    retry: // Retry until successful
180      object oldAnnotations = this.annotations;
181      AnnotationList list = oldAnnotations as AnnotationList;
182      if (list != null) {
183        lock (list)
184          list.RemoveAll(type.IsInstanceOfType);
185      } else if (type.IsInstanceOfType (oldAnnotations)) {
186        if (Interlocked.CompareExchange (ref this.annotations, null, oldAnnotations) != oldAnnotations) {
187          // Operation failed (some other thread wrote to this.annotations first)
188          goto retry;
189        }
190      }
191    }
192   
193    public T Annotation<T> () where T: class
194    {
195      object annotations = this.annotations;
196      AnnotationList list = annotations as AnnotationList;
197      if (list != null) {
198        lock (list) {
199          foreach (object obj in list) {
200            T t = obj as T;
201            if (t != null)
202              return t;
203          }
204          return null;
205        }
206      } else {
207        return annotations as T;
208      }
209    }
210   
211    public object Annotation (Type type)
212    {
213      if (type == null)
214        throw new ArgumentNullException ("type");
215      object annotations = this.annotations;
216      AnnotationList list = annotations as AnnotationList;
217      if (list != null) {
218        lock (list) {
219          foreach (object obj in list) {
220            if (type.IsInstanceOfType (obj))
221              return obj;
222          }
223        }
224      } else {
225        if (type.IsInstanceOfType (annotations))
226          return annotations;
227      }
228      return null;
229    }
230   
231    /// <summary>
232    /// Gets all annotations stored on this AstNode.
233    /// </summary>
234    public IEnumerable<object> Annotations {
235      get {
236        object annotations = this.annotations;
237        AnnotationList list = annotations as AnnotationList;
238        if (list != null) {
239          lock (list) {
240            return list.ToArray ();
241          }
242        } else {
243          if (annotations != null)
244            return new object[] { annotations };
245          else
246            return Enumerable.Empty<object> ();
247        }
248      }
249    }
250  }
251}
252
Note: See TracBrowser for help on using the repository browser.