~halega/+junk/sharpdevelop

« back to all changes in this revision

Viewing changes to src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionDataUsageCache.cs

  • Committer: sk
  • Date: 2011-09-10 05:17:57 UTC
  • Revision ID: halega@halega.com-20110910051757-qfouz1llya9m6boy
4.1.0.7915 Release Candidate 1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
 
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
 
3
 
 
4
using System;
 
5
using System.Collections.Generic;
 
6
using System.IO;
 
7
 
 
8
using ICSharpCode.Core;
 
9
using ICSharpCode.SharpDevelop.Project;
 
10
 
 
11
namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
 
12
{
 
13
        /// <summary>
 
14
        /// Tracks the names of the top-used CodeCompletionData items and gives them higher
 
15
        /// priority in the completion dropdown.
 
16
        /// </summary>
 
17
        public static class CodeCompletionDataUsageCache
 
18
        {
 
19
                struct UsageStruct {
 
20
                        public int Uses;
 
21
                        public int ShowCount;
 
22
                        public UsageStruct(int Uses, int ShowCount) {
 
23
                                this.Uses = Uses;
 
24
                                this.ShowCount = ShowCount;
 
25
                        }
 
26
                }
 
27
                
 
28
                static Dictionary<string, UsageStruct> dict;
 
29
                
 
30
                // File format for stored CodeCompletionDataUsageCache
 
31
                // long   magic   = 0x6567617355444343 (identifies file type = 'CCDUsage')
 
32
                // short  version = 1                  (file version)
 
33
                // int    itemCount
 
34
                // {
 
35
                //   string itemName
 
36
                //   int    itemUses
 
37
                //   int    itemShowCount
 
38
                // }
 
39
                
 
40
                const long magic = 0x6567617355444343;
 
41
                const short version = 1;
 
42
                
 
43
                /// <summary>Minimum number how often an item must be used to be saved to
 
44
                /// the file. Items with less uses than this count also get a priority penalty.
 
45
                /// (Because the first use would otherwise always be 100% priority)</summary>
 
46
                const int MinUsesForSave = 2;
 
47
                
 
48
                public static string CacheFilename {
 
49
                        get {
 
50
                                if (string.IsNullOrEmpty(PropertyService.ConfigDirectory))
 
51
                                        return null;
 
52
                                else
 
53
                                        return Path.Combine(PropertyService.ConfigDirectory, "CodeCompletionUsageCache.dat");
 
54
                        }
 
55
                }
 
56
                
 
57
                static void LoadCache()
 
58
                {
 
59
                        dict = new Dictionary<string, UsageStruct>();
 
60
                        ProjectService.SolutionClosed += delegate(object sender, EventArgs e) { SaveCache(); };
 
61
                        string cacheFileName = CodeCompletionDataUsageCache.CacheFilename;
 
62
                        if (string.IsNullOrEmpty(cacheFileName) || !File.Exists(cacheFileName))
 
63
                                return;
 
64
                        using (FileStream fs = new FileStream(cacheFileName, FileMode.Open, FileAccess.Read)) {
 
65
                                using (BinaryReader reader = new BinaryReader(fs)) {
 
66
                                        if (reader.ReadInt64() != magic) {
 
67
                                                LoggingService.Warn("CodeCompletionDataUsageCache: wrong file magic");
 
68
                                                return;
 
69
                                        }
 
70
                                        if (reader.ReadInt16() != version) {
 
71
                                                LoggingService.Warn("CodeCompletionDataUsageCache: unknown file version");
 
72
                                                return;
 
73
                                        }
 
74
                                        int itemCount = reader.ReadInt32();
 
75
                                        for (int i = 0; i < itemCount; i++) {
 
76
                                                string key = reader.ReadString();
 
77
                                                int uses = reader.ReadInt32();
 
78
                                                int showCount = reader.ReadInt32();
 
79
                                                if (showCount > 1000) {
 
80
                                                        // reduce count because the usage in the next time
 
81
                                                        // should have more influence on the past
 
82
                                                        showCount /= 3;
 
83
                                                        uses /= 3;
 
84
                                                }
 
85
                                                dict.Add(key, new UsageStruct(uses, showCount));
 
86
                                        }
 
87
                                }
 
88
                        }
 
89
                        LoggingService.Info("Loaded CodeCompletionDataUsageCache (" + dict.Count + " items)");
 
90
                }
 
91
                
 
92
                public static void SaveCache()
 
93
                {
 
94
                        string cacheFileName = CodeCompletionDataUsageCache.CacheFilename;
 
95
                        if (dict == null || string.IsNullOrEmpty(cacheFileName)) {
 
96
                                return;
 
97
                        }
 
98
                        int count;
 
99
                        using (FileStream fs = new FileStream(cacheFileName, FileMode.Create, FileAccess.Write)) {
 
100
                                using (BinaryWriter writer = new BinaryWriter(fs)) {
 
101
                                        count = SaveCache(writer);
 
102
                                }
 
103
                        }
 
104
                        LoggingService.Info("Saved CodeCompletionDataUsageCache (" + count + " of " + dict.Count + " items)");
 
105
                }
 
106
                
 
107
                static int SaveCache(BinaryWriter writer)
 
108
                {
 
109
                        writer.Write(magic);
 
110
                        writer.Write(version);
 
111
                        int maxSaveItems = CodeCompletionOptions.DataUsageCacheItemCount;
 
112
                        if (dict.Count < maxSaveItems) {
 
113
                                writer.Write(dict.Count);
 
114
                                foreach (KeyValuePair<string, UsageStruct> entry in dict) {
 
115
                                        writer.Write(entry.Key);
 
116
                                        writer.Write(entry.Value.Uses);
 
117
                                        writer.Write(entry.Value.ShowCount);
 
118
                                }
 
119
                                return dict.Count;
 
120
                        } else {
 
121
                                List<KeyValuePair<string, UsageStruct>> saveItems = new List<KeyValuePair<string, UsageStruct>>();
 
122
                                foreach (KeyValuePair<string, UsageStruct> entry in dict) {
 
123
                                        if (entry.Value.Uses > MinUsesForSave) {
 
124
                                                saveItems.Add(entry);
 
125
                                        }
 
126
                                }
 
127
                                if (saveItems.Count > maxSaveItems) {
 
128
                                        saveItems.Sort(new SaveItemsComparer());
 
129
                                }
 
130
                                int count = Math.Min(maxSaveItems, saveItems.Count);
 
131
                                writer.Write(count);
 
132
                                for (int i = 0; i < count; i++) {
 
133
                                        KeyValuePair<string, UsageStruct> entry = saveItems[i];
 
134
                                        writer.Write(entry.Key);
 
135
                                        writer.Write(entry.Value.Uses);
 
136
                                        writer.Write(entry.Value.ShowCount);
 
137
                                }
 
138
                                return count;
 
139
                        }
 
140
                }
 
141
                
 
142
                class SaveItemsComparer : IComparer<KeyValuePair<string, UsageStruct>>
 
143
                {
 
144
                        public int Compare(KeyValuePair<string, UsageStruct> x, KeyValuePair<string, UsageStruct> y)
 
145
                        {
 
146
                                double a = ((double)x.Value.Uses / x.Value.ShowCount);
 
147
                                return -a.CompareTo((double)y.Value.Uses / y.Value.ShowCount);
 
148
                        }
 
149
                }
 
150
                
 
151
                public static void ResetCache()
 
152
                {
 
153
                        dict = new Dictionary<string, UsageStruct>();
 
154
                        try {
 
155
                                if (File.Exists(CacheFilename)) {
 
156
                                        File.Delete(CacheFilename);
 
157
                                }
 
158
                        } catch (Exception ex) {
 
159
                                LoggingService.Warn("CodeCompletionDataUsageCache.ResetCache(): " + ex.Message);
 
160
                        }
 
161
                }
 
162
                
 
163
                public static double GetPriority(string dotnetName, bool incrementShowCount)
 
164
                {
 
165
                        if (!CodeCompletionOptions.DataUsageCacheEnabled)
 
166
                                return 0;
 
167
                        if (dict == null) {
 
168
                                LoadCache();
 
169
                        }
 
170
                        UsageStruct usage;
 
171
                        if (!dict.TryGetValue(dotnetName, out usage))
 
172
                                return 0;
 
173
                        double priority = (double)usage.Uses / usage.ShowCount;
 
174
                        if (usage.Uses < MinUsesForSave)
 
175
                                priority *= 0.2;
 
176
                        if (incrementShowCount) {
 
177
                                usage.ShowCount += 1;
 
178
                                dict[dotnetName] = usage;
 
179
                        }
 
180
                        return priority;
 
181
                }
 
182
                
 
183
                public static void IncrementUsage(string dotnetName)
 
184
                {
 
185
                        if (!CodeCompletionOptions.DataUsageCacheEnabled)
 
186
                                return;
 
187
                        if (dict == null) {
 
188
                                LoadCache();
 
189
                        }
 
190
                        UsageStruct usage;
 
191
                        if (!dict.TryGetValue(dotnetName, out usage)) {
 
192
                                usage = new UsageStruct(0, 2);
 
193
                        }
 
194
                        usage.Uses += 1;
 
195
                        dict[dotnetName] = usage;
 
196
                }
 
197
        }
 
198
}