From 97693b44172fa1d045d2960eb8c44d9826f1ede7 Mon Sep 17 00:00:00 2001 From: Ferdinand Majerech Date: Mon, 24 Oct 2011 00:46:35 +0200 Subject: [PATCH] Got rid of most UTF-8 decoding that took a lot of time. Removed unnecessary calls to Stream.available(), again for grat speed gain. Also various small optimizations. Overall, improved loading speed about 400%. --- dyaml/constructor.d | 6 ++- dyaml/emitter.d | 87 +++++++++++++++++------------------- dyaml/loader.d | 2 +- dyaml/node.d | 46 ++++++++++---------- dyaml/parser.d | 24 +++++----- dyaml/reader.d | 54 ++++++++++++----------- dyaml/scanner.d | 104 ++++++++++++++++++++++---------------------- 7 files changed, 159 insertions(+), 164 deletions(-) diff --git a/dyaml/constructor.d b/dyaml/constructor.d index 0c5f487..9c4beab 100644 --- a/dyaml/constructor.d +++ b/dyaml/constructor.d @@ -344,9 +344,11 @@ YAMLMerge constructMerge(Mark start, Mark end, ref Node node) ///Construct a boolean node. bool constructBool(Mark start, Mark end, ref Node node) { + static yes = ["yes", "true", "on"]; + static no = ["no", "false", "off"]; string value = node.as!string().toLower(); - if(["yes", "true", "on"].canFind(value)) {return true;} - if(["no", "false", "off"].canFind(value)){return false;} + if(yes.canFind(value)){return true;} + if(no.canFind(value)) {return false;} throw new Error("Unable to parse boolean value: " ~ value, start, end); } diff --git a/dyaml/emitter.d b/dyaml/emitter.d index 6c30360..7be48f1 100644 --- a/dyaml/emitter.d +++ b/dyaml/emitter.d @@ -14,6 +14,7 @@ module dyaml.emitter; import std.algorithm; import std.array; import std.ascii; +import std.container; import std.conv; import std.exception; import std.format; @@ -78,7 +79,7 @@ struct Emitter Encoding encoding_ = Encoding.UTF_8; ///Stack of states. - void delegate()[] states_; + Array!(void delegate()) states_; ///Current state. void delegate() state_; @@ -155,6 +156,7 @@ struct Emitter in{assert(stream.writeable, "Can't emit YAML to a non-writable stream");} body { + states_.reserve(32); stream_ = stream; canonical_ = canonical; state_ = &expectStreamStart; @@ -171,7 +173,6 @@ struct Emitter { stream_ = null; clear(states_); - states_ = null; clear(events_); clear(indents_); indents_ = null; @@ -201,8 +202,8 @@ struct Emitter { enforce(states_.length > 0, new YAMLException("Emitter: Need to pop a state but there are no states left")); - const result = states_.back(); - states_.popBack; + const result = states_.back; + states_.length = states_.length - 1; return result; } @@ -266,20 +267,12 @@ struct Emitter while(!events_.iterationOver()) { immutable event = events_.next(); - if([EventID.DocumentStart, EventID.SequenceStart, - EventID.MappingStart].canFind(event.id)) - { - ++level; - } - else if([EventID.DocumentEnd, EventID.SequenceEnd, - EventID.MappingEnd].canFind(event.id)) - { - --level; - } - else if(event.id == EventID.StreamStart) - { - level = -1; - } + static starts = [EventID.DocumentStart, EventID.SequenceStart, EventID.MappingStart]; + static ends = [EventID.DocumentEnd, EventID.SequenceEnd, EventID.MappingEnd]; + if(starts.canFind(event.id)) {++level;} + else if(ends.canFind(event.id)) {--level;} + else if(event.id == EventID.StreamStart){level = -1;} + if(level < 0) { return false; @@ -692,8 +685,8 @@ struct Emitter uint length = 0; const id = event_.id; const scalar = id == EventID.Scalar; - const collectionStart = [EventID.MappingStart, - EventID.SequenceStart].canFind(id); + const collectionStart = id == EventID.MappingStart || + id == EventID.SequenceStart; if((id == EventID.Alias || scalar || collectionStart) && !event_.anchor.isNull()) @@ -815,8 +808,8 @@ struct Emitter if(analysis_.flags.isNull){analysis_ = analyzeScalar(event_.value);} const style = event_.scalarStyle; - const invalidOrPlain = [ScalarStyle.Invalid, ScalarStyle.Plain].canFind(style); - const block = [ScalarStyle.Literal, ScalarStyle.Folded].canFind(style); + const invalidOrPlain = style == ScalarStyle.Invalid || style == ScalarStyle.Plain; + const block = style == ScalarStyle.Literal || style == ScalarStyle.Folded; const singleQuoted = style == ScalarStyle.SingleQuoted; const doubleQuoted = style == ScalarStyle.DoubleQuoted; @@ -880,7 +873,7 @@ struct Emitter if(handle.length > 1) foreach(const dchar c; handle[1 .. $ - 1]) { - enforce(isAlphaNum(c) || "-_".canFind(c), + enforce(isAlphaNum(c) || "-_"d.canFind(c), new Error("Invalid character: " ~ to!string(c) ~ " in tag handle " ~ handle)); } @@ -901,7 +894,7 @@ struct Emitter foreach(const size_t i, const dchar c; prefix) { const size_t idx = i + offset; - if(isAlphaNum(c) || "-;/?:@&=+$,_.!~*\'()[]%".canFind(c)) + if(isAlphaNum(c) || "-;/?:@&=+$,_.!~*\'()[]%"d.canFind(c)) { end = idx + 1; continue; @@ -947,7 +940,7 @@ struct Emitter size_t end = 0; foreach(const dchar c; suffix) { - if(isAlphaNum(c) || "-;/?:@&=+$,_.~*\'()[]".canFind(c) || + if(isAlphaNum(c) || "-;/?:@&=+$,_.~*\'()[]"d.canFind(c) || (c == '!' && handle != "!")) { ++end; @@ -973,7 +966,7 @@ struct Emitter const str = anchor.get; foreach(const dchar c; str) { - enforce(isAlphaNum(c) || "-_".canFind(c), + enforce(isAlphaNum(c) || "-_"d.canFind(c), new Error("Invalid character: " ~ to!string(c) ~ " in anchor: " ~ str)); } return str; @@ -1017,7 +1010,7 @@ struct Emitter //Last character or followed by a whitespace. bool followedByWhitespace = scalar.length == 1 || - " \t\0\n\r\u0085\u2028\u2029".canFind(scalar[1]); + " \t\0\n\r\u0085\u2028\u2029"d.canFind(scalar[1]); //The previous character is a space/break (false by default). bool previousSpace, previousBreak; @@ -1028,11 +1021,11 @@ struct Emitter if(index == 0) { //Leading indicators are special characters. - if("#,[]{}&*!|>\'\"%@`".canFind(c)) + if("#,[]{}&*!|>\'\"%@`"d.canFind(c)) { flowIndicators = blockIndicators = true; } - if("?:".canFind(c)) + if("?:"d.canFind(c)) { flowIndicators = true; if(followedByWhitespace){blockIndicators = true;} @@ -1045,7 +1038,7 @@ struct Emitter else { //Some indicators cannot appear within a scalar as well. - if(",?[]{}".canFind(c)){flowIndicators = true;} + if(",?[]{}"d.canFind(c)){flowIndicators = true;} if(c == ':') { flowIndicators = true; @@ -1058,7 +1051,7 @@ struct Emitter } //Check for line breaks, special, and unicode characters. - if("\n\u0085\u2028\u2029".canFind(c)){lineBreaks = true;} + if("\n\u0085\u2028\u2029"d.canFind(c)){lineBreaks = true;} if(!(c == '\n' || (c >= '\x20' && c <= '\x7E')) && !((c == '\u0085' || (c >= '\xA0' && c <= '\uD7FF') || (c >= '\uE000' && c <= '\uFFFD')) && c != '\uFEFF')) @@ -1075,7 +1068,7 @@ struct Emitter previousSpace = true; previousBreak = false; } - else if("\n\u0085\u2028\u2029".canFind(c)) + else if("\n\u0085\u2028\u2029"d.canFind(c)) { if(index == 0){leadingBreak = true;} if(index == scalar.length - 1){trailingBreak = true;} @@ -1089,9 +1082,9 @@ struct Emitter } //Prepare for the next character. - preceededByWhitespace = "\0\n\r\u0085\u2028\u2029 \t".canFind(c); + preceededByWhitespace = "\0\n\r\u0085\u2028\u2029 \t"d.canFind(c); followedByWhitespace = index + 2 >= scalar.length || - "\0\n\r\u0085\u2028\u2029 \t".canFind(scalar[index + 2]); + "\0\n\r\u0085\u2028\u2029 \t"d.canFind(scalar[index + 2]); } with(analysis.flags) @@ -1317,14 +1310,14 @@ struct ScalarWriter } else if(breaks_) { - if(!"\n\u0085\u2028\u2029".canFind(c)) + if(!"\n\u0085\u2028\u2029"d.canFind(c)) { writeStartLineBreak(); writeLineBreaks(); emitter_.writeIndent(); } } - else if((c == dcharNone || "\' \n\u0085\u2028\u2029".canFind(c)) + else if((c == dcharNone || "\' \n\u0085\u2028\u2029"d.canFind(c)) && startChar_ < endChar_) { writeCurrentRange(Flag!"UpdateColumn".yes); @@ -1350,7 +1343,7 @@ struct ScalarWriter { const dchar c = nextChar(); //handle special characters - if(c == dcharNone || "\"\\\u0085\u2028\u2029\uFEFF".canFind(c) || + if(c == dcharNone || "\"\\\u0085\u2028\u2029\uFEFF"d.canFind(c) || !((c >= '\x20' && c <= '\x7E') || ((c >= '\xA0' && c <= '\uD7FF') || (c >= '\uE000' && c <= '\uFFFD')))) { @@ -1417,7 +1410,7 @@ struct ScalarWriter const dchar c = nextChar(); if(breaks_) { - if(!"\n\u0085\u2028\u2029".canFind(c)) + if(!"\n\u0085\u2028\u2029"d.canFind(c)) { if(!leadingSpace && c != dcharNone && c != ' ') { @@ -1440,7 +1433,7 @@ struct ScalarWriter writeCurrentRange(Flag!"UpdateColumn".yes); } } - else if(c == dcharNone || " \n\u0085\u2028\u2029".canFind(c)) + else if(c == dcharNone || " \n\u0085\u2028\u2029"d.canFind(c)) { writeCurrentRange(Flag!"UpdateColumn".yes); if(c == dcharNone){emitter_.writeLineBreak();} @@ -1461,13 +1454,13 @@ struct ScalarWriter const dchar c = nextChar(); if(breaks_) { - if(!"\n\u0085\u2028\u2029".canFind(c)) + if(!"\n\u0085\u2028\u2029"d.canFind(c)) { writeLineBreaks(); if(c != dcharNone){emitter_.writeIndent();} } } - else if(c == dcharNone || "\n\u0085\u2028\u2029".canFind(c)) + else if(c == dcharNone || "\n\u0085\u2028\u2029"d.canFind(c)) { writeCurrentRange(Flag!"UpdateColumn".no); if(c == dcharNone){emitter_.writeLineBreak();} @@ -1507,14 +1500,14 @@ struct ScalarWriter } else if(breaks_) { - if(!"\n\u0085\u2028\u2029".canFind(c)) + if(!"\n\u0085\u2028\u2029"d.canFind(c)) { writeStartLineBreak(); writeLineBreaks(); writeIndent(Flag!"ResetSpace".yes); } } - else if(c == dcharNone || " \n\u0085\u2028\u2029".canFind(c)) + else if(c == dcharNone || " \n\u0085\u2028\u2029"d.canFind(c)) { writeCurrentRange(Flag!"UpdateColumn".yes); } @@ -1562,16 +1555,16 @@ struct ScalarWriter const last = lastChar(text_, end); const secondLast = end > 0 ? lastChar(text_, end) : 0; - if(" \n\u0085\u2028\u2029".canFind(text_[0])) + if(" \n\u0085\u2028\u2029"d.canFind(text_[0])) { hints[hintsIdx++] = cast(char)('0' + bestIndent); } - if(!"\n\u0085\u2028\u2029".canFind(last)) + if(!"\n\u0085\u2028\u2029"d.canFind(last)) { hints[hintsIdx++] = '-'; } else if(std.utf.count(text_) == 1 || - "\n\u0085\u2028\u2029".canFind(secondLast)) + "\n\u0085\u2028\u2029"d.canFind(secondLast)) { hints[hintsIdx++] = '+'; } @@ -1643,7 +1636,7 @@ struct ScalarWriter void updateBreaks(in dchar c, in Flag!"UpdateSpaces" updateSpaces) { if(c == dcharNone){return;} - breaks_ = "\n\u0085\u2028\u2029".canFind(c); + breaks_ = "\n\u0085\u2028\u2029"d.canFind(c); if(updateSpaces){spaces_ = c == ' ';} } diff --git a/dyaml/loader.d b/dyaml/loader.d index 112285a..2a67417 100644 --- a/dyaml/loader.d +++ b/dyaml/loader.d @@ -127,7 +127,7 @@ struct Loader /** * Construct a Loader to load YAML from a _stream. * - * Params: stream = Stream to read from. Must be readable. + * Params: stream = Stream to read from. Must be readable and seekable. * * Throws: YAMLException if stream could not be read. */ diff --git a/dyaml/node.d b/dyaml/node.d index e7b6cf9..0449949 100644 --- a/dyaml/node.d +++ b/dyaml/node.d @@ -666,11 +666,11 @@ struct Node Node k3 = Node("13"); Node k4 = Node("14"); - Node narray = Node(Value([n1, n2, n3, n4])); - Node nmap = Node(Value([Pair(k1, n1), - Pair(k2, n2), - Pair(k3, n3), - Pair(k4, n4)])); + Node narray = Node([n1, n2, n3, n4]); + Node nmap = Node([Pair(k1, n1), + Pair(k2, n2), + Pair(k3, n3), + Pair(k4, n4)]); assert(narray[0].as!int == 11); assert(null !is collectException(narray[42])); @@ -793,7 +793,7 @@ struct Node Node n2 = Node(Value(cast(long)12)); Node n3 = Node(Value(cast(long)13)); Node n4 = Node(Value(cast(long)14)); - Node narray = Node(Value([n1, n2, n3, n4])); + Node narray = Node([n1, n2, n3, n4]); int[] array, array2; foreach(int value; narray) @@ -858,20 +858,20 @@ struct Node alias Node.Value Value; alias Node.Pair Pair; - Node n1 = Node(Value(cast(long)11)); - Node n2 = Node(Value(cast(long)12)); - Node n3 = Node(Value(cast(long)13)); - Node n4 = Node(Value(cast(long)14)); + Node n1 = Node(cast(long)11); + Node n2 = Node(cast(long)12); + Node n3 = Node(cast(long)13); + Node n4 = Node(cast(long)14); - Node k1 = Node(Value("11")); - Node k2 = Node(Value("12")); - Node k3 = Node(Value("13")); - Node k4 = Node(Value("14")); + Node k1 = Node("11"); + Node k2 = Node("12"); + Node k3 = Node("13"); + Node k4 = Node("14"); - Node nmap1 = Node(Value([Pair(k1, n1), - Pair(k2, n2), - Pair(k3, n3), - Pair(k4, n4)])); + Node nmap1 = Node([Pair(k1, n1), + Pair(k2, n2), + Pair(k3, n3), + Pair(k4, n4)]); int[string] expected = ["11" : 11, "12" : 12, @@ -884,10 +884,10 @@ struct Node } assert(array == expected); - Node nmap2 = Node(Value([Pair(k1, Node(Value(cast(long)5))), - Pair(k2, Node(Value(true))), - Pair(k3, Node(Value(cast(real)1.0))), - Pair(k4, Node(Value("yarly")))])); + Node nmap2 = Node([Pair(k1, Node(cast(long)5)), + Pair(k2, Node(true)), + Pair(k3, Node(cast(real)1.0)), + Pair(k4, Node("yarly"))]); foreach(string key, Node value; nmap2) { @@ -1073,7 +1073,7 @@ struct Node auto idx = findPair(index); if(idx >= 0) { - auto pairs = as!(Node.Pair[])(); + auto pairs = get!(Node.Pair[])(); moveAll(pairs[idx + 1 .. $], pairs[idx .. $ - 1]); pairs.length = pairs.length - 1; value_ = Value(pairs); diff --git a/dyaml/parser.d b/dyaml/parser.d index 2e3790d..7b32a79 100644 --- a/dyaml/parser.d +++ b/dyaml/parser.d @@ -122,7 +122,7 @@ final class Parser ///YAML version string. string YAMLVersion_ = null; ///Tag handle shortcuts and replacements. - tagDirective[] tagHandles_; + tagDirective[] tagDirectives_; ///Stack of states. Array!(Event delegate()) states_; @@ -146,8 +146,8 @@ final class Parser ~this() { clear(currentEvent_); - clear(tagHandles_); - tagHandles_ = null; + clear(tagDirectives_); + tagDirectives_ = null; clear(states_); clear(marks_); } @@ -266,7 +266,7 @@ final class Parser if(!scanner_.checkToken(TokenID.Directive, TokenID.DocumentStart, TokenID.StreamEnd)) { - tagHandles_ = defaultTagDirectives_; + tagDirectives_ = defaultTagDirectives_; immutable token = scanner_.peekToken(); states_ ~= &parseDocumentEnd; @@ -339,7 +339,7 @@ final class Parser { //Destroy version and tag handles from previous document. YAMLVersion_ = null; - tagHandles_.length = 0; + tagDirectives_.length = 0; //Process directives. while(scanner_.checkToken(TokenID.Directive)) @@ -363,7 +363,7 @@ final class Parser assert(parts.length == 3, "Tag directive stored incorrectly in a token"); auto handle = parts[1]; - foreach(ref pair; tagHandles_) + foreach(ref pair; tagDirectives_) { //handle auto h = pair[0]; @@ -371,17 +371,17 @@ final class Parser enforce(h != handle, new Error("Duplicate tag handle: " ~ handle, token.startMark)); } - tagHandles_ ~= tagDirective(handle, parts[2]); + tagDirectives_ ~= tagDirective(handle, parts[2]); } } - TagDirectives value = tagHandles_.length == 0 ? TagDirectives() : TagDirectives(tagHandles_); + TagDirectives value = tagDirectives_.length == 0 ? TagDirectives() : TagDirectives(tagDirectives_); //Add any default tag handles that haven't been overridden. foreach(ref defaultPair; defaultTagDirectives_) { bool found = false; - foreach(ref pair; tagHandles_) + foreach(ref pair; tagDirectives_) { if(defaultPair[0] == pair[0] ) { @@ -389,7 +389,7 @@ final class Parser break; } } - if(!found){tagHandles_ ~= defaultPair;} + if(!found){tagDirectives_ ~= defaultPair;} } return value; @@ -541,7 +541,7 @@ final class Parser if(handle.length > 0) { string replacement = null; - foreach(ref pair; tagHandles_) + foreach(ref pair; tagDirectives_) { //pair[0] is handle, pair[1] replacement. if(pair[0] == handle) @@ -550,7 +550,7 @@ final class Parser break; } } - //handle must be in tagHandles_ + //handle must be in tagDirectives_ enforce(replacement !is null, new Error("While parsing a node", startMark, "found undefined tag handle: " ~ handle, tagMark)); diff --git a/dyaml/reader.d b/dyaml/reader.d index 1f96703..7687859 100644 --- a/dyaml/reader.d +++ b/dyaml/reader.d @@ -51,6 +51,8 @@ final class Reader uint line_; ///Current column in file. uint column_; + ///Number of bytes still available (not read) in the stream. + size_t available_; ///Capacity of raw buffers. static immutable bufferLength8_ = 8; @@ -60,9 +62,9 @@ final class Reader union { ///Buffer to hold UTF-8 data before decoding. - char[bufferLength8_] rawBuffer8_; + char[bufferLength8_ + 1] rawBuffer8_; ///Buffer to hold UTF-16 data before decoding. - wchar[bufferLength16_] rawBuffer16_; + wchar[bufferLength16_ + 1] rawBuffer16_; } ///Number of elements held in the used raw buffer. uint rawUsed_ = 0; @@ -71,18 +73,23 @@ final class Reader /** * Construct a Reader. * - * Params: stream = Input stream. Must be readable. + * Params: stream = Input stream. Must be readable and seekable. * * Throws: ReaderException if the stream is invalid. */ this(Stream stream) - in{assert(stream.readable, "Can't read YAML from a non-readable stream");} + in + { + assert(stream.readable && stream.seekable, + "Can't read YAML from a stream that is not readable and seekable"); + } body { stream_ = new EndianStream(stream); + available_ = stream_.available; //handle files short enough not to have a BOM - if(stream_.available < 2) + if(available_ < 2) { encoding_ = Encoding.UTF_8; return; @@ -104,16 +111,17 @@ final class Reader encoding_ = Encoding.UTF_16; rawBuffer16_[0] = stream_.getcw(); rawUsed_ = 1; - enforce(stream_.available % 2 == 0, + enforce(available_ % 2 == 0, new ReaderException("Odd byte count in an UTF-16 stream")); break; case 3, 4: - enforce(stream_.available % 4 == 0, + enforce(available_ % 4 == 0, new ReaderException("Byte count in an UTF-32 stream not divisible by 4")); encoding_ = Encoding.UTF_32; break; default: assert(false, "Unknown UTF BOM"); } + available_ = stream_.available; } ///Destroy the Reader. @@ -209,7 +217,7 @@ final class Reader void forward(size_t length = 1) { //This is here due to optimization. - static newlines = "\n\u0085\u2028\u2029"; + static newlines = "\n\u0085\u2028\u2029"d; updateBuffer(length + 1); while(length > 0) @@ -294,16 +302,10 @@ final class Reader * if nonprintable characters are detected, or * if there is an error reading from the stream. */ - void loadChars(uint chars) + void loadChars(size_t chars) { - /** - * Get next character from the stream. - * - * Params: available = Bytes available in the stream. - * - * Returns: Next character in the stream. - */ - dchar getDChar(in size_t available) + ///Get next character from the stream. + dchar getDChar() { switch(encoding_) { @@ -317,13 +319,14 @@ final class Reader const dchar result = rawBuffer8_[0]; --rawUsed_; //Move the data. - temp[0 .. rawUsed_] = rawBuffer8_[1 .. rawUsed_ + 1]; - rawBuffer8_[0 .. rawUsed_] = temp[0 .. rawUsed_]; + *(cast(ulong*)temp.ptr) = *(cast(ulong*)(rawBuffer8_.ptr + 1)); + *(cast(ulong*)rawBuffer8_.ptr) = *(cast(ulong*)temp.ptr); return result; } //Bytes to read. - const readBytes = min(available, bufferLength8_ - rawUsed_); + const readBytes = min(available_, bufferLength8_ - rawUsed_); + available_ -= readBytes; //Length of data in rawBuffer8_ after reading. const len = rawUsed_ + readBytes; //Read the data. @@ -342,7 +345,8 @@ final class Reader //Temp buffer for moving data in rawBuffer8_. wchar[bufferLength16_] temp; //Words to read. - size_t readWords = min(available / 2, bufferLength16_ - rawUsed_); + size_t readWords = min(available_ / 2, bufferLength16_ - rawUsed_); + available_ -= readWords * 2; //Length of data in rawBuffer16_ after reading. size_t len = rawUsed_; //Read the data. @@ -365,6 +369,7 @@ final class Reader return result; case Encoding.UTF_32: dchar result; + available_ -= 4; stream_.read(result); return result; default: assert(false); @@ -374,13 +379,11 @@ final class Reader const oldLength = buffer_.length; const oldPosition = stream_.position; - //Preallocating memory to limit GC reallocations. buffer_.length = buffer_.length + chars; scope(exit) { buffer_.length = buffer_.length - chars; - enforce(printable(buffer_[oldLength .. $]), new ReaderException("Special unicode characters are not allowed")); } @@ -388,8 +391,7 @@ final class Reader try for(uint c = 0; chars; --chars, ++c) { if(done){break;} - const available = stream_.available; - buffer_[oldLength + c] = getDChar(available); + buffer_[oldLength + c] = getDChar(); } catch(UtfException e) { @@ -428,7 +430,7 @@ final class Reader ///Are we done reading? @property bool done() { - return (stream_.available == 0 && + return (available_ == 0 && ((encoding_ == Encoding.UTF_8 && rawUsed_ == 0) || (encoding_ == Encoding.UTF_16 && rawUsed_ == 0) || encoding_ == Encoding.UTF_32)); diff --git a/dyaml/scanner.d b/dyaml/scanner.d index 52c2206..99564d2 100644 --- a/dyaml/scanner.d +++ b/dyaml/scanner.d @@ -690,7 +690,7 @@ final class Scanner return reader_.column == 0 && reader_.peek() == '-' && reader_.prefix(3) == "---" && - " \t\0\n\r\u0085\u2028\u2029".canFind(reader_.peek(3)); + " \t\0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek(3)); } ///Check if the next token is DOCUMENT-END: ^ '...' (' '|'\n') @@ -700,14 +700,14 @@ final class Scanner return reader_.column == 0 && reader_.peek() == '.' && reader_.prefix(3) == "..." && - " \t\0\n\r\u0085\u2028\u2029".canFind(reader_.peek(3)); + " \t\0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek(3)); } ///Check if the next token is BLOCK-ENTRY: '-' (' '|'\n') bool checkBlockEntry() { return reader_.peek() == '-' && - " \t\0\n\r\u0085\u2028\u2029".canFind(reader_.peek(1)); + " \t\0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek(1)); } /** @@ -719,7 +719,7 @@ final class Scanner { return reader_.peek() == '?' && (flowLevel_ > 0 || - " \t\0\n\r\u0085\u2028\u2029".canFind(reader_.peek(1))); + " \t\0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek(1))); } /** @@ -731,7 +731,7 @@ final class Scanner { return reader_.peek() == ':' && (flowLevel_ > 0 || - " \t\0\n\r\u0085\u2028\u2029".canFind(reader_.peek(1))); + " \t\0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek(1))); } /** @@ -753,9 +753,9 @@ final class Scanner bool checkPlain() { const c = reader_.peek(); - return !("-?:,[]{}#&*!|>\'\"%@` \t\0\n\r\u0085\u2028\u2029".canFind(c)) || - (!" \t\0\n\r\u0085\u2028\u2029".canFind(reader_.peek(1)) && - (c == '-' || (flowLevel_ == 0 && "?:".canFind(c)))); + return !("-?:,[]{}#&*!|>\'\"%@` \t\0\n\r\u0085\u2028\u2029"d.canFind(c)) || + (!" \t\0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek(1)) && + (c == '-' || (flowLevel_ == 0 && "?:"d.canFind(c)))); } @@ -770,7 +770,7 @@ final class Scanner { uint length = 0; dchar c = reader_.peek(); - while(isAlphaNum(c) || "-_".canFind(c)) + while(isAlphaNum(c) || "-_"d.canFind(c)) { ++length; c = reader_.peek(length); @@ -788,7 +788,7 @@ final class Scanner dstring scanToNextBreak() { uint length = 0; - while(!"\0\n\r\u0085\u2028\u2029".canFind(reader_.peek(length))){++length;} + while(!"\0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek(length))){++length;} return reader_.get(length); } @@ -855,7 +855,7 @@ final class Scanner //Scan directive name. const name = scanAlphaNumeric!"a directive"(startMark); - enforce(" \0\n\r\u0085\u2028\u2029".canFind(reader_.peek()), + enforce(" \0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek()), new Error("While scanning a directive", startMark, "expected alphanumeric, - or _, but found " ~ to!string(reader_.peek()), reader_.mark)); @@ -876,7 +876,7 @@ final class Scanner reader_.forward(); result ~= '.' ~ scanYAMLDirectiveNumber(startMark); - enforce(" \0\n\r\u0085\u2028\u2029".canFind(reader_.peek()), + enforce(" \0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek()), new Error("While scanning a directive", startMark, "expected a digit or '.', but found: " ~ to!string(reader_.peek()), reader_.mark)); @@ -922,7 +922,7 @@ final class Scanner dstring scanTagDirectivePrefix(in Mark startMark) { const value = scanTagURI("directive", startMark); - enforce(" \0\n\r\u0085\u2028\u2029".canFind(reader_.peek()), + enforce(" \0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek()), new Error("While scanning a directive prefix", startMark, "expected ' ', but found" ~ to!string(reader_.peek()), reader_.mark)); @@ -935,7 +935,7 @@ final class Scanner { findNextNonSpace(); if(reader_.peek() == '#'){scanToNextBreak();} - enforce("\0\n\r\u0085\u2028\u2029".canFind(reader_.peek()), + enforce("\0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek()), new Error("While scanning a directive", startMark, "expected comment or a line break, but found" ~ to!string(reader_.peek()), reader_.mark)); @@ -964,7 +964,7 @@ final class Scanner dstring value = i == '*' ? scanAlphaNumeric!("an alias")(startMark) : scanAlphaNumeric!("an anchor")(startMark); - enforce((" \t\0\n\r\u0085\u2028\u2029".canFind(reader_.peek()) || + enforce((" \t\0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek()) || ("?:,]}%@").canFind(reader_.peek())), new Error("While scanning an " ~ (i == '*') ? "alias" : "anchor", startMark, "expected alphanumeric, - or _, but found "~ @@ -999,7 +999,7 @@ final class Scanner reader_.mark)); reader_.forward(); } - else if(" \t\0\n\r\u0085\u2028\u2029".canFind(c)) + else if(" \t\0\n\r\u0085\u2028\u2029"d.canFind(c)) { suffix = "!"; reader_.forward(); @@ -1009,7 +1009,7 @@ final class Scanner uint length = 1; bool useHandle = false; - while(!" \0\n\r\u0085\u2028\u2029".canFind(c)) + while(!" \0\n\r\u0085\u2028\u2029"d.canFind(c)) { if(c == '!') { @@ -1030,7 +1030,7 @@ final class Scanner suffix = scanTagURI("tag", startMark); } - enforce(" \0\n\r\u0085\u2028\u2029".canFind(reader_.peek()), + enforce(" \0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek()), new Error("While scanning a tag", startMark, "expected ' ' but found" ~ to!string(reader_.peek()), reader_.mark)); @@ -1078,7 +1078,7 @@ final class Scanner while(reader_.column == indent && reader_.peek() != '\0') { appender_.put(breaks); - const bool leadingNonSpace = !" \t".canFind(reader_.peek()); + const bool leadingNonSpace = !" \t"d.canFind(reader_.peek()); appender_.put(scanToNextBreak()); lineBreak = ""d ~ scanLineBreak(); @@ -1092,7 +1092,7 @@ final class Scanner //This is the folding according to the specification: if(style == ScalarStyle.Folded && lineBreak == "\n" && - leadingNonSpace && !" \t".canFind(reader_.peek())) + leadingNonSpace && !" \t"d.canFind(reader_.peek())) { if(breaks.length == 0){appender_.put(' ');} } @@ -1128,7 +1128,7 @@ final class Scanner ///Get chomping indicator, if detected. Return false otherwise. bool getChomping() { - if(!"+-".canFind(c)){return false;} + if(!"+-"d.canFind(c)){return false;} chomping = c == '+' ? Chomping.Keep : Chomping.Strip; reader_.forward(); c = reader_.peek(); @@ -1153,7 +1153,7 @@ final class Scanner if(getChomping()) {getIncrement();} else if(getIncrement()){getChomping();} - enforce(" \0\n\r\u0085\u2028\u2029".canFind(c), + enforce(" \0\n\r\u0085\u2028\u2029"d.canFind(c), new Error("While scanning a block scalar", startMark, "expected chomping or indentation indicator, but found " ~ to!string(c), reader_.mark)); @@ -1167,7 +1167,7 @@ final class Scanner findNextNonSpace(); if(reader_.peek == '#'){scanToNextBreak();} - enforce("\0\n\r\u0085\u2028\u2029".canFind(reader_.peek()), + enforce("\0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek()), new Error("While scanning a block scalar", startMark, "expected a comment or a line break, but found " ~ to!string(reader_.peek()), reader_.mark)); @@ -1181,7 +1181,7 @@ final class Scanner uint maxIndent; Mark endMark = reader_.mark; - while(" \n\r\u0085\u2028\u2029".canFind(reader_.peek())) + while(" \n\r\u0085\u2028\u2029"d.canFind(reader_.peek())) { if(reader_.peek() != ' ') { @@ -1205,7 +1205,7 @@ final class Scanner for(;;) { while(reader_.column < indent && reader_.peek() == ' '){reader_.forward();} - if(!"\n\r\u0085\u2028\u2029".canFind(reader_.peek())){break;} + if(!"\n\r\u0085\u2028\u2029"d.canFind(reader_.peek())){break;} chunks ~= scanLineBreak(); endMark = reader_.mark; } @@ -1242,7 +1242,7 @@ final class Scanner { dchar c = reader_.peek(); uint length = 0; - while(!(" \t\0\n\r\u0085\u2028\u2029".canFind(c) || "\'\"\\".canFind(c))) + while(!(" \t\0\n\r\u0085\u2028\u2029\'\"\\"d.canFind(c))) { ++length; c = reader_.peek(length); @@ -1258,7 +1258,7 @@ final class Scanner reader_.forward(2); } else if((quotes == ScalarStyle.DoubleQuoted && c == '\'') || - (quotes == ScalarStyle.SingleQuoted && "\"\\".canFind(c))) + (quotes == ScalarStyle.SingleQuoted && "\"\\"d.canFind(c))) { appender_.put(c); reader_.forward(); @@ -1290,17 +1290,16 @@ final class Scanner dstring hex = reader_.get(length); appender_.put(cast(dchar)parse!int(hex, 16)); } - else if("\n\r\u0085\u2028\u2029".canFind(c)) + else if("\n\r\u0085\u2028\u2029"d.canFind(c)) { scanLineBreak(); appender_.put(scanFlowScalarBreaks(startMark)); } else { - throw new Error("While scanning a double quoted scalar", - startMark, - "found unknown escape character: " ~ - to!string(c), reader_.mark); + throw new Error("While scanning a double quoted scalar", startMark, + "found unknown escape character: " ~ to!string(c), + reader_.mark); } } else @@ -1314,15 +1313,14 @@ final class Scanner void scanFlowScalarSpaces(in Mark startMark) { uint length = 0; - while(" \t".canFind(reader_.peek(length))){++length;} + while(" \t"d.canFind(reader_.peek(length))){++length;} const whitespaces = reader_.get(length); dchar c = reader_.peek(); - enforce(c != '\0', - new Error("While scanning a quoted scalar", startMark, - "found unexpected end of stream", reader_.mark)); + enforce(c != '\0', new Error("While scanning a quoted scalar", startMark, + "found unexpected end of stream", reader_.mark)); - if("\n\r\u0085\u2028\u2029".canFind(c)) + if("\n\r\u0085\u2028\u2029"d.canFind(c)) { const lineBreak = scanLineBreak(); const breaks = scanFlowScalarBreaks(startMark); @@ -1343,15 +1341,15 @@ final class Scanner //Instead of checking indentation, we check for document separators. const prefix = reader_.prefix(3); if((prefix == "---" || prefix == "...") && - " \t\0\n\r\u0085\u2028\u2029".canFind(reader_.peek(3))) + " \t\0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek(3))) { throw new Error("While scanning a quoted scalar", startMark, "found unexpected document separator", reader_.mark); } - while(" \t".canFind(reader_.peek())){reader_.forward();} + while(" \t"d.canFind(reader_.peek())){reader_.forward();} - if("\n\r\u0085\u2028\u2029".canFind(reader_.peek())) + if("\n\r\u0085\u2028\u2029"d.canFind(reader_.peek())) { appender.put(scanLineBreak()); } @@ -1384,18 +1382,18 @@ final class Scanner for(;;) { c = reader_.peek(length); - bool done = " \t\0\n\r\u0085\u2028\u2029".canFind(c) || + bool done = " \t\0\n\r\u0085\u2028\u2029"d.canFind(c) || (flowLevel_ == 0 && c == ':' && - " \t\0\n\r\u0085\u2028\u2029".canFind(reader_.peek(length + 1))) || - (flowLevel_ > 0 && ",:?[]{}".canFind(c)); + " \t\0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek(length + 1))) || + (flowLevel_ > 0 && ",:?[]{}"d.canFind(c)); if(done){break;} ++length; } //It's not clear what we should do with ':' in the flow context. if(flowLevel_ > 0 && c == ':' && - !" \t\0\n\r\u0085\u2028\u2029".canFind(reader_.peek(length + 1)) && - !",[]{}".canFind(reader_.peek(length + 1))) + !" \t\0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek(length + 1)) && + !",[]{}"d.canFind(reader_.peek(length + 1))) { reader_.forward(length); throw new Error("While scanning a plain scalar", startMark, @@ -1434,7 +1432,7 @@ final class Scanner dstring whitespaces = reader_.get(length); dchar c = reader_.peek(); - if("\n\r\u0085\u2028\u2029".canFind(c)) + if("\n\r\u0085\u2028\u2029"d.canFind(c)) { const lineBreak = scanLineBreak(); allowSimpleKey_ = true; @@ -1442,13 +1440,13 @@ final class Scanner bool end() { return ["---"d, "..."d].canFind(reader_.prefix(3)) && - " \t\0\n\r\u0085\u2028\u2029".canFind(reader_.peek(3)); + " \t\0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek(3)); } if(end()){return "";} dstring breaks; - while(" \n\r\u0085\u2028\u2029".canFind(reader_.peek())) + while(" \n\r\u0085\u2028\u2029"d.canFind(reader_.peek())) { if(reader_.peek() == ' '){reader_.forward();} else @@ -1482,7 +1480,7 @@ final class Scanner c = reader_.peek(length); if(c != ' ') { - while(isAlphaNum(c) || "-_".canFind(c)) + while(isAlphaNum(c) || "-_"d.canFind(c)) { ++length; c = reader_.peek(length); @@ -1508,7 +1506,7 @@ final class Scanner uint length = 0; dchar c = reader_.peek(); - while(isAlphaNum(c) || "-;/?:@&=+$,_.!~*\'()[]%".canFind(c)) + while(isAlphaNum(c) || "-;/?:@&=+$,_.!~*\'()[]%"d.canFind(c)) { if(c == '%') { @@ -1594,13 +1592,13 @@ final class Scanner { const c = reader_.peek(); - if("\r\n\u0085".canFind(c)) + if("\r\n\u0085"d.canFind(c)) { - if(reader_.prefix(2) == "\r\n"){reader_.forward(2);} + if(reader_.prefix(2) == "\r\n"d){reader_.forward(2);} else{reader_.forward();} return '\n'; } - if("\u2028\u2029".canFind(c)) + if("\u2028\u2029"d.canFind(c)) { reader_.forward(); return c;