<commit_before>/*
 * Copyright (c) 2017,2019,2020 ARM Limited
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2011-2014 Mark D. Hill and David A. Wood
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "mem/ruby/slicc_interface/AbstractController.hh"

#include "debug/RubyQueue.hh"
#include "mem/ruby/network/Network.hh"
#include "mem/ruby/protocol/MemoryMsg.hh"
#include "mem/ruby/system/RubySystem.hh"
#include "mem/ruby/system/Sequencer.hh"
#include "sim/system.hh"

AbstractController::AbstractController(const Params &p)
    : ClockedObject(p), Consumer(this), m_version(p.version),
      m_clusterID(p.cluster_id),
      m_id(p.system->getRequestorId(this)), m_is_blocking(false),
      m_number_of_TBEs(p.number_of_TBEs),
      m_transitions_per_cycle(p.transitions_per_cycle),
      m_buffer_size(p.buffer_size), m_recycle_latency(p.recycle_latency),
      m_mandatory_queue_latency(p.mandatory_queue_latency),
      memoryPort(csprintf("%s.memory", name()), this),
      addrRanges(p.addr_ranges.begin(), p.addr_ranges.end())
{
    if (m_version == 0) {
        // Combine the statistics from all controllers
        // of this particular type.
        Stats::registerDumpCallback([this]() { collateStats(); });
    }
}

void
AbstractController::init()
{
    m_delayHistogram.init(10);
    uint32_t size = Network::getNumberOfVirtualNetworks();
    for (uint32_t i = 0; i < size; i++) {
        m_delayVCHistogram.push_back(new Stats::Histogram());
        m_delayVCHistogram[i]->init(10);
    }

    if (getMemReqQueue()) {
        getMemReqQueue()->setConsumer(this);
    }

    // Initialize the addr->downstream machine mappings. Multiple machines
    // in downstream_destinations can have the same address range if they have
    // different types. If this is the case, mapAddressToDownstreamMachine
    // needs to specify the machine type
    downstreamDestinations.resize();
    for (auto abs_cntrl : params().downstream_destinations) {
        MachineID mid = abs_cntrl->getMachineID();
        const AddrRangeList &ranges = abs_cntrl->getAddrRanges();
        for (const auto addr_range : ranges) {
            auto i = downstreamAddrMap.intersects(addr_range);
            if (i == downstreamAddrMap.end()) {
                i = downstreamAddrMap.insert(addr_range, AddrMapEntry());
            }
            AddrMapEntry &entry = i->second;
            fatal_if(entry.count(mid.getType()) > 0,
                     "%s: %s mapped to multiple machines of the same type\n",
                     name(), addr_range.to_string());
            entry[mid.getType()] = mid;
        }
        downstreamDestinations.add(mid);
    }

}

void
AbstractController::resetStats()
{
    m_delayHistogram.reset();
    uint32_t size = Network::getNumberOfVirtualNetworks();
    for (uint32_t i = 0; i < size; i++) {
        m_delayVCHistogram[i]->reset();
    }
}

void
AbstractController::regStats()
{
    ClockedObject::regStats();

    m_fully_busy_cycles
        .name(name() + ".fully_busy_cycles")
        .desc("cycles for which number of transistions == max transitions")
        .flags(Stats::nozero);
}

void
AbstractController::profileMsgDelay(uint32_t virtualNetwork, Cycles delay)
{
    assert(virtualNetwork < m_delayVCHistogram.size());
    m_delayHistogram.sample(delay);
    m_delayVCHistogram[virtualNetwork]->sample(delay);
}

void
AbstractController::stallBuffer(MessageBuffer* buf, Addr addr)
{
    if (m_waiting_buffers.count(addr) == 0) {
        MsgVecType* msgVec = new MsgVecType;
        msgVec->resize(m_in_ports, NULL);
        m_waiting_buffers[addr] = msgVec;
    }
    DPRINTF(RubyQueue, "stalling %s port %d addr %#x\n", buf, m_cur_in_port,
            addr);
    assert(m_in_ports > m_cur_in_port);
    (*(m_waiting_buffers[addr]))[m_cur_in_port] = buf;
}

void
AbstractController::wakeUpBuffers(Addr addr)
{
    if (m_waiting_buffers.count(addr) > 0) {
        //
        // Wake up all possible lower rank (i.e. lower priority) buffers that could
        // be waiting on this message.
        //
        for (int in_port_rank = m_cur_in_port - 1;
             in_port_rank >= 0;
             in_port_rank--) {
            if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
                (*(m_waiting_buffers[addr]))[in_port_rank]->
                    reanalyzeMessages(addr, clockEdge());
            }
        }
        delete m_waiting_buffers[addr];
        m_waiting_buffers.erase(addr);
    }
}

void
AbstractController::wakeUpAllBuffers(Addr addr)
{
    if (m_waiting_buffers.count(addr) > 0) {
        //
        // Wake up all possible buffers that could be waiting on this message.
        //
        for (int in_port_rank = m_in_ports - 1;
             in_port_rank >= 0;
             in_port_rank--) {
            if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
                (*(m_waiting_buffers[addr]))[in_port_rank]->
                    reanalyzeMessages(addr, clockEdge());
            }
        }
        delete m_waiting_buffers[addr];
        m_waiting_buffers.erase(addr);
    }
}

void
AbstractController::wakeUpAllBuffers()
{
    //
    // Wake up all possible buffers that could be waiting on any message.
    //

    std::vector<MsgVecType*> wokeUpMsgVecs;
    MsgBufType wokeUpMsgBufs;

    if (m_waiting_buffers.size() > 0) {
        for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
             buf_iter != m_waiting_buffers.end();
             ++buf_iter) {
             for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
                  vec_iter != buf_iter->second->end();
                  ++vec_iter) {
                  //
                  // Make sure the MessageBuffer has not already be reanalyzed
                  //
                  if (*vec_iter != NULL &&
                      (wokeUpMsgBufs.count(*vec_iter) == 0)) {
                      (*vec_iter)->reanalyzeAllMessages(clockEdge());
                      wokeUpMsgBufs.insert(*vec_iter);
                  }
             }
             wokeUpMsgVecs.push_back(buf_iter->second);
        }

        for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
             wb_iter != wokeUpMsgVecs.end();
             ++wb_iter) {
             delete (*wb_iter);
        }

        m_waiting_buffers.clear();
    }
}

bool
AbstractController::serviceMemoryQueue()
{
    auto mem_queue = getMemReqQueue();
    assert(mem_queue);
    if (!mem_queue->isReady(clockEdge())) {
        return false;
    }

    const MemoryMsg *mem_msg = (const MemoryMsg*)mem_queue->peek();
    unsigned int req_size = RubySystem::getBlockSizeBytes();
    if (mem_msg->m_Len > 0) {
        req_size = mem_msg->m_Len;
    }

    RequestPtr req
        = std::make_shared<Request>(mem_msg->m_addr, req_size, 0, m_id);
    PacketPtr pkt;
    if (mem_msg->getType() == MemoryRequestType_MEMORY_WB) {
        pkt = Packet::createWrite(req);
        pkt->allocate();
        pkt->setData(mem_msg->m_DataBlk.getData(getOffset(mem_msg->m_addr),
            req_size));
    } else if (mem_msg->getType() == MemoryRequestType_MEMORY_READ) {
        pkt = Packet::createRead(req);
        uint8_t *newData = new uint8_t[req_size];
        pkt->dataDynamic(newData);
    } else {
        panic("Unknown memory request type (%s) for addr %p",
              MemoryRequestType_to_string(mem_msg->getType()),
              mem_msg->m_addr);
    }

    SenderState *s = new SenderState(mem_msg->m_Sender);
    pkt->pushSenderState(s);

    if (RubySystem::getWarmupEnabled()) {
        // Use functional rather than timing accesses during warmup
        mem_queue->dequeue(clockEdge());
        memoryPort.sendFunctional(pkt);
        // Since the queue was popped the controller may be able
        // to make more progress. Make sure it wakes up
        scheduleEvent(Cycles(1));
        recvTimingResp(pkt);
    } else if (memoryPort.sendTimingReq(pkt)) {
        mem_queue->dequeue(clockEdge());
        // Since the queue was popped the controller may be able
        // to make more progress. Make sure it wakes up
        scheduleEvent(Cycles(1));
    } else {
        scheduleEvent(Cycles(1));
        delete pkt;
        delete s;
    }

    return true;
}

void
AbstractController::blockOnQueue(Addr addr, MessageBuffer* port)
{
    m_is_blocking = true;
    m_block_map[addr] = port;
}

bool
AbstractController::isBlocked(Addr addr) const
{
    return m_is_blocking && (m_block_map.find(addr) != m_block_map.end());
}

void
AbstractController::unblock(Addr addr)
{
    m_block_map.erase(addr);
    if (m_block_map.size() == 0) {
       m_is_blocking = false;
    }
}

bool
AbstractController::isBlocked(Addr addr)
{
    return (m_block_map.count(addr) > 0);
}

Port &
AbstractController::getPort(const std::string &if_name, PortID idx)
{
    return memoryPort;
}

void
AbstractController::functionalMemoryRead(PacketPtr pkt)
{
    memoryPort.sendFunctional(pkt);
}

int
AbstractController::functionalMemoryWrite(PacketPtr pkt)
{
    int num_functional_writes = 0;

    // Update memory itself.
    memoryPort.sendFunctional(pkt);
    return num_functional_writes + 1;
}

void
AbstractController::recvTimingResp(PacketPtr pkt)
{
    assert(getMemRespQueue());
    assert(pkt->isResponse());

    std::shared_ptr<MemoryMsg> msg = std::make_shared<MemoryMsg>(clockEdge());
    (*msg).m_addr = pkt->getAddr();
    (*msg).m_Sender = m_machineID;

    SenderState *s = dynamic_cast<SenderState *>(pkt->senderState);
    (*msg).m_OriginalRequestorMachId = s->id;
    delete s;

    if (pkt->isRead()) {
        (*msg).m_Type = MemoryRequestType_MEMORY_READ;
        (*msg).m_MessageSize = MessageSizeType_Response_Data;

        // Copy data from the packet
        (*msg).m_DataBlk.setData(pkt->getPtr<uint8_t>(), 0,
                                 RubySystem::getBlockSizeBytes());
    } else if (pkt->isWrite()) {
        (*msg).m_Type = MemoryRequestType_MEMORY_WB;
        (*msg).m_MessageSize = MessageSizeType_Writeback_Control;
    } else {
        panic("Incorrect packet type received from memory controller!");
    }

    getMemRespQueue()->enqueue(msg, clockEdge(), cyclesToTicks(Cycles(1)));
    delete pkt;
}

Tick
AbstractController::recvAtomic(PacketPtr pkt)
{
   return ticksToCycles(memoryPort.sendAtomic(pkt));
}

MachineID
AbstractController::mapAddressToMachine(Addr addr, MachineType mtype) const
{
    NodeID node = m_net_ptr->addressToNodeID(addr, mtype);
    MachineID mach = {mtype, node};
    return mach;
}

MachineID
AbstractController::mapAddressToDownstreamMachine(Addr addr, MachineType mtype)
const
{
    const auto i = downstreamAddrMap.contains(addr);
    fatal_if(i == downstreamAddrMap.end(),
      "%s: couldn't find mapping for address %x\n", name(), addr);

    const AddrMapEntry &entry = i->second;
    assert(!entry.empty());

    if (mtype == MachineType_NUM) {
        fatal_if(entry.size() > 1,
          "%s: address %x mapped to multiple machine types.\n", name(), addr);
        return entry.begin()->second;
    } else {
        auto j = entry.find(mtype);
        fatal_if(j == entry.end(),
          "%s: couldn't find mapping for address %x\n", name(), addr);
        return j->second;
    }
}

bool
AbstractController::MemoryPort::recvTimingResp(PacketPtr pkt)
{
    controller->recvTimingResp(pkt);
    return true;
}

void
AbstractController::MemoryPort::recvReqRetry()
{
    controller->serviceMemoryQueue();
}

AbstractController::MemoryPort::MemoryPort(const std::string &_name,
                                           AbstractController *_controller,
                                           PortID id)
    : RequestPort(_name, _controller, id), controller(_controller)
{
}
<commit_msg>mem-ruby: Fix const copy of addr range in AbstractController<commit_after>/*
 * Copyright (c) 2017,2019,2020 ARM Limited
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2011-2014 Mark D. Hill and David A. Wood
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "mem/ruby/slicc_interface/AbstractController.hh"

#include "debug/RubyQueue.hh"
#include "mem/ruby/network/Network.hh"
#include "mem/ruby/protocol/MemoryMsg.hh"
#include "mem/ruby/system/RubySystem.hh"
#include "mem/ruby/system/Sequencer.hh"
#include "sim/system.hh"

AbstractController::AbstractController(const Params &p)
    : ClockedObject(p), Consumer(this), m_version(p.version),
      m_clusterID(p.cluster_id),
      m_id(p.system->getRequestorId(this)), m_is_blocking(false),
      m_number_of_TBEs(p.number_of_TBEs),
      m_transitions_per_cycle(p.transitions_per_cycle),
      m_buffer_size(p.buffer_size), m_recycle_latency(p.recycle_latency),
      m_mandatory_queue_latency(p.mandatory_queue_latency),
      memoryPort(csprintf("%s.memory", name()), this),
      addrRanges(p.addr_ranges.begin(), p.addr_ranges.end())
{
    if (m_version == 0) {
        // Combine the statistics from all controllers
        // of this particular type.
        Stats::registerDumpCallback([this]() { collateStats(); });
    }
}

void
AbstractController::init()
{
    m_delayHistogram.init(10);
    uint32_t size = Network::getNumberOfVirtualNetworks();
    for (uint32_t i = 0; i < size; i++) {
        m_delayVCHistogram.push_back(new Stats::Histogram());
        m_delayVCHistogram[i]->init(10);
    }

    if (getMemReqQueue()) {
        getMemReqQueue()->setConsumer(this);
    }

    // Initialize the addr->downstream machine mappings. Multiple machines
    // in downstream_destinations can have the same address range if they have
    // different types. If this is the case, mapAddressToDownstreamMachine
    // needs to specify the machine type
    downstreamDestinations.resize();
    for (auto abs_cntrl : params().downstream_destinations) {
        MachineID mid = abs_cntrl->getMachineID();
        const AddrRangeList &ranges = abs_cntrl->getAddrRanges();
        for (const auto &addr_range : ranges) {
            auto i = downstreamAddrMap.intersects(addr_range);
            if (i == downstreamAddrMap.end()) {
                i = downstreamAddrMap.insert(addr_range, AddrMapEntry());
            }
            AddrMapEntry &entry = i->second;
            fatal_if(entry.count(mid.getType()) > 0,
                     "%s: %s mapped to multiple machines of the same type\n",
                     name(), addr_range.to_string());
            entry[mid.getType()] = mid;
        }
        downstreamDestinations.add(mid);
    }

}

void
AbstractController::resetStats()
{
    m_delayHistogram.reset();
    uint32_t size = Network::getNumberOfVirtualNetworks();
    for (uint32_t i = 0; i < size; i++) {
        m_delayVCHistogram[i]->reset();
    }
}

void
AbstractController::regStats()
{
    ClockedObject::regStats();

    m_fully_busy_cycles
        .name(name() + ".fully_busy_cycles")
        .desc("cycles for which number of transistions == max transitions")
        .flags(Stats::nozero);
}

void
AbstractController::profileMsgDelay(uint32_t virtualNetwork, Cycles delay)
{
    assert(virtualNetwork < m_delayVCHistogram.size());
    m_delayHistogram.sample(delay);
    m_delayVCHistogram[virtualNetwork]->sample(delay);
}

void
AbstractController::stallBuffer(MessageBuffer* buf, Addr addr)
{
    if (m_waiting_buffers.count(addr) == 0) {
        MsgVecType* msgVec = new MsgVecType;
        msgVec->resize(m_in_ports, NULL);
        m_waiting_buffers[addr] = msgVec;
    }
    DPRINTF(RubyQueue, "stalling %s port %d addr %#x\n", buf, m_cur_in_port,
            addr);
    assert(m_in_ports > m_cur_in_port);
    (*(m_waiting_buffers[addr]))[m_cur_in_port] = buf;
}

void
AbstractController::wakeUpBuffers(Addr addr)
{
    if (m_waiting_buffers.count(addr) > 0) {
        //
        // Wake up all possible lower rank (i.e. lower priority) buffers that could
        // be waiting on this message.
        //
        for (int in_port_rank = m_cur_in_port - 1;
             in_port_rank >= 0;
             in_port_rank--) {
            if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
                (*(m_waiting_buffers[addr]))[in_port_rank]->
                    reanalyzeMessages(addr, clockEdge());
            }
        }
        delete m_waiting_buffers[addr];
        m_waiting_buffers.erase(addr);
    }
}

void
AbstractController::wakeUpAllBuffers(Addr addr)
{
    if (m_waiting_buffers.count(addr) > 0) {
        //
        // Wake up all possible buffers that could be waiting on this message.
        //
        for (int in_port_rank = m_in_ports - 1;
             in_port_rank >= 0;
             in_port_rank--) {
            if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
                (*(m_waiting_buffers[addr]))[in_port_rank]->
                    reanalyzeMessages(addr, clockEdge());
            }
        }
        delete m_waiting_buffers[addr];
        m_waiting_buffers.erase(addr);
    }
}

void
AbstractController::wakeUpAllBuffers()
{
    //
    // Wake up all possible buffers that could be waiting on any message.
    //

    std::vector<MsgVecType*> wokeUpMsgVecs;
    MsgBufType wokeUpMsgBufs;

    if (m_waiting_buffers.size() > 0) {
        for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
             buf_iter != m_waiting_buffers.end();
             ++buf_iter) {
             for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
                  vec_iter != buf_iter->second->end();
                  ++vec_iter) {
                  //
                  // Make sure the MessageBuffer has not already be reanalyzed
                  //
                  if (*vec_iter != NULL &&
                      (wokeUpMsgBufs.count(*vec_iter) == 0)) {
                      (*vec_iter)->reanalyzeAllMessages(clockEdge());
                      wokeUpMsgBufs.insert(*vec_iter);
                  }
             }
             wokeUpMsgVecs.push_back(buf_iter->second);
        }

        for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
             wb_iter != wokeUpMsgVecs.end();
             ++wb_iter) {
             delete (*wb_iter);
        }

        m_waiting_buffers.clear();
    }
}

bool
AbstractController::serviceMemoryQueue()
{
    auto mem_queue = getMemReqQueue();
    assert(mem_queue);
    if (!mem_queue->isReady(clockEdge())) {
        return false;
    }

    const MemoryMsg *mem_msg = (const MemoryMsg*)mem_queue->peek();
    unsigned int req_size = RubySystem::getBlockSizeBytes();
    if (mem_msg->m_Len > 0) {
        req_size = mem_msg->m_Len;
    }

    RequestPtr req
        = std::make_shared<Request>(mem_msg->m_addr, req_size, 0, m_id);
    PacketPtr pkt;
    if (mem_msg->getType() == MemoryRequestType_MEMORY_WB) {
        pkt = Packet::createWrite(req);
        pkt->allocate();
        pkt->setData(mem_msg->m_DataBlk.getData(getOffset(mem_msg->m_addr),
            req_size));
    } else if (mem_msg->getType() == MemoryRequestType_MEMORY_READ) {
        pkt = Packet::createRead(req);
        uint8_t *newData = new uint8_t[req_size];
        pkt->dataDynamic(newData);
    } else {
        panic("Unknown memory request type (%s) for addr %p",
              MemoryRequestType_to_string(mem_msg->getType()),
              mem_msg->m_addr);
    }

    SenderState *s = new SenderState(mem_msg->m_Sender);
    pkt->pushSenderState(s);

    if (RubySystem::getWarmupEnabled()) {
        // Use functional rather than timing accesses during warmup
        mem_queue->dequeue(clockEdge());
        memoryPort.sendFunctional(pkt);
        // Since the queue was popped the controller may be able
        // to make more progress. Make sure it wakes up
        scheduleEvent(Cycles(1));
        recvTimingResp(pkt);
    } else if (memoryPort.sendTimingReq(pkt)) {
        mem_queue->dequeue(clockEdge());
        // Since the queue was popped the controller may be able
        // to make more progress. Make sure it wakes up
        scheduleEvent(Cycles(1));
    } else {
        scheduleEvent(Cycles(1));
        delete pkt;
        delete s;
    }

    return true;
}

void
AbstractController::blockOnQueue(Addr addr, MessageBuffer* port)
{
    m_is_blocking = true;
    m_block_map[addr] = port;
}

bool
AbstractController::isBlocked(Addr addr) const
{
    return m_is_blocking && (m_block_map.find(addr) != m_block_map.end());
}

void
AbstractController::unblock(Addr addr)
{
    m_block_map.erase(addr);
    if (m_block_map.size() == 0) {
       m_is_blocking = false;
    }
}

bool
AbstractController::isBlocked(Addr addr)
{
    return (m_block_map.count(addr) > 0);
}

Port &
AbstractController::getPort(const std::string &if_name, PortID idx)
{
    return memoryPort;
}

void
AbstractController::functionalMemoryRead(PacketPtr pkt)
{
    memoryPort.sendFunctional(pkt);
}

int
AbstractController::functionalMemoryWrite(PacketPtr pkt)
{
    int num_functional_writes = 0;

    // Update memory itself.
    memoryPort.sendFunctional(pkt);
    return num_functional_writes + 1;
}

void
AbstractController::recvTimingResp(PacketPtr pkt)
{
    assert(getMemRespQueue());
    assert(pkt->isResponse());

    std::shared_ptr<MemoryMsg> msg = std::make_shared<MemoryMsg>(clockEdge());
    (*msg).m_addr = pkt->getAddr();
    (*msg).m_Sender = m_machineID;

    SenderState *s = dynamic_cast<SenderState *>(pkt->senderState);
    (*msg).m_OriginalRequestorMachId = s->id;
    delete s;

    if (pkt->isRead()) {
        (*msg).m_Type = MemoryRequestType_MEMORY_READ;
        (*msg).m_MessageSize = MessageSizeType_Response_Data;

        // Copy data from the packet
        (*msg).m_DataBlk.setData(pkt->getPtr<uint8_t>(), 0,
                                 RubySystem::getBlockSizeBytes());
    } else if (pkt->isWrite()) {
        (*msg).m_Type = MemoryRequestType_MEMORY_WB;
        (*msg).m_MessageSize = MessageSizeType_Writeback_Control;
    } else {
        panic("Incorrect packet type received from memory controller!");
    }

    getMemRespQueue()->enqueue(msg, clockEdge(), cyclesToTicks(Cycles(1)));
    delete pkt;
}

Tick
AbstractController::recvAtomic(PacketPtr pkt)
{
   return ticksToCycles(memoryPort.sendAtomic(pkt));
}

MachineID
AbstractController::mapAddressToMachine(Addr addr, MachineType mtype) const
{
    NodeID node = m_net_ptr->addressToNodeID(addr, mtype);
    MachineID mach = {mtype, node};
    return mach;
}

MachineID
AbstractController::mapAddressToDownstreamMachine(Addr addr, MachineType mtype)
const
{
    const auto i = downstreamAddrMap.contains(addr);
    fatal_if(i == downstreamAddrMap.end(),
      "%s: couldn't find mapping for address %x\n", name(), addr);

    const AddrMapEntry &entry = i->second;
    assert(!entry.empty());

    if (mtype == MachineType_NUM) {
        fatal_if(entry.size() > 1,
          "%s: address %x mapped to multiple machine types.\n", name(), addr);
        return entry.begin()->second;
    } else {
        auto j = entry.find(mtype);
        fatal_if(j == entry.end(),
          "%s: couldn't find mapping for address %x\n", name(), addr);
        return j->second;
    }
}

bool
AbstractController::MemoryPort::recvTimingResp(PacketPtr pkt)
{
    controller->recvTimingResp(pkt);
    return true;
}

void
AbstractController::MemoryPort::recvReqRetry()
{
    controller->serviceMemoryQueue();
}

AbstractController::MemoryPort::MemoryPort(const std::string &_name,
                                           AbstractController *_controller,
                                           PortID id)
    : RequestPort(_name, _controller, id), controller(_controller)
{
}
<|endoftext|>


<commit_before>/* Copyright 2010 Thomas McGuire <mcguire@kde.org>

   This library is free software; you can redistribute it and/or modify
   it under the terms of the GNU Library General Public License as published
   by the Free Software Foundation; either version 2 of the License or
   ( at your option ) version 3 or, at the discretion of KDE e.V.
   ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/
#include "settingsdialog.h"
#include "facebookresource.h"
#include "settings.h"
#include <libkfacebook/authenticationdialog.h>

#include <KWindowSystem>

using namespace Akonadi;

SettingsDialog::SettingsDialog( FacebookResource *parentResource, WId parentWindow )
  : KDialog(),
    mParentResource( parentResource )
{
  KWindowSystem::setMainWindow( this, parentWindow );
  setButtons( Ok|Cancel );
  setWindowIcon( KIcon( "facebookresource" ) );
  setWindowTitle( i18n("Facebook Settings") );

  setupWidgets();
  loadSettings();
}

SettingsDialog::~SettingsDialog()
{
}

void SettingsDialog::setupWidgets()
{
  QWidget *page = new QWidget( this );
  setupUi( page );
  setMainWidget( page );
  updateAuthenticationWidgets();
  connect( resetButton, SIGNAL(clicked(bool)), this, SLOT(resetAuthentication()) );
  connect( authenticateButton, SIGNAL(clicked(bool)), this, SLOT(showAuthenticationDialog()) );
}

void SettingsDialog::showAuthenticationDialog()
{
  QStringList permissions;
  permissions << "create_event"
              << "rsvp_event"
              << "offline_access"
              << "user_about_me"
              << "friends_about_me"
              << "user_birthday"
              << "friends_birthday"
              << "user_events"
              << "user_website"
              << "friends_website"
              << "read_friendlists"
              << "read_mailbox";
  AuthenticationDialog *authDialog = new AuthenticationDialog( this );
  authDialog->setAppId( Settings::self()->appID() );
  authDialog->setPermissions( permissions );
  connect( authDialog, SIGNAL(authenticated(QString)),
           this, SLOT(authenticationDone(QString)) );
  connect( authDialog, SIGNAL(canceled()),
           this, SLOT(authenticationCanceled()) );
  authenticateButton->setEnabled( false );
  authDialog->start();
}

void SettingsDialog::authenticationCanceled()
{
  authenticateButton->setEnabled( true );
}

void SettingsDialog::authenticationDone(const QString& accessToken)
{
  Settings::self()->setAccessToken( accessToken );
  updateAuthenticationWidgets();
}

void SettingsDialog::updateAuthenticationWidgets()
{
  if ( Settings::self()->accessToken().isEmpty() ) {
    authenticationStack->setCurrentIndex( 0 );
  } else {
    authenticationStack->setCurrentIndex( 1 );
    //authenticationLabel->setText( i18n( "Authenticated as %1.", Settings::self()->userName() ) );
    authenticationLabel->setText( i18n( "Authenticated." ) );
  }
}

void SettingsDialog::resetAuthentication()
{
  Settings::self()->setAccessToken( QString() );
  updateAuthenticationWidgets();
}

void SettingsDialog::loadSettings()
{
  if ( mParentResource->name() == mParentResource->identifier() )
    mParentResource->setName( i18n( "Faceboook Account") );

  nameEdit->setText( mParentResource->name() );
  nameEdit->setFocus();
}

void SettingsDialog::saveSettings()
{
  mParentResource->setName( nameEdit->text() );
  Settings::self()->writeConfig();
}

void SettingsDialog::slotButtonClicked( int button )
{
  switch( button ) {
  case Ok:
    saveSettings();
    accept();
    break;
  case Cancel:
    reject();
    return;
  }
}

#include "settingsdialog.moc"
<commit_msg>Better default resource name.<commit_after>/* Copyright 2010 Thomas McGuire <mcguire@kde.org>

   This library is free software; you can redistribute it and/or modify
   it under the terms of the GNU Library General Public License as published
   by the Free Software Foundation; either version 2 of the License or
   ( at your option ) version 3 or, at the discretion of KDE e.V.
   ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/
#include "settingsdialog.h"
#include "facebookresource.h"
#include "settings.h"
#include <libkfacebook/authenticationdialog.h>

#include <KWindowSystem>

using namespace Akonadi;

SettingsDialog::SettingsDialog( FacebookResource *parentResource, WId parentWindow )
  : KDialog(),
    mParentResource( parentResource )
{
  KWindowSystem::setMainWindow( this, parentWindow );
  setButtons( Ok|Cancel );
  setWindowIcon( KIcon( "facebookresource" ) );
  setWindowTitle( i18n("Facebook Settings") );

  setupWidgets();
  loadSettings();
}

SettingsDialog::~SettingsDialog()
{
}

void SettingsDialog::setupWidgets()
{
  QWidget *page = new QWidget( this );
  setupUi( page );
  setMainWidget( page );
  updateAuthenticationWidgets();
  connect( resetButton, SIGNAL(clicked(bool)), this, SLOT(resetAuthentication()) );
  connect( authenticateButton, SIGNAL(clicked(bool)), this, SLOT(showAuthenticationDialog()) );
}

void SettingsDialog::showAuthenticationDialog()
{
  QStringList permissions;
  permissions << "create_event"
              << "rsvp_event"
              << "offline_access"
              << "user_about_me"
              << "friends_about_me"
              << "user_birthday"
              << "friends_birthday"
              << "user_events"
              << "user_website"
              << "friends_website"
              << "read_friendlists"
              << "read_mailbox";
  AuthenticationDialog *authDialog = new AuthenticationDialog( this );
  authDialog->setAppId( Settings::self()->appID() );
  authDialog->setPermissions( permissions );
  connect( authDialog, SIGNAL(authenticated(QString)),
           this, SLOT(authenticationDone(QString)) );
  connect( authDialog, SIGNAL(canceled()),
           this, SLOT(authenticationCanceled()) );
  authenticateButton->setEnabled( false );
  authDialog->start();
}

void SettingsDialog::authenticationCanceled()
{
  authenticateButton->setEnabled( true );
}

void SettingsDialog::authenticationDone(const QString& accessToken)
{
  Settings::self()->setAccessToken( accessToken );
  updateAuthenticationWidgets();
}

void SettingsDialog::updateAuthenticationWidgets()
{
  if ( Settings::self()->accessToken().isEmpty() ) {
    authenticationStack->setCurrentIndex( 0 );
  } else {
    authenticationStack->setCurrentIndex( 1 );
    //authenticationLabel->setText( i18n( "Authenticated as %1.", Settings::self()->userName() ) );
    authenticationLabel->setText( i18n( "Authenticated." ) );
  }
}

void SettingsDialog::resetAuthentication()
{
  Settings::self()->setAccessToken( QString() );
  updateAuthenticationWidgets();
}

void SettingsDialog::loadSettings()
{
  if ( mParentResource->name() == mParentResource->identifier() )
    mParentResource->setName( i18n( "Faceboook" ) );

  nameEdit->setText( mParentResource->name() );
  nameEdit->setFocus();
}

void SettingsDialog::saveSettings()
{
  mParentResource->setName( nameEdit->text() );
  Settings::self()->writeConfig();
}

void SettingsDialog::slotButtonClicked( int button )
{
  switch( button ) {
  case Ok:
    saveSettings();
    accept();
    break;
  case Cancel:
    reject();
    return;
  }
}

#include "settingsdialog.moc"
<|endoftext|>


<commit_before>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_GRID_WALKER_HH
#define DUNE_STUFF_GRID_WALKER_HH

#include <vector>
#include <memory>
#include <type_traits>
#include <functional>

#if HAVE_TBB
# include <tbb/blocked_range.h>
# include <tbb/parallel_reduce.h>
# include <tbb/tbb_stddef.h>
#endif

#include <dune/grid/common/gridview.hh>

#if HAVE_DUNE_FEM
# include <dune/fem/gridpart/common/gridpart.hh>
#endif

#include <dune/stuff/grid/entity.hh>
#include <dune/stuff/grid/intersection.hh>
#include <dune/stuff/common/parallel/threadmanager.hh>

#include "walker/functors.hh"
#include "walker/apply-on.hh"
#include "walker/wrapper.hh"

namespace Dune {
namespace Stuff {
namespace Grid {

template< class GridViewImp >
class Walker
  : public Functor::Codim0And1< GridViewImp >
{
  static_assert(std::is_base_of< Dune::GridView< typename GridViewImp::Traits >, GridViewImp >::value
                || std::is_base_of< Dune::Fem::GridPartInterface< typename GridViewImp::Traits >, GridViewImp >::value,
                "GridViewImp has to be derived from either Dune::GridView or Dune::Fem::GridPartInterface!");
  typedef Walker< GridViewImp > ThisType;
public:
  typedef GridViewImp GridViewType;
  typedef typename Stuff::Grid::Entity< GridViewType >::Type       EntityType;
  typedef typename Stuff::Grid::Intersection< GridViewType >::Type IntersectionType;

  Walker(const GridViewType& grd_vw)
    : grid_view_(grd_vw)
  {}

  const GridViewType& grid_view() const
  {
    return grid_view_;
  }

  void add(std::function< void(const EntityType&) > lambda,
           const ApplyOn::WhichEntity< GridViewType >* where = new ApplyOn::AllEntities< GridViewType >())
  {
    codim0_functors_.emplace_back(new internal::Codim0LambdaWrapper< GridViewType >(lambda, where));
  }

  void add(Functor::Codim0< GridViewType >& functor,
           const ApplyOn::WhichEntity< GridViewType >* where = new ApplyOn::AllEntities< GridViewType >())
  {
    codim0_functors_.emplace_back(
          new internal::Codim0FunctorWrapper<GridViewType, Functor::Codim0< GridViewType > >(functor, where));
  }

  void add(Functor::Codim1< GridViewType >& functor,
           const ApplyOn::WhichIntersection< GridViewType >* where = new ApplyOn::AllIntersections< GridViewType >())
  {
    codim1_functors_.emplace_back(
          new internal::Codim1FunctorWrapper<GridViewType, Functor::Codim1< GridViewType > >(functor, where));
  }

  void add(Functor::Codim0And1< GridViewType >& functor,
           const ApplyOn::WhichEntity< GridViewType >* which_entities = new ApplyOn::AllEntities< GridViewType >(),
           const ApplyOn::WhichIntersection< GridViewType >* which_intersections
              = new ApplyOn::AllIntersections< GridViewType >())
  {
    codim0_functors_.emplace_back(
          new internal::Codim0FunctorWrapper<GridViewType, Functor::Codim0And1< GridViewType > >(functor,
                                                                                which_entities));
    codim1_functors_.emplace_back(
          new internal::Codim1FunctorWrapper<GridViewType, Functor::Codim0And1< GridViewType > >(functor,
                                                                                which_intersections));
  }

  void add(Functor::Codim0And1< GridViewType >& functor,
           const ApplyOn::WhichIntersection< GridViewType >* which_intersections,
           const ApplyOn::WhichEntity< GridViewType >* which_entities = new ApplyOn::AllEntities< GridViewType >())
  {
    codim0_functors_.emplace_back(
          new internal::Codim0FunctorWrapper<GridViewType, Functor::Codim0And1< GridViewType > >(functor,
                                                                                which_entities));
    codim1_functors_.emplace_back(
          new internal::Codim1FunctorWrapper<GridViewType, Functor::Codim0And1< GridViewType > >(functor,
                                                                                which_intersections));
  }

  void add(ThisType& other,
           const ApplyOn::WhichEntity< GridViewType >* which_entities = new ApplyOn::AllEntities< GridViewType >(),
           const ApplyOn::WhichIntersection< GridViewType >* which_intersections
              = new ApplyOn::AllIntersections< GridViewType >())
  {
    if (&other == this)
      DUNE_THROW(Stuff::Exceptions::you_are_using_this_wrong, "Do not add a Walker to itself!");
    codim0_functors_.emplace_back(new internal::WalkerWrapper< GridViewType, ThisType >(other, which_entities));
    codim1_functors_.emplace_back(new internal::WalkerWrapper< GridViewType, ThisType >(other, which_intersections));
  } // ... add(...)

  void add(ThisType& other,
           const ApplyOn::WhichIntersection< GridViewType >* which_intersections,
           const ApplyOn::WhichEntity< GridViewType >* which_entities = new ApplyOn::AllEntities< GridViewType >())
  {
    if (&other == this)
      DUNE_THROW(Stuff::Exceptions::you_are_using_this_wrong, "Do not add a Walker to itself!");
    codim0_functors_.emplace_back(new internal::WalkerWrapper< GridViewType, ThisType >(other, which_entities));
    codim1_functors_.emplace_back(new internal::WalkerWrapper< GridViewType, ThisType >(other, which_intersections));
  } // ... add(...)

  void clear()
  {
    codim0_functors_.clear();
    codim1_functors_.clear();
  } // ... clear()

  virtual void prepare()
  {
    for (auto& functor : codim0_functors_)
      functor->prepare();
    for (auto& functor : codim1_functors_)
      functor->prepare();
  } // ... prepare()

  bool apply_on(const EntityType& entity) const
  {
    for (const auto& functor : codim0_functors_)
      if (functor->apply_on(grid_view_, entity))
        return true;
    return false;
  } // ... apply_on(...)

  bool apply_on(const IntersectionType& intersection) const
  {
    for (const auto& functor : codim1_functors_)
      if (functor->apply_on(grid_view_, intersection))
        return true;
    return false;
  } // ... apply_on(...)

  virtual void apply_local(const EntityType& entity)
  {
    for (auto& functor : codim0_functors_)
      if (functor->apply_on(grid_view_, entity))
        functor->apply_local(entity);
  } // ... apply_local(...)

  virtual void apply_local(const IntersectionType& intersection,
                           const EntityType& inside_entity,
                           const EntityType& outside_entity)
  {
    for (auto& functor : codim1_functors_)
      if (functor->apply_on(grid_view_, intersection))
        functor->apply_local(intersection, inside_entity, outside_entity);
  } // ... apply_local(...)

  virtual void finalize()
  {
    for (auto& functor : codim0_functors_)
      functor->finalize();
    for (auto& functor : codim1_functors_)
      functor->finalize();
  } // ... finalize()

  void walk(const bool clear_stack = true)
  {
    // prepare functors
    prepare();

    // only do something, if we have to
    if ((codim0_functors_.size() + codim1_functors_.size()) > 0) {
      walk_range(DSC::entityRange(grid_view_));
    } // only do something, if we have to

    // finalize functors
    finalize();

    // clear the stack of functors
    if (clear_stack) clear();
  } // ... walk(...)

#if HAVE_TBB

protected:
  template< class PartioningType, class WalkerType >
  struct Body
  {
    Body(WalkerType& walker, PartioningType& partitioning)
      : walker_(walker)
      , partitioning_(partitioning)
    {}

    Body(Body& other, tbb::split /*split*/)
      : walker_(other.walker_)
      , partitioning_(other.partitioning_)
    {}

    void operator()(const tbb::blocked_range< std::size_t > &range)
    {
      // for all partitions in tbb-range
      for(std::size_t p = range.begin(); p != range.end(); ++p) {
        auto partition = partitioning_.partition(p);
        walker_.walk_range(partition);
      }
    }

    void join(Body& /*other*/)
    {}

    WalkerType& walker_;
    const PartioningType& partitioning_;
  }; // struct Body

public:
  template< class PartioningType >
  void tbb_walk(PartioningType& partitioning, const bool clear_stack = true)
  {
    // prepare functors
    prepare();

    // only do something, if we have to
    if ((codim0_functors_.size() + codim1_functors_.size()) > 0) {
      tbb::blocked_range< std::size_t > range(0, partitioning.partitions());
      Body< PartioningType, ThisType > body(*this, partitioning);
      tbb::parallel_reduce(range, body);
    }

    // finalize functors
    finalize();

    // clear the stack of functors
    if (clear_stack) clear();
  } // ... tbb_walk(...)

#endif // HAVE_TBB

protected:
  template< class EntityRange >
  void walk_range(const EntityRange& entity_range)
  {
#ifdef __INTEL_COMPILER
    const auto it_end = entity_range.end();
    for (auto it = entity_range.begin(); it != it_end; ++it) {
      const EntityType& entity = *it;
#else
    for (const EntityType& entity : entity_range) {
#endif
      // apply codim0 functors
      apply_local(entity);

      // only walk the intersections, if there are codim1 functors present
      if (codim1_functors_.size() > 0) {
        // walk the intersections
        const auto intersection_it_end = grid_view_.iend(entity);
        for (auto intersection_it = grid_view_.ibegin(entity);
             intersection_it != intersection_it_end;
             ++intersection_it) {
          const auto& intersection = *intersection_it;

          // apply codim1 functors
          if (intersection.neighbor()) {
            const auto neighbor_ptr = intersection.outside();
            const auto& neighbor = *neighbor_ptr;
            apply_local(intersection, entity, neighbor);
          } else
            apply_local(intersection, entity, entity);

        } // walk the intersections
      } // only walk the intersections, if there are codim1 functors present
    }
  } // ... walk_range(...)

  const GridViewType& grid_view_;
  std::vector< std::unique_ptr< internal::Codim0Object<GridViewType> > > codim0_functors_;
  std::vector< std::unique_ptr< internal::Codim1Object<GridViewType> > > codim1_functors_;
}; // class Walker

} // namespace Grid
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_GRID_WALKER_HH
<commit_msg>Revert "[grid.walker] added static check"<commit_after>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_GRID_WALKER_HH
#define DUNE_STUFF_GRID_WALKER_HH

#include <vector>
#include <memory>
#include <type_traits>
#include <functional>

#if HAVE_TBB
# include <tbb/blocked_range.h>
# include <tbb/parallel_reduce.h>
# include <tbb/tbb_stddef.h>
#endif

#include <dune/stuff/grid/entity.hh>
#include <dune/stuff/grid/intersection.hh>
#include <dune/stuff/common/parallel/threadmanager.hh>

#include "walker/functors.hh"
#include "walker/apply-on.hh"
#include "walker/wrapper.hh"

namespace Dune {
namespace Stuff {
namespace Grid {

template< class GridViewImp >
class Walker
  : public Functor::Codim0And1< GridViewImp >
{
  typedef Walker< GridViewImp > ThisType;
public:
  typedef GridViewImp GridViewType;
  typedef typename Stuff::Grid::Entity< GridViewType >::Type       EntityType;
  typedef typename Stuff::Grid::Intersection< GridViewType >::Type IntersectionType;

  Walker(const GridViewType& grd_vw)
    : grid_view_(grd_vw)
  {}

  const GridViewType& grid_view() const
  {
    return grid_view_;
  }

  void add(std::function< void(const EntityType&) > lambda,
           const ApplyOn::WhichEntity< GridViewType >* where = new ApplyOn::AllEntities< GridViewType >())
  {
    codim0_functors_.emplace_back(new internal::Codim0LambdaWrapper< GridViewType >(lambda, where));
  }

  void add(Functor::Codim0< GridViewType >& functor,
           const ApplyOn::WhichEntity< GridViewType >* where = new ApplyOn::AllEntities< GridViewType >())
  {
    codim0_functors_.emplace_back(
          new internal::Codim0FunctorWrapper<GridViewType, Functor::Codim0< GridViewType > >(functor, where));
  }

  void add(Functor::Codim1< GridViewType >& functor,
           const ApplyOn::WhichIntersection< GridViewType >* where = new ApplyOn::AllIntersections< GridViewType >())
  {
    codim1_functors_.emplace_back(
          new internal::Codim1FunctorWrapper<GridViewType, Functor::Codim1< GridViewType > >(functor, where));
  }

  void add(Functor::Codim0And1< GridViewType >& functor,
           const ApplyOn::WhichEntity< GridViewType >* which_entities = new ApplyOn::AllEntities< GridViewType >(),
           const ApplyOn::WhichIntersection< GridViewType >* which_intersections
              = new ApplyOn::AllIntersections< GridViewType >())
  {
    codim0_functors_.emplace_back(
          new internal::Codim0FunctorWrapper<GridViewType, Functor::Codim0And1< GridViewType > >(functor,
                                                                                which_entities));
    codim1_functors_.emplace_back(
          new internal::Codim1FunctorWrapper<GridViewType, Functor::Codim0And1< GridViewType > >(functor,
                                                                                which_intersections));
  }

  void add(Functor::Codim0And1< GridViewType >& functor,
           const ApplyOn::WhichIntersection< GridViewType >* which_intersections,
           const ApplyOn::WhichEntity< GridViewType >* which_entities = new ApplyOn::AllEntities< GridViewType >())
  {
    codim0_functors_.emplace_back(
          new internal::Codim0FunctorWrapper<GridViewType, Functor::Codim0And1< GridViewType > >(functor,
                                                                                which_entities));
    codim1_functors_.emplace_back(
          new internal::Codim1FunctorWrapper<GridViewType, Functor::Codim0And1< GridViewType > >(functor,
                                                                                which_intersections));
  }

  void add(ThisType& other,
           const ApplyOn::WhichEntity< GridViewType >* which_entities = new ApplyOn::AllEntities< GridViewType >(),
           const ApplyOn::WhichIntersection< GridViewType >* which_intersections
              = new ApplyOn::AllIntersections< GridViewType >())
  {
    if (&other == this)
      DUNE_THROW(Stuff::Exceptions::you_are_using_this_wrong, "Do not add a Walker to itself!");
    codim0_functors_.emplace_back(new internal::WalkerWrapper< GridViewType, ThisType >(other, which_entities));
    codim1_functors_.emplace_back(new internal::WalkerWrapper< GridViewType, ThisType >(other, which_intersections));
  } // ... add(...)

  void add(ThisType& other,
           const ApplyOn::WhichIntersection< GridViewType >* which_intersections,
           const ApplyOn::WhichEntity< GridViewType >* which_entities = new ApplyOn::AllEntities< GridViewType >())
  {
    if (&other == this)
      DUNE_THROW(Stuff::Exceptions::you_are_using_this_wrong, "Do not add a Walker to itself!");
    codim0_functors_.emplace_back(new internal::WalkerWrapper< GridViewType, ThisType >(other, which_entities));
    codim1_functors_.emplace_back(new internal::WalkerWrapper< GridViewType, ThisType >(other, which_intersections));
  } // ... add(...)

  void clear()
  {
    codim0_functors_.clear();
    codim1_functors_.clear();
  } // ... clear()

  virtual void prepare()
  {
    for (auto& functor : codim0_functors_)
      functor->prepare();
    for (auto& functor : codim1_functors_)
      functor->prepare();
  } // ... prepare()

  bool apply_on(const EntityType& entity) const
  {
    for (const auto& functor : codim0_functors_)
      if (functor->apply_on(grid_view_, entity))
        return true;
    return false;
  } // ... apply_on(...)

  bool apply_on(const IntersectionType& intersection) const
  {
    for (const auto& functor : codim1_functors_)
      if (functor->apply_on(grid_view_, intersection))
        return true;
    return false;
  } // ... apply_on(...)

  virtual void apply_local(const EntityType& entity)
  {
    for (auto& functor : codim0_functors_)
      if (functor->apply_on(grid_view_, entity))
        functor->apply_local(entity);
  } // ... apply_local(...)

  virtual void apply_local(const IntersectionType& intersection,
                           const EntityType& inside_entity,
                           const EntityType& outside_entity)
  {
    for (auto& functor : codim1_functors_)
      if (functor->apply_on(grid_view_, intersection))
        functor->apply_local(intersection, inside_entity, outside_entity);
  } // ... apply_local(...)

  virtual void finalize()
  {
    for (auto& functor : codim0_functors_)
      functor->finalize();
    for (auto& functor : codim1_functors_)
      functor->finalize();
  } // ... finalize()

  void walk(const bool clear_stack = true)
  {
    // prepare functors
    prepare();

    // only do something, if we have to
    if ((codim0_functors_.size() + codim1_functors_.size()) > 0) {
      walk_range(DSC::entityRange(grid_view_));
    } // only do something, if we have to

    // finalize functors
    finalize();

    // clear the stack of functors
    if (clear_stack) clear();
  } // ... walk(...)

#if HAVE_TBB

protected:
  template< class PartioningType, class WalkerType >
  struct Body
  {
    Body(WalkerType& walker, PartioningType& partitioning)
      : walker_(walker)
      , partitioning_(partitioning)
    {}

    Body(Body& other, tbb::split /*split*/)
      : walker_(other.walker_)
      , partitioning_(other.partitioning_)
    {}

    void operator()(const tbb::blocked_range< std::size_t > &range)
    {
      // for all partitions in tbb-range
      for(std::size_t p = range.begin(); p != range.end(); ++p) {
        auto partition = partitioning_.partition(p);
        walker_.walk_range(partition);
      }
    }

    void join(Body& /*other*/)
    {}

    WalkerType& walker_;
    const PartioningType& partitioning_;
  }; // struct Body

public:
  template< class PartioningType >
  void tbb_walk(PartioningType& partitioning, const bool clear_stack = true)
  {
    // prepare functors
    prepare();

    // only do something, if we have to
    if ((codim0_functors_.size() + codim1_functors_.size()) > 0) {
      tbb::blocked_range< std::size_t > range(0, partitioning.partitions());
      Body< PartioningType, ThisType > body(*this, partitioning);
      tbb::parallel_reduce(range, body);
    }

    // finalize functors
    finalize();

    // clear the stack of functors
    if (clear_stack) clear();
  } // ... tbb_walk(...)

#endif // HAVE_TBB

protected:
  template< class EntityRange >
  void walk_range(const EntityRange& entity_range)
  {
#ifdef __INTEL_COMPILER
    const auto it_end = entity_range.end();
    for (auto it = entity_range.begin(); it != it_end; ++it) {
      const EntityType& entity = *it;
#else
    for (const EntityType& entity : entity_range) {
#endif
      // apply codim0 functors
      apply_local(entity);

      // only walk the intersections, if there are codim1 functors present
      if (codim1_functors_.size() > 0) {
        // walk the intersections
        const auto intersection_it_end = grid_view_.iend(entity);
        for (auto intersection_it = grid_view_.ibegin(entity);
             intersection_it != intersection_it_end;
             ++intersection_it) {
          const auto& intersection = *intersection_it;

          // apply codim1 functors
          if (intersection.neighbor()) {
            const auto neighbor_ptr = intersection.outside();
            const auto& neighbor = *neighbor_ptr;
            apply_local(intersection, entity, neighbor);
          } else
            apply_local(intersection, entity, entity);

        } // walk the intersections
      } // only walk the intersections, if there are codim1 functors present
    }
  } // ... walk_range(...)

  const GridViewType& grid_view_;
  std::vector< std::unique_ptr< internal::Codim0Object<GridViewType> > > codim0_functors_;
  std::vector< std::unique_ptr< internal::Codim1Object<GridViewType> > > codim1_functors_;
}; // class Walker

} // namespace Grid
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_GRID_WALKER_HH
<|endoftext|>


<commit_before>#include <iostream>
#include <string>

using namespace std;

void PostAction(int x, int y, int n, int m, char field[][101])
{
	for(int i = -1; i <= 1; ++i) {
		for(int j = -1; j <= 1; ++j) {
			if(x + i >= 0 && x + i < n)
				if(y + j >= 0 && y + j < m) {
					if(x + i == x && y + j == y)
						continue;
					if(field[x+i][y+j] == '*')
						continue;
					field[x+i][y+j] += 1;
				}
		}
	}
}
int main()
{
	int count = 0;
	char field[101][101];
	char input;
	int n, m;

	while(1) {
		cin >> n;
		cin >> m;

		if( n == 0 && m == 0)
			break;

		count++;

		for(int i = 0; i < n; ++i) {
			for(int j = 0; j < m; ++j) {
				cin >> input;
				if( input == '.')
					field[i][j] = '0';
				else
					field[i][j] = input;
			}
			field[i][m] = '\0';
		}

		for(int i = 0; i < n; ++i) {
			for(int j = 0; j < m; ++j) {
				if(field[i][j] == '*')
					PostAction(i, j, n, m, field);
			}
		}
		cout << "Field #" << count << ":" << endl;

		for(int i = 0; i < n; ++i)
			cout << field[i] << endl;

		cout << endl;
	}
	return 0;
}
<commit_msg>Fixed the presentation error<commit_after>#include <iostream>
#include <string>

using namespace std;

void PostAction(int x, int y, int n, int m, char field[][101])
{
	for(int i = -1; i <= 1; ++i) {
		for(int j = -1; j <= 1; ++j) {
			if(x + i >= 0 && x + i < n)
				if(y + j >= 0 && y + j < m) {
					if(x + i == x && y + j == y)
						continue;
					if(field[x+i][y+j] == '*')
						continue;
					field[x+i][y+j] += 1;
				}
		}
	}
}
int main()
{
	int count = 0;
	char field[101][101];
	char input;
	int n, m;

	while(1) {
		cin >> n;
		cin >> m;

		if( n == 0 && m == 0)
			break;

		count++;

		for(int i = 0; i < n; ++i) {
			for(int j = 0; j < m; ++j) {
				cin >> input;
				if( input == '.')
					field[i][j] = '0';
				else
					field[i][j] = input;
			}
			field[i][m] = '\0';
		}

		for(int i = 0; i < n; ++i) {
			for(int j = 0; j < m; ++j) {
				if(field[i][j] == '*')
					PostAction(i, j, n, m, field);
			}
		}
		if(count > 1)
            cout << endl;
		cout << "Field #" << count << ":" << endl;

		for(int i = 0; i < n; ++i)
			cout << field[i] << endl;

	}
	return 0;
}
<|endoftext|>


<commit_before>/* semantic.cc
 * Semantic Analyzer Driver class to store all the parse trees and
 * symbol tables.  Also is the class responsible for parsing the trees
 * and populating the symbol tables.
 *
 * UIdaho CS445 120++ Compiler
 * author: Chris Waltrip <walt2178@vandals.uidaho.edu>
 */

#include <cstddef>
#include <iostream>

#include "120rules.hh"
#include "exception.hh"
#include "globals.hh"
#include "semantic.hh"
#include "treenode.hh"

void SemanticAnalyzer::add_tree(TreeNode *r, TypenameTable e) {
	this->tuples.push_back(boost::make_tuple(r,new SymbolTable(),e));
}

/*
 * Generate all of the symbols tables by iterating through each
 * parse tree and creating a symbol table from it.
 */
void SemanticAnalyzer::generate_all_tables() {
	std::deque<
		boost::tuple<TreeNode*,SymbolTable*,TypenameTable>
		>::iterator it;
	for(it = this->tuples.begin(); it != this->tuples.end(); ++it) {
		std::size_t i = it - this->tuples.begin();

		std::clog << "Generating table number " << i << ": ";
		std::clog << std::endl;

		TreeNode *t(this->tuples[i].get<0>());
		SymbolTable *s(this->tuples[i].get<1>());
		TypenameTable &e(this->tuples[i].get<2>());
		this->generate_table(t,s,e);
	}
}

/*
 * Iterate through each of the tuples and print the symbol tables from each
 * of them.
 */
void SemanticAnalyzer::print_all_tables() {
	std::deque<
		boost::tuple<TreeNode*,SymbolTable*,TypenameTable>
		>::iterator it;
	for(it = this->tuples.begin(); it != this->tuples.end(); ++it) {
		std::size_t i = it - this->tuples.begin();

		std::clog << "Printing symbol table #" << i << std::endl;
		std::clog << "===================================" << std::endl;

		this->tuples[i].get<1>()->print_table();

		std::clog << std::endl;
	}
}

/*
 * Parse the parse tree in a pre-order traversal, identifying and creating
 * all symbols along the way and populating the proper symbol table.
 */
void SemanticAnalyzer::generate_table(TreeNode *t, SymbolTable *s,
					TypenameTable &e) {
	/*
	 * Get each part of the production rule using integer division
	 * and modulo.
	 */
	std::size_t base_rule = t->prod_num / 1000;
	std::size_t rule_num = t->prod_num % 1000;

	switch(base_rule) {
		case SIMPLE_DECL_R:
			this->symbolize_simple_decl(t, s);
			break;
		/*
		 * If no rule is matched, parse all of the children that exist.
		 */
		default:
			if(t->num_kids > 0) {
				for(int i = 0; i < t->num_kids; ++i) {
					if(t->kids[i] != NULL) {
						this->generate_table(
							t->kids[i], s, e);
					}
				}
			}
			break;
	}
}

/*
 * After a symbol has been built, attempt to insert it into the symbol table.
 * If the symbol already exists, EDuplicateSymbol is thrown.  Report an error
 * an then throw the same exception if this occurs.  This allows the calling
 * function to decide to keep running or exit on a per-case basis.  Right now,
 * this function exits the compiler before this throw happens because I don't
 * have a case where I don't want to exit on a duplicate symbol.
 */
void SemanticAnalyzer::add_symbol(AbstractSymbol a, SymbolTable *s) {
	try {
		s->insert(a.name,a);
	} catch (EDuplicateSymbol e) {
		std::cerr << e.what() << ": " << a.name << std::endl;
		exit(EXIT_SEMANTIC_ERROR);
		throw EDuplicateSymbol(); /* Never reached, maybe future use */
	}
	std::clog << "'" << a.name << "' (" << a.type << ") added to table!";
	std::clog << std::endl;
}

/*
 * Check the current symbol table to make sure a symbol hasn't already been
 * declared and if not then create a new symbol and add it to the table.
 */
void SemanticAnalyzer::add_basic_symbol(TreeNode *t, SymbolTable *s,
							std::string type) {
	if(t->t != NULL) {
		std::string n = t->t->get_text();
		BasicSymbol basic(n, type);

		this->add_symbol(basic, s);
	} else {
		std::stringstream ss;
		ss << "Cannot add a non-terminal to symbol table (";
		ss << t->prod_text << ")";
		std::cerr << ss.str() << std::endl;
		exit(EXIT_SEMANTIC_ERROR);
	}
}

/*
 * Parse a simple declaration and find all symbols that need to be added
 * and then add them to the symbol table.
 *
 * A simple declarator will either be an initialization list or a
 * class/function initialization.
 */
void SemanticAnalyzer::symbolize_simple_decl(TreeNode *t, SymbolTable *s) {
	std::string ts;
	switch(t->prod_num) {
		case SIMPLE_DECL_1:
			ts = t->kids[0]->t->get_text();
			switch(t->kids[1]->prod_num) {
				case INIT_DECL_1:
					this->symbolize_init_decl(
						t->kids[1], s, ts);
					break;
				case INIT_DECL_LIST_2:
					this->symbolize_init_decl_list(
						t->kids[1], s, ts);
					break;
			}
			break;
		case SIMPLE_DECL_2:
			std::clog << "SIMPLE_DECL_2 ???" << std::endl;
			break;
		default:
			break;
	}
}
/*
 * Initialization declarations include basic variable declarations as well as
 * function prototypes.  Parse the subtree and identify the type of declaration
 * and add the necessary symbols to the symbol table.
 */
void SemanticAnalyzer::symbolize_init_decl(TreeNode *t, SymbolTable *s,
							std::string ident) {

	/* Basic types contain a leaf in the first child position */
	if(is_token(t->kids[0])) {
		this->add_basic_symbol(t->kids[0], s, ident);
		return;
	}

	/* Function prototypes */
	if(t->kids[0]->prod_num == DIRECT_DECL_5) {
		this->symbolize_function_prototype(t->kids[0], s, ident);
		return;
	}

	/* Undefined parse reached */
	throw EBadGrammarParse();
}

/*
 * An init-decl-list can be either the variable name itself or could be
 * something like a function that we need to dig further down into.
 */
void SemanticAnalyzer::symbolize_init_decl_list(TreeNode *t, SymbolTable *s,
							std::string ident) {
	for(std::size_t i = 0; i < t->num_kids; ++i) {
		if(node_exists(t->kids[i])) {
			switch(t->kids[i]->prod_num) {
				case INIT_DECL_LIST_2:
					this->symbolize_init_decl_list(
							t->kids[i], s, ident);
					break;
				case INIT_DECL_1:
					this->symbolize_init_decl(
							t->kids[i], s, ident);
					break;
			}
		}
	}
}

/*
 * Parameter declarations are similar (if not identical) to initialization
 * declarations.
 *
 * Is ident actually needed?  It should be because we never actually have a
 * long list -- it's always individual variables.
 */
void SemanticAnalyzer::symbolize_param_decl(TreeNode *t, SymbolTable *s) {
	this->add_basic_symbol(t->kids[1], s, t->kids[0]->t->get_text());
}

/*
 * Parameter declaration lists are similar (if not identical) to initialization
 * declaration lists.
 */
void SemanticAnalyzer::symbolize_param_decl_list(TreeNode *t, SymbolTable *s) {
	for(std::size_t i = 0; i < t->num_kids; ++i) {
		if(node_exists(t->kids[i])) {
			switch(t->kids[i]->prod_num) {
				case PARAM_DECL_LIST_2:
					this->symbolize_param_decl_list(
							t->kids[i], s);
					break;
				case PARAM_DECL_1:
					this->symbolize_param_decl(
							t->kids[i], s);
					break;
			}
		}
	}
}

/*
 * Function prototypes are defined in DIRECT_DECL_5.  This also adds a function
 * symbol to the symbol table.
 *
 * TODO: Move addition to symbol table to a separate function!
 *
 * kids[0] <-- function name
 * kids[2] <-- possible parameter list
 */
void SemanticAnalyzer::symbolize_function_prototype(TreeNode *t, SymbolTable *s,
							std::string ident) {

	FunctionSymbol func(t->kids[0]->t->get_text(), ident);

	/* Parse parameter list if it exists */
	if(node_exists(t->kids[2])) {
		SymbolTable *p = new SymbolTable(s);
		switch(t->kids[2]->prod_num) {
			case PARAM_DECL_LIST_2:
				this->symbolize_param_decl_list(t->kids[2], p);
				break;
			case PARAM_DECL_1:
				this->symbolize_param_decl(t->kids[2], p);
				break;
			default:
				throw EBadGrammarParse();
				break;
		}
		func.params = p;
		s->add_sub_table(p);
	}
	/* Add the FunctionSymbol to the SymbolTable */

	this->add_symbol(s,func);
}<commit_msg>Fixing function symbol adding to use add_symbol parameter order<commit_after>/* semantic.cc
 * Semantic Analyzer Driver class to store all the parse trees and
 * symbol tables.  Also is the class responsible for parsing the trees
 * and populating the symbol tables.
 *
 * UIdaho CS445 120++ Compiler
 * author: Chris Waltrip <walt2178@vandals.uidaho.edu>
 */

#include <cstddef>
#include <iostream>

#include "120rules.hh"
#include "exception.hh"
#include "globals.hh"
#include "semantic.hh"
#include "treenode.hh"

void SemanticAnalyzer::add_tree(TreeNode *r, TypenameTable e) {
	this->tuples.push_back(boost::make_tuple(r,new SymbolTable(),e));
}

/*
 * Generate all of the symbols tables by iterating through each
 * parse tree and creating a symbol table from it.
 */
void SemanticAnalyzer::generate_all_tables() {
	std::deque<
		boost::tuple<TreeNode*,SymbolTable*,TypenameTable>
		>::iterator it;
	for(it = this->tuples.begin(); it != this->tuples.end(); ++it) {
		std::size_t i = it - this->tuples.begin();

		std::clog << "Generating table number " << i << ": ";
		std::clog << std::endl;

		TreeNode *t(this->tuples[i].get<0>());
		SymbolTable *s(this->tuples[i].get<1>());
		TypenameTable &e(this->tuples[i].get<2>());
		this->generate_table(t,s,e);
	}
}

/*
 * Iterate through each of the tuples and print the symbol tables from each
 * of them.
 */
void SemanticAnalyzer::print_all_tables() {
	std::deque<
		boost::tuple<TreeNode*,SymbolTable*,TypenameTable>
		>::iterator it;
	for(it = this->tuples.begin(); it != this->tuples.end(); ++it) {
		std::size_t i = it - this->tuples.begin();

		std::clog << "Printing symbol table #" << i << std::endl;
		std::clog << "===================================" << std::endl;

		this->tuples[i].get<1>()->print_table();

		std::clog << std::endl;
	}
}

/*
 * Parse the parse tree in a pre-order traversal, identifying and creating
 * all symbols along the way and populating the proper symbol table.
 */
void SemanticAnalyzer::generate_table(TreeNode *t, SymbolTable *s,
					TypenameTable &e) {
	/*
	 * Get each part of the production rule using integer division
	 * and modulo.
	 */
	std::size_t base_rule = t->prod_num / 1000;
	std::size_t rule_num = t->prod_num % 1000;

	switch(base_rule) {
		case SIMPLE_DECL_R:
			this->symbolize_simple_decl(t, s);
			break;
		/*
		 * If no rule is matched, parse all of the children that exist.
		 */
		default:
			if(t->num_kids > 0) {
				for(int i = 0; i < t->num_kids; ++i) {
					if(t->kids[i] != NULL) {
						this->generate_table(
							t->kids[i], s, e);
					}
				}
			}
			break;
	}
}

/*
 * After a symbol has been built, attempt to insert it into the symbol table.
 * If the symbol already exists, EDuplicateSymbol is thrown.  Report an error
 * an then throw the same exception if this occurs.  This allows the calling
 * function to decide to keep running or exit on a per-case basis.  Right now,
 * this function exits the compiler before this throw happens because I don't
 * have a case where I don't want to exit on a duplicate symbol.
 */
void SemanticAnalyzer::add_symbol(AbstractSymbol a, SymbolTable *s) {
	try {
		s->insert(a.name,a);
	} catch (EDuplicateSymbol e) {
		std::cerr << e.what() << ": " << a.name << std::endl;
		exit(EXIT_SEMANTIC_ERROR);
		throw EDuplicateSymbol(); /* Never reached, maybe future use */
	}
	std::clog << "'" << a.name << "' (" << a.type << ") added to table!";
	std::clog << std::endl;
}

/*
 * Check the current symbol table to make sure a symbol hasn't already been
 * declared and if not then create a new symbol and add it to the table.
 */
void SemanticAnalyzer::add_basic_symbol(TreeNode *t, SymbolTable *s,
							std::string type) {
	if(t->t != NULL) {
		std::string n = t->t->get_text();
		BasicSymbol basic(n, type);

		this->add_symbol(basic, s);
	} else {
		std::stringstream ss;
		ss << "Cannot add a non-terminal to symbol table (";
		ss << t->prod_text << ")";
		std::cerr << ss.str() << std::endl;
		exit(EXIT_SEMANTIC_ERROR);
	}
}

/*
 * Parse a simple declaration and find all symbols that need to be added
 * and then add them to the symbol table.
 *
 * A simple declarator will either be an initialization list or a
 * class/function initialization.
 */
void SemanticAnalyzer::symbolize_simple_decl(TreeNode *t, SymbolTable *s) {
	std::string ts;
	switch(t->prod_num) {
		case SIMPLE_DECL_1:
			ts = t->kids[0]->t->get_text();
			switch(t->kids[1]->prod_num) {
				case INIT_DECL_1:
					this->symbolize_init_decl(
						t->kids[1], s, ts);
					break;
				case INIT_DECL_LIST_2:
					this->symbolize_init_decl_list(
						t->kids[1], s, ts);
					break;
			}
			break;
		case SIMPLE_DECL_2:
			std::clog << "SIMPLE_DECL_2 ???" << std::endl;
			break;
		default:
			break;
	}
}
/*
 * Initialization declarations include basic variable declarations as well as
 * function prototypes.  Parse the subtree and identify the type of declaration
 * and add the necessary symbols to the symbol table.
 */
void SemanticAnalyzer::symbolize_init_decl(TreeNode *t, SymbolTable *s,
							std::string ident) {

	/* Basic types contain a leaf in the first child position */
	if(is_token(t->kids[0])) {
		this->add_basic_symbol(t->kids[0], s, ident);
		return;
	}

	/* Function prototypes */
	if(t->kids[0]->prod_num == DIRECT_DECL_5) {
		this->symbolize_function_prototype(t->kids[0], s, ident);
		return;
	}

	/* Undefined parse reached */
	throw EBadGrammarParse();
}

/*
 * An init-decl-list can be either the variable name itself or could be
 * something like a function that we need to dig further down into.
 */
void SemanticAnalyzer::symbolize_init_decl_list(TreeNode *t, SymbolTable *s,
							std::string ident) {
	for(std::size_t i = 0; i < t->num_kids; ++i) {
		if(node_exists(t->kids[i])) {
			switch(t->kids[i]->prod_num) {
				case INIT_DECL_LIST_2:
					this->symbolize_init_decl_list(
							t->kids[i], s, ident);
					break;
				case INIT_DECL_1:
					this->symbolize_init_decl(
							t->kids[i], s, ident);
					break;
			}
		}
	}
}

/*
 * Parameter declarations are similar (if not identical) to initialization
 * declarations.
 *
 * Is ident actually needed?  It should be because we never actually have a
 * long list -- it's always individual variables.
 */
void SemanticAnalyzer::symbolize_param_decl(TreeNode *t, SymbolTable *s) {
	this->add_basic_symbol(t->kids[1], s, t->kids[0]->t->get_text());
}

/*
 * Parameter declaration lists are similar (if not identical) to initialization
 * declaration lists.
 */
void SemanticAnalyzer::symbolize_param_decl_list(TreeNode *t, SymbolTable *s) {
	for(std::size_t i = 0; i < t->num_kids; ++i) {
		if(node_exists(t->kids[i])) {
			switch(t->kids[i]->prod_num) {
				case PARAM_DECL_LIST_2:
					this->symbolize_param_decl_list(
							t->kids[i], s);
					break;
				case PARAM_DECL_1:
					this->symbolize_param_decl(
							t->kids[i], s);
					break;
			}
		}
	}
}

/*
 * Function prototypes are defined in DIRECT_DECL_5.  This also adds a function
 * symbol to the symbol table.
 *
 * TODO: Move addition to symbol table to a separate function!
 *
 * kids[0] <-- function name
 * kids[2] <-- possible parameter list
 */
void SemanticAnalyzer::symbolize_function_prototype(TreeNode *t, SymbolTable *s,
							std::string ident) {

	FunctionSymbol func(t->kids[0]->t->get_text(), ident);

	/* Parse parameter list if it exists */
	if(node_exists(t->kids[2])) {
		SymbolTable *p = new SymbolTable(s);
		switch(t->kids[2]->prod_num) {
			case PARAM_DECL_LIST_2:
				this->symbolize_param_decl_list(t->kids[2], p);
				break;
			case PARAM_DECL_1:
				this->symbolize_param_decl(t->kids[2], p);
				break;
			default:
				throw EBadGrammarParse();
				break;
		}
		func.params = p;
		s->add_sub_table(p);
	}
	/* Add the FunctionSymbol to the SymbolTable */

	this->add_symbol(func,s);
}<|endoftext|>


<commit_before>#include "factor_graph.h"
#include "factor.h"
#include "binary_format.h"
#include <iostream>

#include <fstream>

// sort according to id
template <class T>
class idsorter : public std::binary_function<T, T, bool> {
 public:
  inline bool operator()(const T &left, const T &right) {
    return left.id < right.id;
  }
};

dd::FactorGraph::FactorGraph(long _n_var, long _n_factor, long _n_weight,
                             long _n_edge)
    : n_var(_n_var),
      n_factor(_n_factor),
      n_weight(_n_weight),
      n_edge(_n_edge),
      c_nvar(0),
      c_nfactor(0),
      c_nweight(0),
      n_evid(0),
      n_query(0),
      variables(new RawVariable[_n_var]),
      factors(new RawFactor[_n_factor]),
      weights(new Weight[_n_weight]),
      sorted(false),
      safety_check_passed(false) {}

void dd::FactorGraph::compile(CompiledFactorGraph &cfg) {
  cfg.c_nvar = c_nvar;
  cfg.c_nfactor = c_nfactor;
  cfg.c_nweight = c_nweight;

  cfg.n_evid = n_evid;
  cfg.n_query = n_query;

  cfg.stepsize = stepsize;

  long i_edge = 0;

  /*
   * For each factor, put the variables sorted within each factor in an
   * array.
   */
  for (long i = 0; i < n_factor; i++) {
    RawFactor &rf = factors[i];
    rf.n_start_i_vif = i_edge;

    /*
     * Each factor knows how many variables it has. After sorting the variables
     * within the factor by their position, lay the variables in this factor
     * one after another in the vifs array.
     */
    std::sort(rf.tmp_variables.begin(), rf.tmp_variables.end(),
              dd::compare_position);
    for (const VariableInFactor &vif : rf.tmp_variables) {
      cfg.vifs[i_edge] = vif;
      i_edge++;
    }

    /* Also copy the clean factor without the temp crap */
    Factor f(rf);
    cfg.factors[i] = f;
  }
  dprintf("i_edge = %ld n_edge = %ld", i_edge, n_edge);
  assert(i_edge == n_edge);

  i_edge = 0;
  long ntallies = 0;

  /*
   * For each variable, lay the factors sequentially in an array as well.
   */
  for (long i = 0; i < n_var; i++) {
    RawVariable &rv = variables[i];
    // I guess it's only at this point that we're sure tmp_factor_ids won't
    // change since we've fully loaded the graph.
    rv.n_factors = rv.tmp_factor_ids.size();
    rv.n_start_i_factors = i_edge;

    if (rv.domain_type == DTYPE_MULTINOMIAL) {
      rv.n_start_i_tally = ntallies;
      ntallies += rv.cardinality;
    }

    for (const long &fid : rv.tmp_factor_ids) {
      cfg.factor_ids[i_edge] = fid;

      cfg.compact_factors[i_edge].id = factors[fid].id;
      cfg.compact_factors[i_edge].func_id = factors[fid].func_id;
      cfg.compact_factors[i_edge].n_variables = factors[fid].n_variables;
      cfg.compact_factors[i_edge].n_start_i_vif = factors[fid].n_start_i_vif;

      cfg.compact_factors_weightids[i_edge] = factors[fid].weight_id;

      i_edge++;
    }

    /* Also remember to copy the clean variable without the temp crap */
    Variable v(rv);
    cfg.variables[i] = v;
  }

  /* Initialize the InferenceResult array in the end of compilation */
  cfg.infrs->init(cfg.variables, weights);

  assert(i_edge == n_edge);
  /*
   * XXX: Ideally, we don't care about the factor graph anymore at this
   * point, but for consistency, I will update the c_edge variable as well.
   */
  c_edge = i_edge;
  cfg.c_edge = i_edge;
}

void dd::FactorGraph::safety_check() {
  // check whether variables, factors, and weights are stored
  // in the order of their id
  long s = n_var;
  for (long i = 0; i < s; i++) {
    assert(this->variables[i].id == i);
  }
  s = n_factor;
  for (long i = 0; i < s; i++) {
    assert(this->factors[i].id == i);
  }
  s = n_weight;
  for (long i = 0; i < s; i++) {
    assert(this->weights[i].id == i);
  }
  this->sorted = true;
  this->safety_check_passed = true;
}

bool dd::FactorGraph::is_usable() {
  return this->sorted && this->safety_check_passed;
}

dd::CompiledFactorGraph::CompiledFactorGraph(long _n_var, long _n_factor,
                                             long _n_weight, long _n_edge)
    : n_var(_n_var),
      n_factor(_n_factor),
      n_weight(_n_weight),
      n_edge(_n_edge),
      c_nvar(0),
      c_nfactor(0),
      c_nweight(0),
      c_edge(0),
      n_evid(0),
      n_query(0),
      variables(new Variable[_n_var]),
      factors(new Factor[_n_factor]),
      compact_factors(new CompactFactor[_n_edge]),
      compact_factors_weightids(new int[_n_edge]),
      factor_ids(new long[_n_edge]),
      vifs(new VariableInFactor[_n_edge]),
      infrs(new InferenceResult(_n_var, _n_weight)),
      safety_check_passed(false) {}

void dd::CompiledFactorGraph::copy_from(
    const CompiledFactorGraph *const p_other_fg) {
  c_nvar = p_other_fg->c_nvar;
  c_nfactor = p_other_fg->c_nfactor;
  c_nweight = p_other_fg->c_nweight;
  c_edge = p_other_fg->c_edge;

  n_evid = p_other_fg->n_evid;
  n_query = p_other_fg->n_query;

  // copy each member from the given graph
  memcpy(variables, p_other_fg->variables, sizeof(Variable) * n_var);
  memcpy(factors, p_other_fg->factors, sizeof(Factor) * n_factor);

  memcpy(compact_factors, p_other_fg->compact_factors,
         sizeof(CompactFactor) * n_edge);
  memcpy(compact_factors_weightids, p_other_fg->compact_factors_weightids,
         sizeof(int) * n_edge);
  memcpy(factor_ids, p_other_fg->factor_ids, sizeof(long) * n_edge);
  memcpy(vifs, p_other_fg->vifs, sizeof(VariableInFactor) * n_edge);

  sorted = p_other_fg->sorted;
  safety_check_passed = p_other_fg->safety_check_passed;

  infrs->copy_from(*p_other_fg->infrs);
  infrs->ntallies = p_other_fg->infrs->ntallies;
  infrs->multinomial_tallies = new int[p_other_fg->infrs->ntallies];
  for (long i = 0; i < infrs->ntallies; i++) {
    infrs->multinomial_tallies[i] = p_other_fg->infrs->multinomial_tallies[i];
  }
}

long dd::CompiledFactorGraph::get_multinomial_weight_id(
    const VariableValue *assignments, const CompactFactor &fs, long vid,
    long proposal) {
  /**
   * The weight ids are aligned in a continuous region according
   * to the numerical order of variable values.
   * For example, for variable assignment indexes i1, ..., ik with cardinality
   * d1, ..., dk
   * The weight index is
   * (...((((0 * d1 + i1) * d2) + i2) * d3 + i3) * d4 + ...) * dk + ik
   */
  long weight_offset = 0;
  // for each variable in the factor
  for (long i = fs.n_start_i_vif; i < fs.n_start_i_vif + fs.n_variables; ++i) {
    const VariableInFactor &vif = vifs[i];
    const Variable &variable = variables[vif.vid];
    weight_offset *= variable.cardinality;
    weight_offset += variable.get_domain_index(
        (vif.vid == vid) ? proposal : (int)assignments[vif.vid]);
  }

  long weight_id = 0;
  switch (fs.func_id) {
    case FUNC_SPARSE_MULTINOMIAL:
      weight_id = factors[fs.id].weight_ids[weight_offset];
      break;
    case FUNC_MULTINOMIAL:
      weight_id = *(compact_factors_weightids + (&fs - compact_factors)) +
                  weight_offset;
      break;
  }
  return weight_id;
}

void dd::CompiledFactorGraph::update_weight(const Variable &variable) {
  // corresponding factors and weights in a continous region
  CompactFactor *const fs = compact_factors + variable.n_start_i_factors;
  const int *const ws = compact_factors_weightids + variable.n_start_i_factors;
  // for each factor
  for (long i = 0; i < variable.n_factors; i++) {
    // boolean variable
    switch (variable.domain_type) {
      case DTYPE_BOOLEAN: {
        // only update weight when it is not fixed
        if (infrs->weights_isfixed[ws[i]] == false) {
          // stochastic gradient ascent
          // increment weight with stepsize * gradient of weight
          // gradient of weight = E[f|D] - E[f], where D is evidence variables,
          // f is the factor function, E[] is expectation. Expectation is
          // calculated
          // using a sample of the variable.
          infrs->weight_values[ws[i]] +=
              stepsize *
              (this->potential(false, fs[i]) - this->potential(true, fs[i]));
        }
        break;
      }
      case DTYPE_MULTINOMIAL: {
        // two weights need to be updated
        // sample with evidence fixed, I0, with corresponding weight w1
        // sample without evidence unfixed, I1, with corresponding weight w2
        // gradient of wd0 = f(I0) - I(w1==w2)f(I1)
        // gradient of wd1 = I(w1==w2)f(I0) - f(I1)
        long wid1 =
            get_multinomial_weight_id(infrs->assignments_evid, fs[i], -1, -1);
        long wid2 =
            get_multinomial_weight_id(infrs->assignments_free, fs[i], -1, -1);
        int equal = (wid1 == wid2);

        if (infrs->weights_isfixed[wid1] == false) {
          infrs->weight_values[wid1] +=
              stepsize * (this->potential(false, fs[i]) -
                          equal * this->potential(true, fs[i]));
        }

        if (infrs->weights_isfixed[wid2] == false) {
          infrs->weight_values[wid2] +=
              stepsize * (equal * this->potential(false, fs[i]) -
                          this->potential(true, fs[i]));
        }
        break;
      }

      default:
        abort();
    }
  }
}

bool dd::compare_position(const VariableInFactor &x,
                          const VariableInFactor &y) {
  return x.n_position < y.n_position;
}
<commit_msg>More dead code removal<commit_after>#include "factor_graph.h"
#include "factor.h"
#include "binary_format.h"
#include <iostream>

#include <fstream>

dd::FactorGraph::FactorGraph(long _n_var, long _n_factor, long _n_weight,
                             long _n_edge)
    : n_var(_n_var),
      n_factor(_n_factor),
      n_weight(_n_weight),
      n_edge(_n_edge),
      c_nvar(0),
      c_nfactor(0),
      c_nweight(0),
      n_evid(0),
      n_query(0),
      variables(new RawVariable[_n_var]),
      factors(new RawFactor[_n_factor]),
      weights(new Weight[_n_weight]),
      sorted(false),
      safety_check_passed(false) {}

void dd::FactorGraph::compile(CompiledFactorGraph &cfg) {
  cfg.c_nvar = c_nvar;
  cfg.c_nfactor = c_nfactor;
  cfg.c_nweight = c_nweight;

  cfg.n_evid = n_evid;
  cfg.n_query = n_query;

  cfg.stepsize = stepsize;

  long i_edge = 0;

  /*
   * For each factor, put the variables sorted within each factor in an
   * array.
   */
  for (long i = 0; i < n_factor; i++) {
    RawFactor &rf = factors[i];
    rf.n_start_i_vif = i_edge;

    /*
     * Each factor knows how many variables it has. After sorting the variables
     * within the factor by their position, lay the variables in this factor
     * one after another in the vifs array.
     */
    std::sort(rf.tmp_variables.begin(), rf.tmp_variables.end(),
              dd::compare_position);
    for (const VariableInFactor &vif : rf.tmp_variables) {
      cfg.vifs[i_edge] = vif;
      i_edge++;
    }

    /* Also copy the clean factor without the temp crap */
    Factor f(rf);
    cfg.factors[i] = f;
  }
  dprintf("i_edge = %ld n_edge = %ld", i_edge, n_edge);
  assert(i_edge == n_edge);

  i_edge = 0;
  long ntallies = 0;

  /*
   * For each variable, lay the factors sequentially in an array as well.
   */
  for (long i = 0; i < n_var; i++) {
    RawVariable &rv = variables[i];
    // I guess it's only at this point that we're sure tmp_factor_ids won't
    // change since we've fully loaded the graph.
    rv.n_factors = rv.tmp_factor_ids.size();
    rv.n_start_i_factors = i_edge;

    if (rv.domain_type == DTYPE_MULTINOMIAL) {
      rv.n_start_i_tally = ntallies;
      ntallies += rv.cardinality;
    }

    for (const long &fid : rv.tmp_factor_ids) {
      cfg.factor_ids[i_edge] = fid;

      cfg.compact_factors[i_edge].id = factors[fid].id;
      cfg.compact_factors[i_edge].func_id = factors[fid].func_id;
      cfg.compact_factors[i_edge].n_variables = factors[fid].n_variables;
      cfg.compact_factors[i_edge].n_start_i_vif = factors[fid].n_start_i_vif;

      cfg.compact_factors_weightids[i_edge] = factors[fid].weight_id;

      i_edge++;
    }

    /* Also remember to copy the clean variable without the temp crap */
    Variable v(rv);
    cfg.variables[i] = v;
  }

  /* Initialize the InferenceResult array in the end of compilation */
  cfg.infrs->init(cfg.variables, weights);

  assert(i_edge == n_edge);
  /*
   * XXX: Ideally, we don't care about the factor graph anymore at this
   * point, but for consistency, I will update the c_edge variable as well.
   */
  c_edge = i_edge;
  cfg.c_edge = i_edge;
}

void dd::FactorGraph::safety_check() {
  // check whether variables, factors, and weights are stored
  // in the order of their id
  long s = n_var;
  for (long i = 0; i < s; i++) {
    assert(this->variables[i].id == i);
  }
  s = n_factor;
  for (long i = 0; i < s; i++) {
    assert(this->factors[i].id == i);
  }
  s = n_weight;
  for (long i = 0; i < s; i++) {
    assert(this->weights[i].id == i);
  }
  this->sorted = true;
  this->safety_check_passed = true;
}

bool dd::FactorGraph::is_usable() {
  return this->sorted && this->safety_check_passed;
}

dd::CompiledFactorGraph::CompiledFactorGraph(long _n_var, long _n_factor,
                                             long _n_weight, long _n_edge)
    : n_var(_n_var),
      n_factor(_n_factor),
      n_weight(_n_weight),
      n_edge(_n_edge),
      c_nvar(0),
      c_nfactor(0),
      c_nweight(0),
      c_edge(0),
      n_evid(0),
      n_query(0),
      variables(new Variable[_n_var]),
      factors(new Factor[_n_factor]),
      compact_factors(new CompactFactor[_n_edge]),
      compact_factors_weightids(new int[_n_edge]),
      factor_ids(new long[_n_edge]),
      vifs(new VariableInFactor[_n_edge]),
      infrs(new InferenceResult(_n_var, _n_weight)),
      safety_check_passed(false) {}

void dd::CompiledFactorGraph::copy_from(
    const CompiledFactorGraph *const p_other_fg) {
  c_nvar = p_other_fg->c_nvar;
  c_nfactor = p_other_fg->c_nfactor;
  c_nweight = p_other_fg->c_nweight;
  c_edge = p_other_fg->c_edge;

  n_evid = p_other_fg->n_evid;
  n_query = p_other_fg->n_query;

  // copy each member from the given graph
  memcpy(variables, p_other_fg->variables, sizeof(Variable) * n_var);
  memcpy(factors, p_other_fg->factors, sizeof(Factor) * n_factor);

  memcpy(compact_factors, p_other_fg->compact_factors,
         sizeof(CompactFactor) * n_edge);
  memcpy(compact_factors_weightids, p_other_fg->compact_factors_weightids,
         sizeof(int) * n_edge);
  memcpy(factor_ids, p_other_fg->factor_ids, sizeof(long) * n_edge);
  memcpy(vifs, p_other_fg->vifs, sizeof(VariableInFactor) * n_edge);

  sorted = p_other_fg->sorted;
  safety_check_passed = p_other_fg->safety_check_passed;

  infrs->copy_from(*p_other_fg->infrs);
  infrs->ntallies = p_other_fg->infrs->ntallies;
  infrs->multinomial_tallies = new int[p_other_fg->infrs->ntallies];
  for (long i = 0; i < infrs->ntallies; i++) {
    infrs->multinomial_tallies[i] = p_other_fg->infrs->multinomial_tallies[i];
  }
}

long dd::CompiledFactorGraph::get_multinomial_weight_id(
    const VariableValue *assignments, const CompactFactor &fs, long vid,
    long proposal) {
  /**
   * The weight ids are aligned in a continuous region according
   * to the numerical order of variable values.
   * For example, for variable assignment indexes i1, ..., ik with cardinality
   * d1, ..., dk
   * The weight index is
   * (...((((0 * d1 + i1) * d2) + i2) * d3 + i3) * d4 + ...) * dk + ik
   */
  long weight_offset = 0;
  // for each variable in the factor
  for (long i = fs.n_start_i_vif; i < fs.n_start_i_vif + fs.n_variables; ++i) {
    const VariableInFactor &vif = vifs[i];
    const Variable &variable = variables[vif.vid];
    weight_offset *= variable.cardinality;
    weight_offset += variable.get_domain_index(
        (vif.vid == vid) ? proposal : (int)assignments[vif.vid]);
  }

  long weight_id = 0;
  switch (fs.func_id) {
    case FUNC_SPARSE_MULTINOMIAL:
      weight_id = factors[fs.id].weight_ids[weight_offset];
      break;
    case FUNC_MULTINOMIAL:
      weight_id = *(compact_factors_weightids + (&fs - compact_factors)) +
                  weight_offset;
      break;
  }
  return weight_id;
}

void dd::CompiledFactorGraph::update_weight(const Variable &variable) {
  // corresponding factors and weights in a continous region
  CompactFactor *const fs = compact_factors + variable.n_start_i_factors;
  const int *const ws = compact_factors_weightids + variable.n_start_i_factors;
  // for each factor
  for (long i = 0; i < variable.n_factors; i++) {
    // boolean variable
    switch (variable.domain_type) {
      case DTYPE_BOOLEAN: {
        // only update weight when it is not fixed
        if (infrs->weights_isfixed[ws[i]] == false) {
          // stochastic gradient ascent
          // increment weight with stepsize * gradient of weight
          // gradient of weight = E[f|D] - E[f], where D is evidence variables,
          // f is the factor function, E[] is expectation. Expectation is
          // calculated
          // using a sample of the variable.
          infrs->weight_values[ws[i]] +=
              stepsize *
              (this->potential(false, fs[i]) - this->potential(true, fs[i]));
        }
        break;
      }
      case DTYPE_MULTINOMIAL: {
        // two weights need to be updated
        // sample with evidence fixed, I0, with corresponding weight w1
        // sample without evidence unfixed, I1, with corresponding weight w2
        // gradient of wd0 = f(I0) - I(w1==w2)f(I1)
        // gradient of wd1 = I(w1==w2)f(I0) - f(I1)
        long wid1 =
            get_multinomial_weight_id(infrs->assignments_evid, fs[i], -1, -1);
        long wid2 =
            get_multinomial_weight_id(infrs->assignments_free, fs[i], -1, -1);
        int equal = (wid1 == wid2);

        if (infrs->weights_isfixed[wid1] == false) {
          infrs->weight_values[wid1] +=
              stepsize * (this->potential(false, fs[i]) -
                          equal * this->potential(true, fs[i]));
        }

        if (infrs->weights_isfixed[wid2] == false) {
          infrs->weight_values[wid2] +=
              stepsize * (equal * this->potential(false, fs[i]) -
                          this->potential(true, fs[i]));
        }
        break;
      }

      default:
        abort();
    }
  }
}

bool dd::compare_position(const VariableInFactor &x,
                          const VariableInFactor &y) {
  return x.n_position < y.n_position;
}
<|endoftext|>