1 /* 2 * Copyright 2015 The Netty Project 3 * 4 * The Netty Project licenses this file to you under the Apache License, version 2.0 (the 5 * "License"); you may not use this file except in compliance with the License. You may obtain a 6 * copy of the License at: 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software distributed under the License 11 * is distributed on an "AS IS" ~BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 12 * or implied. See the License for the specific language governing permissions and limitations under 13 * the License. 14 */ 15 module hunt.net.buffer.ByteProcessor; 16 17 import std.concurrency : initOnce; 18 19 /** 20 * Provides a mechanism to iterate over a collection of bytes. 21 */ 22 interface ByteProcessor { 23 24 enum byte SPACE = ' '; 25 enum byte HTAB = '\t'; 26 enum byte CARRIAGE_RETURN = '\r'; 27 enum byte LINE_FEED = '\n'; 28 29 /** 30 * Aborts on a {@code NUL (0x00)}. 31 */ 32 static ByteProcessor FIND_NUL() { 33 __gshared ByteProcessor inst; 34 return initOnce!inst(new IndexOfProcessor(cast(byte) 0)); 35 } 36 37 /** 38 * Aborts on a non-{@code NUL (0x00)}. 39 */ 40 static ByteProcessor FIND_NON_NUL() { 41 __gshared ByteProcessor inst; 42 return initOnce!inst(new IndexNotOfProcessor(cast(byte) 0)); 43 } 44 45 /** 46 * Aborts on a {@code CR ('\r')}. 47 */ 48 static ByteProcessor FIND_CR() { 49 __gshared ByteProcessor inst; 50 return initOnce!inst(new IndexOfProcessor(CARRIAGE_RETURN)); 51 } 52 53 /** 54 * Aborts on a non-{@code CR ('\r')}. 55 */ 56 static ByteProcessor FIND_NON_CR() { 57 __gshared ByteProcessor inst; 58 return initOnce!inst(new IndexNotOfProcessor(CARRIAGE_RETURN)); 59 } 60 61 /** 62 * Aborts on a {@code LF ('\n')}. 63 */ 64 static ByteProcessor FIND_LF() { 65 __gshared ByteProcessor inst; 66 return initOnce!inst(new IndexOfProcessor(LINE_FEED)); 67 } 68 69 /** 70 * Aborts on a non-{@code LF ('\n')}. 71 */ 72 static ByteProcessor FIND_NON_LF() { 73 __gshared ByteProcessor inst; 74 return initOnce!inst(new IndexNotOfProcessor(LINE_FEED)); 75 } 76 77 /** 78 * Aborts on a semicolon {@code (';')}. 79 */ 80 static ByteProcessor FIND_SEMI_COLON() { 81 __gshared ByteProcessor inst; 82 return initOnce!inst(new IndexOfProcessor(cast(byte) ';')); 83 } 84 85 /** 86 * Aborts on a comma {@code (',')}. 87 */ 88 static ByteProcessor FIND_COMMA() { 89 __gshared ByteProcessor inst; 90 return initOnce!inst(new IndexOfProcessor(cast(byte) ',')); 91 } 92 93 /** 94 * Aborts on a ascii space character ({@code ' '}). 95 */ 96 static ByteProcessor FIND_ASCII_SPACE() { 97 __gshared ByteProcessor inst; 98 return initOnce!inst(new IndexOfProcessor(SPACE)); 99 } 100 101 /** 102 * Aborts on a {@code CR ('\r')} or a {@code LF ('\n')}. 103 */ 104 static ByteProcessor FIND_CRLF() { 105 __gshared ByteProcessor inst; 106 return initOnce!inst(new class ByteProcessor { 107 bool process(byte value) { 108 return value != CARRIAGE_RETURN && value != LINE_FEED; 109 } 110 }); 111 } 112 113 /** 114 * Aborts on a byte which is neither a {@code CR ('\r')} nor a {@code LF ('\n')}. 115 */ 116 static ByteProcessor FIND_NON_CRLF() { 117 __gshared ByteProcessor inst; 118 return initOnce!inst(new class ByteProcessor { 119 bool process(byte value) { 120 return value == CARRIAGE_RETURN || value == LINE_FEED; 121 } 122 }); 123 } 124 125 /** 126 * Aborts on a linear whitespace (a ({@code ' '} or a {@code '\t'}). 127 */ 128 static ByteProcessor FIND_LINEAR_WHITESPACE() { 129 __gshared ByteProcessor inst; 130 return initOnce!inst(new class ByteProcessor { 131 bool process(byte value) { 132 return value != SPACE && value != HTAB; 133 } 134 }); 135 } 136 137 /** 138 * Aborts on a byte which is not a linear whitespace (neither {@code ' '} nor {@code '\t'}). 139 */ 140 static ByteProcessor FIND_NON_LINEAR_WHITESPACE() { 141 __gshared ByteProcessor inst; 142 return initOnce!inst(new class ByteProcessor { 143 bool process(byte value) { 144 return value == SPACE || value == HTAB; 145 } 146 }); 147 } 148 149 /** 150 * @return {@code true} if the processor wants to continue the loop and handle the next byte in the buffer. 151 * {@code false} if the processor wants to stop handling bytes and abort the loop. 152 */ 153 bool process(byte value); 154 } 155 156 157 /** 158 * A {@link ByteProcessor} which finds the first appearance of a specific byte. 159 */ 160 class IndexOfProcessor : ByteProcessor { 161 private byte byteToFind; 162 163 this(byte byteToFind) { 164 this.byteToFind = byteToFind; 165 } 166 167 override 168 bool process(byte value) { 169 return value != byteToFind; 170 } 171 } 172 173 /** 174 * A {@link ByteProcessor} which finds the first appearance which is not of a specific byte. 175 */ 176 class IndexNotOfProcessor : ByteProcessor { 177 private byte byteToNotFind; 178 179 this(byte byteToNotFind) { 180 this.byteToNotFind = byteToNotFind; 181 } 182 183 override 184 bool process(byte value) { 185 return value == byteToNotFind; 186 } 187 }