substring

cesars/melody/substring

No description
substring
@/substring
INstring
Input string
STRTnumber
Start character index. Zero-based. Fractional indexes are truncated to integers, negative values are interpreted as zero. Indexes past the string length lead to an empty result.
ENDnumber
End character index. Not inclusive, that is, the value of string length will return the string’s tail. If `STRT` is `0` it is equivalent to number of characters in the slice. Fractional indexes are truncated to integers, negative values are interpreted as zero which, in turn, lead to an always empty result.
substring
OUT
IN
STRT
END
OUTstring
Resulting substring (aka part, slice). Will be empty if `END` ≤ `STRT` or `STRT` is past the input length.
To use the node in your project you should have the cesars/melody library installed. Use the “File → Add Library” menu item in XOD IDE if you don’t have it yet. See Using libraries for more info.

C++ implementation

template<typename T> class SliceView : public ListView<T> {
  public:
    class Cursor : public xod::detail::Cursor<T> {
      public:
        Cursor(const SliceView* owner)
            : _iter(owner->_list.iterate())
            , _owner(owner)
        {
            // Fast-forward to the start position
            _idx = _owner->_start;
            for (size_t i = 0; i < _idx; ++i)
                ++_iter;
        }

        bool isValid() const override {
            return _iter && isInRange();
        }

        bool value(T* out) const override {
            if (!isInRange())
                return false;
            return _iter.value(out);
        }

        void next() override {
            ++_idx;
            ++_iter;
        }

      private:
        bool isInRange() const {
            return _idx < _owner->_end;
        }

      private:
        const SliceView* _owner;
        Iterator<T> _iter;
        size_t _idx;
    };

  public:
    SliceView(List<T> list, size_t start, size_t end)
        : _list(list)
        , _start(start)
        , _end(end)
    { }

    virtual Iterator<T> iterate() const override {
        return Iterator<T>(new Cursor(this));
    }

  private:
    friend class Cursor;
    List<T> _list;
    size_t _start;
    size_t _end;
};

struct State {
    uint8_t mem[sizeof(SliceView<char>)];
};

{{ GENERATED_CODE }}

void evaluate(Context ctx) {

    auto state = getState(ctx);
    auto view = new (state->mem) SliceView<char>(
        getValue<input_IN>(ctx),
        getValue<input_STRT>(ctx),
        getValue<input_END>(ctx)
    );

    emitValue<output_OUT>(ctx, XString(view));
}