<commit_before>/*
 * 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/protocol/MemoryMsg.hh"
#include "mem/ruby/system/RubySystem.hh"
#include "mem/ruby/system/Sequencer.hh"
#include "sim/system.hh"

AbstractController::AbstractController(const Params *p)
    : MemObject(p), Consumer(this), m_version(p->version),
      m_clusterID(p->cluster_id),
      m_masterId(p->system->getMasterId(name())), 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),
      memoryPort(csprintf("%s.memory", name()), this, "")
{
    if (m_version == 0) {
        // Combine the statistics from all controllers
        // of this particular type.
        Stats::registerDumpCallback(new StatsCallback(this));
    }
}

void
AbstractController::init()
{
    params()->ruby_system->registerAbstractController(this);
    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);
    }
}

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()
{
    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 lower rank (i.e. lower priority) 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();
    }
}

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

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

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

void
AbstractController::queueMemoryRead(const MachineID &id, Addr addr,
                                    Cycles latency)
{
    RequestPtr req = new Request(addr, RubySystem::getBlockSizeBytes(), 0,
                                 m_masterId);

    PacketPtr pkt = Packet::createRead(req);
    uint8_t *newData = new uint8_t[RubySystem::getBlockSizeBytes()];
    pkt->dataDynamic(newData);

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

    // Use functional rather than timing accesses during warmup
    if (RubySystem::getWarmupEnabled()) {
        memoryPort.sendFunctional(pkt);
        recvTimingResp(pkt);
        return;
    }

    memoryPort.schedTimingReq(pkt, clockEdge(latency));
}

void
AbstractController::queueMemoryWrite(const MachineID &id, Addr addr,
                                     Cycles latency, const DataBlock &block)
{
    RequestPtr req = new Request(addr, RubySystem::getBlockSizeBytes(), 0,
                                 m_masterId);

    PacketPtr pkt = Packet::createWrite(req);
    uint8_t *newData = new uint8_t[RubySystem::getBlockSizeBytes()];
    pkt->dataDynamic(newData);
    memcpy(newData, block.getData(0, RubySystem::getBlockSizeBytes()),
           RubySystem::getBlockSizeBytes());

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

    // Use functional rather than timing accesses during warmup
    if (RubySystem::getWarmupEnabled()) {
        memoryPort.sendFunctional(pkt);
        recvTimingResp(pkt);
        return;
    }

    // Create a block and copy data from the block.
    memoryPort.schedTimingReq(pkt, clockEdge(latency));
}

void
AbstractController::queueMemoryWritePartial(const MachineID &id, Addr addr,
                                            Cycles latency,
                                            const DataBlock &block, int size)
{
    RequestPtr req = new Request(addr, RubySystem::getBlockSizeBytes(), 0,
                                 m_masterId);

    PacketPtr pkt = Packet::createWrite(req);
    uint8_t *newData = new uint8_t[size];
    pkt->dataDynamic(newData);
    memcpy(newData, block.getData(getOffset(addr), size), size);

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

    // Create a block and copy data from the block.
    memoryPort.schedTimingReq(pkt, clockEdge(latency));
}

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

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

    // Check the buffer from the controller to the memory.
    if (memoryPort.checkFunctional(pkt)) {
        num_functional_writes++;
    }

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

void
AbstractController::recvTimingResp(PacketPtr pkt)
{
    assert(getMemoryQueue());
    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!");
    }

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

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

AbstractController::MemoryPort::MemoryPort(const std::string &_name,
                                           AbstractController *_controller,
                                           const std::string &_label)
    : QueuedMasterPort(_name, _controller, reqQueue, snoopRespQueue),
      reqQueue(*_controller, *this, _label),
      snoopRespQueue(*_controller, *this, _label),
      controller(_controller)
{
}
<commit_msg>ruby: Fix memory leak in AbstractController<commit_after>/*
 * 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/protocol/MemoryMsg.hh"
#include "mem/ruby/system/RubySystem.hh"
#include "mem/ruby/system/Sequencer.hh"
#include "sim/system.hh"

AbstractController::AbstractController(const Params *p)
    : MemObject(p), Consumer(this), m_version(p->version),
      m_clusterID(p->cluster_id),
      m_masterId(p->system->getMasterId(name())), 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),
      memoryPort(csprintf("%s.memory", name()), this, "")
{
    if (m_version == 0) {
        // Combine the statistics from all controllers
        // of this particular type.
        Stats::registerDumpCallback(new StatsCallback(this));
    }
}

void
AbstractController::init()
{
    params()->ruby_system->registerAbstractController(this);
    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);
    }
}

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()
{
    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 lower rank (i.e. lower priority) 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();
    }
}

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

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

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

void
AbstractController::queueMemoryRead(const MachineID &id, Addr addr,
                                    Cycles latency)
{
    RequestPtr req = new Request(addr, RubySystem::getBlockSizeBytes(), 0,
                                 m_masterId);

    PacketPtr pkt = Packet::createRead(req);
    uint8_t *newData = new uint8_t[RubySystem::getBlockSizeBytes()];
    pkt->dataDynamic(newData);

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

    // Use functional rather than timing accesses during warmup
    if (RubySystem::getWarmupEnabled()) {
        memoryPort.sendFunctional(pkt);
        recvTimingResp(pkt);
        return;
    }

    memoryPort.schedTimingReq(pkt, clockEdge(latency));
}

void
AbstractController::queueMemoryWrite(const MachineID &id, Addr addr,
                                     Cycles latency, const DataBlock &block)
{
    RequestPtr req = new Request(addr, RubySystem::getBlockSizeBytes(), 0,
                                 m_masterId);

    PacketPtr pkt = Packet::createWrite(req);
    uint8_t *newData = new uint8_t[RubySystem::getBlockSizeBytes()];
    pkt->dataDynamic(newData);
    memcpy(newData, block.getData(0, RubySystem::getBlockSizeBytes()),
           RubySystem::getBlockSizeBytes());

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

    // Use functional rather than timing accesses during warmup
    if (RubySystem::getWarmupEnabled()) {
        memoryPort.sendFunctional(pkt);
        recvTimingResp(pkt);
        return;
    }

    // Create a block and copy data from the block.
    memoryPort.schedTimingReq(pkt, clockEdge(latency));
}

void
AbstractController::queueMemoryWritePartial(const MachineID &id, Addr addr,
                                            Cycles latency,
                                            const DataBlock &block, int size)
{
    RequestPtr req = new Request(addr, RubySystem::getBlockSizeBytes(), 0,
                                 m_masterId);

    PacketPtr pkt = Packet::createWrite(req);
    uint8_t *newData = new uint8_t[size];
    pkt->dataDynamic(newData);
    memcpy(newData, block.getData(getOffset(addr), size), size);

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

    // Create a block and copy data from the block.
    memoryPort.schedTimingReq(pkt, clockEdge(latency));
}

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

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

    // Check the buffer from the controller to the memory.
    if (memoryPort.checkFunctional(pkt)) {
        num_functional_writes++;
    }

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

void
AbstractController::recvTimingResp(PacketPtr pkt)
{
    assert(getMemoryQueue());
    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!");
    }

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

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

AbstractController::MemoryPort::MemoryPort(const std::string &_name,
                                           AbstractController *_controller,
                                           const std::string &_label)
    : QueuedMasterPort(_name, _controller, reqQueue, snoopRespQueue),
      reqQueue(*_controller, *this, _label),
      snoopRespQueue(*_controller, *this, _label),
      controller(_controller)
{
}
<|endoftext|>


<commit_before>//
// Test Suite for Geometry's covers() and coveredBy() functions

// tut
#include <tut.hpp>
// geos
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/Polygon.h>
#include <geos/io/WKTReader.h>
// std
#include <memory>
#include <string>

namespace tut {

//
// Test Group
//

struct test_contains_data
{
	typedef std::auto_ptr<geos::geom::Geometry> GeomAutoPtr;
	geos::geom::GeometryFactory factory;
	geos::io::WKTReader reader;

	test_contains_data()
	    : reader(&factory)
	{}
};

typedef test_group<test_contains_data> group;
typedef group::object object;

group test_contains_data("geos::geom::Geometry::covers");

//
// Test Cases
//

// 1 - Boundaries touch, still g1 covers g2
template<>
template<>
void object::test<1>()
{
	GeomAutoPtr g1(reader.read(
		"POLYGON ((0 0, 0 100, 100 100, 100 0, 0 0))"
	));
	GeomAutoPtr g2(reader.read(
		"POLYGON ((0 0, 0 100, 90 90, 90 0, 0 0))"
	));

	ensure( g1->covers(g2.get()) );
	ensure( g2->coveredBy(g1.get()) );

}

// 2 - Polygon covers line (laying on it's boundary)
template<>
template<>
void object::test<2>()
{
	GeomAutoPtr g1(reader.read(
		"POLYGON ((0 0, 0 100, 100 100, 100 0, 0 0))"
	));
	GeomAutoPtr g2(reader.read(
		"LINESTRING (0 0, 0 100)"
	));

	ensure( g1->covers(g2.get()) );
	ensure( g2->coveredBy(g1.get()) );
	ensure( ! g1->contains(g2.get()) );

}

// 3 - Line covers point (laying on it's boundary or interior)
template<>
template<>
void object::test<3>()
{
	GeomAutoPtr g1(reader.read(
		"LINESTRING (0 0, 0 100)"
	));
	GeomAutoPtr g2(reader.read(
		"POINT(0 0)"
	));

	ensure( g1->covers(g2.get()) );
	ensure( g2->coveredBy(g1.get()) );
	ensure( ! g1->contains(g2.get()) );

	g2.reset(reader.read(
		"POINT(0 2)"
	));

	ensure( g1->covers(g2.get()) );
	ensure( g2->coveredBy(g1.get()) );
	ensure( g1->contains(g2.get()) );

}

} // namespace tut

<commit_msg>Add test for #580 (successful)<commit_after>//
// Test Suite for Geometry's covers(), coveredBy() and contains() functions

// tut
#include <tut.hpp>
// geos
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/Polygon.h>
#include <geos/io/WKTReader.h>
// std
#include <memory>
#include <string>

namespace tut {

//
// Test Group
//

struct test_contains_data
{
	typedef std::auto_ptr<geos::geom::Geometry> GeomAutoPtr;
	geos::geom::GeometryFactory factory;
	geos::io::WKTReader reader;

	test_contains_data()
	    : reader(&factory)
	{}
};

typedef test_group<test_contains_data> group;
typedef group::object object;

group test_contains_data("geos::geom::Geometry::covers");

//
// Test Cases
//

// 1 - Boundaries touch, still g1 covers g2
template<>
template<>
void object::test<1>()
{
	GeomAutoPtr g1(reader.read(
		"POLYGON ((0 0, 0 100, 100 100, 100 0, 0 0))"
	));
	GeomAutoPtr g2(reader.read(
		"POLYGON ((0 0, 0 100, 90 90, 90 0, 0 0))"
	));

	ensure( g1->covers(g2.get()) );
	ensure( g2->coveredBy(g1.get()) );

}

// 2 - Polygon covers line (laying on it's boundary)
template<>
template<>
void object::test<2>()
{
	GeomAutoPtr g1(reader.read(
		"POLYGON ((0 0, 0 100, 100 100, 100 0, 0 0))"
	));
	GeomAutoPtr g2(reader.read(
		"LINESTRING (0 0, 0 100)"
	));

	ensure( g1->covers(g2.get()) );
	ensure( g2->coveredBy(g1.get()) );
	ensure( ! g1->contains(g2.get()) );

}

// 3 - Line covers point (laying on it's boundary or interior)
template<>
template<>
void object::test<3>()
{
	GeomAutoPtr g1(reader.read(
		"LINESTRING (0 0, 0 100)"
	));
	GeomAutoPtr g2(reader.read(
		"POINT(0 0)"
	));

	ensure( g1->covers(g2.get()) );
	ensure( g2->coveredBy(g1.get()) );
	ensure( ! g1->contains(g2.get()) );

	g2.reset(reader.read(
		"POINT(0 2)"
	));

	ensure( g1->covers(g2.get()) );
	ensure( g2->coveredBy(g1.get()) );
	ensure( g1->contains(g2.get()) );

}

// 4 - http://trac.osgeo.org/geos/ticket/580
template<>
template<>
void object::test<4>()
{
	GeomAutoPtr g1(reader.read(
		"POLYGON ((-1.183864 52.951915, -1.183862 52.951903, -1.183890 52.951900, -1.183924 52.951897, -1.183958 52.951894, -1.183954 52.951880, -1.183954 52.951878, -1.183932 52.951841, -1.183904 52.951844, -1.183870 52.951847, -1.183832 52.951852, -1.183824 52.951838, -1.183820 52.951830, -1.183870 52.951819, -1.183886 52.951815, -1.183890 52.951819, -1.183929 52.951810, -1.183909 52.951776, -1.183861 52.951787, -1.183853 52.951788, -1.183842 52.951770, -1.183970 52.951742, -1.183983 52.951763, -1.183963 52.951768, -1.183975 52.951788, -1.183994 52.951785, -1.184009 52.951807, -1.184002 52.951808, -1.184009 52.951835, -1.183990 52.951836, -1.183990 52.951836, -1.183990 52.951838, -1.184001 52.951880, -1.184018 52.951954, -1.184020 52.951956, -1.183998 52.951957, -1.183998 52.951956, -1.183996 52.951948, -1.183970 52.951906, -1.183936 52.951909, -1.183864 52.951915))"
	));
	GeomAutoPtr g2(reader.read(
		"POINT (-1.183972 52.951871)"
	));

	ensure( g1->covers(g2.get()) );
	ensure( g2->coveredBy(g1.get()) );
	ensure( g1->contains(g2.get()) );

}

} // namespace tut

<|endoftext|>


<commit_before>#ifndef GNR_ANYFUNC_HPP
# define GNR_ANYFUNC_HPP
# pragma once

#include <cassert>

// std::size_t
#include <cstddef>

#include <any>

#include <functional>

#include <tuple>

#include <type_traits>

#include <utility>

namespace gnr
{

namespace detail
{

namespace anyfunc
{

constexpr auto default_size = 4 * sizeof(void*);

template <typename>
struct signature
{
};

//
template <typename>
struct class_ref;

//
template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...)>
{
  using type = C&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const>
{
  using type = C const&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const volatile>
{
  using type = C const volatile&;
};

//
template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) &>
{
  using type = C&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const &>
{
  using type = C const&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const volatile &>
{
  using type = C const volatile&;
};

//
template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) &&>
{
  using type = C&&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const &&>
{
  using type = C const&&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const volatile &&>
{
  using type = C const volatile&&;
};

//
template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) noexcept>
{
  using type = C&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const noexcept>
{
  using type = C const&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const volatile noexcept>
{
  using type = C const volatile&;
};

//
template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) & noexcept>
{
  using type = C&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const & noexcept>
{
  using type = C const&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const volatile & noexcept>
{
  using type = C const volatile&;
};

//
template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) && noexcept>
{
  using type = C&&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const && noexcept>
{
  using type = C const &&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const volatile && noexcept>
{
  using type = C const volatile &&;
};

template <typename F>
using class_ref_t = typename class_ref<F>::type;

//
template <typename>
struct remove_cv_seq;

//
template <typename R, typename ...A>
struct remove_cv_seq<R(A...)>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) volatile>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const volatile>
{
  using type = R(A...);
};

//
template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const noexcept>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) volatile noexcept>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const volatile noexcept>
{
  using type = R(A...);
};

//
template <typename R, typename ...A>
struct remove_cv_seq<R(A...) &>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const &>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) volatile &>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const volatile &>
{
  using type = R(A...);
};

//
template <typename R, typename ...A>
struct remove_cv_seq<R(A...) & noexcept>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const & noexcept >
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) volatile & noexcept>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const volatile & noexcept>
{
  using type = R(A...);
};

//
template <typename R, typename ...A>
struct remove_cv_seq<R(A...) &&>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const &&>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) volatile &&>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const volatile &&>
{
  using type = R(A...);
};

//
template <typename R, typename ...A>
struct remove_cv_seq<R(A...) && noexcept>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const && noexcept>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) volatile && noexcept>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const volatile && noexcept>
{
  using type = R(A...);
};

template <typename F>
constexpr inline auto extract_signature(F* const) noexcept
{
  return signature<typename remove_cv_seq<F>::type>();
}

template <typename C, typename F>
constexpr inline auto extract_signature(F C::* const) noexcept
{
  return signature<typename remove_cv_seq<F>::type>();
}

template <typename F>
constexpr inline auto extract_signature(F const&) noexcept ->
  decltype(&F::operator(), extract_signature(&F::operator()))
{
  return extract_signature(&F::operator());
}

}

}

template <typename Any = std::any>
class anyfunc
{
  using typeid_t = void(*)();

  template <typename T>
  static typeid_t type_id() noexcept
  {
    return typeid_t(type_id<T>);
  }

  void (*f_)(Any const&, void const*, void*) {};

  Any any_;

#ifndef NDEBUG
  typeid_t type_id_;
#endif // NDEBUG

  template <typename F, typename R, typename ...A>
  static std::enable_if_t<
    !std::is_member_function_pointer<F>{} &&
    !std::is_void<R>{}
  >
  invoker(Any const& any, void const* const v, void* const r)
  {
    *static_cast<R*>(r) = std::apply(std::any_cast<F>(any),
      *static_cast<std::tuple<A...> const*>(v)
    );
  }

  template <typename F, typename R, typename ...A>
  static std::enable_if_t<
    !std::is_member_function_pointer<F>{} &&
    std::is_void<R>{}
  >
  invoker(Any const& any, void const* const v, void*)
  {
    std::apply(std::any_cast<F>(any),
      *static_cast<std::tuple<A...> const*>(v)
    );
  }

  template <typename F, typename R, typename ...A>
  static std::enable_if_t<
    std::is_member_function_pointer<F>{} &&
    !std::is_void<R>{}
  >
  invoker(Any const& any, void const* const v, void* const r)
  {
    *static_cast<R*>(r) = std::apply(std::any_cast<F>(any),
      *static_cast<
        std::tuple<detail::anyfunc::class_ref_t<F>, A...> const*
      >(v)
    );
  }

  template <typename F, typename R, typename ...A>
  static std::enable_if_t<
    std::is_member_function_pointer<F>{} &&
    std::is_void<R>{}
  >
  invoker(Any const& any, void const* const v, void*)
  {
    std::apply(std::any_cast<F>(any),
      *static_cast<
        std::tuple<detail::anyfunc::class_ref_t<F>, A...> const*
      >(v)
    );
  }

  template <typename F, typename R, typename ...A>
  std::enable_if_t<!std::is_member_function_pointer<F>{}>
  assign(detail::anyfunc::signature<R(A...)>) noexcept
  {
    f_ = invoker<std::decay_t<F>, R, A...>;

#ifndef NDEBUG
    type_id_ = type_id<std::tuple<R, A...>>();
#endif // NDEBUG
  }

  template <typename F, typename R, typename ...A>
  std::enable_if_t<std::is_member_function_pointer<F>{}>
  assign(detail::anyfunc::signature<R(A...)>) noexcept
  {
    f_ = invoker<F, R, A...>;

#ifndef NDEBUG
    type_id_ = type_id<
      std::tuple<R, detail::anyfunc::class_ref_t<F>, A...>
    >();
#endif // NDEBUG
  }

public:
  template <typename T>
  struct arg_type
  {
    using type = std::decay_t<T>;
  };

  template <typename T>
  struct arg_type<std::reference_wrapper<T> >
  {
    using type = T&;
  };

  template <typename T>
  using arg_type_t = typename arg_type<T>::type;

  anyfunc() = default;

  template <typename F,
    typename = std::enable_if_t<
      !std::is_same<std::decay_t<F>, anyfunc>{}
    >
  >
  anyfunc(F&& f) :
    any_(std::forward<F>(f))
  {
    assign<F>(detail::anyfunc::extract_signature(std::forward<F>(f)));
  }

  anyfunc(anyfunc const&) = default;

  anyfunc(anyfunc&&) = default;

  anyfunc& operator=(anyfunc const&) = default;

  anyfunc& operator=(anyfunc&&) = default;

  template <typename F,
    typename = std::enable_if_t<
      !std::is_same<std::decay_t<F>, anyfunc>{}
    >
  >
  anyfunc& operator=(F&& f)
  {
    assign(std::forward<F>(f));

    return *this;
  }

  bool operator==(std::nullptr_t) const noexcept
  {
    return f_;
  }

  bool operator!=(std::nullptr_t) const noexcept
  {
    return !operator==(nullptr);
  }

  explicit operator bool() const noexcept
  {
    return any_.has_value();
  }

  template <typename R, typename ...A>
  std::enable_if_t<!std::is_void<R>{}, R>
  operator()(A&&... args) const noexcept(
    noexcept(std::declval<anyfunc>().template invoke<R>(
        std::forward<A>(args)...
      )
    )
  )
  {
    return invoke<R>(std::forward<A>(args)...);
  }

  template <typename R = void, typename ...A>
  std::enable_if_t<std::is_void<R>{}, R>
  operator()(A&&... args) const noexcept(
    noexcept(std::declval<anyfunc>().template invoke<R>(
        std::forward<A>(args)...
      )
    )
  )
  {
    invoke<R>(std::forward<A>(args)...);
  }

  void assign(std::nullptr_t) noexcept
  {
    reset();
  }

  template <typename F>
  void assign(F&& f)
  {
    any_ = std::forward<F>(f);

    assign<F>(detail::anyfunc::extract_signature(std::forward<F>(f)));
  }

  bool empty() const noexcept
  {
    return !*this;
  }

  bool has_value() const noexcept
  {
    return *this;
  }

  template <typename R, typename ...A>
  std::enable_if_t<!std::is_void<R>{}, R>
  invoke(A... args) const noexcept(noexcept(f_(any_, {}, {})))
  {
    assert(f_);
#ifndef NDEBUG
    using test_t = std::tuple<R, arg_type_t<A>...>;
    assert(type_id<test_t>() == type_id_);
#endif // NDEBUG

    R r;

    auto const a(std::tuple<arg_type_t<A>...>{std::forward<A>(args)...});

    f_(any_, &a, &r);

    return r;
  }

  template <typename R = void, typename ...A>
  std::enable_if_t<std::is_void<R>{}, R>
  invoke(A... args) const noexcept(noexcept(f_(any_, {}, {})))
  {
    assert(f_);
#ifndef NDEBUG
    using test_t = std::tuple<R, arg_type_t<A>...>;
    assert(type_id<test_t>() == type_id_);
#endif // NDEBUG

    auto const a(std::tuple<arg_type_t<A>...>{std::forward<A>(args)...});

    f_(any_, &a, {});
  }

  void reset() noexcept { f_ = {}; }

  void swap(anyfunc& other) noexcept
  {
    std::swap(*this, other);
  }

  void swap(anyfunc&& other) noexcept
  {
    std::swap(*this, std::move(other));
  }
};

}

#endif // GNR_ANYFUNC_HPP
<commit_msg>some fixes<commit_after>#ifndef GNR_ANYFUNC_HPP
# define GNR_ANYFUNC_HPP
# pragma once

#include <cassert>

// std::size_t
#include <cstddef>

#include <any>

#include <functional>

#include <tuple>

#include <type_traits>

#include <utility>

namespace gnr
{

namespace detail
{

namespace anyfunc
{

constexpr auto default_size = 4 * sizeof(void*);

template <typename>
struct signature
{
};

//
template <typename>
struct class_ref;

//
template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...)>
{
  using type = C&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const>
{
  using type = C const&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const volatile>
{
  using type = C const volatile&;
};

//
template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) &>
{
  using type = C&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const &>
{
  using type = C const&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const volatile &>
{
  using type = C const volatile&;
};

//
template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) &&>
{
  using type = C&&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const &&>
{
  using type = C const&&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const volatile &&>
{
  using type = C const volatile&&;
};

//
template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) noexcept>
{
  using type = C&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const noexcept>
{
  using type = C const&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const volatile noexcept>
{
  using type = C const volatile&;
};

//
template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) & noexcept>
{
  using type = C&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const & noexcept>
{
  using type = C const&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const volatile & noexcept>
{
  using type = C const volatile&;
};

//
template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) && noexcept>
{
  using type = C&&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const && noexcept>
{
  using type = C const &&;
};

template <typename R, typename C, typename ...A>
struct class_ref<R (C::*)(A...) const volatile && noexcept>
{
  using type = C const volatile &&;
};

template <typename F>
using class_ref_t = typename class_ref<F>::type;

//
template <typename>
struct remove_cv_seq;

//
template <typename R, typename ...A>
struct remove_cv_seq<R(A...)>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) volatile>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const volatile>
{
  using type = R(A...);
};

//
template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const noexcept>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) volatile noexcept>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const volatile noexcept>
{
  using type = R(A...);
};

//
template <typename R, typename ...A>
struct remove_cv_seq<R(A...) &>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const &>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) volatile &>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const volatile &>
{
  using type = R(A...);
};

//
template <typename R, typename ...A>
struct remove_cv_seq<R(A...) & noexcept>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const & noexcept >
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) volatile & noexcept>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const volatile & noexcept>
{
  using type = R(A...);
};

//
template <typename R, typename ...A>
struct remove_cv_seq<R(A...) &&>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const &&>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) volatile &&>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const volatile &&>
{
  using type = R(A...);
};

//
template <typename R, typename ...A>
struct remove_cv_seq<R(A...) && noexcept>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const && noexcept>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) volatile && noexcept>
{
  using type = R(A...);
};

template <typename R, typename ...A>
struct remove_cv_seq<R(A...) const volatile && noexcept>
{
  using type = R(A...);
};

template <typename F>
constexpr inline auto extract_signature(F* const) noexcept
{
  return signature<typename remove_cv_seq<F>::type>();
}

template <typename C, typename F>
constexpr inline auto extract_signature(F C::* const) noexcept
{
  return signature<typename remove_cv_seq<F>::type>();
}

template <typename F>
constexpr inline auto extract_signature(F const&) noexcept ->
  decltype(&F::operator(), extract_signature(&F::operator()))
{
  return extract_signature(&F::operator());
}

}

}

template <typename Any = std::any>
class anyfunc
{
  using typeid_t = void(*)();

  template <typename T>
  static typeid_t type_id() noexcept
  {
    return typeid_t(type_id<T>);
  }

  void (*f_)(Any const&, void const*, void*) {};

  Any any_;

#ifndef NDEBUG
  typeid_t type_id_;
#endif // NDEBUG

  template <typename F, typename R, typename ...A>
  static std::enable_if_t<
    !std::is_member_function_pointer<F>{} &&
    !std::is_void<R>{}
  >
  invoker(Any const& any, void const* const v, void* const r)
  {
    *static_cast<R*>(r) = std::apply(std::any_cast<F>(any),
      *static_cast<std::tuple<A...> const*>(v)
    );
  }

  template <typename F, typename R, typename ...A>
  static std::enable_if_t<
    !std::is_member_function_pointer<F>{} &&
    std::is_void<R>{}
  >
  invoker(Any const& any, void const* const v, void*)
  {
    std::apply(std::any_cast<F>(any),
      *static_cast<std::tuple<A...> const*>(v)
    );
  }

  template <typename F, typename R, typename ...A>
  static std::enable_if_t<
    std::is_member_function_pointer<F>{} &&
    !std::is_void<R>{}
  >
  invoker(Any const& any, void const* const v, void* const r)
  {
    *static_cast<R*>(r) = std::apply(std::any_cast<F>(any),
      *static_cast<
        std::tuple<detail::anyfunc::class_ref_t<F>, A...> const*
      >(v)
    );
  }

  template <typename F, typename R, typename ...A>
  static std::enable_if_t<
    std::is_member_function_pointer<F>{} &&
    std::is_void<R>{}
  >
  invoker(Any const& any, void const* const v, void*)
  {
    std::apply(std::any_cast<F>(any),
      *static_cast<
        std::tuple<detail::anyfunc::class_ref_t<F>, A...> const*
      >(v)
    );
  }

  template <typename F, typename R, typename ...A>
  std::enable_if_t<!std::is_member_function_pointer<F>{}>
  assign(detail::anyfunc::signature<R(A...)>) noexcept
  {
    f_ = invoker<std::decay_t<F>, R, A...>;

#ifndef NDEBUG
    type_id_ = type_id<std::tuple<R, A...>>();
#endif // NDEBUG
  }

  template <typename F, typename R, typename ...A>
  std::enable_if_t<std::is_member_function_pointer<F>{}>
  assign(detail::anyfunc::signature<R(A...)>) noexcept
  {
    f_ = invoker<F, R, A...>;

#ifndef NDEBUG
    type_id_ = type_id<
      std::tuple<R, detail::anyfunc::class_ref_t<F>, A...>
    >();
#endif // NDEBUG
  }

public:
  template <typename T>
  struct arg_type
  {
    using type = std::decay_t<T>;
  };

  template <typename T>
  struct arg_type<std::reference_wrapper<T> >
  {
    using type = T&;
  };

  template <typename T>
  using arg_type_t = typename arg_type<T>::type;

  anyfunc() = default;

  template <typename F,
    typename = std::enable_if_t<
      !std::is_same<std::decay_t<F>, anyfunc>{}
    >
  >
  anyfunc(F&& f) :
    any_(std::forward<F>(f))
  {
    assign<F>(detail::anyfunc::extract_signature(std::forward<F>(f)));
  }

  anyfunc(anyfunc const&) = default;

  anyfunc(anyfunc&&) = default;

  anyfunc& operator=(anyfunc const&) = default;

  anyfunc& operator=(anyfunc&&) = default;

  template <typename F,
    typename = std::enable_if_t<
      !std::is_same<std::decay_t<F>, anyfunc>{}
    >
  >
  anyfunc& operator=(F&& f)
  {
    assign(std::forward<F>(f));

    return *this;
  }

  bool operator==(std::nullptr_t) const noexcept
  {
    return f_;
  }

  bool operator!=(std::nullptr_t) const noexcept
  {
    return !operator==(nullptr);
  }

  explicit operator bool() const noexcept
  {
    return f_;
  }

  template <typename R, typename ...A>
  std::enable_if_t<!std::is_void<R>{}, R>
  operator()(A&&... args) const noexcept(
    noexcept(std::declval<anyfunc>().template invoke<R>(
        std::forward<A>(args)...
      )
    )
  )
  {
    return invoke<R>(std::forward<A>(args)...);
  }

  template <typename R = void, typename ...A>
  std::enable_if_t<std::is_void<R>{}, R>
  operator()(A&&... args) const noexcept(
    noexcept(std::declval<anyfunc>().template invoke<R>(
        std::forward<A>(args)...
      )
    )
  )
  {
    invoke<R>(std::forward<A>(args)...);
  }

  void assign(std::nullptr_t) noexcept
  {
    reset();
  }

  template <typename F>
  void assign(F&& f)
  {
    any_ = std::forward<F>(f);

    assign<F>(detail::anyfunc::extract_signature(std::forward<F>(f)));
  }

  bool empty() const noexcept
  {
    return !*this;
  }

  bool has_value() const noexcept
  {
    return *this;
  }

  template <typename R, typename ...A>
  std::enable_if_t<!std::is_void<R>{}, R>
  invoke(A... args) const noexcept(noexcept(f_(any_, {}, {})))
  {
    assert(f_);
#ifndef NDEBUG
    using test_t = std::tuple<R, arg_type_t<A>...>;
    assert(type_id<test_t>() == type_id_);
#endif // NDEBUG

    R r;

    auto const a(std::tuple<arg_type_t<A>...>{std::forward<A>(args)...});

    f_(any_, &a, &r);

    return r;
  }

  template <typename R = void, typename ...A>
  std::enable_if_t<std::is_void<R>{}, R>
  invoke(A... args) const noexcept(noexcept(f_(any_, {}, {})))
  {
    assert(f_);
#ifndef NDEBUG
    using test_t = std::tuple<R, arg_type_t<A>...>;
    assert(type_id<test_t>() == type_id_);
#endif // NDEBUG

    auto const a(std::tuple<arg_type_t<A>...>{std::forward<A>(args)...});

    f_(any_, &a, {});
  }

  void reset() noexcept { f_ = {}; }

  void swap(anyfunc& other) noexcept
  {
    std::swap(*this, other);
  }

  void swap(anyfunc&& other) noexcept
  {
    std::swap(*this, std::move(other));
  }
};

}

#endif // GNR_ANYFUNC_HPP
<|endoftext|>


<commit_before>#include "formulation/cfem_diffusion_stamper.h"

#include <memory>

#include <deal.II/base/mpi.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/distributed/tria.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/grid_tools.h>
#include <deal.II/lac/dynamic_sparsity_pattern.h>
#include <deal.II/lac/petsc_parallel_sparse_matrix.h>

#include "domain/tests/definition_mock.h"
#include "formulation/scalar/tests/cfem_diffusion_mock.h"
#include "problem/parameter_types.h"
#include "test_helpers/gmock_wrapper.h"
#include "test_helpers/test_helper_functions.h"

namespace {

using ::testing::AssertionResult;
using ::testing::AssertionFailure, ::testing::AssertionSuccess;
using ::testing::DoDefault;
using ::testing::Invoke;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::Unused;
using ::testing::_;

using namespace bart;
using Cell = domain::DefinitionI<2>::Cell;
using InitToken = formulation::scalar::CFEM_DiffusionI<2>::InitializationToken;
using Matrix = dealii::FullMatrix<double>;

class CFEMDiffusionStamperTest : public ::testing::Test {
 protected:
  std::unique_ptr<NiceMock<domain::DefinitionMock<2>>> mock_definition_ptr;
  std::unique_ptr<NiceMock<formulation::scalar::CFEM_DiffusionMock<2>>> mock_diffusion_ptr;
  void SetUp() override;
  InitToken init_token_;
};

// TODO(Josh) Move this to a header where other stamper tests can use it
void FillMatrixWithOnes(Matrix& to_fill, Unused, Unused, Unused) {
  for (unsigned int i = 0; i < to_fill.n_rows(); ++i) {
    for (unsigned int j = 0; j < to_fill.n_cols(); ++j) {
      to_fill(i,j) = 1;
    }
  }
}

void CFEMDiffusionStamperTest::SetUp() {
  mock_definition_ptr = std::make_unique<NiceMock<domain::DefinitionMock<2>>>();
  mock_diffusion_ptr =
      std::make_unique<NiceMock<formulation::scalar::CFEM_DiffusionMock<2>>>();

  ON_CALL(*mock_diffusion_ptr, Precalculate(_))
      .WillByDefault(Return(init_token_));
}

TEST_F(CFEMDiffusionStamperTest, Constructor) {
  Cell test_cell;
  std::vector<Cell> cells{test_cell};

  EXPECT_CALL(*mock_definition_ptr, Cells())
      .WillOnce(Return(cells));
  EXPECT_CALL(*mock_diffusion_ptr, Precalculate(_))
      .WillOnce(DoDefault());

  formulation::CFEM_DiffusionStamper<2> test_stamper(
      std::move(mock_diffusion_ptr),
      std::move(mock_definition_ptr));

  EXPECT_EQ(mock_diffusion_ptr, nullptr);
  EXPECT_EQ(mock_definition_ptr, nullptr);
}

// TODO(Josh) Put this in it's own header file?
class CFEMDiffusionStamperMPITests : public CFEMDiffusionStamperTest {
 protected:
  using Cell = typename dealii::DoFHandler<2>::active_cell_iterator;

  CFEMDiffusionStamperMPITests();

  void SetUp() override;
  void SetUpDealii();
  void SetUpBoundaries();
  AssertionResult CompareMPIMatrices(
      const dealii::PETScWrappers::MPI::SparseMatrix& expected,
      const dealii::PETScWrappers::MPI::SparseMatrix& result);

  dealii::ConstraintMatrix constraint_matrix_;
  dealii::parallel::distributed::Triangulation<2> triangulation_;
  dealii::DoFHandler<2> dof_handler_;
  dealii::FE_Q<2> fe_;
  dealii::IndexSet locally_relevant_dofs;
  dealii::IndexSet locally_owned_dofs_;
  dealii::PETScWrappers::MPI::SparseMatrix system_matrix_, index_hits_;
  std::vector<Cell> cells_;
  std::vector<int> material_ids_;
};

AssertionResult CFEMDiffusionStamperMPITests::CompareMPIMatrices(
    const dealii::PETScWrappers::MPI::SparseMatrix& expected,
    const dealii::PETScWrappers::MPI::SparseMatrix& result) {

  auto [first_local_row, last_local_row] = expected.local_range();
  unsigned int n_columns = expected.n();

  for (unsigned int i = first_local_row; i < last_local_row; ++i) {
    for (unsigned int j = 0; j < n_columns; ++j) {
      if (result(i, j) != expected(i, j)) {
        return AssertionFailure() << "Entry (" << i << ", " << j <<
                                  ") has value: " << result.el(i, j) <<
                                  ", expected: " << expected.el(i, j);
      }
    }
  }
  return AssertionSuccess();
}

CFEMDiffusionStamperMPITests::CFEMDiffusionStamperMPITests()
    : triangulation_(MPI_COMM_WORLD,
                     typename dealii::Triangulation<2>::MeshSmoothing(
                         dealii::Triangulation<2>::smoothing_on_refinement |
                             dealii::Triangulation<2>::smoothing_on_coarsening)),
      dof_handler_(triangulation_),
      fe_(1) {}

void CFEMDiffusionStamperMPITests::SetUp() {
  CFEMDiffusionStamperTest::SetUp();
  SetUpDealii();
  SetUpBoundaries();

  for (const auto& cell : cells_) {
    int mat_id = btest::RandomDouble(0, 10);
    material_ids_.push_back(mat_id);
    cell->set_material_id(mat_id);
  }

  ON_CALL(*mock_definition_ptr, Cells())
      .WillByDefault(Return(cells_));
  dealii::FullMatrix<double> cell_matrix(fe_.dofs_per_cell,
                                         fe_.dofs_per_cell);
  ON_CALL(*mock_definition_ptr, GetCellMatrix())
      .WillByDefault(Return(cell_matrix));
}

void CFEMDiffusionStamperMPITests::SetUpDealii() {
  // Create triangulation
  dealii::GridGenerator::hyper_cube(triangulation_, 0, 1);
  triangulation_.refine_global(2);
  // Distribute DOFS, get local index sets and cells
  dof_handler_.distribute_dofs(fe_);
  dealii::DoFTools::extract_locally_relevant_dofs(dof_handler_,
                                                  locally_relevant_dofs);
  locally_owned_dofs_ = dof_handler_.locally_owned_dofs();
  for (auto cell = dof_handler_.begin_active(); cell != dof_handler_.end(); ++ cell) {
    if (cell->is_locally_owned())
      cells_.push_back(cell);
  }

  // Make constraint matrix and DSP for matrices
  constraint_matrix_.clear();
  constraint_matrix_.reinit(locally_relevant_dofs);
  dealii::DoFTools::make_hanging_node_constraints(dof_handler_,
                                                  constraint_matrix_);
  constraint_matrix_.close();

  dealii::DynamicSparsityPattern dsp(locally_relevant_dofs);
  dealii::DoFTools::make_sparsity_pattern(dof_handler_, dsp,
                                          constraint_matrix_, false);
  dealii::SparsityTools::distribute_sparsity_pattern(
      dsp,
      dof_handler_.n_locally_owned_dofs_per_processor(),
      MPI_COMM_WORLD, locally_relevant_dofs);
  constraint_matrix_.condense(dsp);

  // Set up MPI matrices
  system_matrix_.reinit(locally_owned_dofs_, locally_owned_dofs_, dsp, MPI_COMM_WORLD);
  index_hits_.reinit(locally_owned_dofs_, locally_owned_dofs_, dsp, MPI_COMM_WORLD);

  std::vector<dealii::types::global_dof_index> local_dof_indices(fe_.dofs_per_cell);

  for (auto cell : cells_) {
    cell->get_dof_indices(local_dof_indices);
    for (auto index_i : local_dof_indices) {
      for (auto index_j : local_dof_indices) {
        index_hits_.add(index_i, index_j, 1);
      }
    }
    index_hits_.compress(dealii::VectorOperation::add);
  }
}

void CFEMDiffusionStamperMPITests::SetUpBoundaries() {
  using Boundary = bart::problem::Boundary;
  int faces_per_cell = dealii::GeometryInfo<2>::faces_per_cell;
  double zero_tol = 1.0e-14;

  for (auto &cell : cells_) {
    for (int face_id = 0; face_id < faces_per_cell; ++face_id) {
      auto face = cell->face(face_id);
      dealii::Point<2> face_center = face->center();

      if (std::fabs(face_center[1]) < zero_tol) {
        face->set_boundary_id(static_cast<int>(Boundary::kYMin));
      } else if (std::fabs(face_center[1] - 1) < zero_tol) {
        face->set_boundary_id(static_cast<int>(Boundary::kYMax));
      } else if (std::fabs(face_center[0]) < zero_tol) {
        face->set_boundary_id(static_cast<int>(Boundary::kXMin));
      } else if (std::fabs(face_center[0] - 1) < zero_tol) {
        face->set_boundary_id(static_cast<int>(Boundary::kXMax));
      }
    }
  }
}

TEST_F(CFEMDiffusionStamperMPITests, StampStreaming) {

  int group_number = 1;

  for (auto const& cell : cells_) {
    EXPECT_CALL(*mock_diffusion_ptr,
        FillCellStreamingTerm(_, _, cell, group_number))
        .WillOnce(Invoke(FillMatrixWithOnes));
  }
  EXPECT_CALL(*mock_definition_ptr, GetCellMatrix())
      .WillOnce(DoDefault());

  formulation::CFEM_DiffusionStamper<2> test_stamper(
      std::move(mock_diffusion_ptr),
      std::move(mock_definition_ptr));

  test_stamper.StampStreamingTerm(system_matrix_, group_number);

  EXPECT_TRUE(CompareMPIMatrices(system_matrix_, index_hits_));
}

TEST_F(CFEMDiffusionStamperMPITests, StampCollision) {

  int group_number = 1;

  for (auto const& cell : cells_) {
    EXPECT_CALL(*mock_diffusion_ptr,
                FillCellCollisionTerm(_, _, cell, group_number))
        .WillOnce(Invoke(FillMatrixWithOnes));
  }
  EXPECT_CALL(*mock_definition_ptr, GetCellMatrix())
      .WillOnce(DoDefault());

  formulation::CFEM_DiffusionStamper<2> test_stamper(
      std::move(mock_diffusion_ptr),
      std::move(mock_definition_ptr));

  test_stamper.StampCollisionTerm(system_matrix_, group_number);

  EXPECT_TRUE(CompareMPIMatrices(system_matrix_, index_hits_));
}

} // namespace<commit_msg>added boundary_hits to CFEM_DiffusionStamper tests<commit_after>#include "formulation/cfem_diffusion_stamper.h"

#include <memory>

#include <deal.II/base/mpi.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/distributed/tria.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/grid_tools.h>
#include <deal.II/lac/dynamic_sparsity_pattern.h>
#include <deal.II/lac/petsc_parallel_sparse_matrix.h>

#include "domain/tests/definition_mock.h"
#include "formulation/scalar/tests/cfem_diffusion_mock.h"
#include "problem/parameter_types.h"
#include "test_helpers/gmock_wrapper.h"
#include "test_helpers/test_helper_functions.h"

namespace {

using ::testing::AssertionResult;
using ::testing::AssertionFailure, ::testing::AssertionSuccess;
using ::testing::DoDefault;
using ::testing::Invoke;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::Unused;
using ::testing::_;

using namespace bart;
using Cell = domain::DefinitionI<2>::Cell;
using InitToken = formulation::scalar::CFEM_DiffusionI<2>::InitializationToken;
using Matrix = dealii::FullMatrix<double>;

class CFEMDiffusionStamperTest : public ::testing::Test {
 protected:
  std::unique_ptr<NiceMock<domain::DefinitionMock<2>>> mock_definition_ptr;
  std::unique_ptr<NiceMock<formulation::scalar::CFEM_DiffusionMock<2>>> mock_diffusion_ptr;
  void SetUp() override;
  InitToken init_token_;

};

// TODO(Josh) Move this to a header where other stamper tests can use it
void OnesFill(Matrix& to_fill) {
  for (unsigned int i = 0; i < to_fill.n_rows(); ++i) {
    for (unsigned int j = 0; j < to_fill.n_cols(); ++j) {
      to_fill(i,j) = 1;
    }
  }
}

void FillMatrixWithOnes(Matrix& to_fill, Unused, Unused, Unused) {
  OnesFill(to_fill);
}

void FillMatrixWithOnesBoundary(Matrix& to_fill, Unused, Unused, Unused, Unused) {
  OnesFill(to_fill);
}

void CFEMDiffusionStamperTest::SetUp() {
  mock_definition_ptr = std::make_unique<NiceMock<domain::DefinitionMock<2>>>();
  mock_diffusion_ptr =
      std::make_unique<NiceMock<formulation::scalar::CFEM_DiffusionMock<2>>>();

  ON_CALL(*mock_diffusion_ptr, Precalculate(_))
      .WillByDefault(Return(init_token_));
}

TEST_F(CFEMDiffusionStamperTest, Constructor) {
  Cell test_cell;
  std::vector<Cell> cells{test_cell};

  EXPECT_CALL(*mock_definition_ptr, Cells())
      .WillOnce(Return(cells));
  EXPECT_CALL(*mock_diffusion_ptr, Precalculate(_))
      .WillOnce(DoDefault());

  formulation::CFEM_DiffusionStamper<2> test_stamper(
      std::move(mock_diffusion_ptr),
      std::move(mock_definition_ptr));

  EXPECT_EQ(mock_diffusion_ptr, nullptr);
  EXPECT_EQ(mock_definition_ptr, nullptr);
}

// TODO(Josh) Put this in it's own header file?
class CFEMDiffusionStamperMPITests : public CFEMDiffusionStamperTest {
 protected:
  using Cell = typename dealii::DoFHandler<2>::active_cell_iterator;

  CFEMDiffusionStamperMPITests();

  void SetUp() override;
  void SetUpDealii();
  void SetUpBoundaries();
  AssertionResult CompareMPIMatrices(
      const dealii::PETScWrappers::MPI::SparseMatrix& expected,
      const dealii::PETScWrappers::MPI::SparseMatrix& result);

  dealii::ConstraintMatrix constraint_matrix_;
  dealii::parallel::distributed::Triangulation<2> triangulation_;
  dealii::DoFHandler<2> dof_handler_;
  dealii::FE_Q<2> fe_;
  dealii::IndexSet locally_relevant_dofs;
  dealii::IndexSet locally_owned_dofs_;
  dealii::PETScWrappers::MPI::SparseMatrix system_matrix_;
  dealii::PETScWrappers::MPI::SparseMatrix index_hits_, boundary_hits_;
  std::vector<Cell> cells_;
  std::vector<int> material_ids_;
};

AssertionResult CFEMDiffusionStamperMPITests::CompareMPIMatrices(
    const dealii::PETScWrappers::MPI::SparseMatrix& expected,
    const dealii::PETScWrappers::MPI::SparseMatrix& result) {

  auto [first_local_row, last_local_row] = expected.local_range();
  unsigned int n_columns = expected.n();

  for (unsigned int i = first_local_row; i < last_local_row; ++i) {
    for (unsigned int j = 0; j < n_columns; ++j) {
      if (result(i, j) != expected(i, j)) {
        return AssertionFailure() << "Entry (" << i << ", " << j <<
                                  ") has value: " << result.el(i, j) <<
                                  ", expected: " << expected.el(i, j);
      }
    }
  }
  return AssertionSuccess();
}

CFEMDiffusionStamperMPITests::CFEMDiffusionStamperMPITests()
    : triangulation_(MPI_COMM_WORLD,
                     typename dealii::Triangulation<2>::MeshSmoothing(
                         dealii::Triangulation<2>::smoothing_on_refinement |
                             dealii::Triangulation<2>::smoothing_on_coarsening)),
      dof_handler_(triangulation_),
      fe_(1) {}

void CFEMDiffusionStamperMPITests::SetUp() {
  CFEMDiffusionStamperTest::SetUp();
  SetUpDealii();
  SetUpBoundaries();

  for (const auto& cell : cells_) {
    int mat_id = btest::RandomDouble(0, 10);
    material_ids_.push_back(mat_id);
    cell->set_material_id(mat_id);
  }

  ON_CALL(*mock_definition_ptr, Cells())
      .WillByDefault(Return(cells_));
  dealii::FullMatrix<double> cell_matrix(fe_.dofs_per_cell,
                                         fe_.dofs_per_cell);
  ON_CALL(*mock_definition_ptr, GetCellMatrix())
      .WillByDefault(Return(cell_matrix));
}

void CFEMDiffusionStamperMPITests::SetUpDealii() {
  // Create triangulation
  dealii::GridGenerator::hyper_cube(triangulation_, 0, 1);
  triangulation_.refine_global(2);
  // Distribute DOFS, get local index sets and cells
  dof_handler_.distribute_dofs(fe_);
  dealii::DoFTools::extract_locally_relevant_dofs(dof_handler_,
                                                  locally_relevant_dofs);
  locally_owned_dofs_ = dof_handler_.locally_owned_dofs();
  for (auto cell = dof_handler_.begin_active(); cell != dof_handler_.end(); ++ cell) {
    if (cell->is_locally_owned())
      cells_.push_back(cell);
  }

  // Make constraint matrix and DSP for matrices
  constraint_matrix_.clear();
  constraint_matrix_.reinit(locally_relevant_dofs);
  dealii::DoFTools::make_hanging_node_constraints(dof_handler_,
                                                  constraint_matrix_);
  constraint_matrix_.close();

  dealii::DynamicSparsityPattern dsp(locally_relevant_dofs);
  dealii::DoFTools::make_sparsity_pattern(dof_handler_, dsp,
                                          constraint_matrix_, false);
  dealii::SparsityTools::distribute_sparsity_pattern(
      dsp,
      dof_handler_.n_locally_owned_dofs_per_processor(),
      MPI_COMM_WORLD, locally_relevant_dofs);
  constraint_matrix_.condense(dsp);

  // Set up MPI matrices
  system_matrix_.reinit(locally_owned_dofs_, locally_owned_dofs_, dsp, MPI_COMM_WORLD);
  index_hits_.reinit(locally_owned_dofs_, locally_owned_dofs_, dsp, MPI_COMM_WORLD);
  boundary_hits_.reinit(locally_owned_dofs_, locally_owned_dofs_, dsp, MPI_COMM_WORLD);

  std::vector<dealii::types::global_dof_index> local_dof_indices(fe_.dofs_per_cell);

  for (auto cell : cells_) {
    cell->get_dof_indices(local_dof_indices);
    for (auto index_i : local_dof_indices) {
      for (auto index_j : local_dof_indices) {
        index_hits_.add(index_i, index_j, 1);
        if (cell->at_boundary())
          boundary_hits_.add(index_i, index_j, 1);
      }
    }
    index_hits_.compress(dealii::VectorOperation::add);
    boundary_hits_.compress(dealii::VectorOperation::add);
  }
}

void CFEMDiffusionStamperMPITests::SetUpBoundaries() {
  using Boundary = bart::problem::Boundary;
  int faces_per_cell = dealii::GeometryInfo<2>::faces_per_cell;
  double zero_tol = 1.0e-14;

  for (auto &cell : cells_) {
    for (int face_id = 0; face_id < faces_per_cell; ++face_id) {
      auto face = cell->face(face_id);
      dealii::Point<2> face_center = face->center();

      if (std::fabs(face_center[1]) < zero_tol) {
        face->set_boundary_id(static_cast<int>(Boundary::kYMin));
      } else if (std::fabs(face_center[1] - 1) < zero_tol) {
        face->set_boundary_id(static_cast<int>(Boundary::kYMax));
      } else if (std::fabs(face_center[0]) < zero_tol) {
        face->set_boundary_id(static_cast<int>(Boundary::kXMin));
      } else if (std::fabs(face_center[0] - 1) < zero_tol) {
        face->set_boundary_id(static_cast<int>(Boundary::kXMax));
      }
    }
  }
}

TEST_F(CFEMDiffusionStamperMPITests, StampStreaming) {

  int group_number = 1;

  for (auto const& cell : cells_) {
    EXPECT_CALL(*mock_diffusion_ptr,
        FillCellStreamingTerm(_, _, cell, group_number))
        .WillOnce(Invoke(FillMatrixWithOnes));
  }
  EXPECT_CALL(*mock_definition_ptr, GetCellMatrix())
      .WillOnce(DoDefault());

  formulation::CFEM_DiffusionStamper<2> test_stamper(
      std::move(mock_diffusion_ptr),
      std::move(mock_definition_ptr));

  test_stamper.StampStreamingTerm(system_matrix_, group_number);

  EXPECT_TRUE(CompareMPIMatrices(system_matrix_, index_hits_));
}

TEST_F(CFEMDiffusionStamperMPITests, StampCollision) {

  int group_number = 1;

  for (auto const& cell : cells_) {
    EXPECT_CALL(*mock_diffusion_ptr,
                FillCellCollisionTerm(_, _, cell, group_number))
        .WillOnce(Invoke(FillMatrixWithOnes));
  }
  EXPECT_CALL(*mock_definition_ptr, GetCellMatrix())
      .WillOnce(DoDefault());

  formulation::CFEM_DiffusionStamper<2> test_stamper(
      std::move(mock_diffusion_ptr),
      std::move(mock_definition_ptr));

  test_stamper.StampCollisionTerm(system_matrix_, group_number);

  EXPECT_TRUE(CompareMPIMatrices(system_matrix_, index_hits_));
}

} // namespace<|endoftext|>


<commit_before>/** \file    MediaTypeUtil.cc
 *  \brief   Implementation of Media Type utility functions.
 *  \author  Dr. Gordon W. Paynter
 *  \author  Dr. Johannes Ruscheinski
 */

/*
 *  Copyright 2004-2008 Project iVia.
 *  Copyright 2004-2008 The Regents of The University of California.
 *  Copyright 2016 Universitätsbibliothek Tübingen.
 *
 *  This file is part of the libiViaCore package.
 *
 *  The libiViaCore package is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License as published
 *  by the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  libiViaCore 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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with libiViaCore; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "MediaTypeUtil.h"
#include <stdexcept>
#include <cctype>
#include <magic.h>
#include "File.h"
#include "HttpHeader.h"
#include "PerlCompatRegExp.h"
#include "StringUtil.h"
#include "Url.h"
#include "WebUtil.h"

namespace MediaTypeUtil {

std::string GetHtmlMediaType(const std::string &document) {
    static const PerlCompatRegExp doctype_regexp("^\\s*<(?:!DOCTYPE\\s+HTML\\s+PUBLIC\\s+\"-//W3C//DTD\\s+){0,1}(X?HTML)",
						 PerlCompatRegExp::OPTIMIZE_FOR_MULTIPLE_USE, PCRE_CASELESS);

    // If we have a match we have either HTML or XHTML...
    std::string matched_substring;
    if (doctype_regexp.match(document) and doctype_regexp.getMatchedSubstring(1, &matched_substring))
	return matched_substring.length() == 4 ? "text/html" : "text/xhtml";

    // ...otherwise we have no idea what we have:
    return "";
}

static std::string LZ4_MAGIC("\000\042\115\030");

// GetMediaType -- Get the media type of a document.
//
std::string GetMediaType(const std::string &document, const bool auto_simplify) {
    if (document.empty())
	return "";

    // 1. See if we have (X)HTML:
    std::string media_type(GetHtmlMediaType(document));
    if (not media_type.empty())
	return media_type;

    // 2. Check for LZ4 compression:
    if (document.substr(0, 4) == LZ4_MAGIC)
	return "application/lz4";

    // 3. Next try libmagic:
    const magic_t cookie = ::magic_open(MAGIC_MIME);
    if (unlikely(cookie == nullptr))
	throw std::runtime_error("in MediaTypeUtil::GetMediaType: could not open libmagic!");

    // Load the default "magic" definitions file:
    if (unlikely(::magic_load(cookie, nullptr /* use default magic file */) != 0)) {
	::magic_close(cookie);
	throw std::runtime_error("in MediaTypeUtil::GetMediaType: could not load libmagic ("
	                         + std::string(::magic_error(cookie)) + ").");
    }

    // Use magic to get the mime type of the buffer:
    const char *magic_mime_type = ::magic_buffer(cookie, document.c_str(), document.length());
    if (unlikely(magic_mime_type == nullptr)) {
	::magic_close(cookie);
	throw std::runtime_error("in MediaTypeUtil::GetMediaType: error in libmagic ("
	                         + std::string(::magic_error(cookie)) + ").");
    }

    // Attempt to remove possible leading junk (no idea why libmagic behaves in this manner every now and then):
    if (std::strncmp(magic_mime_type, "\\012- ", 6) == 0)
	magic_mime_type += 6;

    // Close the library:
    media_type = magic_mime_type;
    ::magic_close(cookie);

    // 4. If the libmagic could not determine the document's MIME type, test for XML:
    if (media_type.empty() and document.size() > 5)
	return std::strncmp(document.c_str(), "<?xml", 5) == 0 ? "text/xml" : "";

    if (auto_simplify)
	SimplifyMediaType(&media_type);

    return media_type;
}

std::string GetFileMediaType(const std::string &filename, const bool auto_simplify) {
    const magic_t cookie = ::magic_open(MAGIC_MIME | MAGIC_SYMLINK);
    if (unlikely(cookie == nullptr))
	throw std::runtime_error("in MediaTypeUtil::GetMediaType: could not open libmagic!");

    // Load the default "magic" definitions file:
    if (unlikely(::magic_load(cookie, nullptr /* use default magic file */) != 0)) {
	::magic_close(cookie);
	throw std::runtime_error("in MediaTypeUtil::GetMediaType: could not load libmagic ("
	                         + std::string(::magic_error(cookie)) + ").");
    }

    // Use magic to get the mime type of the buffer:
    const char *magic_mime_type(::magic_file(cookie, filename.c_str()));
    if (unlikely(magic_mime_type == nullptr)) {
	::magic_close(cookie);
	throw std::runtime_error("in MediaTypeUtil::GetFileMediaType: error in libmagic ("
	                         + std::string(::magic_error(cookie)) + ").");
    }

    // Attempt to remove possible leading junk (no idea why libmagic behaves in this manner every now and then):
    if (std::strncmp(magic_mime_type, "\\012- ", 6) == 0)
	magic_mime_type += 6;

    // Close the library:
    std::string media_type(magic_mime_type);
    ::magic_close(cookie);

    if (auto_simplify)
	SimplifyMediaType(&media_type);

    if (StringUtil::StartsWith(media_type, "application/octet-stream")) {
	File input(filename, "rb");
	    char buf[LZ4_MAGIC.size()];
	    if ((input.read(buf, sizeof(buf)) == sizeof(buf)) and std::strncmp(LZ4_MAGIC.c_str(), buf, LZ4_MAGIC.size()) == 0)
		return "application/lz4";
    }

    return media_type;
}

// GetMediaType -- get the media type of a Web page.
//
std::string GetMediaType(const std::string &page_header, const std::string &page_body, const bool auto_simplify) {
    // First, attempt to find the media type in the header:
    HttpHeader http_header(page_header);
    if (http_header.isValid()) {
	std::string media_type(http_header.getMediaType());
	if (not media_type.empty()) {
	    StringUtil::ToLower(&media_type);
	    if (auto_simplify)
		SimplifyMediaType(&media_type);
	    return media_type;
	}
    }

    // Otherwise, check the content:
    return GetMediaType(page_body, auto_simplify);
}

// GetMediaType -- Get the MediaType of the page.  Returns true if "media_type" is known and set.
//
bool GetMediaType(const Url &url, const HttpHeader &http_header, const std::string &page_content,
		  std::string * const media_type, const bool auto_simplify)
{
    // First, attempt to find the media type in the header:
    if (http_header.isValid()) {
	*media_type = http_header.getMediaType();
	if (not media_type->empty()) {
	    if (auto_simplify)
		SimplifyMediaType(media_type);
	    return true;
	}
    }

    // Second, attempt to use the "magic" library (libmagic) to analyse the page:
    *media_type = MediaTypeUtil::GetMediaType(page_content);
    if (not media_type->empty()) {
	if (auto_simplify)
	    SimplifyMediaType(media_type);
	return true;
    }

    // Third, guess based on URL:
    *media_type = WebUtil::GuessMediaType(url);
    if (not media_type->empty() and auto_simplify)
	SimplifyMediaType(media_type);
    return not media_type->empty();
}

std::string GetMediaType(const HttpHeader &http_header, const std::string &page_body, const bool auto_simplify) {
    std::string media_type;

    // First, attempt to find the media type in the header:
    if (http_header.isValid()) {
	media_type = http_header.getMediaType();
	if (not media_type.empty()) {
	    StringUtil::ToLower(&media_type);
	    if (auto_simplify)
		SimplifyMediaType(&media_type);
	    return media_type;
	}
    }

    // Second, attempt to use the "magic" library (libmagic) to analyse the page:
    media_type = MediaTypeUtil::GetMediaType(page_body, auto_simplify);

    return media_type;
}

bool GetMediaType(const std::string &url, const HttpHeader &http_header, const std::string &page_content,
		  std::string * const media_type, const bool auto_simplify)
{
    return GetMediaType(Url(url), http_header, page_content, media_type, auto_simplify);
}

bool SimplifyMediaType(std::string * const media_type) {
    if (media_type->empty())
	return false;

    // This is the format of the Content-Type field for Web pages:
    // 	media-type     = type "/" subtype *( ";" parameter )
    // 	type           = token
    //      subtype        = token
    // See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7

    const std::string initial_media_type(*media_type);

    // Search for a semicolon and delete any 'parameter' parts:
    const std::string::size_type semicolon_pos(media_type->find(';'));
    if (semicolon_pos != std::string::npos)
	media_type->resize(semicolon_pos);
    else { // Try a space instead of a semicolon.
	const std::string::size_type space_pos(media_type->find(' '));
	if (space_pos != std::string::npos)
	    media_type->resize(space_pos);
    }

    StringUtil::TrimWhite(media_type);

    // Return if "media_type" has changed:
    return initial_media_type != *media_type;
}

} // namespace MediaTypeUtil
<commit_msg>Use alloca to keep g++ happy.  (clang++ liked it before the change.)<commit_after>/** \file    MediaTypeUtil.cc
 *  \brief   Implementation of Media Type utility functions.
 *  \author  Dr. Gordon W. Paynter
 *  \author  Dr. Johannes Ruscheinski
 */

/*
 *  Copyright 2004-2008 Project iVia.
 *  Copyright 2004-2008 The Regents of The University of California.
 *  Copyright 2016 Universitätsbibliothek Tübingen.
 *
 *  This file is part of the libiViaCore package.
 *
 *  The libiViaCore package is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License as published
 *  by the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  libiViaCore 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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with libiViaCore; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "MediaTypeUtil.h"
#include <stdexcept>
#include <cctype>
#include <alloca.h>
#include <magic.h>
#include "File.h"
#include "HttpHeader.h"
#include "PerlCompatRegExp.h"
#include "StringUtil.h"
#include "Url.h"
#include "WebUtil.h"

namespace MediaTypeUtil {

std::string GetHtmlMediaType(const std::string &document) {
    static const PerlCompatRegExp doctype_regexp("^\\s*<(?:!DOCTYPE\\s+HTML\\s+PUBLIC\\s+\"-//W3C//DTD\\s+){0,1}(X?HTML)",
						 PerlCompatRegExp::OPTIMIZE_FOR_MULTIPLE_USE, PCRE_CASELESS);

    // If we have a match we have either HTML or XHTML...
    std::string matched_substring;
    if (doctype_regexp.match(document) and doctype_regexp.getMatchedSubstring(1, &matched_substring))
	return matched_substring.length() == 4 ? "text/html" : "text/xhtml";

    // ...otherwise we have no idea what we have:
    return "";
}

static std::string LZ4_MAGIC("\000\042\115\030");

// GetMediaType -- Get the media type of a document.
//
std::string GetMediaType(const std::string &document, const bool auto_simplify) {
    if (document.empty())
	return "";

    // 1. See if we have (X)HTML:
    std::string media_type(GetHtmlMediaType(document));
    if (not media_type.empty())
	return media_type;

    // 2. Check for LZ4 compression:
    if (document.substr(0, 4) == LZ4_MAGIC)
	return "application/lz4";

    // 3. Next try libmagic:
    const magic_t cookie = ::magic_open(MAGIC_MIME);
    if (unlikely(cookie == nullptr))
	throw std::runtime_error("in MediaTypeUtil::GetMediaType: could not open libmagic!");

    // Load the default "magic" definitions file:
    if (unlikely(::magic_load(cookie, nullptr /* use default magic file */) != 0)) {
	::magic_close(cookie);
	throw std::runtime_error("in MediaTypeUtil::GetMediaType: could not load libmagic ("
	                         + std::string(::magic_error(cookie)) + ").");
    }

    // Use magic to get the mime type of the buffer:
    const char *magic_mime_type = ::magic_buffer(cookie, document.c_str(), document.length());
    if (unlikely(magic_mime_type == nullptr)) {
	::magic_close(cookie);
	throw std::runtime_error("in MediaTypeUtil::GetMediaType: error in libmagic ("
	                         + std::string(::magic_error(cookie)) + ").");
    }

    // Attempt to remove possible leading junk (no idea why libmagic behaves in this manner every now and then):
    if (std::strncmp(magic_mime_type, "\\012- ", 6) == 0)
	magic_mime_type += 6;

    // Close the library:
    media_type = magic_mime_type;
    ::magic_close(cookie);

    // 4. If the libmagic could not determine the document's MIME type, test for XML:
    if (media_type.empty() and document.size() > 5)
	return std::strncmp(document.c_str(), "<?xml", 5) == 0 ? "text/xml" : "";

    if (auto_simplify)
	SimplifyMediaType(&media_type);

    return media_type;
}

std::string GetFileMediaType(const std::string &filename, const bool auto_simplify) {
    const magic_t cookie = ::magic_open(MAGIC_MIME | MAGIC_SYMLINK);
    if (unlikely(cookie == nullptr))
	throw std::runtime_error("in MediaTypeUtil::GetMediaType: could not open libmagic!");

    // Load the default "magic" definitions file:
    if (unlikely(::magic_load(cookie, nullptr /* use default magic file */) != 0)) {
	::magic_close(cookie);
	throw std::runtime_error("in MediaTypeUtil::GetMediaType: could not load libmagic ("
	                         + std::string(::magic_error(cookie)) + ").");
    }

    // Use magic to get the mime type of the buffer:
    const char *magic_mime_type(::magic_file(cookie, filename.c_str()));
    if (unlikely(magic_mime_type == nullptr)) {
	::magic_close(cookie);
	throw std::runtime_error("in MediaTypeUtil::GetFileMediaType: error in libmagic ("
	                         + std::string(::magic_error(cookie)) + ").");
    }

    // Attempt to remove possible leading junk (no idea why libmagic behaves in this manner every now and then):
    if (std::strncmp(magic_mime_type, "\\012- ", 6) == 0)
	magic_mime_type += 6;

    // Close the library:
    std::string media_type(magic_mime_type);
    ::magic_close(cookie);

    if (auto_simplify)
	SimplifyMediaType(&media_type);

    if (StringUtil::StartsWith(media_type, "application/octet-stream")) {
	File input(filename, "rb");
	char *buf = reinterpret_cast<char *>(::alloca(LZ4_MAGIC.size()));
	if ((input.read(buf, sizeof(buf)) == sizeof(buf)) and std::strncmp(LZ4_MAGIC.c_str(), buf, LZ4_MAGIC.size()) == 0)
	    return "application/lz4";
    }

    return media_type;
}

// GetMediaType -- get the media type of a Web page.
//
std::string GetMediaType(const std::string &page_header, const std::string &page_body, const bool auto_simplify) {
    // First, attempt to find the media type in the header:
    HttpHeader http_header(page_header);
    if (http_header.isValid()) {
	std::string media_type(http_header.getMediaType());
	if (not media_type.empty()) {
	    StringUtil::ToLower(&media_type);
	    if (auto_simplify)
		SimplifyMediaType(&media_type);
	    return media_type;
	}
    }

    // Otherwise, check the content:
    return GetMediaType(page_body, auto_simplify);
}

// GetMediaType -- Get the MediaType of the page.  Returns true if "media_type" is known and set.
//
bool GetMediaType(const Url &url, const HttpHeader &http_header, const std::string &page_content,
		  std::string * const media_type, const bool auto_simplify)
{
    // First, attempt to find the media type in the header:
    if (http_header.isValid()) {
	*media_type = http_header.getMediaType();
	if (not media_type->empty()) {
	    if (auto_simplify)
		SimplifyMediaType(media_type);
	    return true;
	}
    }

    // Second, attempt to use the "magic" library (libmagic) to analyse the page:
    *media_type = MediaTypeUtil::GetMediaType(page_content);
    if (not media_type->empty()) {
	if (auto_simplify)
	    SimplifyMediaType(media_type);
	return true;
    }

    // Third, guess based on URL:
    *media_type = WebUtil::GuessMediaType(url);
    if (not media_type->empty() and auto_simplify)
	SimplifyMediaType(media_type);
    return not media_type->empty();
}

std::string GetMediaType(const HttpHeader &http_header, const std::string &page_body, const bool auto_simplify) {
    std::string media_type;

    // First, attempt to find the media type in the header:
    if (http_header.isValid()) {
	media_type = http_header.getMediaType();
	if (not media_type.empty()) {
	    StringUtil::ToLower(&media_type);
	    if (auto_simplify)
		SimplifyMediaType(&media_type);
	    return media_type;
	}
    }

    // Second, attempt to use the "magic" library (libmagic) to analyse the page:
    media_type = MediaTypeUtil::GetMediaType(page_body, auto_simplify);

    return media_type;
}

bool GetMediaType(const std::string &url, const HttpHeader &http_header, const std::string &page_content,
		  std::string * const media_type, const bool auto_simplify)
{
    return GetMediaType(Url(url), http_header, page_content, media_type, auto_simplify);
}

bool SimplifyMediaType(std::string * const media_type) {
    if (media_type->empty())
	return false;

    // This is the format of the Content-Type field for Web pages:
    // 	media-type     = type "/" subtype *( ";" parameter )
    // 	type           = token
    //      subtype        = token
    // See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7

    const std::string initial_media_type(*media_type);

    // Search for a semicolon and delete any 'parameter' parts:
    const std::string::size_type semicolon_pos(media_type->find(';'));
    if (semicolon_pos != std::string::npos)
	media_type->resize(semicolon_pos);
    else { // Try a space instead of a semicolon.
	const std::string::size_type space_pos(media_type->find(' '));
	if (space_pos != std::string::npos)
	    media_type->resize(space_pos);
    }

    StringUtil::TrimWhite(media_type);

    // Return if "media_type" has changed:
    return initial_media_type != *media_type;
}

} // namespace MediaTypeUtil
<|endoftext|>