shared_ptr<const Data>
InMemoryStorage::find(const Interest& interest)
{
  // if the interest contains implicit digest, it is possible to directly locate a packet.
  auto it = m_cache.get<byFullName>().find(interest.getName());

  // if a packet is located by its full name, it must be the packet to return.
  if (it != m_cache.get<byFullName>().end()) {
    return ((*it)->getData()).shared_from_this();
  }

  // if the packet is not discovered by last step, either the packet is not in the storage or
  // the interest doesn't contains implicit digest.
  it = m_cache.get<byFullName>().lower_bound(interest.getName());

  if (it == m_cache.get<byFullName>().end()) {
    return nullptr;
  }

  // to locate the element that has a just smaller name than the interest's
  if (it != m_cache.get<byFullName>().begin()) {
    it--;
  }

  InMemoryStorageEntry* ret = selectChild(interest, it);
  if (ret == nullptr) {
    return nullptr;
  }

  // let derived class do something with the entry
  afterAccess(ret);
  return ret->getData().shared_from_this();
}
BOOST_AUTO_TEST_CASE_TEMPLATE(DigestCalculation, T, InMemoryStorages)
{
  shared_ptr<Data> data = makeData("/digest/compute");

  ndn::ConstBufferPtr digest1 = ndn::crypto::computeSha256Digest(data->wireEncode().wire(),
                                                                 data->wireEncode().size());
  BOOST_CHECK_EQUAL(digest1->size(), 32);

  InMemoryStorageEntry* entry = new InMemoryStorageEntry();
  entry->setData(*data);

  BOOST_CHECK_EQUAL_COLLECTIONS(digest1->begin(), digest1->end(),
                                entry->getFullName()[-1].value_begin(),
                                entry->getFullName()[-1].value_end());
}
void
InMemoryStorage::insert(const Data& data, const time::milliseconds& mustBeFreshProcessingWindow)
{
  // check if identical Data/Name already exists
  auto it = m_cache.get<byFullName>().find(data.getFullName());
  if (it != m_cache.get<byFullName>().end())
    return;

  //if full, double the capacity
  bool doesReachLimit = (getLimit() == getCapacity());
  if (isFull() && !doesReachLimit) {
    // note: This is incorrect if 2*capacity overflows, but memory should run out before that
    size_t newCapacity = std::min(2 * getCapacity(), getLimit());
    setCapacity(newCapacity);
  }

  //if full and reach limitation of the capacity, employ replacement policy
  if (isFull() && doesReachLimit) {
    evictItem();
  }

  //insert to cache
  BOOST_ASSERT(m_freeEntries.size() > 0);
  // take entry for the memory pool
  InMemoryStorageEntry* entry = m_freeEntries.top();
  m_freeEntries.pop();
  m_nPackets++;
  entry->setData(data);
  if (m_scheduler != nullptr && mustBeFreshProcessingWindow > ZERO_WINDOW) {
    entry->scheduleMarkStale(*m_scheduler, mustBeFreshProcessingWindow);
  }
  m_cache.insert(entry);

  //let derived class do something with the entry
  afterInsert(entry);
}