parseUpdate method

void parseUpdate(
  1. List<int> bytes,
  2. int start,
  3. int end
)

Tries to update its fields based on information from the specified bytes, which should come from a JSON file. Creates and sends new points to resultReporter when such fully defined points are detected.

Valid JSON input will have forms like:

  • "key": -456
  • "key": "123"
  • 'key' : '78'

The implementation is very much aimed at specifically the way the Google location history export looks, rather than being a generic JSON parser. This makes it possible to optimize it a lot in terms of speed and memory usage, at the expense of legibility.

Implementation

void parseUpdate(List<int> bytes, int start, int end) {
  pos = start;
  posStartNextStreamChunk = null; // indicates we haven't parsed anything
  var prevLoopStartPos = -1;
  while (pos < end) {
    // If we're just spinning our wheels, stop.
    if (pos == prevLoopStartPos) {
      break;
    }
    prevLoopStartPos = pos;

    // Find first key we're interested in.
    final index = _getKeyIndex(bytes, end);
    if (index == _indexUninterestingKey) {
      // Even if the key is not interesting, it is correctly parsed and
      // doesn't need to be parsed again if it happens to be towards the
      // end of [bytes] and the next chunk will be appended.
      posStartNextStreamChunk = pos;
      continue;
    }
    if (index == null) {
      continue;
    }

    // Get the key's value
    final valueString = _parseValueString(bytes, end);
    if (valueString == null) {
      break;
    }
    // Remember the position, because if we don't find a proper value in the
    // next loop, that may be because the stream is split at an unfortunate
    // place (e.g. between a key and its value, or in the middle of a key or
    // something like that). The part after the current, known correct,
    // key-value pair may need to be re-parsed including additional information
    // from the next chunk of the stream providing our [bytes].
    posStartNextStreamChunk = pos;

    final value = int.tryParse(valueString);
    if (value == null) {
      // Cannot really happen given the parsing method, but just in case.
      continue;
    }

    // If starting the definition of a new point and the current state looks
    // like a fully defined point, report the current state.
    if (_values[index] != null && !isUndefined) {
      toGpsPointAndReset();
    }

    _setValue(index, value);
  }
}