Ejemplo n.º 1
0
        private static void NoAllocationWithForeach(Utf8String s, int n)
        {
            var start = GC.GetTotalMemory(false);

            for (int i = 0; i < n; i++)
            {
                foreach (var x in s.CodePoints)
                    ;

                if (s.Length > 3)
                {
                    var sub1 = s.Substring(1, 1);
                    var sub2 = s.Substring(2);
                    var sub3 = s.Substring(3);
                }
            }

            var end = GC.GetTotalMemory(false);

            Assert.AreEqual(start, end);
        }
        public static void Run()
        {
            var utf8RawData = new byte[] { 0x7B, 0x20, 0x22, 0x6B, 0x65, 0x79, 0x22, 0x3A, 0x20, 0x22, 0x61, 0xE3, 0x81, 0x82, 0xF0, 0x9F, 0x98, 0x80, 0x22, 0x20, 0x7D };
            var utf16RawData = new char[] { '{', ' ', '"', 'k', 'e', 'y', '"', ':', ' ', '"', 'a', 'あ', (char)0xD83D, (char)0xDE00, '"', ' ', '}' };

            // string 型
            {
                // UTF-8 → UTF-16 の変換でヒープ確保が必要
                var s1 = System.Text.Encoding.UTF8.GetString(utf8RawData);

                // string 型は char[] を受け取る場合でも、内部でコピーを作るのでヒープ確保発生
                var s2 = new string(utf16RawData);

                // string.Substring もコピー発生
                var sub = s1.Substring(10, 4);

                Console.WriteLine(sub);
            }

            // Utf8String 型
            {
                // ヒープ確保しない実装
                var s = new Utf8String(utf8RawData);

                // インデックスでの文字取得はできない。s[0] は byte 単位のアクセスになる
                // コード ポイントの取り出しには CodePoints を使う
                // foreach もすべて構造体で展開されるのでヒープ確保不要
                foreach (var c in s.CodePoints)
                {
                    Console.WriteLine(c);
                }

                // Substring もコピー不要な実装になっている
                var sub = s.Substring(10, 8);

                foreach (var c in sub.CodePoints)
                {
                    Console.WriteLine(c);
                }
            }

            // string 型
            {
                // 内部でコピーしているので…
                var s1 = new string(utf16RawData);
                var s2 = new string(utf16RawData);

                // 元データを書き換えても
                utf16RawData[0] = '[';
                utf16RawData[16] = ']';

                // 影響は出ない
                Console.WriteLine(s1); // { "key": "aあ😀" }
                Console.WriteLine(s2); // { "key": "aあ😀" }
            }

            // Utf8String 型
            {
                // データを共有しているので…
                var s1 = new Utf8String(utf8RawData);
                var s2 = new Utf8String(utf8RawData);

                //98, 227, 129, 132, 240, 159, 144, 136
                // 元データを書き換えると
                utf8RawData[10] = 98;
                utf8RawData[11] = 227;
                utf8RawData[12] = 129;
                utf8RawData[13] = 132;
                utf8RawData[14] = 240;
                utf8RawData[15] = 159;
                utf8RawData[16] = 144;
                utf8RawData[17] = 136;

                // 影響がある
                Console.WriteLine(s1); // { "key": "bい🐈" }
                Console.WriteLine(s2); // { "key": "bい🐈" }
                Console.WriteLine(s1.Substring(10, 8)); // bい🐈
            }
        }