/// <summary> /// Returns a list of direct ArraySegment<byte>, if the currently pending messages are made of /// <see cref="IByteBuffer"/> instances only. <see cref="NioBufferSize"/> will return the total number of /// readable bytes of these buffers. /// <para> /// Note that the returned array is reused and thus should not escape /// <see cref="AbstractChannel.DoWrite(ChannelOutboundBuffer)"/>. Refer to /// <see cref="TcpSocketChannel.DoWrite(ChannelOutboundBuffer)"/> for an example. /// </para> /// </summary> /// <param name="maxCount">The maximum amount of buffers that will be added to the return value.</param> /// <param name="maxBytes">A hint toward the maximum number of bytes to include as part of the return value. Note that this value maybe exceeded because we make a best effort to include at least 1 <see cref="IByteBuffer"/> in the return value to ensure write progress is made.</param> /// <returns>A list of ArraySegment<byte> buffers.</returns> public List <ArraySegment <byte> > GetSharedBufferList(int maxCount, long maxBytes) { Debug.Assert(maxCount > 0); Debug.Assert(maxBytes > 0); long ioBufferSize = 0; int nioBufferCount = 0; InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.Get(); List <ArraySegment <byte> > nioBuffers = NioBuffers.Get(threadLocalMap); Entry entry = this.flushedEntry; while (this.IsFlushedEntry(entry) && entry.Message is IByteBuffer) { if (!entry.Cancelled) { var buf = (IByteBuffer)entry.Message; int readerIndex = buf.ReaderIndex; int readableBytes = buf.WriterIndex - readerIndex; if (readableBytes > 0) { if (maxBytes - readableBytes < ioBufferSize && nioBufferCount != 0) { // If the nioBufferSize + readableBytes will overflow an Integer we stop populate the // ByteBuffer array. This is done as bsd/osx don't allow to write more bytes then // Integer.MAX_VALUE with one writev(...) call and so will return 'EINVAL', which will // raise an IOException. On Linux it may work depending on the // architecture and kernel but to be safe we also enforce the limit here. // This said writing more the Integer.MAX_VALUE is not a good idea anyway. // // See also: // - https://www.freebsd.org/cgi/man.cgi?query=write&sektion=2 // - http://linux.die.net/man/2/writev break; } ioBufferSize += readableBytes; int count = entry.Count; if (count == -1) { entry.Count = count = buf.IoBufferCount; } if (count == 1) { ArraySegment <byte> nioBuf = entry.Buffer; if (nioBuf.Array == null) { // cache ByteBuffer as it may need to create a new ByteBuffer instance if its a // derived buffer entry.Buffer = nioBuf = buf.GetIoBuffer(readerIndex, readableBytes); } nioBuffers.Add(nioBuf); nioBufferCount++; } else { ArraySegment <byte>[] nioBufs = entry.Buffers; if (nioBufs == null) { // cached ByteBuffers as they may be expensive to create in terms // of Object allocation entry.Buffers = nioBufs = buf.GetIoBuffers(); } for (int i = 0; i < nioBufs.Length && nioBufferCount < maxCount; i++) { ArraySegment <byte> nioBuf = nioBufs[i]; if (nioBuf.Array == null) { break; } else if (nioBuf.Count == 0) { continue; } nioBuffers.Add(nioBuf); nioBufferCount++; } } if (nioBufferCount == maxCount) { break; } } } entry = entry.Next; } this.nioBufferSize = ioBufferSize; return(nioBuffers); }
internal static StringBuilder StringBuilder() => InternalThreadLocalMap.Get().StringBuilder;
public static IList <ICharSequence> UnescapeCsvFields(ICharSequence value) { var unescaped = new List <ICharSequence>(2); StringBuilder current = InternalThreadLocalMap.Get().StringBuilder; bool quoted = false; int last = value.Count - 1; for (int i = 0; i <= last; i++) { char c = value[i]; if (quoted) { switch (c) { case DoubleQuote: if (i == last) { // Add the last field and return unescaped.Add((StringCharSequence)current.ToString()); return(unescaped); } char next = value[++i]; if (next == DoubleQuote) { // 2 double-quotes should be unescaped to one current.Append(DoubleQuote); } else if (next == Comma) { // This is the end of a field. Let's start to parse the next field. quoted = false; unescaped.Add((StringCharSequence)current.ToString()); current.Length = 0; } else { // double-quote followed by other character is invalid throw new ArgumentException($"invalid escaped CSV field: {value} index: {i - 1}"); } break; default: current.Append(c); break; } } else { switch (c) { case Comma: // Start to parse the next field unescaped.Add((StringCharSequence)current.ToString()); current.Length = 0; break; case DoubleQuote: if (current.Length == 0) { quoted = true; } else { // double-quote appears without being enclosed with double-quotes current.Append(c); } break; case LineFeed: case CarriageReturn: // special characters appears without being enclosed with double-quotes throw new ArgumentException($"invalid escaped CSV field: {value} index: {i}"); default: current.Append(c); break; } } } if (quoted) { throw new ArgumentException($"invalid escaped CSV field: {value} index: {last}"); } unescaped.Add((StringCharSequence)current.ToString()); return(unescaped); }
/// ///Returns an array of direct NIO buffers if the currently pending messages are made of {@link ByteBuf} only. ///{@link #nioBufferCount()} and {@link #nioBufferSize()} will return the number of NIO buffers in the returned ///array and the total number of readable bytes of the NIO buffers respectively. ///<p> ///Note that the returned array is reused and thus should not escape ///{@link AbstractChannel#doWrite(ChannelOutboundBuffer)}. ///Refer to {@link NioSocketChannel#doWrite(ChannelOutboundBuffer)} for an example. ///</p> /// public List <ArraySegment <byte> > GetNioBuffers() { long nioBufferSize = 0; InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.Get(); List <ArraySegment <byte> > nioBuffers = NioBuffers.Get(threadLocalMap); Entry entry = _flushedEntry; while (IsFlushedEntry(entry) && entry.Message is IByteBuf) { if (!entry.Cancelled) { var buf = (IByteBuf)entry.Message; int readerIndex = buf.ReaderIndex; int readableBytes = buf.WriterIndex - readerIndex; if (readableBytes > 0) { if (int.MaxValue - readableBytes < nioBufferSize) { // If the nioBufferSize + readableBytes will overflow an Integer we stop populate the // ByteBuffer array. This is done as bsd/osx don't allow to write more bytes then // Integer.MAX_VALUE with one writev(...) call and so will return 'EINVAL', which will // raise an IOException. On Linux it may work depending on the // architecture and kernel but to be safe we also enforce the limit here. // This said writing more the Integer.MAX_VALUE is not a good idea anyway. // // See also: // - https://www.freebsd.org/cgi/man.cgi?query=write&sektion=2 // - http://linux.die.net/man/2/writev break; } nioBufferSize += readableBytes; int count = entry.Count; if (count == -1) { //noinspection ConstantValueVariableUse entry.Count = count = buf.IoBufferCount; } if (count == 1) { ArraySegment <byte> nioBuf = entry.Buffer; if (nioBuf.Array == null) { // cache ByteBuffer as it may need to create a new ByteBuffer instance if its a // derived buffer entry.Buffer = nioBuf = buf.GetIoBuffer(readerIndex, readableBytes); } nioBuffers.Add(nioBuf); } else { ArraySegment <byte>[] nioBufs = entry.Buffers; if (nioBufs == null) { // cached ByteBuffers as they may be expensive to create in terms // of Object allocation entry.Buffers = nioBufs = buf.GetIoBuffers(); } foreach (ArraySegment <byte> b in nioBufs) { nioBuffers.Add(b); } } } } entry = entry.Next; } this.NioBufferSize = nioBufferSize; return(nioBuffers); }