function encodeOps(ops, forDocument) {
  const columns = {
    objActor: new RLEEncoder("uint"),
    objCtr: new RLEEncoder("uint"),
    keyActor: new RLEEncoder("uint"),
    keyCtr: new DeltaEncoder(),
    keyStr: new RLEEncoder("utf8"),
    insert: new BooleanEncoder(),
    action: new RLEEncoder("uint"),
    valLen: new RLEEncoder("uint"),
    valRaw: new Encoder(),
    chldActor: new RLEEncoder("uint"),
    chldCtr: new DeltaEncoder(),
  }

  if (forDocument) {
    columns.idActor = new RLEEncoder("uint")
    columns.idCtr = new DeltaEncoder()
    columns.succNum = new RLEEncoder("uint")
    columns.succActor = new RLEEncoder("uint")
    columns.succCtr = new DeltaEncoder()
  } else {
    columns.predNum = new RLEEncoder("uint")
    columns.predCtr = new DeltaEncoder()
    columns.predActor = new RLEEncoder("uint")
  }

  for (let op of ops) {
    encodeObjectId(op, columns)
    encodeOperationKey(op, columns)
    columns.insert.appendValue(!!op.insert)
    encodeOperationAction(op, columns)
    encodeValue(op, columns)

    if (op.child && op.child.counter) {
      columns.chldActor.appendValue(op.child.actorNum)
      columns.chldCtr.appendValue(op.child.counter)
    } else {
      columns.chldActor.appendValue(null)
      columns.chldCtr.appendValue(null)
    }

    if (forDocument) {
      columns.idActor.appendValue(op.id.actorNum)
      columns.idCtr.appendValue(op.id.counter)
      columns.succNum.appendValue(op.succ.length)
      op.succ.sort(compareParsedOpIds)
      for (let i = 0; i < op.succ.length; i++) {
        columns.succActor.appendValue(op.succ[i].actorNum)
        columns.succCtr.appendValue(op.succ[i].counter)
      }
    } else {
      columns.predNum.appendValue(op.pred.length)
      op.pred.sort(compareParsedOpIds)
      for (let i = 0; i < op.pred.length; i++) {
        columns.predActor.appendValue(op.pred[i].actorNum)
        columns.predCtr.appendValue(op.pred[i].counter)
      }
    }
  }

  let columnList = []
  for (let { columnName, columnId } of forDocument
    ? DOC_OPS_COLUMNS
    : CHANGE_COLUMNS) {
    if (columns[columnName])
      columnList.push({ columnId, columnName, encoder: columns[columnName] })
  }
  return columnList.sort((a, b) => a.columnId - b.columnId)
}
Encodes an array of operations in a set of columns. The operations need to
be parsed with `parseAllOpIds()` beforehand. If `forDocument` is true, we use
the column structure of a whole document, otherwise we use the column
structure for an individual change. Returns an array of
`{columnId, columnName, encoder}` objects.