Jump To …

DataIterator.coffee

fs = require 'fs'
Addr64 = (require './Addr64.coffee').Addr64
LogUtil = (require './LogUtil.coffee').LogUtil
CompoundByteIteratorBase =
  (require './iterate/CompoundByteIteratorBase.coffee').CompoundByteIteratorBase

TODO Implement many other methods!!! This class provides access to data stored in cache. It is lazy - it gets information from cache only when getValue or getData are called. Also it is changable.

class DataIterator extends CompoundByteIteratorBase

@private

  cache: undefined

@private

  addr: undefined

@private

  pageAddr: undefined

@private

  offset: undefined

@private

  buffer: undefined

Constructor.

@param cache the cache where data is stored (or where it can be loaded). @param addr the address in virtual address space.

  @create$LogCache$Addr64: (cache, addr, o) ->
    if !o? then o = new DataIterator
    o.cache = cache
    o.addr = addr
    o.cache.parseAddr$Addr64 o.addr
    o.pageAddr = o.cache.getPageAddr()
    o.offset = o.cache.getPageOffset()
    o.buffer = undefined
    return o

  getAddress: () ->
    return @addr

Makes a copy of the current state of iterator.

@return new DataIterator

  copy: () ->
    return DataIterator.create$LogCache$Addr64 @cache, @addr

Check whether there is next.

  hasNext$emit: () ->
    return @addr.plus$int(1).less$Addr64 @cache.getHighAddress()

@private Moves pointer to data to the next byte. This method changes object.

  moveNext: () ->
    @addr = @addr.plus$int 1
    @offset += 1
    if @offset == @cache.getPageSize()
      @pageAddr = @pageAddr.plus$int @offset
      @offset = 0
      @buffer = undefined

Move pointer to data to current position plus offset. This method changes object.

@param length items to skip (result is undefined for non-positive length). @return how many items were skipped, zero if no elements left.

  skip$int: (length) ->
    if length < 0
      return undefined
    if !(@cache.getHighAddress().less$Addr64 @addr.plus$int(length))
      res = length
    else
      res = @cache.getHighAddress().diff$Addr64 @addr
    @addr = @addr.plus$int res
    @cache.parseAddr$Addr64 @addr
    @pageAddr = @cache.getPageAddr()
    @offset = @cache.getPageOffset()
    @buffer = undefined
    return res

Get value of byte at current position and move next.

@return If buffer is defined or can be instantly got from cache returns value. Otherwise returns undefined and emits 'getValue' event. If undefined is returned, do not call this method again before event is emitted!

  next$emit: () ->
    if @buffer?
      res = @buffer[@offset]
      @moveNext()
      return res
    else
      addrStr = Addr64.addr64ToString$Addr64$int(@pageAddr,
              LogUtil.LOG_NAME_BASE)
      @cache.once 'getPage' + addrStr, (buffer, addrStr) =>
        @buffer = buffer
        res = @buffer[@offset]
        @moveNext()
        @emit 'next', res
      @buffer = @cache.getPage$Addr64$emit @pageAddr
      if @buffer?
        res = @buffer[@offset]
        @moveNext()
        return res
      else
        return undefined

  getHighAddress: () ->
    return @addr

This class should be used ONLY when it is known that the data is in one buffer and doesn't need to be uploaded from disk. It is EventEmitter to let it be used with compressor. Think twice before using it! It can be used if you have made a copy of data dorm ReadLogable and want to parse it.

class LightReadIterator extends CompoundByteIteratorBase

@private

  offset: undefined

@private

  buffer: undefined

Constructor.

@param buffer. @param offset in buffer.

  @create$Buffer$int: (buffer, offset) ->
    @buffer = buffer
    @offset = offset

Makes a copy of the current state of iterator.

@return new DataIterator

  copy: () ->
    return LightReadIterator.create$Buffer$int @buffer, @offset

Check whether there is next.

  hasNext$emit: () ->
    return @offset + 1 < @buffer.length

Reads data at current position and moves pointer to data to the next byte. This method changes object.

  next$emit: () ->
    res = @buffer[@offset]
    @offset += 1
    return res

Move pointer to data to current position plus offset. This method changes object.

@param length items to skip (result is undefined for non-positive length). @return how many items were skipped, zero if no elements left.

  skip$int: (length) ->
    if length < 0
      return undefined
    rest = @buffer.length - @offset
    if rest >= length
      @offset += length
      return length
    else
      @offset += rest
      return rest

Get buffer with data at current position.

@param length the length of data to be read. @return buffer with data.

  getData$int$emit: (length) ->
    b = new Buffer(length)
    @buffer.copy b, 0, @offset, @offset + length
    return b

exports.DataIterator = DataIterator
exports.LightReadIterator = LightReadIterator