<commit_before>#include "cmm_socket.private.h"
#include "csocket.h"
#include "debug.h"
#include "cmm_socket_scheduler.h"
#include "cmm_socket_control.h"
#include "cmm_socket_sender.h"
#include "cmm_socket_receiver.h"
#include <netinet/in.h>
#include <arpa/inet.h>

class CSocketSender : public CMMSocketScheduler<struct CMMSocketRequest> {
  public:
    explicit CSocketSender(CSocket *csock_);
  protected:
    virtual void dispatch(struct CMMSocketRequest);
    virtual void Finish();
  private:
    CSocket *csock;

    void send_request(struct CMMSocketRequest req);
    void do_begin_irob(struct CMMSocketRequest req);
    void do_end_irob(struct CMMSocketRequest req);
    void do_irob_chunk(struct CMMSocketRequest req);

    void send_header(struct CMMSocketControlHdr hdr);
};

void
CSocketSender::dispatch(struct CMMSocketRequest req)
{
    dbgprintf("Sending request\n%s\n", req.describe().c_str());
    CMMSocketScheduler<struct CMMSocketRequest>::dispatch(req);
}

class CSocketReceiver : public CMMSocketScheduler<struct CMMSocketControlHdr> {
  public:
    explicit CSocketReceiver(CSocket *csock_);
    void stop();
  protected:
    virtual void Run();
    virtual void Finish();
  private:
    CSocket *csock;

    void pass_header(struct CMMSocketControlHdr hdr);
    void do_begin_irob(struct CMMSocketControlHdr hdr);
    void do_irob_chunk(struct CMMSocketControlHdr hdr);
};

CSocketSender::CSocketSender(CSocket *csock_)
    : csock(csock_)
{
    handle(CMM_CONTROL_MSG_BEGIN_IROB, this, &CSocketSender::do_begin_irob);
    handle(CMM_CONTROL_MSG_END_IROB, this, &CSocketSender::send_request);
    handle(CMM_CONTROL_MSG_IROB_CHUNK, this, &CSocketSender::do_irob_chunk);
    handle(CMM_CONTROL_MSG_NEW_INTERFACE, this, &CSocketSender::send_request);
    handle(CMM_CONTROL_MSG_DOWN_INTERFACE, this, &CSocketSender::send_request);
    handle(CMM_CONTROL_MSG_ACK, this, &CSocketSender::send_request);
    handle(CMM_CONTROL_MSG_GOODBYE, this, &CSocketSender::send_request);
}

void
CSocketSender::Finish(void)
{
    csock->remove();
}

void CSocketSender::send_header(struct CMMSocketControlHdr hdr)
{
    int rc = send(csock->osfd, &hdr, sizeof(hdr), 0);
    if (rc != sizeof(hdr)) {
	throw Exception::make("Socket error", hdr);
    }
}

void
CSocketSender::send_request(struct CMMSocketRequest req)
{
    struct CMMSocketControlHdr& hdr = req.hdr;
    try {
	send_header(hdr);
    } catch (std::runtime_error& e) {
        /* give this request back to the send scheduler */
        csock->sendr->enqueue(req);
        throw;
    }

    csock->sendr->signal_completion(req.requester_tid, 0);
}

void
CSocketSender::do_begin_irob(struct CMMSocketRequest req)
{
    struct CMMSocketControlHdr& hdr = req.hdr;
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_BEGIN_IROB);
    irob_id_t *deps = hdr.op.begin_irob.deps;
    hdr.op.begin_irob.deps = NULL;

    try {
	int numdeps = ntohl(hdr.op.begin_irob.numdeps);
	if (numdeps > 0) {
	    assert(deps);
	    int datalen = numdeps * sizeof(irob_id_t);
	    send_header(hdr);
	    int rc = send(csock->osfd, deps, datalen, 0);
	    if (rc != datalen) {
		throw Exception::make("Socket error", req);
	    }
	    /* this buffer is no longer needed, so delete it */
	    delete [] deps;
	} else {
	    send_header(hdr);
	}
    } catch (std::runtime_error& e) {
	hdr.op.begin_irob.deps = deps;
	csock->sendr->enqueue(req);
	throw;
    }
    csock->sendr->signal_completion(req.requester_tid, 0);
}

void
CSocketSender::do_irob_chunk(struct CMMSocketRequest req)
{
    struct CMMSocketControlHdr& hdr = req.hdr;
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_IROB_CHUNK);
    int datalen = ntohl(hdr.op.irob_chunk.datalen);
    if (datalen <= 0) {
        throw Exception::make("Expected data with header, got none", hdr);
    }

    char *buf = hdr.op.irob_chunk.data;
    hdr.op.irob_chunk.data = NULL;

    try {
	send_header(hdr);
	int rc = send(csock->osfd, buf, datalen, 0);
	if (rc != datalen) {
	    throw Exception::make("Socket error", req);
	}
    } catch (std::runtime_error& e) {
	hdr.op.irob_chunk.data = buf;
	csock->sendr->enqueue(req);
	throw;
    }
    /* notice that we don't delete the data buffer here,
     * since it is an un-ACK'd part of an IROB.
     * It will be cleaned up later when the ACK is received. */

    csock->sendr->signal_completion(req.requester_tid, datalen);
}

CSocketReceiver::CSocketReceiver(CSocket *csock_)
    : csock(csock_)
{
    handle(CMM_CONTROL_MSG_BEGIN_IROB, this, &CSocketReceiver::do_begin_irob);
    handle(CMM_CONTROL_MSG_END_IROB, this, &CSocketReceiver::pass_header);
    handle(CMM_CONTROL_MSG_IROB_CHUNK, this, &CSocketReceiver::do_irob_chunk);
    handle(CMM_CONTROL_MSG_NEW_INTERFACE, this, &CSocketReceiver::pass_header);
    handle(CMM_CONTROL_MSG_DOWN_INTERFACE, this,
           &CSocketReceiver::pass_header);
    handle(CMM_CONTROL_MSG_ACK, this, &CSocketReceiver::pass_header);
    handle(CMM_CONTROL_MSG_GOODBYE, this, &CSocketReceiver::pass_header);
}

void
CSocketReceiver::Run(void)
{
    while (1) {
        struct CMMSocketControlHdr hdr;

        fd_set readfds;
        FD_ZERO(&readfds);
        FD_SET(csock->osfd, &readfds);
        int rc = select(csock->osfd + 1, &readfds, NULL, NULL, NULL);
        if (rc < 0) {
            if (errno == EINTR) {
                continue;
            } else {
                return;
            }
        }
        rc = recv(csock->osfd, &hdr, sizeof(hdr), 0);
        if (rc != sizeof(hdr)) {
            return;
        }

        dispatch(hdr);
    }
}

void
CSocketReceiver::stop(void)
{
    CMMThread::stop();
}

void
CSocketReceiver::Finish(void)
{
    /* Whether CSocketSender or CSocketReceiver gets here
     * first, the result should be correct.
     * Everything should only get deleted once, and the
     * thread-stopping functions are idempotent. */
    csock->remove();
}

void CSocketReceiver::pass_header(struct CMMSocketControlHdr hdr)
{
    csock->recvr->enqueue(hdr);
}

void CSocketReceiver::do_begin_irob(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_BEGIN_IROB);
    int numdeps = ntohl(hdr.op.begin_irob.numdeps);
    if (numdeps > 0) {
        irob_id_t *deps = new irob_id_t[numdeps];
        int datalen = numdeps * sizeof(irob_id_t);
        int rc = recv(csock->osfd, (char*)deps, datalen, 0);
        if (rc != datalen) {
            if (rc < 0) {
                dbgprintf("Error %d on socket %d\n", errno, csock->osfd);
            } else {
                dbgprintf("Expected %d bytes after header, received %d\n",
                          datalen, rc);
            }
            delete [] deps;
            throw Exception::make("Socket error", hdr);
        }
        hdr.op.begin_irob.deps = deps;
    }

    pass_header(hdr);
}

void CSocketReceiver::do_irob_chunk(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_IROB_CHUNK);
    int datalen = ntohl(hdr.op.irob_chunk.datalen);
    if (datalen <= 0) {
        throw Exception::make("Expected data with header, got none", hdr);
    }

    char *buf = new char[datalen];
    int rc = recv(csock->osfd, buf, datalen, 0);
    if (rc != datalen) {
        if (rc < 0) {
            dbgprintf("Error %d on socket %d\n", errno, csock->osfd);
        } else {
            dbgprintf("Expected %d bytes after header, received %d\n",
                      datalen, rc);
        }
        delete [] buf;
        throw Exception::make("Socket error", hdr);
    }
    dbgprintf("Successfully got %d data bytes\n", datalen);

    hdr.op.irob_chunk.data = buf;
    pass_header(hdr);
}

CSocket::CSocket(CMMSocketImpl *sk_,
                 CMMSocketSender *sendr_,
                 CMMSocketReceiver *recvr_,
                 struct net_interface local_iface_,
                 struct net_interface remote_iface_,
                 int accepted_sock)
    : sk(sk_), sendr(sendr_), recvr(recvr_),
      local_iface(local_iface_), remote_iface(remote_iface_),
      csock_sendr(NULL), csock_recvr(NULL)
{
    assert(sk && sendr && recvr);
    if (accepted_sock == -1) {
        osfd = socket(sk->sock_family, sk->sock_type, sk->sock_protocol);
        if (osfd < 0) {
            /* out of file descriptors or memory at this point */
            throw std::runtime_error("Out of FDs or memory!");
        }

        sk->set_all_sockopts(osfd);
    } else {
        osfd = accepted_sock;
	startup_workers();
    }
}

CSocket::~CSocket()
{
    if (csock_sendr) {
	csock_sendr->stop();
    }
    if (csock_recvr) {
	csock_recvr->stop();
    }
    delete csock_sendr;
    delete csock_recvr;

    if (osfd > 0) {
	/* if it's a real open socket */
	close(osfd);
    }
}

int
CSocket::phys_connect()
{
    struct sockaddr_in local_addr, remote_addr;

    local_addr.sin_family = AF_INET;
    local_addr.sin_addr = local_iface.ip_addr;
    local_addr.sin_port = 0;

    remote_addr.sin_family = AF_INET;
    remote_addr.sin_addr = remote_iface.ip_addr;
    remote_addr.sin_port = sk->remote_listener_port;

    int rc = bind(osfd, (struct sockaddr *)&local_addr,
		  sizeof(local_addr));
    if (rc < 0) {
	perror("bind");
	dbgprintf("Failed to bind osfd %d to %s:%d\n",
		  osfd, inet_ntoa(local_addr.sin_addr),
		  ntohs(local_addr.sin_port));
	return rc;
    }
    dbgprintf("Successfully bound osfd %d to %s:%d\n",
	      osfd, inet_ntoa(local_addr.sin_addr),
	      ntohs(local_addr.sin_port));

    rc = connect(osfd, (struct sockaddr *)&remote_addr,
		 sizeof(remote_addr));
    if (rc < 0) {
	perror("connect");
	dbgprintf("Failed to connect osfd %d to %s:%d\n",
		  osfd, inet_ntoa(remote_addr.sin_addr),
		  ntohs(remote_addr.sin_port));
	return rc;
    }

    startup_workers();
    return 0;
}

void
CSocket::startup_workers()
{
    if (!csock_sendr && !csock_recvr) {
	csock_sendr = new CSocketSender(this);
	csock_recvr = new CSocketReceiver(this);
	csock_sendr->start();
	csock_recvr->start();
    }
}

void
CSocket::send(CMMSocketRequest req)
{
    csock_sendr->enqueue(req);
}

void
CSocket::remove()
{
    sk->csock_map->delete_csock(this);
}
<commit_msg>Trying out shutdown(osfd) to let CSocketReceiver thread be canceled.<commit_after>#include "cmm_socket.private.h"
#include "csocket.h"
#include "debug.h"
#include "cmm_socket_scheduler.h"
#include "cmm_socket_control.h"
#include "cmm_socket_sender.h"
#include "cmm_socket_receiver.h"
#include <netinet/in.h>
#include <arpa/inet.h>

class CSocketSender : public CMMSocketScheduler<struct CMMSocketRequest> {
  public:
    explicit CSocketSender(CSocket *csock_);
  protected:
    virtual void dispatch(struct CMMSocketRequest);
    virtual void Finish();
  private:
    CSocket *csock;

    void send_request(struct CMMSocketRequest req);
    void do_begin_irob(struct CMMSocketRequest req);
    void do_end_irob(struct CMMSocketRequest req);
    void do_irob_chunk(struct CMMSocketRequest req);

    void send_header(struct CMMSocketControlHdr hdr);
};

void
CSocketSender::dispatch(struct CMMSocketRequest req)
{
    dbgprintf("Sending request\n%s\n", req.describe().c_str());
    CMMSocketScheduler<struct CMMSocketRequest>::dispatch(req);
}

class CSocketReceiver : public CMMSocketScheduler<struct CMMSocketControlHdr> {
  public:
    explicit CSocketReceiver(CSocket *csock_);
    void stop();
  protected:
    virtual void Run();
    virtual void Finish();
  private:
    CSocket *csock;

    void pass_header(struct CMMSocketControlHdr hdr);
    void do_begin_irob(struct CMMSocketControlHdr hdr);
    void do_irob_chunk(struct CMMSocketControlHdr hdr);
};

CSocketSender::CSocketSender(CSocket *csock_)
    : csock(csock_)
{
    handle(CMM_CONTROL_MSG_BEGIN_IROB, this, &CSocketSender::do_begin_irob);
    handle(CMM_CONTROL_MSG_END_IROB, this, &CSocketSender::send_request);
    handle(CMM_CONTROL_MSG_IROB_CHUNK, this, &CSocketSender::do_irob_chunk);
    handle(CMM_CONTROL_MSG_NEW_INTERFACE, this, &CSocketSender::send_request);
    handle(CMM_CONTROL_MSG_DOWN_INTERFACE, this, &CSocketSender::send_request);
    handle(CMM_CONTROL_MSG_ACK, this, &CSocketSender::send_request);
    handle(CMM_CONTROL_MSG_GOODBYE, this, &CSocketSender::send_request);
}

void
CSocketSender::Finish(void)
{
    csock->remove();
}

void CSocketSender::send_header(struct CMMSocketControlHdr hdr)
{
    int rc = send(csock->osfd, &hdr, sizeof(hdr), 0);
    if (rc != sizeof(hdr)) {
	throw Exception::make("Socket error", hdr);
    }
}

void
CSocketSender::send_request(struct CMMSocketRequest req)
{
    struct CMMSocketControlHdr& hdr = req.hdr;
    try {
	send_header(hdr);
    } catch (std::runtime_error& e) {
        /* give this request back to the send scheduler */
        csock->sendr->enqueue(req);
        throw;
    }

    csock->sendr->signal_completion(req.requester_tid, 0);
}

void
CSocketSender::do_begin_irob(struct CMMSocketRequest req)
{
    struct CMMSocketControlHdr& hdr = req.hdr;
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_BEGIN_IROB);
    irob_id_t *deps = hdr.op.begin_irob.deps;
    hdr.op.begin_irob.deps = NULL;

    try {
	int numdeps = ntohl(hdr.op.begin_irob.numdeps);
	if (numdeps > 0) {
	    assert(deps);
	    int datalen = numdeps * sizeof(irob_id_t);
	    send_header(hdr);
	    int rc = send(csock->osfd, deps, datalen, 0);
	    if (rc != datalen) {
		throw Exception::make("Socket error", req);
	    }
	    /* this buffer is no longer needed, so delete it */
	    delete [] deps;
	} else {
	    send_header(hdr);
	}
    } catch (std::runtime_error& e) {
	hdr.op.begin_irob.deps = deps;
	csock->sendr->enqueue(req);
	throw;
    }
    csock->sendr->signal_completion(req.requester_tid, 0);
}

void
CSocketSender::do_irob_chunk(struct CMMSocketRequest req)
{
    struct CMMSocketControlHdr& hdr = req.hdr;
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_IROB_CHUNK);
    int datalen = ntohl(hdr.op.irob_chunk.datalen);
    if (datalen <= 0) {
        throw Exception::make("Expected data with header, got none", hdr);
    }

    char *buf = hdr.op.irob_chunk.data;
    hdr.op.irob_chunk.data = NULL;

    try {
	send_header(hdr);
	int rc = send(csock->osfd, buf, datalen, 0);
	if (rc != datalen) {
	    throw Exception::make("Socket error", req);
	}
    } catch (std::runtime_error& e) {
	hdr.op.irob_chunk.data = buf;
	csock->sendr->enqueue(req);
	throw;
    }
    /* notice that we don't delete the data buffer here,
     * since it is an un-ACK'd part of an IROB.
     * It will be cleaned up later when the ACK is received. */

    csock->sendr->signal_completion(req.requester_tid, datalen);
}

CSocketReceiver::CSocketReceiver(CSocket *csock_)
    : csock(csock_)
{
    handle(CMM_CONTROL_MSG_BEGIN_IROB, this, &CSocketReceiver::do_begin_irob);
    handle(CMM_CONTROL_MSG_END_IROB, this, &CSocketReceiver::pass_header);
    handle(CMM_CONTROL_MSG_IROB_CHUNK, this, &CSocketReceiver::do_irob_chunk);
    handle(CMM_CONTROL_MSG_NEW_INTERFACE, this, &CSocketReceiver::pass_header);
    handle(CMM_CONTROL_MSG_DOWN_INTERFACE, this,
           &CSocketReceiver::pass_header);
    handle(CMM_CONTROL_MSG_ACK, this, &CSocketReceiver::pass_header);
    handle(CMM_CONTROL_MSG_GOODBYE, this, &CSocketReceiver::pass_header);
}

void
CSocketReceiver::Run(void)
{
    while (1) {
        struct CMMSocketControlHdr hdr;

        fd_set readfds;
        FD_ZERO(&readfds);
        FD_SET(csock->osfd, &readfds);
        int rc = select(csock->osfd + 1, &readfds, NULL, NULL, NULL);
        if (rc < 0) {
            if (errno == EINTR) {
                continue;
            } else {
                return;
            }
        }
        rc = recv(csock->osfd, &hdr, sizeof(hdr), 0);
        if (rc != sizeof(hdr)) {
            return;
        }

        dispatch(hdr);
    }
}

void
CSocketReceiver::stop(void)
{
    CMMThread::stop();
}

void
CSocketReceiver::Finish(void)
{
    /* Whether CSocketSender or CSocketReceiver gets here
     * first, the result should be correct.
     * Everything should only get deleted once, and the
     * thread-stopping functions are idempotent. */
    csock->remove();
}

void CSocketReceiver::pass_header(struct CMMSocketControlHdr hdr)
{
    csock->recvr->enqueue(hdr);
}

void CSocketReceiver::do_begin_irob(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_BEGIN_IROB);
    int numdeps = ntohl(hdr.op.begin_irob.numdeps);
    if (numdeps > 0) {
        irob_id_t *deps = new irob_id_t[numdeps];
        int datalen = numdeps * sizeof(irob_id_t);
        int rc = recv(csock->osfd, (char*)deps, datalen, 0);
        if (rc != datalen) {
            if (rc < 0) {
                dbgprintf("Error %d on socket %d\n", errno, csock->osfd);
            } else {
                dbgprintf("Expected %d bytes after header, received %d\n",
                          datalen, rc);
            }
            delete [] deps;
            throw Exception::make("Socket error", hdr);
        }
        hdr.op.begin_irob.deps = deps;
    }

    pass_header(hdr);
}

void CSocketReceiver::do_irob_chunk(struct CMMSocketControlHdr hdr)
{
    assert(ntohs(hdr.type) == CMM_CONTROL_MSG_IROB_CHUNK);
    int datalen = ntohl(hdr.op.irob_chunk.datalen);
    if (datalen <= 0) {
        throw Exception::make("Expected data with header, got none", hdr);
    }

    char *buf = new char[datalen];
    int rc = recv(csock->osfd, buf, datalen, 0);
    if (rc != datalen) {
        if (rc < 0) {
            dbgprintf("Error %d on socket %d\n", errno, csock->osfd);
        } else {
            dbgprintf("Expected %d bytes after header, received %d\n",
                      datalen, rc);
        }
        delete [] buf;
        throw Exception::make("Socket error", hdr);
    }
    dbgprintf("Successfully got %d data bytes\n", datalen);

    hdr.op.irob_chunk.data = buf;
    pass_header(hdr);
}

CSocket::CSocket(CMMSocketImpl *sk_,
                 CMMSocketSender *sendr_,
                 CMMSocketReceiver *recvr_,
                 struct net_interface local_iface_,
                 struct net_interface remote_iface_,
                 int accepted_sock)
    : sk(sk_), sendr(sendr_), recvr(recvr_),
      local_iface(local_iface_), remote_iface(remote_iface_),
      csock_sendr(NULL), csock_recvr(NULL)
{
    assert(sk && sendr && recvr);
    if (accepted_sock == -1) {
        osfd = socket(sk->sock_family, sk->sock_type, sk->sock_protocol);
        if (osfd < 0) {
            /* out of file descriptors or memory at this point */
            throw std::runtime_error("Out of FDs or memory!");
        }

        sk->set_all_sockopts(osfd);
    } else {
        osfd = accepted_sock;
	startup_workers();
    }
}

CSocket::~CSocket()
{
    if (osfd > 0) {
	shutdown(osfd, SHUT_RDWR);
    }

    if (csock_sendr) {
	csock_sendr->stop();
    }
    if (csock_recvr) {
	csock_recvr->stop();
    }
    delete csock_sendr;
    delete csock_recvr;

    if (osfd > 0) {
	/* if it's a real open socket */
	close(osfd);
    }
}

int
CSocket::phys_connect()
{
    struct sockaddr_in local_addr, remote_addr;

    local_addr.sin_family = AF_INET;
    local_addr.sin_addr = local_iface.ip_addr;
    local_addr.sin_port = 0;

    remote_addr.sin_family = AF_INET;
    remote_addr.sin_addr = remote_iface.ip_addr;
    remote_addr.sin_port = sk->remote_listener_port;

    int rc = bind(osfd, (struct sockaddr *)&local_addr,
		  sizeof(local_addr));
    if (rc < 0) {
	perror("bind");
	dbgprintf("Failed to bind osfd %d to %s:%d\n",
		  osfd, inet_ntoa(local_addr.sin_addr),
		  ntohs(local_addr.sin_port));
	return rc;
    }
    dbgprintf("Successfully bound osfd %d to %s:%d\n",
	      osfd, inet_ntoa(local_addr.sin_addr),
	      ntohs(local_addr.sin_port));

    rc = connect(osfd, (struct sockaddr *)&remote_addr,
		 sizeof(remote_addr));
    if (rc < 0) {
	perror("connect");
	dbgprintf("Failed to connect osfd %d to %s:%d\n",
		  osfd, inet_ntoa(remote_addr.sin_addr),
		  ntohs(remote_addr.sin_port));
	return rc;
    }

    startup_workers();
    return 0;
}

void
CSocket::startup_workers()
{
    if (!csock_sendr && !csock_recvr) {
	csock_sendr = new CSocketSender(this);
	csock_recvr = new CSocketReceiver(this);
	csock_sendr->start();
	csock_recvr->start();
    }
}

void
CSocket::send(CMMSocketRequest req)
{
    csock_sendr->enqueue(req);
}

void
CSocket::remove()
{
    sk->csock_map->delete_csock(this);
}
<|endoftext|>


<commit_before>#include "Population.hh"

Population::Population(Problem *problem) :
        _winner(NULL),
        _problem(problem),
        selections({
            {"fitness-proportional", &Population::fitnessProportionateSelection},
            {"tournament", &Population::tournamentSelection}})
{
    generate();
}

bool Population::solve() {
    unsigned int generation;
    Chromosome *solution = NULL;
    for (generation = 0; generation < config.simulationNumber; ++generation)
    {
        if ((solution = test()) != NULL)
            break;
        reproduce();
    }
    if (solution)
    {
        std::cout << "Solution found in " << generation + 1 << " generation(s)" << std::endl;
        _problem->print(solution->getStrand());
        return true;
    }
    std::cout <<  "Solution not found" << std::endl;
    print();
    return false;
}

void Population::generate()
{
    _problem->askParameters();
    for (unsigned int i = 0; i < config.populationSize; i++)
        _population.push_back(new Chromosome());
}

Chromosome *Population::test()
{
    double fitness;
    _totalFitness = 0;
    for (auto &candidate : _population)
    {
        if (_problem->test(candidate->getStrand()))
            return candidate;
        fitness = _problem->computeFitnessOf(candidate->getStrand());
        candidate->setFitness(fitness);
        //compute total fitness in case of fitness proportional selection
        _totalFitness += fitness;
    }
    return NULL;
}

void Population::print() const
{
    for (auto &candidate : _population)
        _problem->print(candidate->getStrand());
}

Chromosome *Population::selectChromosome() const
{
    return (this->*selections.at(config.selectionType))();
}

void Population::sortByFitness() {
    std::sort(_population.begin(), _population.end(), Chromosome());
}

void Population::reproduce()
{
  Generation nextGeneration;
  Chromosome *c1, *c2;
  Chromosome::Children children;
  if (config.useElitism == true) {
      sortByFitness();
      for (unsigned int i = 0; i < config.eliteNumber && i < _population.size(); i++)
          nextGeneration.push_back(new Chromosome(_population.at(i)->getStrand()));
  }
  do
  {
    c1 = selectChromosome();
    c2 = selectChromosome();
    if ((double)rand() / RAND_MAX <= config.crossoverRate)
        children = Chromosome::crossover(config.crossoverType, c1, c2);
    else {
	children.first = new Chromosome(c1->getStrand());
	children.second = new Chromosome(c2->getStrand());
    }
    children.first->mutate();
    children.second->mutate();
    nextGeneration.push_back(children.first);
    nextGeneration.push_back(children.second);
  } while (nextGeneration.size() < config.populationSize);
  clean();
  _population = nextGeneration;
}

void Population::clean()
{
    for (Chromosome *p : _population)
        delete p;
}

Population::~Population()
{
  clean();
}

/**
 ** Selections
 */

Chromosome *Population::fitnessProportionateSelection() const
{
    double randomNb = std::fmod(std::rand(), _totalFitness);
    double curFitness = 0;
    for (auto &candidate : _population)
    {
        curFitness += candidate->getFitness();
        if (curFitness >= randomNb)
            return candidate;
    }
    // never happens, just here for the compiler
    return NULL;
}

Chromosome *Population::tournamentSelection() const
{
    const int ts = 5;
    std::vector<int> subPop;
    int id;
    double tmpFitness;
    do {
        do {
            id = rand() % _population.size();
        } while (std::find(subPop.begin(), subPop.end(), id) != subPop.end());
        subPop.push_back(id);
    } while (subPop.size() != ts);
    double f = 0;
    for (auto i : subPop)
    {
        tmpFitness = _population.at(i)->getFitness();
        if (tmpFitness > f)
        {
            f = tmpFitness;
            id = i;
        }
    }
    return _population[id];
}
<commit_msg>change the way the population is tested<commit_after>#include "Population.hh"

Population::Population(Problem *problem) :
        _winner(NULL),
        _problem(problem),
        selections({
            {"fitness-proportional", &Population::fitnessProportionateSelection},
            {"tournament", &Population::tournamentSelection}})
{
    generate();
}

bool Population::solve() {
    unsigned int generation;
    Chromosome *solution = NULL;
    for (generation = 0; generation < config.simulationNumber; ++generation)
    {
        if ((solution = test()) != NULL)
            break;
        reproduce();
    }
    if (solution)
    {
        std::cout << "Solution found in " << generation + 1 << " generation(s)" << std::endl;
        _problem->print(solution->getStrand());
        return true;
    }
    std::cout <<  "Solution not found" << std::endl;
    print();
    return false;
}

void Population::generate()
{
    _problem->askParameters();
    for (unsigned int i = 0; i < config.populationSize; i++)
        _population.push_back(new Chromosome());
}

Chromosome *Population::test()
{
    double fitness;
    _totalFitness = 0;
    // compute fitness of all chromosome
    for (auto &candidate : _population) {
        fitness = _problem->computeFitnessOf(candidate->getStrand());
        candidate->setFitness(fitness);
        _totalFitness += fitness;
    }
    // sort them by fitness
    sortByFitness();
    // test if the best candidate solution solves the problem
    if (_problem->test(_population.front()->getStrand()))
        return _population.front();
    return NULL;
}

void Population::print() const
{
    for (auto &candidate : _population)
        _problem->print(candidate->getStrand());
}

Chromosome *Population::selectChromosome() const
{
    return (this->*selections.at(config.selectionType))();
}

void Population::sortByFitness() {
    std::sort(_population.begin(), _population.end(), Chromosome());
}

void Population::reproduce()
{
  Generation nextGeneration;
  Chromosome *c1, *c2;
  Chromosome::Children children;
  if (config.useElitism == true) {
      for (unsigned int i = 0; i < config.eliteNumber && i < _population.size(); i++)
          nextGeneration.push_back(new Chromosome(_population.at(i)->getStrand()));
  }
  do
  {
    c1 = selectChromosome();
    c2 = selectChromosome();
    if ((double)rand() / RAND_MAX <= config.crossoverRate)
        children = Chromosome::crossover(config.crossoverType, c1, c2);
    else {
	children.first = new Chromosome(c1->getStrand());
	children.second = new Chromosome(c2->getStrand());
    }
    children.first->mutate();
    children.second->mutate();
    nextGeneration.push_back(children.first);
    nextGeneration.push_back(children.second);
  } while (nextGeneration.size() < config.populationSize);
  clean();
  _population = nextGeneration;
}

void Population::clean()
{
    for (Chromosome *p : _population)
        delete p;
}

Population::~Population()
{
  clean();
}

/**
 ** Selections
 */

Chromosome *Population::fitnessProportionateSelection() const
{
    double randomNb = std::fmod(std::rand(), _totalFitness);
    double curFitness = 0;
    for (auto &candidate : _population)
    {
        curFitness += candidate->getFitness();
        if (curFitness >= randomNb)
            return candidate;
    }
    // never happens, just here for the compiler
    return NULL;
}

Chromosome *Population::tournamentSelection() const
{
    const int ts = 5;
    std::vector<int> subPop;
    int id;
    double tmpFitness;
    do {
        do {
            id = rand() % _population.size();
        } while (std::find(subPop.begin(), subPop.end(), id) != subPop.end());
        subPop.push_back(id);
    } while (subPop.size() != ts);
    double f = 0;
    for (auto i : subPop)
    {
        tmpFitness = _population.at(i)->getFitness();
        if (tmpFitness > f)
        {
            f = tmpFitness;
            id = i;
        }
    }
    return _population[id];
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 David Edmundson <kde@davidedmundson.co.uk>
 *
 * This library 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.1 of the License, or (at your option) 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "text-channel-watcher-proxy-model.h"

#include <TelepathyQt/TextChannel>
#include <TelepathyQt/ChannelClassSpecList>
#include <TelepathyQt/MethodInvocationContext>
#include <TelepathyQt/Types>
#include <TelepathyQt/ReceivedMessage>

#include <KTp/types.h>
#include <KTp/contact.h>
#include <KTp/message.h>

inline Tp::ChannelClassSpecList channelClasses() {
    return Tp::ChannelClassSpecList() << Tp::ChannelClassSpec::textChat();
}

class ChannelWatcher : public QObject, public Tp::RefCounted
{
    Q_OBJECT
public:
    ChannelWatcher(const QPersistentModelIndex &index, const Tp::TextChannelPtr &channel, QObject *parent=0);
    int unreadMessageCount() const;
    QString lastMessage() const;
    KTp::Message::MessageDirection lastMessageDirection() const;
    QPersistentModelIndex modelIndex() const;
Q_SIGNALS:
    void messagesChanged();
    void invalidated();
private Q_SLOTS:
    void onMessageReceived(const Tp::ReceivedMessage &message);
    void onMessageSent(const Tp::Message &message);
private:
    QPersistentModelIndex m_index;
    Tp::TextChannelPtr m_channel;
    QString m_lastMessage;
    KTp::Message::MessageDirection m_lastMessageDirection;
};

typedef Tp::SharedPtr<ChannelWatcher> ChannelWatcherPtr;

ChannelWatcher::ChannelWatcher(const QPersistentModelIndex &index, const Tp::TextChannelPtr &channel, QObject *parent):
    QObject(parent),
    m_index(index),
    m_channel(channel),
    m_lastMessageDirection(KTp::Message::LocalToRemote)
{
    connect(channel.data(), SIGNAL(pendingMessageRemoved(Tp::ReceivedMessage)), SIGNAL(messagesChanged()));
    connect(channel.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SIGNAL(invalidated()));

    connect(channel.data(), SIGNAL(messageReceived(Tp::ReceivedMessage)), SLOT(onMessageReceived(Tp::ReceivedMessage)));
    connect(channel.data(), SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)), SLOT(onMessageSent(Tp::Message)));

    //trigger an update to the contact straight away
    QTimer::singleShot(0, this, SIGNAL(messagesChanged()));
}

QPersistentModelIndex ChannelWatcher::modelIndex() const
{
    return m_index;
}

int ChannelWatcher::unreadMessageCount() const
{
    return m_channel->messageQueue().size();
}

QString ChannelWatcher::lastMessage() const
{
    return m_lastMessage;
}

KTp::Message::MessageDirection ChannelWatcher::lastMessageDirection() const
{
    return m_lastMessageDirection;
}

void ChannelWatcher::onMessageReceived(const Tp::ReceivedMessage &message)
{
    if (!message.isDeliveryReport()) {
        m_lastMessage = message.text();
        m_lastMessageDirection = KTp::Message::RemoteToLocal;
        Q_EMIT messagesChanged();
    }
}

void ChannelWatcher::onMessageSent(const Tp::Message &message)
{
    m_lastMessage = message.text();
    m_lastMessageDirection = KTp::Message::LocalToRemote;
    Q_EMIT messagesChanged();
}

namespace KTp {

class TextChannelWatcherProxyModel::Private {
public:
    QHash<KTp::ContactPtr, ChannelWatcherPtr> currentChannels;
};

} //namespace

KTp::TextChannelWatcherProxyModel::TextChannelWatcherProxyModel(QObject *parent) :
    QIdentityProxyModel(parent),
    Tp::AbstractClientObserver(channelClasses(), true),
    d(new TextChannelWatcherProxyModel::Private)
{
}

KTp::TextChannelWatcherProxyModel::~TextChannelWatcherProxyModel()
{
    delete d;
}

void KTp::TextChannelWatcherProxyModel::observeChannels(const Tp::MethodInvocationContextPtr<> &context, const Tp::AccountPtr &account, const Tp::ConnectionPtr &connection, const QList<Tp::ChannelPtr> &channels, const Tp::ChannelDispatchOperationPtr &dispatchOperation, const QList<Tp::ChannelRequestPtr> &requestsSatisfied, const Tp::AbstractClientObserver::ObserverInfo &observerInfo)
{
    Q_UNUSED(context)
    Q_UNUSED(account)
    Q_UNUSED(connection)
    Q_UNUSED(dispatchOperation)
    Q_UNUSED(requestsSatisfied)
    Q_UNUSED(observerInfo)

    if (!sourceModel()) {
        return;
    }

    Q_FOREACH(const Tp::ChannelPtr & channel, channels) {
        Tp::TextChannelPtr textChannel = Tp::TextChannelPtr::dynamicCast(channel);
        if (textChannel) {
            KTp::ContactPtr targetContact = KTp::ContactPtr::qObjectCast(textChannel->targetContact());

            //skip group chats and situations where we don't have a single contact to mark messages for
            if (targetContact.isNull()) {
                continue;
            }

            //if it's not in our source model, ignore the channel
            QModelIndexList matchedContacts = sourceModel()->match(QModelIndex(sourceModel()->index(0,0)), KTp::ContactRole, QVariant::fromValue(targetContact));
            if (matchedContacts.size() !=1) {
                continue;
            }

            QPersistentModelIndex contactIndex(matchedContacts[0]);

            ChannelWatcherPtr watcher = ChannelWatcherPtr(new ChannelWatcher(contactIndex, textChannel));
            d->currentChannels[targetContact] = watcher;

            connect(watcher.data(), SIGNAL(messagesChanged()), SLOT(onChannelMessagesChanged()));
        }
    }
}

QVariant KTp::TextChannelWatcherProxyModel::data(const QModelIndex &proxyIndex, int role) const
{
    const QModelIndex sourceIndex = mapToSource(proxyIndex);
    if (role == KTp::ContactHasTextChannelRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return true;
            }
        }
        return false;
    }

    if (role == KTp::ContactUnreadMessageCountRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return d->currentChannels[contact]->unreadMessageCount();
            }
        }
        return 0;
    }
    if (role == KTp::ContactLastMessageRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return d->currentChannels[contact]->lastMessage();
            }
        }
        return QString();
    }
    if (role == KTp::ContactLastMessageDirectionRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return d->currentChannels[contact]->lastMessageDirection();
            }
        }
        return KTp::Message::LocalToRemote;
    }

    return sourceIndex.data(role);
}

void KTp::TextChannelWatcherProxyModel::onChannelMessagesChanged()
{
    ChannelWatcher* watcher = qobject_cast<ChannelWatcher*>(sender());
    Q_ASSERT(watcher);
    QModelIndex index = watcher->modelIndex();
    dataChanged(index, index);
}

void KTp::TextChannelWatcherProxyModel::onChannelInvalidated()
{
    ChannelWatcher* watcher = qobject_cast<ChannelWatcher*>(sender());
    Q_ASSERT(watcher);
    QModelIndex index = watcher->modelIndex();
    KTp::ContactPtr contact = index.data(KTp::ContactRole).value<KTp::ContactPtr>();

    d->currentChannels.remove(contact);
    dataChanged(index, index);
}

#include "text-channel-watcher-proxy-model.moc"
#include "moc_text-channel-watcher-proxy-model.cpp"
<commit_msg>Fix crash caused by TextChannelWatcherProxyModel<commit_after>/*
 * Copyright (C) 2013 David Edmundson <kde@davidedmundson.co.uk>
 *
 * This library 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.1 of the License, or (at your option) 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "text-channel-watcher-proxy-model.h"

#include <TelepathyQt/TextChannel>
#include <TelepathyQt/ChannelClassSpecList>
#include <TelepathyQt/MethodInvocationContext>
#include <TelepathyQt/Types>
#include <TelepathyQt/ReceivedMessage>

#include <KTp/types.h>
#include <KTp/contact.h>
#include <KTp/message.h>

inline Tp::ChannelClassSpecList channelClasses() {
    return Tp::ChannelClassSpecList() << Tp::ChannelClassSpec::textChat();
}

class ChannelWatcher : public QObject, public Tp::RefCounted
{
    Q_OBJECT
public:
    ChannelWatcher(const QPersistentModelIndex &index, const Tp::TextChannelPtr &channel, QObject *parent=0);
    int unreadMessageCount() const;
    QString lastMessage() const;
    KTp::Message::MessageDirection lastMessageDirection() const;
    QPersistentModelIndex modelIndex() const;
Q_SIGNALS:
    void messagesChanged();
    void invalidated();
private Q_SLOTS:
    void onMessageReceived(const Tp::ReceivedMessage &message);
    void onMessageSent(const Tp::Message &message);
private:
    QPersistentModelIndex m_index;
    Tp::TextChannelPtr m_channel;
    QString m_lastMessage;
    KTp::Message::MessageDirection m_lastMessageDirection;
};

typedef Tp::SharedPtr<ChannelWatcher> ChannelWatcherPtr;

ChannelWatcher::ChannelWatcher(const QPersistentModelIndex &index, const Tp::TextChannelPtr &channel, QObject *parent):
    QObject(parent),
    m_index(index),
    m_channel(channel),
    m_lastMessageDirection(KTp::Message::LocalToRemote)
{
    connect(channel.data(), SIGNAL(pendingMessageRemoved(Tp::ReceivedMessage)), SIGNAL(messagesChanged()));
    connect(channel.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)), SIGNAL(invalidated()));

    connect(channel.data(), SIGNAL(messageReceived(Tp::ReceivedMessage)), SLOT(onMessageReceived(Tp::ReceivedMessage)));
    connect(channel.data(), SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)), SLOT(onMessageSent(Tp::Message)));

    //trigger an update to the contact straight away
    QTimer::singleShot(0, this, SIGNAL(messagesChanged()));
}

QPersistentModelIndex ChannelWatcher::modelIndex() const
{
    return m_index;
}

int ChannelWatcher::unreadMessageCount() const
{
    return m_channel->messageQueue().size();
}

QString ChannelWatcher::lastMessage() const
{
    return m_lastMessage;
}

KTp::Message::MessageDirection ChannelWatcher::lastMessageDirection() const
{
    return m_lastMessageDirection;
}

void ChannelWatcher::onMessageReceived(const Tp::ReceivedMessage &message)
{
    if (!message.isDeliveryReport()) {
        m_lastMessage = message.text();
        m_lastMessageDirection = KTp::Message::RemoteToLocal;
        Q_EMIT messagesChanged();
    }
}

void ChannelWatcher::onMessageSent(const Tp::Message &message)
{
    m_lastMessage = message.text();
    m_lastMessageDirection = KTp::Message::LocalToRemote;
    Q_EMIT messagesChanged();
}

namespace KTp {

class TextChannelWatcherProxyModel::Private {
public:
    QHash<KTp::ContactPtr, ChannelWatcherPtr> currentChannels;
};

} //namespace

KTp::TextChannelWatcherProxyModel::TextChannelWatcherProxyModel(QObject *parent) :
    QIdentityProxyModel(parent),
    Tp::AbstractClientObserver(channelClasses(), true),
    d(new TextChannelWatcherProxyModel::Private)
{
}

KTp::TextChannelWatcherProxyModel::~TextChannelWatcherProxyModel()
{
    delete d;
}

void KTp::TextChannelWatcherProxyModel::observeChannels(const Tp::MethodInvocationContextPtr<> &context, const Tp::AccountPtr &account, const Tp::ConnectionPtr &connection, const QList<Tp::ChannelPtr> &channels, const Tp::ChannelDispatchOperationPtr &dispatchOperation, const QList<Tp::ChannelRequestPtr> &requestsSatisfied, const Tp::AbstractClientObserver::ObserverInfo &observerInfo)
{
    Q_UNUSED(context)
    Q_UNUSED(account)
    Q_UNUSED(connection)
    Q_UNUSED(dispatchOperation)
    Q_UNUSED(requestsSatisfied)
    Q_UNUSED(observerInfo)

    if (!sourceModel()) {
        return;
    }

    Q_FOREACH(const Tp::ChannelPtr & channel, channels) {
        Tp::TextChannelPtr textChannel = Tp::TextChannelPtr::dynamicCast(channel);
        if (textChannel) {
            KTp::ContactPtr targetContact = KTp::ContactPtr::qObjectCast(textChannel->targetContact());

            //skip group chats and situations where we don't have a single contact to mark messages for
            if (targetContact.isNull()) {
                continue;
            }

            //if it's not in our source model, ignore the channel
            QModelIndexList matchedContacts = sourceModel()->match(QModelIndex(sourceModel()->index(0,0)), KTp::ContactRole, QVariant::fromValue(targetContact));
            if (matchedContacts.size() !=1) {
                continue;
            }

            QPersistentModelIndex contactIndex(matchedContacts[0]);

            ChannelWatcherPtr watcher = ChannelWatcherPtr(new ChannelWatcher(contactIndex, textChannel));
            d->currentChannels[targetContact] = watcher;

            connect(watcher.data(), SIGNAL(messagesChanged()), SLOT(onChannelMessagesChanged()));
        }
    }
}

QVariant KTp::TextChannelWatcherProxyModel::data(const QModelIndex &proxyIndex, int role) const
{
    const QModelIndex sourceIndex = mapToSource(proxyIndex);
    if (role == KTp::ContactHasTextChannelRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return true;
            }
        }
        return false;
    }

    if (role == KTp::ContactUnreadMessageCountRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return d->currentChannels[contact]->unreadMessageCount();
            }
        }
        return 0;
    }
    if (role == KTp::ContactLastMessageRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return d->currentChannels[contact]->lastMessage();
            }
        }
        return QString();
    }
    if (role == KTp::ContactLastMessageDirectionRole) {
        KTp::ContactPtr contact = sourceIndex.data(KTp::ContactRole).value<KTp::ContactPtr>();
        if (contact) {
            if (d->currentChannels.contains(contact)) {
                return d->currentChannels[contact]->lastMessageDirection();
            }
        }
        return KTp::Message::LocalToRemote;
    }

    return sourceIndex.data(role);
}

void KTp::TextChannelWatcherProxyModel::onChannelMessagesChanged()
{
    ChannelWatcher* watcher = qobject_cast<ChannelWatcher*>(sender());
    Q_ASSERT(watcher);
    const QModelIndex &index = mapFromSource(watcher->modelIndex());
    dataChanged(index, index);
}

void KTp::TextChannelWatcherProxyModel::onChannelInvalidated()
{
    ChannelWatcher* watcher = qobject_cast<ChannelWatcher*>(sender());
    Q_ASSERT(watcher);
    const QModelIndex &index = mapFromSource(watcher->modelIndex());
    const KTp::ContactPtr &contact = index.data(KTp::ContactRole).value<KTp::ContactPtr>();

    d->currentChannels.remove(contact);
    dataChanged(index, index);
}

#include "text-channel-watcher-proxy-model.moc"
#include "moc_text-channel-watcher-proxy-model.cpp"
<|endoftext|>


<commit_before>// Copyright (c) 2020 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

/// major todo: the function_ref.hpp has some persistency problem
/// storing a free function pointer and calling it later will not work properly
/// in some cases it seems
/// further investigation is needed whether this can be repaired
/// use this alternative for the time being
/// expectation: a function_ref is valid as long as the referenced
/// function exists (e.g. whole program runtime for a free function)

#include <type_traits>
#include <utility>

namespace iox
{
namespace cxx
{
template <typename ReturnType, typename... Args>
using signature = ReturnType(Args...);

template <typename T>
class function_ref;

template <typename ReturnType, typename... Args>
class function_ref<signature<ReturnType, Args...>>
{
    using obj_t = void*;
    using func_t = ReturnType (*)(Args...);
    using invocation_t = ReturnType (*)(func_t, obj_t, Args...);

  public:
    function_ref() = default;

    // from functor (includes lambda)
    template <typename Functor,
              typename = typename std::enable_if<std::is_class<Functor>::value
                                                 /*&& std::is_invocable_r<ReturnType, Functor, Args...>::value*/,
                                                 void>::type>
    function_ref(const Functor& functor)
    {
        assign((obj_t)&functor, functor_call<Functor>);
    }

    // from function pointer
    function_ref(ReturnType (*function)(Args...))
    {
        // note: we cannot cast function to void safely, we need to keep it as a function pointer
        assign(function, function_call);
    }

    template <typename T>
    function_ref(T& object, ReturnType (T::*method)(Args...))
    {
        // assign(object, method);
    }

    // from method, not possible with ctor (it seems, needs further research)
    template <typename T, ReturnType (T::*Func)(Args...)>
    static function_ref create(T& obj)
    {
        return function_ref((obj_t)&obj, method_call<T, Func>);
    }

    template <typename T, ReturnType (T::*Func)(Args...) const>
    static function_ref create(T& obj)
    {
        return function_ref((obj_t)&obj, const_method_call<T, Func>);
    }

    template <ReturnType (*Func)(Args...)>
    static function_ref create()
    {
        return function_ref(function_call_template<Func>);
    }

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

    ReturnType operator()(Args... args)
    {
        return (*m_invocation)(m_func, m_obj, std::forward<Args>(args)...);
    }

    operator bool()
    {
        return m_invocation != nullptr;
    }

    // note: equal operator makes not much sense in general if a callable is stored so we do not provide one

  private:
    // note: we cannot cast between void* and function pointers or member function pointers in a safe way...
    // therefore we need an erased type for function pointers (func_t) and for callable objects (obj_t)
    // we furthermore construct a helper invocation that given m_func and m_obj together with user provided arguments
    // will handle the actual call of the target function the wrapper stores

    func_t m_func; // the target function (from a function pointer)
    obj_t m_obj;   // the object to call the function on or on which to call operator()
    invocation_t m_invocation{
        nullptr}; // the wrapping invocation for the current case (functor, free function or member function)

    void assign(func_t func, invocation_t invocation)
    {
        m_func = func;
        m_obj = nullptr;
        m_invocation = invocation;
    }

    void assign(obj_t obj, invocation_t invocation)
    {
        m_func = nullptr;
        m_obj = obj;
        m_invocation = invocation;
    }

    void assign(func_t func, obj_t obj, invocation_t invocation)
    {
        m_func = func;
        m_obj = obj;
        m_invocation = invocation;
    }

    void assign(invocation_t invocation)
    {
        m_func = nullptr;
        m_obj = nullptr;
        m_invocation = invocation;
    }

    function_ref(obj_t obj, invocation_t invocation)
    {
        assign(obj, invocation);
    }

    function_ref(invocation_t invocation)
    {
        assign(invocation);
    }

    template <typename Functor>
    static ReturnType functor_call(func_t, obj_t obj, Args... args)
    {
        Functor* p = reinterpret_cast<Functor*>(obj);
        return (*p)(args...);
    }

    static ReturnType function_call(func_t func, obj_t, Args... args)
    {
        return func(args...);
    }

    template <ReturnType (*Func)(Args...)>
    static ReturnType function_call_template(func_t, obj_t, Args... args)
    {
        return (Func)(args...);
    }

    template <typename T, ReturnType (T::*Func)(Args...)>
    static ReturnType method_call(func_t, obj_t obj, Args... args)
    {
        T* p = reinterpret_cast<T*>(obj);
        return (p->*Func)(args...);
    }

    template <typename T, ReturnType (T::*Func)(Args...) const>
    static ReturnType const_method_call(func_t, obj_t obj, Args... args)
    {
        const T* p = reinterpret_cast<T*>(obj);
        return (p->*Func)(args...);
    }
};

} // namespace cxx
} // namespace iox<commit_msg>iox-#391 removed function_ref alternative<commit_after><|endoftext|>


<commit_before>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "summarymanager.h"
#include "documentstoreadapter.h"
#include "summarycompacttarget.h"
#include "summaryflushtarget.h"
#include <vespa/config/print/ostreamconfigwriter.h>
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/juniper/rpinterface.h>
#include <vespa/searchcore/proton/flushengine/shrink_lid_space_flush_target.h>
#include <vespa/vespalib/util/lambdatask.h>
#include <vespa/searchsummary/docsummary/docsumconfig.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/fastlib/text/normwordfolder.h>

#include <sstream>

#include <vespa/log/log.h>
LOG_SETUP(".proton.docsummary.summarymanager");

using namespace config;
using namespace document;
using namespace search::docsummary;
using namespace vespa::config::search::summary;
using namespace vespa::config::search;
using vespalib::make_string;
using vespalib::IllegalArgumentException;
using vespalib::compression::CompressionConfig;

using search::DocumentStore;
using search::IDocumentStore;
using search::LogDocumentStore;
using search::WriteableFileChunk;
using vespalib::makeLambdaTask;

using search::TuneFileSummary;
using search::common::FileHeaderContext;
using searchcorespi::IFlushTarget;

namespace proton {

namespace {

class ShrinkSummaryLidSpaceFlushTarget : public  ShrinkLidSpaceFlushTarget
{
    using ICompactableLidSpace = search::common::ICompactableLidSpace;
    vespalib::Executor & _summaryService;

public:
    ShrinkSummaryLidSpaceFlushTarget(const vespalib::string &name, Type type, Component component,
                                     SerialNum flushedSerialNum, vespalib::system_time lastFlushTime,
                                     vespalib::Executor & summaryService,
                                     std::shared_ptr<ICompactableLidSpace> target);
    ~ShrinkSummaryLidSpaceFlushTarget() override;
    Task::UP initFlush(SerialNum currentSerial, std::shared_ptr<search::IFlushToken> flush_token) override;
};

ShrinkSummaryLidSpaceFlushTarget::
ShrinkSummaryLidSpaceFlushTarget(const vespalib::string &name, Type type, Component component,
                                 SerialNum flushedSerialNum, vespalib::system_time lastFlushTime,
                                 vespalib::Executor & summaryService,
                                 std::shared_ptr<ICompactableLidSpace> target)
    : ShrinkLidSpaceFlushTarget(name, type, component, flushedSerialNum, lastFlushTime, std::move(target)),
      _summaryService(summaryService)
{
}

ShrinkSummaryLidSpaceFlushTarget::~ShrinkSummaryLidSpaceFlushTarget() = default;

IFlushTarget::Task::UP
ShrinkSummaryLidSpaceFlushTarget::initFlush(SerialNum currentSerial, std::shared_ptr<search::IFlushToken> flush_token)
{
    std::promise<Task::UP> promise;
    std::future<Task::UP> future = promise.get_future();
    _summaryService.execute(makeLambdaTask([&]() { promise.set_value(ShrinkLidSpaceFlushTarget::initFlush(currentSerial, flush_token)); }));
    return future.get();
}

}

SummaryManager::SummarySetup::
SummarySetup(const vespalib::string & baseDir, const DocTypeName & docTypeName, const SummaryConfig & summaryCfg,
             const SummarymapConfig & summarymapCfg, const JuniperrcConfig & juniperCfg,
             search::IAttributeManager::SP attributeMgr, search::IDocumentStore::SP docStore,
             std::shared_ptr<const DocumentTypeRepo> repo)
    : _docsumWriter(),
      _wordFolder(std::make_unique<Fast_NormalizeWordFolder>()),
      _juniperProps(juniperCfg),
      _juniperConfig(),
      _attributeMgr(std::move(attributeMgr)),
      _docStore(std::move(docStore)),
      _fieldCacheRepo(),
      _repo(repo),
      _markupFields()
{
    DocsumBlobEntryFilter docsum_blob_entry_filter;
    docsum_blob_entry_filter.add_skip(RES_INT);
    docsum_blob_entry_filter.add_skip(RES_SHORT);
    docsum_blob_entry_filter.add_skip(RES_BOOL);
    docsum_blob_entry_filter.add_skip(RES_BYTE);
    docsum_blob_entry_filter.add_skip(RES_FLOAT);
    docsum_blob_entry_filter.add_skip(RES_DOUBLE);
    docsum_blob_entry_filter.add_skip(RES_INT64);
    docsum_blob_entry_filter.add_skip(RES_DATA);
    docsum_blob_entry_filter.add_skip(RES_LONG_DATA);
    docsum_blob_entry_filter.add_skip(RES_JSONSTRING);
    docsum_blob_entry_filter.add_skip(RES_TENSOR);
    docsum_blob_entry_filter.add_skip(RES_FEATUREDATA);
    auto resultConfig = std::make_unique<ResultConfig>(docsum_blob_entry_filter);
    if (!resultConfig->ReadConfig(summaryCfg, make_string("SummaryManager(%s)", baseDir.c_str()).c_str())) {
        std::ostringstream oss;
        ::config::OstreamConfigWriter writer(oss);
        writer.write(summaryCfg);
        throw IllegalArgumentException
            (make_string("Could not initialize summary result config for directory '%s' based on summary config '%s'",
                         baseDir.c_str(), oss.str().c_str()));
    }

    _juniperConfig = std::make_unique<juniper::Juniper>(&_juniperProps, _wordFolder.get());
    _docsumWriter = std::make_unique<DynamicDocsumWriter>(resultConfig.release(), nullptr);
    DynamicDocsumConfig dynCfg(this, _docsumWriter.get());
    dynCfg.configure(summarymapCfg);
    for (const auto & o : summarymapCfg.override) {
        if (o.command == "dynamicteaser" || o.command == "textextractor") {
            vespalib::string markupField = o.arguments;
            if (markupField.empty())
                continue;
            // Assume just one argument: source field that must contain markup
            _markupFields.insert(markupField);
        }
    }
    const DocumentType *docType = repo->getDocumentType(docTypeName.getName());
    if (docType != nullptr) {
        _fieldCacheRepo = std::make_unique<FieldCacheRepo>(getResultConfig(), *docType);
    } else if (getResultConfig().GetNumResultClasses() == 0) {
        LOG(debug, "Create empty field cache repo for document type '%s'", docTypeName.toString().c_str());
        _fieldCacheRepo = std::make_unique<FieldCacheRepo>();
    } else {
        throw IllegalArgumentException(make_string("Did not find document type '%s' in current document type repo."
                                                   " Cannot setup field cache repo for the summary setup",
                                                   docTypeName.toString().c_str()));
    }
}

IDocsumStore::UP
SummaryManager::SummarySetup::createDocsumStore(const vespalib::string &resultClassName) {
    return std::make_unique<DocumentStoreAdapter>(*_docStore, *_repo, getResultConfig(), resultClassName,
                                                  _fieldCacheRepo->getFieldCache(resultClassName), _markupFields);
}

ISummaryManager::ISummarySetup::SP
SummaryManager::createSummarySetup(const SummaryConfig & summaryCfg, const SummarymapConfig & summarymapCfg,
                                   const JuniperrcConfig & juniperCfg, const std::shared_ptr<const DocumentTypeRepo> &repo,
                                   const search::IAttributeManager::SP &attributeMgr)
{
    return std::make_shared<SummarySetup>(_baseDir, _docTypeName, summaryCfg, summarymapCfg,
                                          juniperCfg, attributeMgr, _docStore, repo);
}

SummaryManager::SummaryManager(vespalib::Executor &shared_executor, const LogDocumentStore::Config & storeConfig,
                               const search::GrowStrategy & growStrategy, const vespalib::string &baseDir,
                               const DocTypeName &docTypeName, const TuneFileSummary &tuneFileSummary,
                               const FileHeaderContext &fileHeaderContext, search::transactionlog::SyncProxy &tlSyncer,
                               search::IBucketizer::SP bucketizer)
    : _baseDir(baseDir),
      _docTypeName(docTypeName),
      _docStore()
{
    _docStore = std::make_shared<LogDocumentStore>(shared_executor, baseDir, storeConfig, growStrategy, tuneFileSummary,
                                                   fileHeaderContext, tlSyncer, std::move(bucketizer));
}

SummaryManager::~SummaryManager() = default;

void
SummaryManager::putDocument(uint64_t syncToken, search::DocumentIdT lid, const Document & doc)
{
    _docStore->write(syncToken, lid, doc);
}

void
SummaryManager::putDocument(uint64_t syncToken, search::DocumentIdT lid, const vespalib::nbostream & doc)
{
    _docStore->write(syncToken, lid, doc);
}

void
SummaryManager::removeDocument(uint64_t syncToken, search::DocumentIdT lid)
{
    _docStore->remove(syncToken, lid);
}

namespace {

IFlushTarget::SP
createShrinkLidSpaceFlushTarget(vespalib::Executor & summaryService, IDocumentStore::SP docStore)
{
    return std::make_shared<ShrinkSummaryLidSpaceFlushTarget>("summary.shrink",
                                                       IFlushTarget::Type::GC,
                                                       IFlushTarget::Component::DOCUMENT_STORE,
                                                       docStore->lastSyncToken(),
                                                       docStore->getLastFlushTime(),
                                                       summaryService,
                                                       std::move(docStore));
}

}

IFlushTarget::List
SummaryManager::getFlushTargets(vespalib::Executor & summaryService)
{
    IFlushTarget::List ret;
    ret.push_back(std::make_shared<SummaryFlushTarget>(getBackingStore(), summaryService));
    if (dynamic_cast<LogDocumentStore *>(_docStore.get()) != nullptr) {
        ret.push_back(std::make_shared<SummaryCompactBloatTarget>(summaryService, getBackingStore()));
        ret.push_back(std::make_shared<SummaryCompactSpreadTarget>(summaryService, getBackingStore()));
    }
    ret.push_back(createShrinkLidSpaceFlushTarget(summaryService, _docStore));
    return ret;
}

void
SummaryManager::reconfigure(const LogDocumentStore::Config & config) {
    auto & docStore = dynamic_cast<LogDocumentStore &> (*_docStore);
    docStore.reconfigure(config);
}

} // namespace proton
<commit_msg>Stop storing string values in docsum blobs for indexed search.<commit_after>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "summarymanager.h"
#include "documentstoreadapter.h"
#include "summarycompacttarget.h"
#include "summaryflushtarget.h"
#include <vespa/config/print/ostreamconfigwriter.h>
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/juniper/rpinterface.h>
#include <vespa/searchcore/proton/flushengine/shrink_lid_space_flush_target.h>
#include <vespa/vespalib/util/lambdatask.h>
#include <vespa/searchsummary/docsummary/docsumconfig.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/fastlib/text/normwordfolder.h>

#include <sstream>

#include <vespa/log/log.h>
LOG_SETUP(".proton.docsummary.summarymanager");

using namespace config;
using namespace document;
using namespace search::docsummary;
using namespace vespa::config::search::summary;
using namespace vespa::config::search;
using vespalib::make_string;
using vespalib::IllegalArgumentException;
using vespalib::compression::CompressionConfig;

using search::DocumentStore;
using search::IDocumentStore;
using search::LogDocumentStore;
using search::WriteableFileChunk;
using vespalib::makeLambdaTask;

using search::TuneFileSummary;
using search::common::FileHeaderContext;
using searchcorespi::IFlushTarget;

namespace proton {

namespace {

class ShrinkSummaryLidSpaceFlushTarget : public  ShrinkLidSpaceFlushTarget
{
    using ICompactableLidSpace = search::common::ICompactableLidSpace;
    vespalib::Executor & _summaryService;

public:
    ShrinkSummaryLidSpaceFlushTarget(const vespalib::string &name, Type type, Component component,
                                     SerialNum flushedSerialNum, vespalib::system_time lastFlushTime,
                                     vespalib::Executor & summaryService,
                                     std::shared_ptr<ICompactableLidSpace> target);
    ~ShrinkSummaryLidSpaceFlushTarget() override;
    Task::UP initFlush(SerialNum currentSerial, std::shared_ptr<search::IFlushToken> flush_token) override;
};

ShrinkSummaryLidSpaceFlushTarget::
ShrinkSummaryLidSpaceFlushTarget(const vespalib::string &name, Type type, Component component,
                                 SerialNum flushedSerialNum, vespalib::system_time lastFlushTime,
                                 vespalib::Executor & summaryService,
                                 std::shared_ptr<ICompactableLidSpace> target)
    : ShrinkLidSpaceFlushTarget(name, type, component, flushedSerialNum, lastFlushTime, std::move(target)),
      _summaryService(summaryService)
{
}

ShrinkSummaryLidSpaceFlushTarget::~ShrinkSummaryLidSpaceFlushTarget() = default;

IFlushTarget::Task::UP
ShrinkSummaryLidSpaceFlushTarget::initFlush(SerialNum currentSerial, std::shared_ptr<search::IFlushToken> flush_token)
{
    std::promise<Task::UP> promise;
    std::future<Task::UP> future = promise.get_future();
    _summaryService.execute(makeLambdaTask([&]() { promise.set_value(ShrinkLidSpaceFlushTarget::initFlush(currentSerial, flush_token)); }));
    return future.get();
}

}

SummaryManager::SummarySetup::
SummarySetup(const vespalib::string & baseDir, const DocTypeName & docTypeName, const SummaryConfig & summaryCfg,
             const SummarymapConfig & summarymapCfg, const JuniperrcConfig & juniperCfg,
             search::IAttributeManager::SP attributeMgr, search::IDocumentStore::SP docStore,
             std::shared_ptr<const DocumentTypeRepo> repo)
    : _docsumWriter(),
      _wordFolder(std::make_unique<Fast_NormalizeWordFolder>()),
      _juniperProps(juniperCfg),
      _juniperConfig(),
      _attributeMgr(std::move(attributeMgr)),
      _docStore(std::move(docStore)),
      _fieldCacheRepo(),
      _repo(repo),
      _markupFields()
{
    DocsumBlobEntryFilter docsum_blob_entry_filter;
    docsum_blob_entry_filter.add_skip(RES_INT);
    docsum_blob_entry_filter.add_skip(RES_SHORT);
    docsum_blob_entry_filter.add_skip(RES_BOOL);
    docsum_blob_entry_filter.add_skip(RES_BYTE);
    docsum_blob_entry_filter.add_skip(RES_FLOAT);
    docsum_blob_entry_filter.add_skip(RES_DOUBLE);
    docsum_blob_entry_filter.add_skip(RES_INT64);
    docsum_blob_entry_filter.add_skip(RES_STRING);
    docsum_blob_entry_filter.add_skip(RES_DATA);
    docsum_blob_entry_filter.add_skip(RES_LONG_DATA);
    docsum_blob_entry_filter.add_skip(RES_JSONSTRING);
    docsum_blob_entry_filter.add_skip(RES_TENSOR);
    docsum_blob_entry_filter.add_skip(RES_FEATUREDATA);
    auto resultConfig = std::make_unique<ResultConfig>(docsum_blob_entry_filter);
    if (!resultConfig->ReadConfig(summaryCfg, make_string("SummaryManager(%s)", baseDir.c_str()).c_str())) {
        std::ostringstream oss;
        ::config::OstreamConfigWriter writer(oss);
        writer.write(summaryCfg);
        throw IllegalArgumentException
            (make_string("Could not initialize summary result config for directory '%s' based on summary config '%s'",
                         baseDir.c_str(), oss.str().c_str()));
    }

    _juniperConfig = std::make_unique<juniper::Juniper>(&_juniperProps, _wordFolder.get());
    _docsumWriter = std::make_unique<DynamicDocsumWriter>(resultConfig.release(), nullptr);
    DynamicDocsumConfig dynCfg(this, _docsumWriter.get());
    dynCfg.configure(summarymapCfg);
    for (const auto & o : summarymapCfg.override) {
        if (o.command == "dynamicteaser" || o.command == "textextractor") {
            vespalib::string markupField = o.arguments;
            if (markupField.empty())
                continue;
            // Assume just one argument: source field that must contain markup
            _markupFields.insert(markupField);
        }
    }
    const DocumentType *docType = repo->getDocumentType(docTypeName.getName());
    if (docType != nullptr) {
        _fieldCacheRepo = std::make_unique<FieldCacheRepo>(getResultConfig(), *docType);
    } else if (getResultConfig().GetNumResultClasses() == 0) {
        LOG(debug, "Create empty field cache repo for document type '%s'", docTypeName.toString().c_str());
        _fieldCacheRepo = std::make_unique<FieldCacheRepo>();
    } else {
        throw IllegalArgumentException(make_string("Did not find document type '%s' in current document type repo."
                                                   " Cannot setup field cache repo for the summary setup",
                                                   docTypeName.toString().c_str()));
    }
}

IDocsumStore::UP
SummaryManager::SummarySetup::createDocsumStore(const vespalib::string &resultClassName) {
    return std::make_unique<DocumentStoreAdapter>(*_docStore, *_repo, getResultConfig(), resultClassName,
                                                  _fieldCacheRepo->getFieldCache(resultClassName), _markupFields);
}

ISummaryManager::ISummarySetup::SP
SummaryManager::createSummarySetup(const SummaryConfig & summaryCfg, const SummarymapConfig & summarymapCfg,
                                   const JuniperrcConfig & juniperCfg, const std::shared_ptr<const DocumentTypeRepo> &repo,
                                   const search::IAttributeManager::SP &attributeMgr)
{
    return std::make_shared<SummarySetup>(_baseDir, _docTypeName, summaryCfg, summarymapCfg,
                                          juniperCfg, attributeMgr, _docStore, repo);
}

SummaryManager::SummaryManager(vespalib::Executor &shared_executor, const LogDocumentStore::Config & storeConfig,
                               const search::GrowStrategy & growStrategy, const vespalib::string &baseDir,
                               const DocTypeName &docTypeName, const TuneFileSummary &tuneFileSummary,
                               const FileHeaderContext &fileHeaderContext, search::transactionlog::SyncProxy &tlSyncer,
                               search::IBucketizer::SP bucketizer)
    : _baseDir(baseDir),
      _docTypeName(docTypeName),
      _docStore()
{
    _docStore = std::make_shared<LogDocumentStore>(shared_executor, baseDir, storeConfig, growStrategy, tuneFileSummary,
                                                   fileHeaderContext, tlSyncer, std::move(bucketizer));
}

SummaryManager::~SummaryManager() = default;

void
SummaryManager::putDocument(uint64_t syncToken, search::DocumentIdT lid, const Document & doc)
{
    _docStore->write(syncToken, lid, doc);
}

void
SummaryManager::putDocument(uint64_t syncToken, search::DocumentIdT lid, const vespalib::nbostream & doc)
{
    _docStore->write(syncToken, lid, doc);
}

void
SummaryManager::removeDocument(uint64_t syncToken, search::DocumentIdT lid)
{
    _docStore->remove(syncToken, lid);
}

namespace {

IFlushTarget::SP
createShrinkLidSpaceFlushTarget(vespalib::Executor & summaryService, IDocumentStore::SP docStore)
{
    return std::make_shared<ShrinkSummaryLidSpaceFlushTarget>("summary.shrink",
                                                       IFlushTarget::Type::GC,
                                                       IFlushTarget::Component::DOCUMENT_STORE,
                                                       docStore->lastSyncToken(),
                                                       docStore->getLastFlushTime(),
                                                       summaryService,
                                                       std::move(docStore));
}

}

IFlushTarget::List
SummaryManager::getFlushTargets(vespalib::Executor & summaryService)
{
    IFlushTarget::List ret;
    ret.push_back(std::make_shared<SummaryFlushTarget>(getBackingStore(), summaryService));
    if (dynamic_cast<LogDocumentStore *>(_docStore.get()) != nullptr) {
        ret.push_back(std::make_shared<SummaryCompactBloatTarget>(summaryService, getBackingStore()));
        ret.push_back(std::make_shared<SummaryCompactSpreadTarget>(summaryService, getBackingStore()));
    }
    ret.push_back(createShrinkLidSpaceFlushTarget(summaryService, _docStore));
    return ret;
}

void
SummaryManager::reconfigure(const LogDocumentStore::Config & config) {
    auto & docStore = dynamic_cast<LogDocumentStore &> (*_docStore);
    docStore.reconfigure(config);
}

} // namespace proton
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "iree/compiler/Conversion/LinalgToVector/Passes.h"
#include "iree/compiler/Dialect/IREE/IR/IREEDialect.h"
#include "iree/compiler/Dialect/IREE/IR/IREEOps.h"
#include "llvm/Support/ErrorHandling.h"
#include "mlir/Dialect/Linalg/IR/LinalgOps.h"
#include "mlir/Dialect/Linalg/Passes.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "mlir/Dialect/Vector/VectorOps.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/IR/StandardTypes.h"
#include "mlir/Transforms/DialectConversion.h"

namespace mlir {
namespace iree_compiler {

namespace {

constexpr int kVectorizationSizeInBits = 128;
constexpr int kVecSize = kVectorizationSizeInBits / (sizeof(float) * 8);

/// Returns a VectorType in `kVectorizationSizeInBits` bits if `t` is a scalar.
static VectorType getVecType(OpBuilder &builder, Type t) {
  if (!t.isa<IntegerType, FloatType>()) return {};
  if (t.getIntOrFloatBitWidth() != 32) return {};
  Type newElemType = t.isa<IntegerType>() ? builder.getI32Type().cast<Type>()
                                          : builder.getF32Type().cast<Type>();
  return VectorType::get(kVecSize, newElemType);
}

/// Returns the memref of vector converted from `type`.
static MemRefType getVectorizedMemRefType(OpBuilder &builder, MemRefType type) {
  Type elemType = type.getElementType();
  VectorType vecType = getVecType(builder, elemType);
  if (!vecType) return {};
  unsigned elemSize = elemType.getIntOrFloatBitWidth();
  unsigned vecSize = kVectorizationSizeInBits / elemSize;
  SmallVector<int64_t, 2> newShape(type.getShape().begin(),
                                   type.getShape().end());
  if (newShape.empty()) return {};
  if (newShape.back() % vecSize != 0) return {};
  newShape.back() = newShape.back() / vecSize;
  return MemRefType::get(newShape, vecType, {}, type.getMemorySpace());
}

/// Returns a vectorized `val`, ie, the result type is a VectorType.
static Value legalizeToVectorType(OpBuilder &builder, Value val) {
  Type type = val.getType();
  if (type.isa<VectorType>()) {
    return val;
  } else if (type.isIntOrFloat()) {
    auto vecType = getVecType(builder, type);
    if (!vecType) return nullptr;
    // TODO(hanchung): Add a folder on vector::BroadcastOp so we don't need to
    // create manually.
    if (auto cst = val.getDefiningOp<ConstantOp>()) {
      auto cstVecValue = DenseElementsAttr::get(vecType, cst.value());
      return builder.create<ConstantOp>(val.getLoc(), vecType, cstVecValue)
          .getResult();
    }
    return builder.create<vector::BroadcastOp>(val.getLoc(), vecType, val)
        .getResult();
  }
  return nullptr;
}

/// Base class to vectorize std ops. If a generic op is vectorized, all the std
/// ops in the region should be vectorized as well.
///
/// This base class handles the check on operands and vectorization for all the
/// operands.
///
/// All derived classes implement a static apply method with the following
/// signature:
///
/// ```c++
/// LogicalResult apply(SrcOpTy op, ArrayRef<Value> args,
///                     ConversionPatternRewriter& rewriter) const;
/// ```
template <typename DerivedTy, typename SrcOpTy>
struct VectorizeOpBase : public OpConversionPattern<SrcOpTy> {
  using OpConversionPattern<SrcOpTy>::OpConversionPattern;
  LogicalResult matchAndRewrite(
      SrcOpTy op, ArrayRef<Value> args,
      ConversionPatternRewriter &rewriter) const override {
    if (llvm::all_of(args, [](Value arg) {
          return arg.getType().isIntOrIndexOrFloat();
        })) {
      return failure();
    }
    SmallVector<Value, 4> vecArgs;
    for (Value arg : args) {
      Value val = legalizeToVectorType(rewriter, arg);
      if (!val) return failure();
      vecArgs.push_back(val);
    }
    return static_cast<DerivedTy const *>(this)->apply(op, vecArgs, rewriter);
  }
};

template <typename OpTy>
struct VectorizeElementwiseOp
    : public VectorizeOpBase<VectorizeElementwiseOp<OpTy>, OpTy> {
  using VectorizeOpBase<VectorizeElementwiseOp<OpTy>, OpTy>::VectorizeOpBase;
  LogicalResult apply(OpTy op, ArrayRef<Value> args,
                      ConversionPatternRewriter &rewriter) const {
    auto vecType = getVecType(rewriter, op.getResult().getType());
    if (!vecType) return failure();
    auto newOp = rewriter.create<OpTy>(op.getLoc(), vecType, args);
    rewriter.replaceOp(op, newOp.getOperation()->getResults());
    return success();
  }
};

template <typename OpTy>
struct VectorizeCmpOp : public VectorizeOpBase<VectorizeCmpOp<OpTy>, OpTy> {
  using VectorizeOpBase<VectorizeCmpOp<OpTy>, OpTy>::VectorizeOpBase;
  LogicalResult apply(OpTy op, ArrayRef<Value> args,
                      ConversionPatternRewriter &rewriter) const {
    auto newOp =
        rewriter.create<OpTy>(op.getLoc(), op.predicate(), args[0], args[1]);
    rewriter.replaceOp(op, newOp.getResult());
    return success();
  }
};

struct VectorizeSelectOp
    : public VectorizeOpBase<VectorizeSelectOp, mlir::SelectOp> {
  using VectorizeOpBase<VectorizeSelectOp, mlir::SelectOp>::VectorizeOpBase;
  LogicalResult apply(mlir::SelectOp op, ArrayRef<Value> args,
                      ConversionPatternRewriter &rewriter) const {
    auto newOp =
        rewriter.create<SelectOp>(op.getLoc(), args[0], args[1], args[2]);
    rewriter.replaceOp(op, newOp.getResult());
    return success();
  }
};

struct VectorizeGenericOp : public OpConversionPattern<linalg::GenericOp> {
  using OpConversionPattern<linalg::GenericOp>::OpConversionPattern;
  LogicalResult matchAndRewrite(
      linalg::GenericOp genericOp, ArrayRef<Value> args,
      ConversionPatternRewriter &rewriter) const override {
    if (llvm::any_of(genericOp.iterator_types(), [](Attribute attr) {
          return attr.cast<StringAttr>().getValue() !=
                 getParallelIteratorTypeName();
        })) {
      return failure();
    }

    // Do not vectorize if one of the operand is 0-D or one of the operand is
    // not iterated on contiguous memory.
    for (auto map : genericOp.getIndexingMaps()) {
      if (map.getNumResults() == 0) return failure();
      AffineDimExpr innerMostExpr =
          map.getResults().back().dyn_cast<AffineDimExpr>();
      if (!innerMostExpr ||
          innerMostExpr.getPosition() != map.getNumDims() - 1) {
        return failure();
      }
    }

    SmallVector<IREE::PlaceholderOp, 4> operands;
    SmallVector<MemRefType, 4> vecMemRefs;
    for (auto operand : args) {
      auto op = operand.getDefiningOp<IREE::PlaceholderOp>();
      if (!op) return failure();
      if (!op.getOperation()->hasOneUse()) return failure();
      auto memrefType = op.getResult().getType().dyn_cast<MemRefType>();
      if (!memrefType) return failure();
      auto vecMemRef = getVectorizedMemRefType(rewriter, memrefType);
      if (!vecMemRef) return failure();
      operands.push_back(op);
      vecMemRefs.push_back(vecMemRef);
    }

    SmallVector<Value, 4> newArgs;
    for (auto it : llvm::zip(operands, vecMemRefs)) {
      IREE::PlaceholderOp placeholder = std::get<0>(it);
      MemRefType vecMemRef = std::get<1>(it);
      auto arg = rewriter.create<IREE::PlaceholderOp>(placeholder.getLoc(),
                                                      vecMemRef, ValueRange{},
                                                      placeholder.getAttrs());
      rewriter.replaceOp(placeholder, arg.getResult());
      newArgs.push_back(arg.getResult());
    }

    auto newOp = rewriter.create<linalg::GenericOp>(
        genericOp.getLoc(), genericOp.getResultTypes(), newArgs,
        rewriter.getI64IntegerAttr(genericOp.getNumInputs()),
        rewriter.getI64IntegerAttr(genericOp.getNumOutputs()),
        genericOp.indexing_mapsAttr(), genericOp.iterator_types(),
        /*doc=*/nullptr,
        /*library_call=*/nullptr,
        /*symbol_source=*/nullptr);

    Region &newRegion = newOp.region();
    rewriter.inlineRegionBefore(genericOp.getRegion(), newRegion,
                                newRegion.end());
    Block &newBlock = newOp.region().front();
    TypeConverter::SignatureConversion signatureConverter(
        newBlock.getNumArguments());
    for (auto arg : llvm::enumerate(vecMemRefs)) {
      signatureConverter.addInputs(arg.index(), arg.value().getElementType());
    }
    rewriter.applySignatureConversion(&newOp.region(), signatureConverter);
    rewriter.replaceOp(genericOp, newOp.getResults());
    return success();
  }
};

struct LoadStoreVectorizationPass
    : public PassWrapper<LoadStoreVectorizationPass, OperationPass<FuncOp>> {
  void getDependentDialects(DialectRegistry &registry) const override {
    registry.insert<linalg::LinalgDialect, vector::VectorDialect>();
  }

  void runOnOperation() override {
    MLIRContext *context = &getContext();
    OwningRewritePatternList patterns;
    // clang-format off
    patterns.insert<
        VectorizeGenericOp,
        VectorizeCmpOp<CmpFOp>,
        VectorizeCmpOp<CmpIOp>,
        VectorizeSelectOp,
        VectorizeElementwiseOp<AbsFOp>,
        VectorizeElementwiseOp<AndOp>,
        VectorizeElementwiseOp<OrOp>,
        VectorizeElementwiseOp<XOrOp>,
        VectorizeElementwiseOp<AddFOp>,
        VectorizeElementwiseOp<AddIOp>,
        VectorizeElementwiseOp<CeilFOp>,
        VectorizeElementwiseOp<CosOp>,
        VectorizeElementwiseOp<DivFOp>,
        VectorizeElementwiseOp<ExpOp>,
        VectorizeElementwiseOp<FPExtOp>,
        VectorizeElementwiseOp<FPToSIOp>,
        VectorizeElementwiseOp<FPTruncOp>,
        VectorizeElementwiseOp<FloorFOp>,
        VectorizeElementwiseOp<LogOp>,
        VectorizeElementwiseOp<MulFOp>,
        VectorizeElementwiseOp<MulIOp>,
        VectorizeElementwiseOp<NegFOp>,
        VectorizeElementwiseOp<RemFOp>,
        VectorizeElementwiseOp<RsqrtOp>,
        VectorizeElementwiseOp<SIToFPOp>,
        VectorizeElementwiseOp<ShiftLeftOp>,
        VectorizeElementwiseOp<SignExtendIOp>,
        VectorizeElementwiseOp<SignedDivIOp>,
        VectorizeElementwiseOp<SignedShiftRightOp>,
        VectorizeElementwiseOp<SinOp>,
        VectorizeElementwiseOp<SqrtOp>,
        VectorizeElementwiseOp<SubFOp>,
        VectorizeElementwiseOp<SubIOp>,
        VectorizeElementwiseOp<TanhOp>,
        VectorizeElementwiseOp<TruncateIOp>,
        VectorizeElementwiseOp<UnsignedDivIOp>,
        VectorizeElementwiseOp<UnsignedRemIOp>,
        VectorizeElementwiseOp<UnsignedShiftRightOp>,
        VectorizeElementwiseOp<ZeroExtendIOp>>(context);
    // clang-format on

    ConversionTarget target(*context);
    // Mark vector dialect and plancholder op legal.
    target.addLegalDialect<vector::VectorDialect>();
    target.addLegalOp<IREE::PlaceholderOp>();

    // If a generic op is vectorized, it is legal.
    target.addDynamicallyLegalOp<linalg::GenericOp>([](linalg::GenericOp op) {
      if (!op.hasBufferSemantics()) return false;
      for (auto arg : op.getOperands()) {
        if (arg.getType()
                .cast<MemRefType>()
                .getElementType()
                .isSignlessIntOrFloat())
          return false;
      }
      return true;
    });

    // Mark all standard ops legal if they are operating on vector types.
    target.addDynamicallyLegalDialect<mlir::StandardOpsDialect>(
        Optional<ConversionTarget::DynamicLegalityCallbackFn>(
            [](Operation *op) {
              auto isVectorType = [](Type t) { return t.isa<VectorType>(); };
              return llvm::any_of(op->getOperandTypes(), isVectorType) ||
                     llvm::any_of(op->getResultTypes(), isVectorType);
            }));
    if (failed(applyPartialConversion(getOperation(), target, patterns)))
      return signalPassFailure();
  }
};
}  // namespace

std::unique_ptr<Pass> createLoadStoreVectorizationPass() {
  return std::make_unique<LoadStoreVectorizationPass>();
}

static PassRegistration<LoadStoreVectorizationPass> pass(
    "iree-codegen-vectorize-linalg-ops", "Vectorize Linalg operations");

}  // namespace iree_compiler
}  // namespace mlir
<commit_msg>Remove special handling for vector.broadcast on constants. (#3236)<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "iree/compiler/Conversion/LinalgToVector/Passes.h"
#include "iree/compiler/Dialect/IREE/IR/IREEDialect.h"
#include "iree/compiler/Dialect/IREE/IR/IREEOps.h"
#include "llvm/Support/ErrorHandling.h"
#include "mlir/Dialect/Linalg/IR/LinalgOps.h"
#include "mlir/Dialect/Linalg/Passes.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "mlir/Dialect/Vector/VectorOps.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/IR/StandardTypes.h"
#include "mlir/Transforms/DialectConversion.h"

namespace mlir {
namespace iree_compiler {

namespace {

constexpr int kVectorizationSizeInBits = 128;
constexpr int kVecSize = kVectorizationSizeInBits / (sizeof(float) * 8);

/// Returns a VectorType in `kVectorizationSizeInBits` bits if `t` is a scalar.
static VectorType getVecType(OpBuilder &builder, Type t) {
  if (!t.isa<IntegerType, FloatType>()) return {};
  if (t.getIntOrFloatBitWidth() != 32) return {};
  Type newElemType = t.isa<IntegerType>() ? builder.getI32Type().cast<Type>()
                                          : builder.getF32Type().cast<Type>();
  return VectorType::get(kVecSize, newElemType);
}

/// Returns the memref of vector converted from `type`.
static MemRefType getVectorizedMemRefType(OpBuilder &builder, MemRefType type) {
  Type elemType = type.getElementType();
  VectorType vecType = getVecType(builder, elemType);
  if (!vecType) return {};
  unsigned elemSize = elemType.getIntOrFloatBitWidth();
  unsigned vecSize = kVectorizationSizeInBits / elemSize;
  SmallVector<int64_t, 2> newShape(type.getShape().begin(),
                                   type.getShape().end());
  if (newShape.empty()) return {};
  if (newShape.back() % vecSize != 0) return {};
  newShape.back() = newShape.back() / vecSize;
  return MemRefType::get(newShape, vecType, {}, type.getMemorySpace());
}

/// Returns a vectorized `val`, ie, the result type is a VectorType.
static Value legalizeToVectorType(OpBuilder &builder, Value val) {
  Type type = val.getType();
  if (type.isa<VectorType>()) {
    return val;
  } else if (type.isIntOrFloat()) {
    auto vecType = getVecType(builder, type);
    if (!vecType) return nullptr;
    return builder.createOrFold<vector::BroadcastOp>(val.getLoc(), vecType,
                                                     val);
  }
  return nullptr;
}

/// Base class to vectorize std ops. If a generic op is vectorized, all the std
/// ops in the region should be vectorized as well.
///
/// This base class handles the check on operands and vectorization for all the
/// operands.
///
/// All derived classes implement a static apply method with the following
/// signature:
///
/// ```c++
/// LogicalResult apply(SrcOpTy op, ArrayRef<Value> args,
///                     ConversionPatternRewriter& rewriter) const;
/// ```
template <typename DerivedTy, typename SrcOpTy>
struct VectorizeOpBase : public OpConversionPattern<SrcOpTy> {
  using OpConversionPattern<SrcOpTy>::OpConversionPattern;
  LogicalResult matchAndRewrite(
      SrcOpTy op, ArrayRef<Value> args,
      ConversionPatternRewriter &rewriter) const override {
    if (llvm::all_of(args, [](Value arg) {
          return arg.getType().isIntOrIndexOrFloat();
        })) {
      return failure();
    }
    SmallVector<Value, 4> vecArgs;
    for (Value arg : args) {
      Value val = legalizeToVectorType(rewriter, arg);
      if (!val) return failure();
      vecArgs.push_back(val);
    }
    return static_cast<DerivedTy const *>(this)->apply(op, vecArgs, rewriter);
  }
};

template <typename OpTy>
struct VectorizeElementwiseOp
    : public VectorizeOpBase<VectorizeElementwiseOp<OpTy>, OpTy> {
  using VectorizeOpBase<VectorizeElementwiseOp<OpTy>, OpTy>::VectorizeOpBase;
  LogicalResult apply(OpTy op, ArrayRef<Value> args,
                      ConversionPatternRewriter &rewriter) const {
    auto vecType = getVecType(rewriter, op.getResult().getType());
    if (!vecType) return failure();
    auto newOp = rewriter.create<OpTy>(op.getLoc(), vecType, args);
    rewriter.replaceOp(op, newOp.getOperation()->getResults());
    return success();
  }
};

template <typename OpTy>
struct VectorizeCmpOp : public VectorizeOpBase<VectorizeCmpOp<OpTy>, OpTy> {
  using VectorizeOpBase<VectorizeCmpOp<OpTy>, OpTy>::VectorizeOpBase;
  LogicalResult apply(OpTy op, ArrayRef<Value> args,
                      ConversionPatternRewriter &rewriter) const {
    auto newOp =
        rewriter.create<OpTy>(op.getLoc(), op.predicate(), args[0], args[1]);
    rewriter.replaceOp(op, newOp.getResult());
    return success();
  }
};

struct VectorizeSelectOp
    : public VectorizeOpBase<VectorizeSelectOp, mlir::SelectOp> {
  using VectorizeOpBase<VectorizeSelectOp, mlir::SelectOp>::VectorizeOpBase;
  LogicalResult apply(mlir::SelectOp op, ArrayRef<Value> args,
                      ConversionPatternRewriter &rewriter) const {
    auto newOp =
        rewriter.create<SelectOp>(op.getLoc(), args[0], args[1], args[2]);
    rewriter.replaceOp(op, newOp.getResult());
    return success();
  }
};

struct VectorizeGenericOp : public OpConversionPattern<linalg::GenericOp> {
  using OpConversionPattern<linalg::GenericOp>::OpConversionPattern;
  LogicalResult matchAndRewrite(
      linalg::GenericOp genericOp, ArrayRef<Value> args,
      ConversionPatternRewriter &rewriter) const override {
    if (llvm::any_of(genericOp.iterator_types(), [](Attribute attr) {
          return attr.cast<StringAttr>().getValue() !=
                 getParallelIteratorTypeName();
        })) {
      return failure();
    }

    // Do not vectorize if one of the operand is 0-D or one of the operand is
    // not iterated on contiguous memory.
    for (auto map : genericOp.getIndexingMaps()) {
      if (map.getNumResults() == 0) return failure();
      AffineDimExpr innerMostExpr =
          map.getResults().back().dyn_cast<AffineDimExpr>();
      if (!innerMostExpr ||
          innerMostExpr.getPosition() != map.getNumDims() - 1) {
        return failure();
      }
    }

    SmallVector<IREE::PlaceholderOp, 4> operands;
    SmallVector<MemRefType, 4> vecMemRefs;
    for (auto operand : args) {
      auto op = operand.getDefiningOp<IREE::PlaceholderOp>();
      if (!op) return failure();
      if (!op.getOperation()->hasOneUse()) return failure();
      auto memrefType = op.getResult().getType().dyn_cast<MemRefType>();
      if (!memrefType) return failure();
      auto vecMemRef = getVectorizedMemRefType(rewriter, memrefType);
      if (!vecMemRef) return failure();
      operands.push_back(op);
      vecMemRefs.push_back(vecMemRef);
    }

    SmallVector<Value, 4> newArgs;
    for (auto it : llvm::zip(operands, vecMemRefs)) {
      IREE::PlaceholderOp placeholder = std::get<0>(it);
      MemRefType vecMemRef = std::get<1>(it);
      auto arg = rewriter.create<IREE::PlaceholderOp>(placeholder.getLoc(),
                                                      vecMemRef, ValueRange{},
                                                      placeholder.getAttrs());
      rewriter.replaceOp(placeholder, arg.getResult());
      newArgs.push_back(arg.getResult());
    }

    auto newOp = rewriter.create<linalg::GenericOp>(
        genericOp.getLoc(), genericOp.getResultTypes(), newArgs,
        rewriter.getI64IntegerAttr(genericOp.getNumInputs()),
        rewriter.getI64IntegerAttr(genericOp.getNumOutputs()),
        genericOp.indexing_mapsAttr(), genericOp.iterator_types(),
        /*doc=*/nullptr,
        /*library_call=*/nullptr,
        /*symbol_source=*/nullptr);

    Region &newRegion = newOp.region();
    rewriter.inlineRegionBefore(genericOp.getRegion(), newRegion,
                                newRegion.end());
    Block &newBlock = newOp.region().front();
    TypeConverter::SignatureConversion signatureConverter(
        newBlock.getNumArguments());
    for (auto arg : llvm::enumerate(vecMemRefs)) {
      signatureConverter.addInputs(arg.index(), arg.value().getElementType());
    }
    rewriter.applySignatureConversion(&newOp.region(), signatureConverter);
    rewriter.replaceOp(genericOp, newOp.getResults());
    return success();
  }
};

struct LoadStoreVectorizationPass
    : public PassWrapper<LoadStoreVectorizationPass, OperationPass<FuncOp>> {
  void getDependentDialects(DialectRegistry &registry) const override {
    registry.insert<linalg::LinalgDialect, vector::VectorDialect>();
  }

  void runOnOperation() override {
    MLIRContext *context = &getContext();
    OwningRewritePatternList patterns;
    // clang-format off
    patterns.insert<
        VectorizeGenericOp,
        VectorizeCmpOp<CmpFOp>,
        VectorizeCmpOp<CmpIOp>,
        VectorizeSelectOp,
        VectorizeElementwiseOp<AbsFOp>,
        VectorizeElementwiseOp<AndOp>,
        VectorizeElementwiseOp<OrOp>,
        VectorizeElementwiseOp<XOrOp>,
        VectorizeElementwiseOp<AddFOp>,
        VectorizeElementwiseOp<AddIOp>,
        VectorizeElementwiseOp<CeilFOp>,
        VectorizeElementwiseOp<CosOp>,
        VectorizeElementwiseOp<DivFOp>,
        VectorizeElementwiseOp<ExpOp>,
        VectorizeElementwiseOp<FPExtOp>,
        VectorizeElementwiseOp<FPToSIOp>,
        VectorizeElementwiseOp<FPTruncOp>,
        VectorizeElementwiseOp<FloorFOp>,
        VectorizeElementwiseOp<LogOp>,
        VectorizeElementwiseOp<MulFOp>,
        VectorizeElementwiseOp<MulIOp>,
        VectorizeElementwiseOp<NegFOp>,
        VectorizeElementwiseOp<RemFOp>,
        VectorizeElementwiseOp<RsqrtOp>,
        VectorizeElementwiseOp<SIToFPOp>,
        VectorizeElementwiseOp<ShiftLeftOp>,
        VectorizeElementwiseOp<SignExtendIOp>,
        VectorizeElementwiseOp<SignedDivIOp>,
        VectorizeElementwiseOp<SignedShiftRightOp>,
        VectorizeElementwiseOp<SinOp>,
        VectorizeElementwiseOp<SqrtOp>,
        VectorizeElementwiseOp<SubFOp>,
        VectorizeElementwiseOp<SubIOp>,
        VectorizeElementwiseOp<TanhOp>,
        VectorizeElementwiseOp<TruncateIOp>,
        VectorizeElementwiseOp<UnsignedDivIOp>,
        VectorizeElementwiseOp<UnsignedRemIOp>,
        VectorizeElementwiseOp<UnsignedShiftRightOp>,
        VectorizeElementwiseOp<ZeroExtendIOp>>(context);
    // clang-format on

    ConversionTarget target(*context);
    // Mark vector dialect and plancholder op legal.
    target.addLegalDialect<vector::VectorDialect>();
    target.addLegalOp<IREE::PlaceholderOp>();

    // If a generic op is vectorized, it is legal.
    target.addDynamicallyLegalOp<linalg::GenericOp>([](linalg::GenericOp op) {
      if (!op.hasBufferSemantics()) return false;
      for (auto arg : op.getOperands()) {
        if (arg.getType()
                .cast<MemRefType>()
                .getElementType()
                .isSignlessIntOrFloat())
          return false;
      }
      return true;
    });

    // Mark all standard ops legal if they are operating on vector types.
    target.addDynamicallyLegalDialect<mlir::StandardOpsDialect>(
        Optional<ConversionTarget::DynamicLegalityCallbackFn>(
            [](Operation *op) {
              auto isVectorType = [](Type t) { return t.isa<VectorType>(); };
              return llvm::any_of(op->getOperandTypes(), isVectorType) ||
                     llvm::any_of(op->getResultTypes(), isVectorType);
            }));
    if (failed(applyPartialConversion(getOperation(), target, patterns)))
      return signalPassFailure();
  }
};
}  // namespace

std::unique_ptr<Pass> createLoadStoreVectorizationPass() {
  return std::make_unique<LoadStoreVectorizationPass>();
}

static PassRegistration<LoadStoreVectorizationPass> pass(
    "iree-codegen-vectorize-linalg-ops", "Vectorize Linalg operations");

}  // namespace iree_compiler
}  // namespace mlir
<|endoftext|>


<commit_before>// Copyright (c) 2013-2018 mogemimi. Distributed under the MIT license.

#pragma once

#if defined(_MSC_VER) && (_MSC_VER > 1910)
#include <optional>
#else
#include <experimental/optional>
#endif

namespace Pomdog {

#if defined(_MSC_VER) && (_MSC_VER > 1910)
template <typename T>
using Optional = std::optional<T>;

constexpr auto NullOpt = std::nullopt;

template <typename T>
inline constexpr Optional<T> MakeOptional(T && v)
{
    return std::make_optional(std::forward<T>(v));
}
#else
template <typename T>
using Optional = std::experimental::optional<T>;

constexpr auto NullOpt = std::experimental::nullopt;

template <typename T>
inline constexpr Optional<T> MakeOptional(T && v)
{
    return std::experimental::make_optional(std::forward<T>(v));
}
#endif

} // namespace Pomdog
<commit_msg>Use std::optional whenever possible<commit_after>// Copyright (c) 2013-2018 mogemimi. Distributed under the MIT license.

#pragma once

#if __has_include(<optional>)
#include <optional>
#else
#include <experimental/optional>
#endif

namespace Pomdog {

#if defined(__cpp_lib_optional)
template <typename T>
using Optional = std::optional<T>;

constexpr auto NullOpt = std::nullopt;

template <typename T>
inline constexpr Optional<T> MakeOptional(T && v)
{
    return std::make_optional(std::forward<T>(v));
}
#else
template <typename T>
using Optional = std::experimental::optional<T>;

constexpr auto NullOpt = std::experimental::nullopt;

template <typename T>
inline constexpr Optional<T> MakeOptional(T && v)
{
    return std::experimental::make_optional(std::forward<T>(v));
}
#endif

} // namespace Pomdog
<|endoftext|>