diff --git a/source/dyaml/reader.d b/source/dyaml/reader.d index 16c5fb0..08a96de 100644 --- a/source/dyaml/reader.d +++ b/source/dyaml/reader.d @@ -134,7 +134,6 @@ final class Reader new ReaderException(validateResult.msg ~ validateResult.sequence.to!string)); - this.sliceBuilder = SliceBuilder(this); this.sliceBuilder8 = SliceBuilder8(this); } @@ -301,7 +300,6 @@ final class Reader } /// Used to build slices of read data in Reader; to avoid allocations. - SliceBuilder sliceBuilder; SliceBuilder8 sliceBuilder8; /// Get a string describing current buffer position, used for error messages. @@ -627,254 +625,9 @@ private: } } -/// Used to build slices of already read data in Reader buffer, avoiding allocations. -/// -/// Usually these slices point to unchanged Reader data, but sometimes the data is -/// changed due to how YAML interprets certain characters/strings. -/// -/// See begin() documentation. -struct SliceBuilder -{ -private: - // No copying by the user. - @disable this(this); - @disable void opAssign(ref SliceBuilder); - - // Reader this builder works in. - Reader reader_; - - // Start of the slice om reader_.buffer_ (size_t.max while no slice being build) - size_t start_ = size_t.max; - // End of the slice om reader_.buffer_ (size_t.max while no slice being build) - size_t end_ = size_t.max; - - // Stack of slice ends to revert to (see Transaction) - // - // Very few levels as we don't want arbitrarily nested transactions. - size_t[4] endStack_; - // The number of elements currently in endStack_. - size_t endStackUsed_ = 0; - - @safe pure nothrow const @nogc invariant() - { - if(!inProgress) { return; } - assert(end_ <= reader_.bufferOffset_, "Slice ends after buffer position"); - assert(start_ <= end_, "Slice start after slice end"); - } - - // Is a slice currently being built? - bool inProgress() @safe pure nothrow const @nogc - { - assert(start_ == size_t.max ? end_ == size_t.max : - end_ != size_t.max, "start_/end_ are not consistent"); - return start_ != size_t.max; - } - -public: - /// Begin building a slice. - /// - /// Only one slice can be built at any given time; before beginning a new slice, - /// finish the previous one (if any). - /// - /// The slice starts at the current position in the Reader buffer. It can only be - /// extended up to the current position in the buffer; Reader methods get() and - /// forward() move the position. E.g. it is valid to extend a slice by write()-ing - /// a string just returned by get() - but not one returned by prefix() unless the - /// position has changed since the prefix() call. - void begin() @system pure nothrow @nogc - { - assert(!inProgress, "Beginning a slice while another slice is being built"); - assert(endStackUsed_ == 0, "Slice stack not empty at slice begin"); - - start_ = reader_.bufferOffset_; - end_ = reader_.bufferOffset_; - } - - /// Finish building a slice and return it. - /// - /// Any Transactions on the slice must be committed or destroyed before the slice - /// is finished. - /// - /// Returns a string; once a slice is finished it is definitive that its contents - /// will not be changed. - dstring finish() @system pure nothrow @nogc - { - assert(inProgress, "finish called without begin"); - assert(endStackUsed_ == 0, "Finishing a slice with running transactions."); - - const result = reader_.buffer_[start_ .. end_]; - start_ = end_ = size_t.max; - return cast(dstring)result; - } - - /// Write a string to the slice being built. - /// - /// Data can only be written up to the current position in the Reader buffer. - /// - /// If str is a string returned by a Reader method, and str starts right after the - /// end of the slice being built, the slice is extended (trivial operation). - /// - /// See_Also: begin - void write(dchar[] str) @system pure nothrow @nogc - { - assert(inProgress, "write called without begin"); - - // If str starts at the end of the slice (is a string returned by a Reader - // method), just extend the slice to contain str. - if(str.ptr == reader_.buffer_.ptr + end_) - { - end_ += str.length; - } - // Even if str does not start at the end of the slice, it still may be returned - // by a Reader method and point to buffer. So we need to memmove. - else - { - core.stdc.string.memmove(reader_.buffer_.ptr + end_, cast(dchar*)str.ptr, - str.length * dchar.sizeof); - end_ += str.length; - } - } - - /// Write a character to the slice being built. - /// - /// Data can only be written up to the current position in the Reader buffer. - /// - /// See_Also: begin - void write(dchar c) @system pure nothrow @nogc - { - assert(inProgress, "write called without begin"); - - reader_.buffer_[end_++] = c; - } - - /// Insert a character to a specified position in the slice. - /// - /// Enlarges the slice by 1 char. Note that the slice can only extend up to the - /// current position in the Reader buffer. - /// - /// Params: - /// - /// c = The character to insert. - /// position = Position to insert the character at in code units, not code points. - /// Must be less than slice length(); a previously returned length() - /// can be used. - void insert(const dchar c, const size_t position) @system pure nothrow @nogc - { - assert(inProgress, "insert called without begin"); - assert(start_ + position <= end_, "Trying to insert after the end of the slice"); - - const point = start_ + position; - const movedLength = end_ - point; - if(movedLength > 0) - { - core.stdc.string.memmove(reader_.buffer_.ptr + point + 1, - reader_.buffer_.ptr + point, - movedLength * dchar.sizeof); - } - ++end_; - reader_.buffer_[point] = c; - } - - /// Get the current length of the slice. - size_t length() @safe pure nothrow const @nogc - { - return end_ - start_; - } - - /// A slice building transaction. - /// - /// Can be used to save and revert back to slice state. - struct Transaction - { - private: - // The slice builder affected by the transaction. - SliceBuilder* builder_ = null; - // Index of the return point of the transaction in StringBuilder.endStack_. - size_t stackLevel_; - // True after commit() has been called. - bool committed_; - - public: - /// Begins a transaction on a SliceBuilder object. - /// - /// The transaction must end $(B after) any transactions created within the - /// transaction but $(B before) the slice is finish()-ed. A transaction can be - /// ended either by commit()-ing or reverting through the destructor. - /// - /// Saves the current state of a slice. - this(ref SliceBuilder builder) @system pure nothrow @nogc - { - builder_ = &builder; - stackLevel_ = builder_.endStackUsed_; - builder_.push(); - } - - /// Commit changes to the slice. - /// - /// Ends the transaction - can only be called once, and removes the possibility - /// to revert slice state. - /// - /// Does nothing for a default-initialized transaction (the transaction has not - /// been started yet). - void commit() @system pure nothrow @nogc - { - assert(!committed_, "Can't commit a transaction more than once"); - - if(builder_ is null) { return; } - assert(builder_.endStackUsed_ == stackLevel_ + 1, - "Parent transactions don't fully contain child transactions"); - builder_.apply(); - committed_ = true; - } - - /// Destroy the transaction and revert it if it hasn't been committed yet. - /// - /// Does nothing for a default-initialized transaction. - ~this() @system pure nothrow @nogc - { - if(builder_ is null || committed_) { return; } - assert(builder_.endStackUsed_ == stackLevel_ + 1, - "Parent transactions don't fully contain child transactions"); - builder_.pop(); - builder_ = null; - } - } private: - // Push the current end of the slice so we can revert to it if needed. - // - // Used by Transaction. - void push() @system pure nothrow @nogc - { - assert(inProgress, "push called without begin"); - assert(endStackUsed_ < endStack_.length, "Slice stack overflow"); - endStack_[endStackUsed_++] = end_; - } - // Pop the current end of endStack_ and set the end of the slice to the popped - // value, reverting changes since the old end was pushed. - // - // Used by Transaction. - void pop() @system pure nothrow @nogc - { - assert(inProgress, "pop called without begin"); - assert(endStackUsed_ > 0, "Trying to pop an empty slice stack"); - end_ = endStack_[--endStackUsed_]; - } - - // Pop the current end of endStack_, but keep the current end of the slice, applying - // changes made since pushing the old end. - // - // Used by Transaction. - void apply() @system pure nothrow @nogc - { - assert(inProgress, "apply called without begin"); - assert(endStackUsed_ > 0, "Trying to apply an empty slice stack"); - --endStackUsed_; - } -} - -private: // Decode an UTF-8/16/32 buffer to UTF-32 (for UTF-32 this does nothing). //