1- using Monocle ;
2- using System . Collections ;
1+ using Celeste . Mod . Helpers ;
2+ using Monocle ;
33using System . Collections . Generic ;
44using System . Collections . ObjectModel ;
5- using System . Linq ;
65using System . Text ;
76using System . Xml ;
87
@@ -16,16 +15,20 @@ public static class Emoji {
1615 /// A list of all registered emoji names, in order of their IDs.
1716 /// </summary>
1817 public static ReadOnlyCollection < string > Registered => new ReadOnlyCollection < string > ( _Registered ) ;
18+
1919 public static char Last => ( char ) ( '\uE000 ' + _Registered . Count - 1 ) ;
2020
2121 private static List < string > _Registered = new List < string > ( ) ;
2222 private static Dictionary < string , int > _IDs = new Dictionary < string , int > ( ) ;
2323 private static List < bool > _IsMonochrome = new List < bool > ( ) ;
2424 private static List < PixelFontCharacter > _Chars = new List < PixelFontCharacter > ( ) ;
2525
26+ private static readonly CachedApply cachedApplies = new CachedApply ( ) ;
27+
2628 private static bool Initialized = false ;
2729 private static Queue < KeyValuePair < string , MTexture > > Queue = new Queue < KeyValuePair < string , MTexture > > ( ) ;
2830 private static XmlElement _FakeXML ;
31+
2932 public static XmlElement FakeXML {
3033 get {
3134 if ( _FakeXML != null )
@@ -129,6 +132,7 @@ public static void Register(string name, MTexture emoji, float scale) {
129132 }
130133
131134 _Chars . Add ( new PixelFontCharacter ( Start + id , emoji , xml ) ) ;
135+ cachedApplies . Clear ( ) ;
132136 }
133137
134138 /// <summary>
@@ -174,68 +178,76 @@ public static bool TryGet(string name, out char c) {
174178 public static bool IsMonochrome ( char c )
175179 => _IsMonochrome [ c - Start ] ;
176180
177- /// <summary>
178- /// Transforms all instances of :emojiname: to \uSTART+ID
179- /// </summary>
180- /// <param name="text"></param>
181- /// <returns></returns>
182- public static string Apply ( string text ) {
183- if ( text == null )
184- return text ;
185- // TODO: This trashes the GC and doesn't allow escaping!
186- lock ( _IDs ) {
187- StringBuilder resultBuilder = new StringBuilder ( ) ;
188- int appendStartIndex = 0 ;
189- int head = - 1 , tail = 0 ;
190- // suppose text is "aaaa:1111:2222:bbbb", and only ":2222:" is emoji name
191- // H = head, T = tail, S = appendStartIndex
192- while ( tail < text . Length ) {
193- if ( text [ tail ] == ':' ) {
194- if ( head >= 0 && text [ head ] == ':' ) {
195- /*
196- aaaa:1111:2222:bbbb
197- (2) ^S ^H ^T ^
198- (4) ^S ^H ^T
199- now head and tail are pointing to colons so we need to check if the text inside colons is an emoji name
200- */
201- string name = text . Substring ( head + 1 , ( tail - 1 ) - ( head + 1 ) + 1 ) ;
202- if ( _IDs . TryGetValue ( name , out int value ) ) {
203- // if it is, we need to first append the text before emoji
204- resultBuilder . Append ( text , appendStartIndex , ( head - 1 ) - appendStartIndex + 1 ) ;
205- // then append the emoji itself
206- resultBuilder . Append ( ( char ) ( Start + value ) ) ;
207- // the emoji name has been replaced, we need to advance tail pointer once
208- // because the colon is used and can't belong to next emoji
209- tail ++ ;
210- appendStartIndex = tail ;
181+ private class CachedApply : CacheHelper < string , string > {
182+ public CachedApply ( ) : base ( name : "Emoji.Apply" , maxSize : 1000 ) { }
183+
184+ protected override string Compute ( string text ) {
185+ if ( text == null )
186+ return text ;
187+
188+ // TODO: This trashes the GC and doesn't allow escaping!
189+ lock ( _IDs ) {
190+ StringBuilder resultBuilder = new StringBuilder ( ) ;
191+ int appendStartIndex = 0 ;
192+ int head = - 1 , tail = 0 ;
193+ // suppose text is "aaaa:1111:2222:bbbb", and only ":2222:" is emoji name
194+ // H = head, T = tail, S = appendStartIndex
195+ while ( tail < text . Length ) {
196+ if ( text [ tail ] == ':' ) {
197+ if ( head >= 0 && text [ head ] == ':' ) {
211198 /*
212199 aaaa:1111:2222:bbbb
213- (5) ^H S^T
200+ (2) ^S ^H ^T ^
201+ (4) ^S ^H ^T
202+ now head and tail are pointing to colons so we need to check if the text inside colons is an emoji name
214203 */
204+ string name = text . Substring ( head + 1 , ( tail - 1 ) - ( head + 1 ) + 1 ) ;
205+ if ( _IDs . TryGetValue ( name , out int value ) ) {
206+ // if it is, we need to first append the text before emoji
207+ resultBuilder . Append ( text , appendStartIndex , ( head - 1 ) - appendStartIndex + 1 ) ;
208+ // then append the emoji itself
209+ resultBuilder . Append ( ( char ) ( Start + value ) ) ;
210+ // the emoji name has been replaced, we need to advance tail pointer once
211+ // because the colon is used and can't belong to next emoji
212+ tail ++ ;
213+ appendStartIndex = tail ;
214+ /*
215+ aaaa:1111:2222:bbbb
216+ (5) ^H S^T
217+ */
218+ }
215219 }
220+ head = tail ;
221+ /*
222+ aaaa:1111:2222:bbbb
223+ (1) ^S H^T ^
224+ (3) ^S H^T
225+ when tail is pointing to a colon, we need to let head also points to it
226+ so when tail moves to next colon, text[head..tail] can be an emoji name and we can check then replace it
227+ */
216228 }
217- head = tail ;
218- /*
219- aaaa:1111:2222:bbbb
220- (1) ^S H^T ^
221- (3) ^S H^T
222- when tail is pointing to a colon, we need to let head also points to it
223- so when tail moves to next colon, text[head..tail] can be an emoji name and we can check then replace it
224- */
229+ tail ++ ;
225230 }
226- tail ++ ;
227- }
228- /*
229- aaaa:1111:2222:bbbb
230- (6) H^S ^T
231- there are still text left since last append, so we need to append them
232- */
233- if ( appendStartIndex < text . Length ) {
234- resultBuilder . Append ( text , appendStartIndex , ( text . Length - 1 ) - appendStartIndex + 1 ) ;
231+ /*
232+ aaaa:1111:2222:bbbb
233+ (6) H^S ^T
234+ there are still text left since last append, so we need to append them
235+ */
236+ if ( appendStartIndex < text . Length ) {
237+ resultBuilder . Append ( text , appendStartIndex , ( text . Length - 1 ) - appendStartIndex + 1 ) ;
238+ }
239+ return resultBuilder . ToString ( ) ;
235240 }
236- return resultBuilder . ToString ( ) ;
237241 }
238242 }
239243
244+ /// <summary>
245+ /// Transforms all instances of :emojiname: to \uSTART+ID
246+ /// </summary>
247+ /// <param name="text"></param>
248+ /// <returns></returns>
249+ public static string Apply ( string text ) {
250+ return cachedApplies . GetCached ( text ) ;
251+ }
240252 }
241253}
0 commit comments