text: /**
   * Copyright (C) 2016-2017 Xilinx, Inc
   *
   * Licensed under the Apache License, Version 2.0 (the "License"). You may
   * not use this file except in compliance with the License. A copy of the
   * License is located at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   * License for the specific language governing permissions and limitations
   * under the License.
   */
  
  #include "memorymanager.h"
  
  namespace xclemulation {
    MemoryManager::MemoryManager(uint64_t size, uint64_t start,
        unsigned alignment) : mSize(size), mStart(start), mAlignment(alignment),
    mCoalesceThreshold(4), mFreeSize(0)
    {
      assert(start % alignment == 0);
      mFreeBufferList.push_back(std::make_pair(mStart, mSize));
      mFreeSize = mSize;
    }
  
    MemoryManager::~MemoryManager()
    {
  
    }
  
    uint64_t MemoryManager::alloc(size_t& origSize, unsigned int paddingFactor)
    {
      if (origSize == 0)
        origSize = mAlignment;
  
      uint64_t result = mNull;
      const size_t mod_size = origSize % mAlignment;
      const size_t pad = (mod_size > 0) ? (mAlignment - mod_size) : 0;
      origSize += pad;
      size_t size = origSize;
      size = size +(2*paddingFactor*size);
  
      std::lock_guard<std::mutex> lock(mMemManagerMutex);
  
      for (PairList::iterator i = mFreeBufferList.begin(), e = mFreeBufferList.end(); i != e; ++i) 
      {
        if (i->second < size)
          continue;
        result = i->first;
        if (i->second > size) 
        {
          // Resize the existing entry in freelist
          i->first += size;
          i->second -= size;
        }
        else 
        {
          // remove the exact match found
          mFreeBufferList.erase(i);
        }
        mBusyBufferList.push_back(std::make_pair(result, size));
        mFreeSize -= size;
        break;
      }
      return result;
    }
  
    void MemoryManager::free(uint64_t buf)
    {
      std::lock_guard<std::mutex> lock(mMemManagerMutex);
      PairList::iterator i = find(buf);
      if (i == mBusyBufferList.end())
        return;
      mFreeSize += i->second;
      mFreeBufferList.push_back(std::make_pair(i->first, i->second));
      mBusyBufferList.erase(i);
      if (mFreeBufferList.size() > mCoalesceThreshold) {
        coalesce();
      }
    }
  
  
    void MemoryManager::coalesce()
    {
      // First sort the free buffers and then attempt to coalesce the neighbors
      mFreeBufferList.sort();
  
      PairList::iterator curr = mFreeBufferList.begin();
      PairList::iterator next = curr;
      ++next;
      PairList::iterator last = mFreeBufferList.end();
      while (next != last) {
        if ((curr->first + curr->second) != next->first) {
          // Non contiguous blocks
          curr = next;
          ++next;
          continue;
        }
        // Coalesce curr and next
        curr->second += next->second;
        mFreeBufferList.erase(next);
        next = curr;
        ++next;
      }
    }
  
  
    MemoryManager::PairList::iterator MemoryManager::find(uint64_t buf)
    {
  #if GCC_VERSION >= 40800
      PairList::iterator i = std::find_if(mBusyBufferList.begin(), mBusyBufferList.end(), [&] (const PairList::value_type& s)
          { return s.first == buf; });
  #else
      PairList::iterator i = mBusyBufferList.begin();
      PairList::iterator last  = mBusyBufferList.end();
      while(i != last) {
        if (i->first == buf)
          break;
        ++i;
      }
  #endif
      return i;
    }
  
    void MemoryManager::reset()
    {
      std::lock_guard<std::mutex> lock(mMemManagerMutex);
      mFreeBufferList.clear();
      mBusyBufferList.clear();
      mFreeBufferList.push_back(std::make_pair(mStart, mSize));
      mFreeSize = 0;
    }
  
    std::pair<uint64_t, uint64_t> MemoryManager::lookup(uint64_t buf)
    {
      std::lock_guard<std::mutex> lock(mMemManagerMutex);
      PairList::iterator i = find(buf);
      if (i != mBusyBufferList.end())
        return *i;
      // Compiler bug -- Some versions of GCC C++11 compiler do not
      // like mNull directly inside std::make_pair, so capture mNull
      // in a temporary 
      const uint64_t v = mNull;
      return std::make_pair(v, v);
    }
  }
  
  