CïŒã«ã¯ãããªãèå³æ·±ãããã£ãã«äœ¿çšãããªãããŒã¯ãŒã
stackalloc
ãŸãã ã³ãŒãå ã§ã¯éåžžã«ãŸãã§ããããïŒããã§ã¯ããŸãã«ããšããèšèã§æ§ããã«èšã£ãŠããŸããã決ããŠããšã¯èšããŸããïŒããã®äœ¿çšã®é©åãªäŸãèŠã€ããã®ã¯éåžžã«é£ãããèŠã€ããã®ã¯ããã«é£ãããªããŸãã圌ãšä»äºãããã®ã¯å°ããããŸãã ãããŠããªãã§ããïŒ ãªããªãããã®ã³ãã³ããäœãããã®ããæçµçã«æ±ºå®ãã人ã«ãšã£ãŠã
stackalloc
ãªããš
stackalloc
ããåšå§çã«ãªãããã§ã
stackalloc
ã®ããŒã¯ãµã€ãã¯å®å šã§ãªãã³ãŒãã§ãã è¿ãããçµæã¯ãããŒãžãã€ã³ã¿ãŒã§ã¯ãããŸãããå€ã¯ãä¿è·ãããŠããªãã¡ã¢ãªã®ã»ã¯ã·ã§ã³ãžã®éåžžã®ãã€ã³ã¿ãŒã§ãã ããã«ãã¡ãœãããåäœãå®äºããåŸã«ãã®ã¢ãã¬ã¹ã§ã¬ã³ãŒããäœæãããšãã¡ãœããã®ããŒã«ã«å€æ°ãžã®æžã蟌ã¿ãéå§ããããã¡ãœããããæ»ãã¢ãã¬ã¹ãæ¶å»ããããšããã§ããŸãããã®åŸãã¢ããªã±ãŒã·ã§ã³ã¯ãšã©ãŒã§åäœãçµäºããŸãã ããããç§ãã¡ã®ä»äºã¯ããŸãã«ãã®é ã«äŸµå ¥ããããã«é ãããŠãããã®ãèŠã€ãåºãããšã§ãã ãããŠç¹ã«ã圌ãããã®ããŒã«ãæäŸããŠãããã®ã¯ããããç§ãã¡ãç§å¯ã®çæãèŠã€ããŠãããããããããèžãããšãã§ãããšããããšã ãã§ã¯ãªãããšãç解ããããã§ãã ããã©ãããã圌ãã¯ç§ãã¡ã«ãã®ããŒã«ãæäŸããŠãããã®ã§ãããã䜿ã£ãŠæ¬åœã«é«éãªãœãããŠã§ã¢ãäœãããšãã§ããŸããã ç§ã¯ããªãã«ã€ã³ã¹ãã¬ãŒã·ã§ã³ãäžããããšæããŸããïŒ ããã§ã¯å§ããŸãããã
ã泚æ
Habréã§å ¬éãããŠããç« ã¯æŽæ°ãããŠãããããããããã§ã«å€ããã®ã§ãã ãã®ãããææ°ã®ããã¹ãã«ã€ããŠã¯å ã«æ»ããŠãã ããã
- CLR BookïŒ GitHubãç®æ¬¡
- CLR BookïŒ GitHubãç« ããã¹ã¿ãã¯ãžã®ã¡ã¢ãªã®å²ãåœãŠïŒstackallocããžã®ãªã³ã¯
- ãªãªãŒã¹0.5.2ã®æžç±ãPDFïŒ GitHubãªãªãŒã¹
ãã®ããŒã¯ãŒãã®æ£ãã䜿çšäŸãèŠã€ããã«ã¯ããŸããã®äœæè ã§ããMicrosoftã«ã¢ã¯ã»ã¹ããŠããã®äœ¿çšæ¹æ³ã確èªããå¿ èŠããããŸãã ãããè¡ãã«ã¯ã coreclrãªããžããªã§å šææ€çŽ¢ã䜿çšããŠæ€çŽ¢ããŸãã ããŒã¯ãŒãèªäœã®ããŸããŸãªãã¹ãã«å ããŠãã©ã€ãã©ãªã³ãŒãã«ãããã®ããŒã¯ãŒãã®äœ¿çšã¯25ãè¶ ããªãããšãããããŸãã åã®ãã©ã°ã©ãã§ããã®å°ããªæ°åãèŠãŠãç§ã®ä»äºãéããªãã£ããšãã«ãèªãã®ããããªãããã«ååãªåæ©ä»ããããããšæããŸãã æ£çŽã«èšããšãCLRããŒã ã¯.NET FrameworkããŒã ãããã¯ããã«å èŠã®æãããããããã§ãã·ã§ãã«ã§ãããäœããããããããã¯ç§ãã¡ã«å€§ãã«åœ¹ç«ã€ã¯ãã§ãã ãããŠãããã.NET Frameworkã§äœ¿çšãããŠããªãå Žå...ããŠãããã§ããã¹ãŠã®ãšã³ãžãã¢ããã®ãããªåŒ·åãªæé©åããŒã«ãããããšãèªèããŠãããšã¯éããŸããã ããããªããšããã®äœ¿çšéãã¯ããã«å€§ãããªããŸãã
ã¯ã©ã¹Interop.ReadDir
unsafe { // s_readBufferSize is zero when the native implementation does not // support reading into a buffer. byte* buffer = stackalloc byte[s_readBufferSize]; InternalDirectoryEntry temp; int ret = ReadDirR(dir.DangerousGetHandle(), buffer, s_readBufferSize, out temp); // We copy data into DirectoryEntry to ensure there are no dangling references. outputEntry = ret == 0 ? new DirectoryEntry() { InodeName = GetDirectoryEntryName(temp), InodeType = temp.InodeType } : default(DirectoryEntry); return ret; }
stackalloc
䜿çšããã
stackalloc
ãšã¯äœã§ããïŒ ã芧ã®ãšãããã¡ã¢ãªãå²ãåœãŠãåŸãã³ãŒãã¯unsafeã¡ãœããã«é²ã¿ãäœæããããããã¡ã«ããŒã¿ãå ¥ããŸãã ããªãã¡ å²ãåœãŠãããã¹ããŒã¹ãçŽæ¥ã¹ã¿ãã¯ã«èšé²ããããã®ãããããå¿ èŠãšããå®å šã§ãªãã¡ãœããïŒåçã ããã¯ã代æ¿æ¡ãæ€èšããéã«æé©ãªæé©åã§ãïŒWindowsãŸãã¯åºå®ïŒåºå®ïŒ.NETã¢ã¬ã€ããã¡ã¢ãªã®äžéšãèŠæ±ããŸããããã¯ãããŒãã®ããŒãã«å ããŠãGCãããŒãããŠãGCãããŒã¿ã«ã¢ã¯ã»ã¹ããŠããéãGCã移åããªãããã«ããŸãã ã¹ã¿ãã¯ã«ã¡ã¢ãªãå²ãåœãŠãããšã§ãäœã®ãªã¹ã¯ããããŸãããã»ãŒç¬æã«å²ãåœãŠãè¡ãããããŒã¿ãå®å šã«åããŠã¡ãœãããçµäºã§ããŸãã ãŸããã¡ãœãããçµäºãããšãã¡ãœããã®ã¹ã¿ãã¯ãã¬ãŒã ãæ¶ããŸãã äžè¬çã«ãæéã®ç¯çŽã¯éåžžã«éèŠã§ãã
å¥ã®äŸãèŠãŠã¿ãŸãããã
ã¯ã©ã¹Number.Formatting :: FormatDecimal
public static string FormatDecimal( decimal value, ReadOnlySpan<char> format, NumberFormatInfo info) { char fmt = ParseFormatSpecifier(format, out int digits); NumberBuffer number = default; DecimalToNumber(value, ref number); ValueStringBuilder sb; unsafe { char* stackPtr = stackalloc char[CharStackBufferSize]; sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize)); } if (fmt != 0) { NumberToString(ref sb, ref number, fmt, digits, info, isDecimal:true); } else { NumberToStringFormat(ref sb, ref number, format, info); } return sb.ToString(); }
ããã¯ã
Span<T>
åºã¥ããŠåäœããValueStringBuilderã¯ã©ã¹ã®ããã«èå³æ·±ãäŸã«åºã¥ãããæ°å€ã®ãã©ãŒãããã®äŸã§ãã ã³ãŒãã®ãã®ã»ã¯ã·ã§ã³ã®æ¬è³ªã¯ããã©ãŒããããããæ°å€ã®ããã¹ãè¡šçŸãã§ããã ãè¿ éã«åéããããã«ãã³ãŒããæåèç©ãããã¡ã«ã¡ã¢ãªå²ãåœãŠã䜿çšããªãããšã§ãã ãã®çŸããã³ãŒãã¯ãã¡ã¢ãªãã¡ãœããã®ã¹ã¿ãã¯ãã¬ãŒã ã«çŽæ¥å²ãåœãŠãŸããããã«ãããã¡ãœããããã®ããŒã¹ã§æ©èœããå Žåãã¬ããŒãžã³ã¬ã¯ã¿ãStringBuilderã€ã³ã¹ã¿ã³ã¹ã§æ©èœããªãããšãä¿èšŒãããŸãã ããã«ãã¡ãœããèªäœã®å®è¡æéã¯ççž®ãããŸããããŒãã«ã¡ã¢ãªãå²ãåœãŠãã®ã«æéãããããŸãã ãŸãããã¢ãã€ã³ã¿ã®ä»£ããã«
Span<T>
ã䜿çšãããšã
stackalloc
ããŒã¹ã®
stackalloc
äœæ¥ã«å®å¿æã
stackalloc
ã
ãããŠæåŸã«ãå¥ã®äŸã
ValueStringBuilder
ãŸãããïŒ
ValueStringBuilder
ã䜿çšããããã«èšèšããã
ValueStringBuilder
ã¯ã©ã¹
ValueStringBuilder
ã ãããªãã§ã¯ããã®ã¯ã©ã¹ã¯ååšããŸããã
ã¯ã©ã¹ValueStringBuilder
internal ref struct ValueStringBuilder { private char[] _arrayToReturnToPool; private Span<char> _chars; private int _pos; public ValueStringBuilder(Span<char> initialBuffer) { _arrayToReturnToPool = null; _chars = initialBuffer; _pos = 0; } public int Length { get => _pos; set { int delta = value - _pos; if (delta > 0) { Append('\0', delta); } else { _pos = value; } } } public override string ToString() { var s = new string(_chars.Slice(0, _pos)); Clear(); return s; } public void Insert(int index, char value, int count) { if (_pos > _chars.Length - count) { Grow(count); } int remaining = _pos - index; _chars.Slice(index, remaining).CopyTo(_chars.Slice(index + count)); _chars.Slice(index, count).Fill(value); _pos += count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Append(char c) { int pos = _pos; if (pos < _chars.Length) { _chars[pos] = c; _pos = pos + 1; } else { GrowAndAppend(c); } } [MethodImpl(MethodImplOptions.NoInlining)] private void GrowAndAppend(char c) { Grow(1); Append(c); } [MethodImpl(MethodImplOptions.NoInlining)] private void Grow(int requiredAdditionalCapacity) { Debug.Assert(requiredAdditionalCapacity > _chars.Length - _pos); char[] poolArray = ArrayPool<char>.Shared.Rent( Math.Max(_pos + requiredAdditionalCapacity, _chars.Length * 2)); _chars.CopyTo(poolArray); char[] toReturn = _arrayToReturnToPool; _chars = _arrayToReturnToPool = poolArray; if (toReturn != null) { ArrayPool<char>.Shared.Return(toReturn); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Clear() { char[] toReturn = _arrayToReturnToPool; // for safety, to avoid using pooled array if this instance is erroneously appended to again this = default; if (toReturn != null) { ArrayPool<char>.Shared.Return(toReturn); } } // private void AppendSlow(string s); public bool TryCopyTo(Span<char> destination, out int charsWritten); public void Append(string s); public void Append(char c, int count); public unsafe void Append(char* value, int length); public Span<char> AppendSpan(int length); }
ãã®ã¯ã©ã¹ã¯æ©èœçã«ã¯å ã® `StringBuilder`ã«äŒŒãŠããŸãããèå³æ·±ãéåžžã«éèŠãªæ©èœã1ã€ãããŸããããã¯éèŠãªåã§ãã ããªãã¡ å€ã ãã§éä¿¡ãããŸãã ãããŠãå宣èšã®çœ²åã«å²ãåœãŠãããå `ref`ã®ææ°ã®ä¿®é£Ÿåã¯ããã®åã«ã¯è¿œå ã®å¶éãããããšãæããŠãããŸãïŒã¹ã¿ãã¯ã«ã®ã¿ååšããæš©å©ããããŸãã ããªãã¡ ã€ã³ã¹ã¿ã³ã¹ãã¯ã©ã¹ãã£ãŒã«ãã«åºåãããšããšã©ãŒãçºçããŸãã ãªãããããã¹ãŠã®ã¹ã¯ã¯ããã§ããïŒ ãã®è³ªåã«çããã«ã¯ã `StringBuilder`ã¯ã©ã¹ãèŠãŠãã ããïŒ
ã¯ã©ã¹StringBuilder
public sealed class StringBuilder : ISerializable { // A StringBuilder is internally represented as a linked list of // blocks each of which holds a chunk of the string. It turns // out string as a whole can also be represented as just a chunk, // so that is what we do. // The characters in this block internal char[] m_ChunkChars; // Link to the block logically before this block internal StringBuilder m_ChunkPrevious; // The index in m_ChunkChars that represent the end of the block internal int m_ChunkLength; // The logical offset (sum of all characters in previous blocks) internal int m_ChunkOffset; internal int m_MaxCapacity = 0; // ... internal const int DefaultCapacity = 16;
StringBuilderã¯ãå éšã«æåã®é åãžã®ãªã³ã¯ãããã¯ã©ã¹ã§ãã ããªãã¡ å®éã«ããããäœæãããšãå°ãªããšã2ã€ã®ãªããžã§ã¯ããäœæãããŸãïŒStringBuilderèªäœãšå°ãªããšã16æåã®æåã®é åïŒãšããã§ãæååã®æšå®é·ãæå®ããããšãéåžžã«éèŠãªçç±ã§ãïŒãã®æ§ç¯ã¯ã16æåã®é åã®åäžãªã³ã¯ãªã¹ãã®çæãééããŸãã -浪費ïŒã ããã¯ãValueStringBuilderã¿ã€ãã«é¢ããäŒè©±ã®ã³ã³ããã¹ãã§ã¯äœãæå³ããŸãããããã©ã«ãã§ã¯å®¹éã¯ãããŸããã ããã¯å€éšããã¡ã¢ãªãååŸããããã«ããèªäœãéèŠãªã¿ã€ãã§ããããŠãŒã¶ãŒã«ã¹ã¿ãã¯äžã®æåã«ãããã¡ãå²ãåœãŠãããã«åŒ·å¶ããŸãã ãã®çµæãåã®ã€ã³ã¹ã¿ã³ã¹å šäœããã®å 容ãšãšãã«ã¹ã¿ãã¯ã«çœ®ãããããã§ã®æé©åã®åé¡ã¯è§£æ±ºãããŸãã ããŒãã«ã¡ã¢ãªå²ãåœãŠããããŸãããïŒ ããŒãã§ã®ããã©ãŒãã³ã¹ã®äœäžã¯åé¡ãããŸããã ããããããªãã¯ç§ã«èšãïŒãªãValueStringBuilderïŒãŸãã¯ãã®èªå·±èšè¿°ããŒãžã§ã³ïŒããã¯å éšã§ãããç§ãã¡ã«ã¢ã¯ã»ã¹ã§ããªãïŒãåžžã«äœ¿çšããªãã®ã§ããïŒ çãã¯ãããªãã解決ããããšããŠããåé¡ãèŠãå¿ èŠããããšããããšã§ãã çµæã®æååã¯æ¢ç¥ã®ãµã€ãºã«ãªããŸããïŒ åœŒå¥³ã«ã¯æ¢ç¥ã®æ倧é·ããããŸããïŒ çãããã¯ããã§ãæååã®ãµã€ãºã劥åœãªå¢çãè¶ ããªãå Žåãæå³ã®ããããŒãžã§ã³ã®StringBuilderã䜿çšã§ããŸãã ãã以å€ã®å Žåãé·ãè¡ãäºæ³ãããå Žåã¯ãéåžžããŒãžã§ã³ã®äœ¿çšã«åãæ¿ããŸãã
ãŸããçµè«ã«é²ãåã«ããããè¡ãæ¹æ³ãäžå¯èœãŸãã¯åã«å±éºã§ããããšã«èšåãã䟡å€ããããŸãã èšãæããã°ãã©ã®ã³ãŒããããŸãæ©èœãããããããŸããããããæç¹ã§ãããã¯æãäžé©åãªç¬éã«èµ·åããŸãã ç¹°ãè¿ããŸãããäŸãèããŠã¿ãŸãããã
void GenerateNoise(int noiseLength) { var buf = new Span(stackalloc int[noiseLength]); // generate noise }
ã³ãŒãã¯å°ããããªã¢ãŒãã§ãããã®ããã«ãµã€ãºãå€æŽããŠãå€éšããã¹ã¿ãã¯äžã®ã¡ã¢ãªãå²ãåœãŠãããšã¯ã§ããŸããã æ¬åœã«å€ã§äžãããããµã€ãºãå¿ èŠã§ãã³ãŒããç¥ã£ãŠããæ¶è²»è ã ãã«ç¥ãããŠãããªããäŸãã°ãããã¡èªäœãåããŸãïŒ
void GenerateNoise(Span<int> noiseBuf) { // generate noise }
ãã®ã³ãŒãã¯ãããæçã§ãããªããªãã æ°åãéžæãããšãããŠãŒã¶ãŒã«èãããã泚æãããŸãã æåã®ãªãã·ã§ã³ã¯ãæ®å¿µãªç¶æ³äžã§ãã¡ãœãããã¹ããªãŒã ã¹ã¿ãã¯ã§ããªãæµ ãå Žåã«
StackOverflowException
ãã¹ããŒããå¯èœæ§ããããŸãããã©ã¡ãŒã¿ãŒãšããŠå€§ããªæ°ãæž¡ãã ãã§ååã§ãã
ç§ãèŠã2çªç®ã®åé¡ïŒã¹ã¿ãã¯ã«å²ãåœãŠããããã¡ã®ãµã€ãºã«èª€ã£ãŠå°éã§ãããäœæ¥å®¹éã倱ããããªãå Žåããã¡ãããããã€ãã®æ¹æ³ããããŸãïŒã¹ã¿ãã¯ã«ã¡ã¢ãªãå床å²ãåœãŠãããŒãäžã§éžæããŸãã ãããŠãã»ãšãã©ã®å Žåã2çªç®ã®ãªãã·ã§ã³ã®æ¹ããã奜ãŸããã§ãããïŒ `ValueStringBuffer`ã®å Žåã¯ããã§ããïŒã ãStackOverflowExceptionããååŸãããšããç¹ã§ããå®å šã§ãã
stackallocã®çµè«
ããã§ã¯ã `stackalloc`ã䜿çšããæè¯ã®æ¹æ³ãšãã®æ¹æ³ã¯äœã§ããïŒ
- ã¢ã³ãããŒãžã³ãŒãã§äœæ¥ããã«ã¯ãç¹å®ã®ããŒã¿ãããã¡ãŒã«ã¢ã³ãããŒãžã¡ãœãããå ¥åããå¿ èŠãããå ŽåããŸãã¯ã¡ãœããæ¬äœã®æå¹æéå ã«äœ¿çšãããã¢ã³ãããŒãžã¡ãœããããããŒã¿ãããã¡ãŒãåãå ¥ããå¿ èŠãããå Žåã
- é åãå¿ èŠãšããã¡ãœããã®å Žåããã ããã¡ãœããèªäœã®æéäžãåæ§ã§ãã æžåŒèšå®ã®äŸã¯éåžžã«åªããŠããŸãããã®ã¡ãœãããé »ç¹ã«åŒã³åºããŠãããŒãã«äžæé åãå²ãåœãŠãããšãã§ããŸãã
- å®å šã§ãªãããŒãžã§ã³ã®ã€ã³ã¿ã©ã¯ã·ã§ã³ã䜿çšããŠããå Žåããªã³ã¯å ã®ã¡ãœããïŒvoid *ïŒã®åäœãæ éã«ç¢ºèªããå¿ èŠããããŸãã ããããã©ããã«ãããäžãããšãã¹ã¿ãã¯ãç Žæããå¯èœæ§ãããã«ãããŸããããšãã°ããã£ãã·ã¥ã®ããã«å€éšã¡ãœããããªã³ã¯ãæž¡ãããšã決å®ããªãããšãä¿èšŒããããšã¯ã§ããŸããã ãããé€å€ãããŠããããšã確å®ãªå Žåã䜿çšã¯å®å šã§ãã
-
ref struct
äœåãŸãã¯Spanåã䜿çšããæ©äŒãããå Žåãstackallocã䜿çšãããšãã³ãŒãã®ç®¡çé åã«å ¥ããŸããã€ãŸããã³ã³ãã€ã©ã¯ãæå³ãããšããã«åã䜿çšã§ããªãããã«ããŸãã
ãã®ã¢ãã±ãŒã¿ãŒã䜿çšãããšãã¢ããªã±ãŒã·ã§ã³ã®ããã©ãŒãã³ã¹ãå€§å¹ ã«æ¹åã§ããŸãã
æ¬å šäœãžã®ãªã³ã¯
- CLR BookïŒ GitHub
- ãªãªãŒã¹0.5.0ã®æžç±ãPDFïŒ GitHubãªãªãŒã¹