void
ParserOpSet<ParserLookAhead>::operator()(Packet *pkt, const char *data,
                                         size_t *bytes_parsed) const {
  (void) bytes_parsed;
  static thread_local ByteContainer bc;
  PHV *phv = pkt->get_phv();
  Field &f_dst = phv->get_field(dst.header, dst.offset);
  int f_bits = f_dst.get_nbits();
  /* I expect the first case to be the most common one. In the first case, we
     extract the packet bytes to the field bytes and sync the bignum value. The
     second case requires extracting the packet bytes to the ByteContainer, then
     importing the bytes into the field's bignum value, then finally exporting
     the bignum value to the field's byte array. I could alternatively write a
     more general extract function which would account for a potential size
     difference between source and destination. */
  // TODO(antonin)
  if (src.bitwidth == f_bits) {
    data += src.byte_offset;
    f_dst.extract(data, src.bit_offset);
  } else {
    bc.clear();
    src.peek(data, &bc);
    f_dst.set(bc);
  }
  BMLOG_DEBUG_PKT(
    *pkt,
    "Parser set: setting field ({}, {}) from lookahead ({}, {}), "
    "new value is {}",
    dst.header, dst.offset, src.bit_offset, src.bitwidth, f_dst);
}
void LearnEngine::LearnList::add_sample(const PHV &phv)
{
  static thread_local ByteContainer sample;
  sample.clear();
  builder(phv, &sample);

  std::unique_lock<std::mutex> lock(mutex);

  const auto it = filter.find(sample);
  if(it != filter.end()) return;

  buffer.insert(buffer.end(), sample.begin(), sample.end());
  num_samples++;
  auto filter_it = filter.insert(filter.end(), std::move(sample));
  FilterPtrs &filter_ptrs = old_buffers[buffer_id];
  filter_ptrs.unacked_count++;
  filter_ptrs.buffer.push_back(filter_it);

  if(num_samples == 1 && max_samples > 1) {
    buffer_started = clock::now(); 
    b_can_send.notify_one(); // wake transmit thread to update cond var wait time
  }
  else if(num_samples >= max_samples) {
    while(buffer_tmp.size() != 0) {
      b_can_swap.wait(lock);
    }
    swap_buffers();

    b_can_send.notify_one();
  }
}
SaveAsJob::SaveAsJob(const String &newName, ByteContainer &src)
: m_newName(newName)
, m_src(src)
, m_size(src.getSize())
, m_fileIndex(0)
{
  m_ok = true;
}
const ParseState *
ParseState::find_next_state(Packet *pkt, const char *data,
                            size_t *bytes_parsed) const {
  // execute parser ops
  PHV *phv = pkt->get_phv();

  register_sync.lock_registers();

  for (auto &parser_op : parser_ops)
    (*parser_op)(pkt, data + *bytes_parsed, bytes_parsed);

  register_sync.unlock_registers();

  if (!has_switch) {
    BMLOG_DEBUG_PKT(
      *pkt,
      "Parser state '{}' has no switch, going to default next state",
      get_name());
    return default_next_state;
  }

  // build key
  static thread_local ByteContainer key;
  key.clear();
  key_builder(*phv, data + *bytes_parsed, &key);

  BMLOG_DEBUG_PKT(*pkt, "Parser state '{}': key is {}",
                  get_name(), key.to_hex());

  // try the matches in order
  const ParseState *next_state = NULL;
  for (const auto &switch_case : parser_switch)
    if (switch_case.match(key, &next_state)) return next_state;

  return default_next_state;
}
bool ModificationMap::addModification(ByteContainer &bc, unsigned __int64 addr, BYTE to, BYTE &old) {
  BytePair *bpp = get(addr);
  if(bpp) {
    if(to == bpp->getFrom()) {
      old = to;
      remove(addr);
      return true;
    } else if(to != bpp->getTo()) {
      BytePair nbp(bpp->getFrom(), to);
      old = bpp->getTo();
      remove(addr);
      put(addr, nbp);
      return true;
    }
  } else { // addr not found in map
    const BYTE from = bc.getByte(addr);
    if(to != from) {
      old = from;
      put(addr, BytePair(from, to));
      return true;
    }
  }
  return false;
}