<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: printdata.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 02:05:30 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _SW_PRINTDATA_HXX
#define _SW_PRINTDATA_HXX

#ifndef _SAL_TYPES_H_
#include <sal/types.h>
#endif
#ifndef _RTL_USTRING_
#include <rtl/ustring>
#endif

struct SwPrintData
{
    sal_Bool bPrintGraphic, bPrintTable, bPrintDraw, bPrintControl, bPrintPageBackground,
             bPrintBlackFont, bPrintLeftPage, bPrintRightPage, bPrintReverse, bPrintProspect,
             bPrintSingleJobs, bPaperFromSetup, bModified;

    sal_Int16           nPrintPostIts;
    rtl::OUString       sFaxName;

    SwPrintData()
    {
        bPrintGraphic           =
        bPrintTable             =
        bPrintDraw              =
        bPrintControl           =
        bPrintLeftPage          =
        bPrintRightPage         =
        bPrintPageBackground    = sal_True;

        bPaperFromSetup         =
        bPrintReverse           =
        bPrintProspect          =
        bPrintSingleJobs        =
        bModified               =
        bPrintBlackFont         = sal_False;

        nPrintPostIts           = 0;
    }

    sal_Bool operator==(const SwPrintData& rData)const
    {
        return
        bPrintGraphic       ==   rData.bPrintGraphic       &&
        bPrintTable         ==   rData.bPrintTable         &&
        bPrintDraw          ==   rData.bPrintDraw          &&
        bPrintControl       ==   rData.bPrintControl       &&
        bPrintPageBackground==   rData.bPrintPageBackground&&
        bPrintBlackFont     ==   rData.bPrintBlackFont     &&
        bPrintLeftPage      ==   rData.bPrintLeftPage      &&
        bPrintRightPage     ==   rData.bPrintRightPage     &&
        bPrintReverse       ==   rData.bPrintReverse       &&
        bPrintProspect      ==   rData.bPrintProspect      &&
        bPrintSingleJobs    ==   rData.bPrintSingleJobs    &&
        bPaperFromSetup     ==   rData.bPaperFromSetup     &&
        nPrintPostIts       ==   rData.nPrintPostIts       &&
        sFaxName            ==   rData.sFaxName;
    }
    sal_Bool IsPrintGraphic()   const { return bPrintGraphic; }
    sal_Bool IsPrintTable()     const { return bPrintTable; }
    sal_Bool IsPrintDraw()      const { return bPrintDraw; }
    sal_Bool IsPrintControl()   const { return bPrintControl; }
    sal_Bool IsPrintLeftPage()  const { return bPrintLeftPage; }
    sal_Bool IsPrintRightPage() const { return bPrintRightPage; }
    sal_Bool IsPrintReverse()   const { return bPrintReverse; }
    sal_Bool IsPaperFromSetup() const { return bPaperFromSetup; }
    sal_Bool IsPrintProspect()  const { return bPrintProspect; }
    sal_Bool IsPrintPageBackground() const { return bPrintPageBackground; }
    sal_Bool IsPrintBlackFont() const { return bPrintBlackFont;}
    sal_Bool IsPrintSingleJobs() const { return bPrintSingleJobs;}
    sal_Int16 GetPrintPostIts() const { return nPrintPostIts; }
    const rtl::OUString     GetFaxName() const{return sFaxName;}

    void SetPrintGraphic  ( sal_Bool b ) { doSetModified(); bPrintGraphic = b;}
    void SetPrintTable    ( sal_Bool b ) { doSetModified(); bPrintTable = b;}
    void SetPrintDraw     ( sal_Bool b ) { doSetModified(); bPrintDraw = b;}
    void SetPrintControl  ( sal_Bool b ) { doSetModified(); bPrintControl = b; }
    void SetPrintLeftPage ( sal_Bool b ) { doSetModified(); bPrintLeftPage = b;}
    void SetPrintRightPage( sal_Bool b ) { doSetModified(); bPrintRightPage = b;}
    void SetPrintReverse  ( sal_Bool b ) { doSetModified(); bPrintReverse = b;}
    void SetPaperFromSetup( sal_Bool b ) { doSetModified(); bPaperFromSetup = b;}
    void SetPrintPostIts    ( sal_Int16 n){ doSetModified(); nPrintPostIts = n; }
    void SetPrintProspect   ( sal_Bool b ) { doSetModified(); bPrintProspect = b; }
    void SetPrintPageBackground(sal_Bool b){ doSetModified(); bPrintPageBackground = b;}
    void SetPrintBlackFont(sal_Bool b){ doSetModified(); bPrintBlackFont = b;}
    void SetPrintSingleJobs(sal_Bool b){ doSetModified(); bPrintSingleJobs = b;}
    void SetFaxName(const rtl::OUString& rSet){sFaxName = rSet;}
    virtual void doSetModified () { bModified = sal_True;}
    sal_Bool WasModified () { return bModified; }
};

#endif  //_SW_PRINTDATA_HXX

<commit_msg>INTEGRATION: CWS emptypage (1.3.152); FILE MERGED 2005/12/13 15:27:09 fme 1.3.152.1: #b6354161# Feature - Print empty pages<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: printdata.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2005-12-21 15:09:55 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _SW_PRINTDATA_HXX
#define _SW_PRINTDATA_HXX

#ifndef _SAL_TYPES_H_
#include <sal/types.h>
#endif
#ifndef _RTL_USTRING_
#include <rtl/ustring>
#endif

struct SwPrintData
{
    sal_Bool bPrintGraphic, bPrintTable, bPrintDraw, bPrintControl, bPrintPageBackground,
             bPrintBlackFont, bPrintLeftPage, bPrintRightPage, bPrintReverse, bPrintProspect,
             bPrintSingleJobs, bPaperFromSetup,
             // --> FME 2005-12-13 #b6354161# Print empty pages
             bPrintEmptyPages,
             // <--
             bModified;

    sal_Int16           nPrintPostIts;
    rtl::OUString       sFaxName;

    SwPrintData()
    {
        bPrintGraphic           =
        bPrintTable             =
        bPrintDraw              =
        bPrintControl           =
        bPrintLeftPage          =
        bPrintRightPage         =
        bPrintPageBackground    =
        bPrintEmptyPages        = sal_True;

        bPaperFromSetup         =
        bPrintReverse           =
        bPrintProspect          =
        bPrintSingleJobs        =
        bModified               =
        bPrintBlackFont         = sal_False;

        nPrintPostIts           = 0;
    }

    sal_Bool operator==(const SwPrintData& rData)const
    {
        return
        bPrintGraphic       ==   rData.bPrintGraphic       &&
        bPrintTable         ==   rData.bPrintTable         &&
        bPrintDraw          ==   rData.bPrintDraw          &&
        bPrintControl       ==   rData.bPrintControl       &&
        bPrintPageBackground==   rData.bPrintPageBackground&&
        bPrintBlackFont     ==   rData.bPrintBlackFont     &&
        bPrintLeftPage      ==   rData.bPrintLeftPage      &&
        bPrintRightPage     ==   rData.bPrintRightPage     &&
        bPrintReverse       ==   rData.bPrintReverse       &&
        bPrintProspect      ==   rData.bPrintProspect      &&
        bPrintSingleJobs    ==   rData.bPrintSingleJobs    &&
        bPaperFromSetup     ==   rData.bPaperFromSetup     &&
        bPrintEmptyPages    ==   rData.bPrintEmptyPages   &&
        nPrintPostIts       ==   rData.nPrintPostIts       &&
        sFaxName            ==   rData.sFaxName;
    }
    sal_Bool IsPrintGraphic()   const { return bPrintGraphic; }
    sal_Bool IsPrintTable()     const { return bPrintTable; }
    sal_Bool IsPrintDraw()      const { return bPrintDraw; }
    sal_Bool IsPrintControl()   const { return bPrintControl; }
    sal_Bool IsPrintLeftPage()  const { return bPrintLeftPage; }
    sal_Bool IsPrintRightPage() const { return bPrintRightPage; }
    sal_Bool IsPrintReverse()   const { return bPrintReverse; }
    sal_Bool IsPaperFromSetup() const { return bPaperFromSetup; }
    sal_Bool IsPrintEmptyPages() const{ return bPrintEmptyPages; }
    sal_Bool IsPrintProspect()  const { return bPrintProspect; }
    sal_Bool IsPrintPageBackground() const { return bPrintPageBackground; }
    sal_Bool IsPrintBlackFont() const { return bPrintBlackFont;}
    sal_Bool IsPrintSingleJobs() const { return bPrintSingleJobs;}
    sal_Int16 GetPrintPostIts() const { return nPrintPostIts; }
    const rtl::OUString     GetFaxName() const{return sFaxName;}

    void SetPrintGraphic  ( sal_Bool b ) { doSetModified(); bPrintGraphic = b;}
    void SetPrintTable    ( sal_Bool b ) { doSetModified(); bPrintTable = b;}
    void SetPrintDraw     ( sal_Bool b ) { doSetModified(); bPrintDraw = b;}
    void SetPrintControl  ( sal_Bool b ) { doSetModified(); bPrintControl = b; }
    void SetPrintLeftPage ( sal_Bool b ) { doSetModified(); bPrintLeftPage = b;}
    void SetPrintRightPage( sal_Bool b ) { doSetModified(); bPrintRightPage = b;}
    void SetPrintReverse  ( sal_Bool b ) { doSetModified(); bPrintReverse = b;}
    void SetPaperFromSetup( sal_Bool b ) { doSetModified(); bPaperFromSetup = b;}
    void SetPrintEmptyPages(sal_Bool b ) { doSetModified(); bPrintEmptyPages = b;}
    void SetPrintPostIts    ( sal_Int16 n){ doSetModified(); nPrintPostIts = n; }
    void SetPrintProspect   ( sal_Bool b ) { doSetModified(); bPrintProspect = b; }
    void SetPrintPageBackground(sal_Bool b){ doSetModified(); bPrintPageBackground = b;}
    void SetPrintBlackFont(sal_Bool b){ doSetModified(); bPrintBlackFont = b;}
    void SetPrintSingleJobs(sal_Bool b){ doSetModified(); bPrintSingleJobs = b;}
    void SetFaxName(const rtl::OUString& rSet){sFaxName = rSet;}
    virtual void doSetModified () { bModified = sal_True;}
    sal_Bool WasModified () { return bModified; }
};

#endif  //_SW_PRINTDATA_HXX

<|endoftext|>


<commit_before>
#include "base.h"

namespace sgraph{

void sgmanager::pause()
{
	this->pause_threads_lock.lock();
	this->pause_threads = true;
	this->pause_threads_lock.unlock();
	//for (std::tuple<>)
}
void sgmanager::start()
{
	this->pause_threads_lock.lock();
	this->pause_threads = false;
	this->pause_threads_lock.unlock();
	this->_pause_threads_finished.notify_all();
	//for (std::tuple<>)
}

void sgmanager::stop()
{
	this->pause_threads_lock.lock();
	this->pause_threads = false;
	this->active=false;
	this->pause_threads_lock.unlock();
	this->_pause_threads_finished.notify_all();

	for (auto it: this->actordict)
	{
		it.second->leave();
	}

	for (auto it: this->actordict)
	{
		it.second->join();
	}
}

bool sgmanager::interrupt_thread(sgactor *actor)
{
	std::unique_lock<std::mutex> lck (this->pause_threads_lock);

	if (this->pause_threads)
	{
		this->_pause_threads_finished.wait(lck);
	}
	return this->active;
}

void sgmanager::updateStreamspec(const std::string &name, sgstreamspec* obj)
{
	this->streamdict.at(name).reset(obj);
}

std::vector<sgraph::sgstreamspec*> sgmanager::getStreamspecs(const std::vector<std::string> &streamnames)
{
	std::vector<sgstreamspec*> ret;
	for (std::string elem: streamnames)
	{
		if (this->streamdict.count(elem)==0)
		{
			throw(MissingStreamException(elem));
		}
		ret.push_back(this->streamdict.at(elem).get());
	}
	return ret;
}

std::vector<sgactor*> sgmanager::getActors(const std::vector<std::string> &actornames)
{
	std::vector<sgactor*> ret;
	for (std::string elem: actornames)
	{
		if (this->actordict.count(elem)==0)
		{
			throw(MissingActorException(elem));
		}
		ret.push_back(this->actordict.at(elem).get());
	}
	return ret;

}

void sgmanager::addActor(const std::string &name, sgactor *actor, const std::vector<std::string> &streamnamesin, const std::vector<std::string> &streamnamesout)
{
	for (std::string elem: streamnamesin)
	{
		if (this->streamdict.count(elem)==0)
		{
			throw(MissingStreamException(elem));
		}
	}

	for (std::string elem: streamnamesout)
	{
		if (this->streamdict.count(elem)==1)
		{
			throw(NameCollisionException("Outputstream: \""+elem+"\" already exists"));
		}
		this->streamdict[elem] = std::shared_ptr<sgstreamspec>(0); //must be initialised in enter
	}

	if (this->actordict.count(name)==1)
	{
		throw(NameCollisionException("Actor: \""+name+"\" already exists"));
	}

	actor->init(name, this, streamnamesin, streamnamesout);
	this->actordict[name] = std::shared_ptr<sgactor>(actor);
}

void sgstreamspec::updateStream(sgstream* streamob)
{
	this->protaccess.lock();
	if (interests>0)
	{
		std::unique_lock<std::mutex> lck(this->protaccess, std::adopt_lock);
		this->reading_finished.wait(lck);
	}

	this->stream = std::shared_ptr<sgstream> (streamob);

	updating_finished.notify_all();
	this->protaccess.unlock();
}

std::shared_ptr<sgstream> sgstreamspec::getStream(int64_t blockingtime)
{
	std::shared_ptr<sgstream> ret;

	this->protaccess.lock();
	std::unique_lock<std::mutex> lck(this->protaccess, std::adopt_lock);
	if (blockingtime==-1)
	{
		this->updating_finished.wait(lck);
	}else if (blockingtime>0)
	{
		if (this->updating_finished.wait_for(lck, std::chrono::nanoseconds(blockingtime)) == std::cv_status::timeout)
		{
			return std::shared_ptr<sgstream> (0);
		}
	}

	ret = this->stream;

	this->reading_finished.notify_one();

	this->protaccess.unlock();
	return ret;
}

sgactor::sgactor(double freq, int64_t blockingtime)
{
	this->blockingtime = blockingtime;
	this->time_sleep = std::chrono::nanoseconds((int64_t)(1000000.0L/freq));
	this->time_previous = std::chrono::steady_clock::now();
}

void sgactor::join()
{
	if (this->intern_thread)
	{
		this->intern_thread->join();
		delete this->intern_thread;
	}
}

std::shared_ptr<sgstream> getStreamhelper(sgstreamspec *t, int64_t blockingtime)
{
	return t->getStream(blockingtime);

}

std::vector<std::shared_ptr<sgstream>> sgactor::getStreams()
{

	this->_tretgetStreams.clear();
	this->_thandlesgetStreams.clear();
	//std::vector<auto> handles;

	for (sgstreamspec* elem: this->streamsin)
	{
		if (elem==0)
		{
			throw(UninitializedStreamException());
		}
		_thandlesgetStreams.push_back(std::async(std::launch::async, getStreamhelper, elem, this->blockingtime));
	}

	for (std::future<std::shared_ptr<sgstream>> &elem: _thandlesgetStreams)
	{
		elem.wait();
		_tretgetStreams.push_back(elem.get());
	}
	return _tretgetStreams;
}

void sgactor::step(){
	this->active=this->manager->interrupt_thread(this);
	if (!this->active)
	{
		return;
	}
	auto tstart =  std::chrono::steady_clock::now();
	auto tosleep = this->time_sleep-(tstart-this->time_previous);
	std::this_thread::sleep_for(std::chrono::duration_cast<std::chrono::nanoseconds> (tosleep));

	this->run(this->getStreams());

	this->time_previous = std::chrono::steady_clock::now();
	//this->transform(sgactor, std::forward(sgactor));
};

void sgactor::init(const std::string &name, sgmanager *manager, const std::vector<std::string> &streamnamesin, const std::vector<std::string> &streamnamesout)
{
	this->name = name;
	this->manager = manager;
	this->owned_instreams.insert(streamnamesin.begin(),streamnamesin.end());
	this->owned_outstreams.insert(streamnamesout.begin(),streamnamesout.end());
	this->streamsin = manager->getStreamspecs(streamnamesin);
	this->_tretgetStreams = std::vector<std::shared_ptr<sgstream>> (this->streamsin.size());
	this->_thandlesgetStreams = std::vector<std::future<std::shared_ptr<sgstream>>> (this->streamsin.size());
	this->enter(this->streamsin, streamnamesout);
	this->streamsout = manager->getStreamspecs(streamnamesout);
}

}
<commit_msg>nano is smaller than a 1000000 second<commit_after>
#include "base.h"

namespace sgraph{

void sgmanager::pause()
{
	this->pause_threads_lock.lock();
	this->pause_threads = true;
	this->pause_threads_lock.unlock();
	//for (std::tuple<>)
}
void sgmanager::start()
{
	this->pause_threads_lock.lock();
	this->pause_threads = false;
	this->pause_threads_lock.unlock();
	this->_pause_threads_finished.notify_all();
	//for (std::tuple<>)
}

void sgmanager::stop()
{
	this->pause_threads_lock.lock();
	this->pause_threads = false;
	this->active=false;
	this->pause_threads_lock.unlock();
	this->_pause_threads_finished.notify_all();

	for (auto it: this->actordict)
	{
		it.second->leave();
	}

	for (auto it: this->actordict)
	{
		it.second->join();
	}
}

bool sgmanager::interrupt_thread(sgactor *actor)
{
	std::unique_lock<std::mutex> lck (this->pause_threads_lock);

	if (this->pause_threads)
	{
		this->_pause_threads_finished.wait(lck);
	}
	return this->active;
}

void sgmanager::updateStreamspec(const std::string &name, sgstreamspec* obj)
{
	this->streamdict.at(name).reset(obj);
}

std::vector<sgraph::sgstreamspec*> sgmanager::getStreamspecs(const std::vector<std::string> &streamnames)
{
	std::vector<sgstreamspec*> ret;
	for (std::string elem: streamnames)
	{
		if (this->streamdict.count(elem)==0)
		{
			throw(MissingStreamException(elem));
		}
		ret.push_back(this->streamdict.at(elem).get());
	}
	return ret;
}

std::vector<sgactor*> sgmanager::getActors(const std::vector<std::string> &actornames)
{
	std::vector<sgactor*> ret;
	for (std::string elem: actornames)
	{
		if (this->actordict.count(elem)==0)
		{
			throw(MissingActorException(elem));
		}
		ret.push_back(this->actordict.at(elem).get());
	}
	return ret;

}

void sgmanager::addActor(const std::string &name, sgactor *actor, const std::vector<std::string> &streamnamesin, const std::vector<std::string> &streamnamesout)
{
	for (std::string elem: streamnamesin)
	{
		if (this->streamdict.count(elem)==0)
		{
			throw(MissingStreamException(elem));
		}
	}

	for (std::string elem: streamnamesout)
	{
		if (this->streamdict.count(elem)==1)
		{
			throw(NameCollisionException("Outputstream: \""+elem+"\" already exists"));
		}
		this->streamdict[elem] = std::shared_ptr<sgstreamspec>(0); //must be initialised in enter
	}

	if (this->actordict.count(name)==1)
	{
		throw(NameCollisionException("Actor: \""+name+"\" already exists"));
	}

	actor->init(name, this, streamnamesin, streamnamesout);
	this->actordict[name] = std::shared_ptr<sgactor>(actor);
}

void sgstreamspec::updateStream(sgstream* streamob)
{
	this->protaccess.lock();
	if (interests>0)
	{
		std::unique_lock<std::mutex> lck(this->protaccess, std::adopt_lock);
		this->reading_finished.wait(lck);
	}

	this->stream = std::shared_ptr<sgstream> (streamob);

	updating_finished.notify_all();
	this->protaccess.unlock();
}

std::shared_ptr<sgstream> sgstreamspec::getStream(int64_t blockingtime)
{
	std::shared_ptr<sgstream> ret;

	this->protaccess.lock();
	std::unique_lock<std::mutex> lck(this->protaccess, std::adopt_lock);
	if (blockingtime==-1)
	{
		this->updating_finished.wait(lck);
	}else if (blockingtime>0)
	{
		if (this->updating_finished.wait_for(lck, std::chrono::nanoseconds(blockingtime)) == std::cv_status::timeout)
		{
			return std::shared_ptr<sgstream> (0);
		}
	}

	ret = this->stream;

	this->reading_finished.notify_one();

	this->protaccess.unlock();
	return ret;
}

sgactor::sgactor(double freq, int64_t blockingtime)
{
	this->blockingtime = blockingtime;
	this->time_sleep = std::chrono::nanoseconds((int64_t)(1000000000.0L/freq));
	this->time_previous = std::chrono::steady_clock::now();
}

void sgactor::join()
{
	if (this->intern_thread)
	{
		this->intern_thread->join();
		delete this->intern_thread;
	}
}

std::shared_ptr<sgstream> getStreamhelper(sgstreamspec *t, int64_t blockingtime)
{
	return t->getStream(blockingtime);

}

std::vector<std::shared_ptr<sgstream>> sgactor::getStreams()
{

	this->_tretgetStreams.clear();
	this->_thandlesgetStreams.clear();
	//std::vector<auto> handles;

	for (sgstreamspec* elem: this->streamsin)
	{
		if (elem==0)
		{
			throw(UninitializedStreamException());
		}
		_thandlesgetStreams.push_back(std::async(std::launch::async, getStreamhelper, elem, this->blockingtime));
	}

	for (std::future<std::shared_ptr<sgstream>> &elem: _thandlesgetStreams)
	{
		elem.wait();
		_tretgetStreams.push_back(elem.get());
	}
	return _tretgetStreams;
}

void sgactor::step(){
	this->active=this->manager->interrupt_thread(this);
	if (!this->active)
	{
		return;
	}
	auto tstart =  std::chrono::steady_clock::now();
	auto tosleep = this->time_sleep-(tstart-this->time_previous);
	std::this_thread::sleep_for(std::chrono::duration_cast<std::chrono::nanoseconds> (tosleep));

	this->run(this->getStreams());

	this->time_previous = std::chrono::steady_clock::now();
	//this->transform(sgactor, std::forward(sgactor));
};

void sgactor::init(const std::string &name, sgmanager *manager, const std::vector<std::string> &streamnamesin, const std::vector<std::string> &streamnamesout)
{
	this->name = name;
	this->manager = manager;
	this->owned_instreams.insert(streamnamesin.begin(),streamnamesin.end());
	this->owned_outstreams.insert(streamnamesout.begin(),streamnamesout.end());
	this->streamsin = manager->getStreamspecs(streamnamesin);
	this->_tretgetStreams = std::vector<std::shared_ptr<sgstream>> (this->streamsin.size());
	this->_thandlesgetStreams = std::vector<std::future<std::shared_ptr<sgstream>>> (this->streamsin.size());
	this->enter(this->streamsin, streamnamesout);
	this->streamsout = manager->getStreamspecs(streamnamesout);
}

}
<|endoftext|>


<commit_before>// Import daughters of track with given label.

Reve::TrackList*
kine_daughter_tracks(Int_t label, Reve::TrackList* cont = 0)
{
  using namespace Reve;

  gSystem->IgnoreSignal(kSigSegmentationViolation, true);
  if (label < 0) {
    Warning("kine_daughter_tracks", "label not set.");
    return 0;
  }

  //Bool_t create_cont;
  //create_cont = cont ? 0:1;
  AliRunLoader* rl =  Alieve::Event::AssertRunLoader();
  rl->LoadKinematics();
  AliStack* stack = rl->Stack();

  TParticle* p = stack->Particle(label);
  if (p->GetNDaughters())
  {
    if (cont == 0)
    {
      printf("create container \n");
      cont =
	new TrackList(Form("%d kine_daughter_tracks %d", p->GetNDaughters(), label));

      Reve::TrackRnrStyle* rnrStyle = cont->GetRnrStyle();
      // !!! Watch the '-', apparently different sign convention then for ESD.
      rnrStyle->SetMagField( - gAlice->Field()->SolenoidField() );
      char tooltip[1000];
      sprintf(tooltip,"%d, mother %d", p->GetNDaughters(), label);
      cont->SetTitle(tooltip);
      cont->SelectByPt(0, 100);
      rnrStyle->fColor = 8;
      rnrStyle->fMaxOrbs = 8;
      gReve->AddRenderElement(cont);
    }

    for (int d=p->GetFirstDaughter(); d>0 && d<=p->GetLastDaughter(); ++d)
    {
      TParticle* dp = stack->Particle(d);
      Track* track = new Reve::Track(dp, d, cont->GetRnrStyle());
      char form[1000];
      sprintf(form,"%s [%d]", dp->GetName(), d);
      track->SetName(form);
      gReve->AddRenderElement(cont, track);
    }

    cont->UpdateItems(); // update list tree
    cont->MakeTracks();
    cont->MakeMarkers();
    gReve->Redraw3D();
    return cont;
  }
  else
  {
    printf("Particle %d does not have daughters.", label);
    return 0;
  }

}
<commit_msg>Set path marks in track container.<commit_after>// Import daughters of track with given label.

Reve::TrackList*
kine_daughter_tracks(Int_t label, Reve::TrackList* cont = 0)
{
  using namespace Reve;

  gSystem->IgnoreSignal(kSigSegmentationViolation, true);
  if (label < 0) {
    Warning("kine_daughter_tracks", "label not set.");
    return 0;
  }

  AliRunLoader* rl =  Alieve::Event::AssertRunLoader();
  rl->LoadKinematics();
  AliStack* stack = rl->Stack();

  TParticle* p = stack->Particle(label);
  if (p->GetNDaughters())
  {
    if (cont == 0)
    {
      cont = new TrackList(Form("%d kine_daughter_tracks %d",
				p->GetNDaughters(), label));

      Reve::TrackRnrStyle* rnrStyle = cont->GetRnrStyle();
      // !!! Watch the '-', apparently different sign convention then for ESD.
      rnrStyle->SetMagField( - gAlice->Field()->SolenoidField() );
      char tooltip[1000];
      sprintf(tooltip,"%d, mother %d", p->GetNDaughters(), label);
      cont->SetTitle(tooltip);
      cont->SelectByPt(0, 100);
      cont->SetEditPathMarks(kTRUE);
      rnrStyle->fColor = 8;
      rnrStyle->fMaxOrbs = 8;
      gReve->AddRenderElement(cont);
    }

    for (int d=p->GetFirstDaughter(); d>0 && d<=p->GetLastDaughter(); ++d)
    {
      TParticle* dp = stack->Particle(d);
      Track* track = new Reve::Track(dp, d, cont->GetRnrStyle());
      char form[1000];
      sprintf(form,"%s [%d]", dp->GetName(), d);
      track->SetName(form);
      gReve->AddRenderElement(cont, track);
    }

    // set path marks
    if(cont->GetEditPathMarks()) {
      Alieve::KineTools kt;
      rl->LoadTrackRefs();
      kt.SetPathMarks(cont,stack, rl->TreeTR());
    }

    cont->UpdateItems(); // update list tree
    cont->MakeTracks();
    cont->MakeMarkers();
    gReve->Redraw3D();
    return cont;
  }
  else
  {
    Warning("kine_daughters_tracks", Form("Particle %d does not have daughters %d.", label));
    return 0;
  }

}
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

// -*- c++ -*-

#include <faiss/IVFlib.h>

#include <memory>

#include <faiss/IndexPreTransform.h>
#include <faiss/impl/FaissAssert.h>
#include <faiss/MetaIndexes.h>

namespace faiss { namespace ivflib {

void check_compatible_for_merge (const Index * index0,
                                 const Index * index1)
{

    const faiss::IndexPreTransform *pt0 =
        dynamic_cast<const faiss::IndexPreTransform *>(index0);

    if (pt0) {
        const faiss::IndexPreTransform *pt1 =
            dynamic_cast<const faiss::IndexPreTransform *>(index1);
        FAISS_THROW_IF_NOT_MSG (pt1, "both indexes should be pretransforms");

        FAISS_THROW_IF_NOT (pt0->chain.size() == pt1->chain.size());
        for (int i = 0; i < pt0->chain.size(); i++) {
            FAISS_THROW_IF_NOT (typeid(pt0->chain[i]) == typeid(pt1->chain[i]));
        }

        index0 = pt0->index;
        index1 = pt1->index;
    }
    FAISS_THROW_IF_NOT (typeid(index0) == typeid(index1));
    FAISS_THROW_IF_NOT (index0->d == index1->d &&
                        index0->metric_type == index1->metric_type);

    const faiss::IndexIVF *ivf0 = dynamic_cast<const faiss::IndexIVF *>(index0);
    if (ivf0) {
        const faiss::IndexIVF *ivf1 =
            dynamic_cast<const faiss::IndexIVF *>(index1);
        FAISS_THROW_IF_NOT (ivf1);

        ivf0->check_compatible_for_merge (*ivf1);
    }

    // TODO: check as thoroughfully for other index types

}

const IndexIVF * try_extract_index_ivf (const Index * index)
{
    if (auto *pt =
        dynamic_cast<const IndexPreTransform *>(index)) {
        index = pt->index;
    }

    if (auto *idmap =
        dynamic_cast<const IndexIDMap *>(index)) {
        index = idmap->index;
    }
    if (auto *idmap =
        dynamic_cast<const IndexIDMap2 *>(index)) {
        index = idmap->index;
    }

    auto *ivf = dynamic_cast<const IndexIVF *>(index);

    return ivf;
}

IndexIVF * try_extract_index_ivf (Index * index) {
    return const_cast<IndexIVF*> (try_extract_index_ivf ((const Index*)(index)));
}

const IndexIVF * extract_index_ivf (const Index * index)
{
    const IndexIVF *ivf = try_extract_index_ivf (index);
    FAISS_THROW_IF_NOT (ivf);
    return ivf;
}

IndexIVF * extract_index_ivf (Index * index) {
    return const_cast<IndexIVF*> (extract_index_ivf ((const Index*)(index)));
}

void merge_into(faiss::Index *index0, faiss::Index *index1, bool shift_ids) {

    check_compatible_for_merge (index0, index1);
    IndexIVF * ivf0 = extract_index_ivf (index0);
    IndexIVF * ivf1 = extract_index_ivf (index1);

    ivf0->merge_from (*ivf1, shift_ids ? ivf0->ntotal : 0);

    // useful for IndexPreTransform
    index0->ntotal = ivf0->ntotal;
    index1->ntotal = ivf1->ntotal;
}

void search_centroid(faiss::Index *index,
                     const float* x, int n,
                     idx_t* centroid_ids)
{
    std::unique_ptr<float[]> del;
    if (auto index_pre = dynamic_cast<faiss::IndexPreTransform*>(index)) {
        x = index_pre->apply_chain(n, x);
        del.reset((float*)x);
        index = index_pre->index;
    }
    faiss::IndexIVF* index_ivf = dynamic_cast<faiss::IndexIVF*>(index);
    assert(index_ivf);
    index_ivf->quantizer->assign(n, x, centroid_ids);
}

void search_and_return_centroids(faiss::Index *index,
                                 size_t n,
                                 const float* xin,
                                 long k,
                                 float *distances,
                                 idx_t* labels,
                                 idx_t* query_centroid_ids,
                                 idx_t* result_centroid_ids)
{
    const float *x = xin;
    std::unique_ptr<float []> del;
    if (auto index_pre = dynamic_cast<faiss::IndexPreTransform*>(index)) {
        x = index_pre->apply_chain(n, x);
        del.reset((float*)x);
        index = index_pre->index;
    }
    faiss::IndexIVF* index_ivf = dynamic_cast<faiss::IndexIVF*>(index);
    assert(index_ivf);

    size_t nprobe = index_ivf->nprobe;
    std::vector<idx_t> cent_nos (n * nprobe);
    std::vector<float> cent_dis (n * nprobe);
    index_ivf->quantizer->search(
        n, x, nprobe, cent_dis.data(), cent_nos.data());

    if (query_centroid_ids) {
        for (size_t i = 0; i < n; i++)
            query_centroid_ids[i] = cent_nos[i * nprobe];
    }

    index_ivf->search_preassigned (n, x, k,
                                   cent_nos.data(), cent_dis.data(),
                                   distances, labels, true);

    for (size_t i = 0; i < n * k; i++) {
        idx_t label = labels[i];
        if (label < 0) {
            if (result_centroid_ids)
                result_centroid_ids[i] = -1;
        } else {
            long list_no = lo_listno (label);
            long list_index = lo_offset (label);
            if (result_centroid_ids)
                result_centroid_ids[i] = list_no;
            labels[i] = index_ivf->invlists->get_single_id(list_no, list_index);
        }
    }
}

SlidingIndexWindow::SlidingIndexWindow (Index *index): index (index) {
    n_slice = 0;
    IndexIVF* index_ivf = const_cast<IndexIVF*>(extract_index_ivf (index));
    ils = dynamic_cast<ArrayInvertedLists *> (index_ivf->invlists);
    nlist = ils->nlist;
    FAISS_THROW_IF_NOT_MSG (ils,
               "only supports indexes with ArrayInvertedLists");
    sizes.resize(nlist);
}

template<class T>
static void shift_and_add (std::vector<T> & dst,
                           size_t remove,
                           const std::vector<T> & src)
{
    if (remove > 0)
        memmove (dst.data(), dst.data() + remove,
                 (dst.size() - remove) * sizeof (T));
    size_t insert_point = dst.size() - remove;
    dst.resize (insert_point + src.size());
    memcpy (dst.data() + insert_point, src.data (), src.size() * sizeof(T));
}

template<class T>
static void remove_from_begin (std::vector<T> & v,
                               size_t remove)
{
    if (remove > 0)
        v.erase (v.begin(), v.begin() + remove);
}

void SlidingIndexWindow::step(const Index *sub_index, bool remove_oldest) {

    FAISS_THROW_IF_NOT_MSG (!remove_oldest || n_slice > 0,
                            "cannot remove slice: there is none");

    const ArrayInvertedLists *ils2 = nullptr;
    if(sub_index) {
        check_compatible_for_merge (index, sub_index);
        ils2 = dynamic_cast<const ArrayInvertedLists*>(
                                   extract_index_ivf (sub_index)->invlists);
        FAISS_THROW_IF_NOT_MSG (ils2, "supports only ArrayInvertedLists");
    }
    IndexIVF *index_ivf = extract_index_ivf (index);

    if (remove_oldest && ils2) {
        for (int i = 0; i < nlist; i++) {
            std::vector<size_t> & sizesi = sizes[i];
            size_t amount_to_remove = sizesi[0];
            index_ivf->ntotal += ils2->ids[i].size() - amount_to_remove;

            shift_and_add (ils->ids[i], amount_to_remove, ils2->ids[i]);
            shift_and_add (ils->codes[i], amount_to_remove * ils->code_size,
                           ils2->codes[i]);
            for (int j = 0; j + 1 < n_slice; j++) {
                sizesi[j] = sizesi[j + 1] - amount_to_remove;
            }
            sizesi[n_slice - 1] = ils->ids[i].size();
        }
    } else if (ils2) {
        for (int i = 0; i < nlist; i++) {
            index_ivf->ntotal += ils2->ids[i].size();
            shift_and_add (ils->ids[i], 0, ils2->ids[i]);
            shift_and_add (ils->codes[i], 0, ils2->codes[i]);
            sizes[i].push_back(ils->ids[i].size());
        }
        n_slice++;
    } else if (remove_oldest) {
        for (int i = 0; i < nlist; i++) {
            size_t amount_to_remove = sizes[i][0];
            index_ivf->ntotal -= amount_to_remove;
            remove_from_begin (ils->ids[i], amount_to_remove);
            remove_from_begin (ils->codes[i],
                               amount_to_remove * ils->code_size);
            for (int j = 0; j + 1 < n_slice; j++) {
                sizes[i][j] = sizes[i][j + 1] - amount_to_remove;
            }
            sizes[i].pop_back ();
        }
        n_slice--;
    } else {
        FAISS_THROW_MSG ("nothing to do???");
    }
    index->ntotal = index_ivf->ntotal;
}

// Get a subset of inverted lists [i0, i1). Works on IndexIVF's and
// IndexIVF's embedded in a IndexPreTransform

ArrayInvertedLists *
get_invlist_range (const Index *index, long i0, long i1)
{
    const IndexIVF *ivf = extract_index_ivf (index);

    FAISS_THROW_IF_NOT (0 <= i0 && i0 <= i1 && i1 <= ivf->nlist);

    const InvertedLists *src = ivf->invlists;

    ArrayInvertedLists * il = new ArrayInvertedLists(i1 - i0, src->code_size);

    for (long i = i0; i < i1; i++) {
        il->add_entries(i - i0, src->list_size(i),
                        InvertedLists::ScopedIds (src, i).get(),
                        InvertedLists::ScopedCodes (src, i).get());
    }
    return il;
}

void set_invlist_range (Index *index, long i0, long i1,
                        ArrayInvertedLists * src)
{
    IndexIVF *ivf = extract_index_ivf (index);

    FAISS_THROW_IF_NOT (0 <= i0 && i0 <= i1 && i1 <= ivf->nlist);

    ArrayInvertedLists *dst = dynamic_cast<ArrayInvertedLists *>(ivf->invlists);
    FAISS_THROW_IF_NOT_MSG (dst, "only ArrayInvertedLists supported");
    FAISS_THROW_IF_NOT (src->nlist == i1 - i0 &&
                        dst->code_size == src->code_size);

    size_t ntotal = index->ntotal;
    for (long i = i0 ; i < i1; i++) {
        ntotal -= dst->list_size (i);
        ntotal += src->list_size (i - i0);
        std::swap (src->codes[i - i0], dst->codes[i]);
        std::swap (src->ids[i - i0], dst->ids[i]);
    }
    ivf->ntotal = index->ntotal = ntotal;
}

void search_with_parameters (const Index *index,
                             idx_t n, const float *x, idx_t k,
                             float *distances, idx_t *labels,
                             IVFSearchParameters *params,
                             size_t *nb_dis_ptr)
{
    FAISS_THROW_IF_NOT (params);
    const float *prev_x = x;
    ScopeDeleter<float> del;

    if (auto ip = dynamic_cast<const IndexPreTransform *> (index)) {
        x = ip->apply_chain (n, x);
        if (x != prev_x) {
            del.set(x);
        }
        index = ip->index;
    }

    std::vector<idx_t> Iq(params->nprobe * n);
    std::vector<float> Dq(params->nprobe * n);

    const IndexIVF *index_ivf = dynamic_cast<const IndexIVF *>(index);
    FAISS_THROW_IF_NOT (index_ivf);

    index_ivf->quantizer->search(n, x, params->nprobe,
                                 Dq.data(), Iq.data());

    if (nb_dis_ptr) {
        size_t nb_dis = 0;
        const InvertedLists *il = index_ivf->invlists;
        for (idx_t i = 0; i < n * params->nprobe; i++) {
          if (Iq[i] >= 0) {
              nb_dis += il->list_size(Iq[i]);
          }
        }
        *nb_dis_ptr = nb_dis;
    }

    index_ivf->search_preassigned(n, x, k, Iq.data(), Dq.data(),
                                  distances, labels,
                                  false, params);
}

} } // namespace faiss::ivflib
<commit_msg>fix ivflib (#1410)<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

// -*- c++ -*-

#include <faiss/IVFlib.h>

#include <memory>

#include <faiss/IndexPreTransform.h>
#include <faiss/impl/FaissAssert.h>
#include <faiss/MetaIndexes.h>

namespace faiss { namespace ivflib {

void check_compatible_for_merge (const Index * index0,
                                 const Index * index1)
{

    const faiss::IndexPreTransform *pt0 =
        dynamic_cast<const faiss::IndexPreTransform *>(index0);

    if (pt0) {
        const faiss::IndexPreTransform *pt1 =
            dynamic_cast<const faiss::IndexPreTransform *>(index1);
        FAISS_THROW_IF_NOT_MSG (pt1, "both indexes should be pretransforms");

        FAISS_THROW_IF_NOT (pt0->chain.size() == pt1->chain.size());
        for (int i = 0; i < pt0->chain.size(); i++) {
            FAISS_THROW_IF_NOT (typeid(pt0->chain[i]) == typeid(pt1->chain[i]));
        }

        index0 = pt0->index;
        index1 = pt1->index;
    }
    FAISS_THROW_IF_NOT (typeid(index0) == typeid(index1));
    FAISS_THROW_IF_NOT (index0->d == index1->d &&
                        index0->metric_type == index1->metric_type);

    const faiss::IndexIVF *ivf0 = dynamic_cast<const faiss::IndexIVF *>(index0);
    if (ivf0) {
        const faiss::IndexIVF *ivf1 =
            dynamic_cast<const faiss::IndexIVF *>(index1);
        FAISS_THROW_IF_NOT (ivf1);

        ivf0->check_compatible_for_merge (*ivf1);
    }

    // TODO: check as thoroughfully for other index types

}

const IndexIVF * try_extract_index_ivf (const Index * index)
{
    if (auto *pt =
        dynamic_cast<const IndexPreTransform *>(index)) {
        index = pt->index;
    }

    if (auto *idmap =
        dynamic_cast<const IndexIDMap *>(index)) {
        index = idmap->index;
    }
    if (auto *idmap =
        dynamic_cast<const IndexIDMap2 *>(index)) {
        index = idmap->index;
    }

    auto *ivf = dynamic_cast<const IndexIVF *>(index);

    return ivf;
}

IndexIVF * try_extract_index_ivf (Index * index) {
    return const_cast<IndexIVF*> (try_extract_index_ivf ((const Index*)(index)));
}

const IndexIVF * extract_index_ivf (const Index * index)
{
    const IndexIVF *ivf = try_extract_index_ivf (index);
    FAISS_THROW_IF_NOT (ivf);
    return ivf;
}

IndexIVF * extract_index_ivf (Index * index) {
    return const_cast<IndexIVF*> (extract_index_ivf ((const Index*)(index)));
}

void merge_into(faiss::Index *index0, faiss::Index *index1, bool shift_ids) {

    check_compatible_for_merge (index0, index1);
    IndexIVF * ivf0 = extract_index_ivf (index0);
    IndexIVF * ivf1 = extract_index_ivf (index1);

    ivf0->merge_from (*ivf1, shift_ids ? ivf0->ntotal : 0);

    // useful for IndexPreTransform
    index0->ntotal = ivf0->ntotal;
    index1->ntotal = ivf1->ntotal;
}

void search_centroid(faiss::Index *index,
                     const float* x, int n,
                     idx_t* centroid_ids)
{
    std::unique_ptr<float[]> del;
    if (auto index_pre = dynamic_cast<faiss::IndexPreTransform*>(index)) {
        x = index_pre->apply_chain(n, x);
        del.reset((float*)x);
        index = index_pre->index;
    }
    faiss::IndexIVF* index_ivf = dynamic_cast<faiss::IndexIVF*>(index);
    assert(index_ivf);
    index_ivf->quantizer->assign(n, x, centroid_ids);
}

void search_and_return_centroids(faiss::Index *index,
                                 size_t n,
                                 const float* xin,
                                 long k,
                                 float *distances,
                                 idx_t* labels,
                                 idx_t* query_centroid_ids,
                                 idx_t* result_centroid_ids)
{
    const float *x = xin;
    std::unique_ptr<float []> del;
    if (auto index_pre = dynamic_cast<faiss::IndexPreTransform*>(index)) {
        x = index_pre->apply_chain(n, x);
        del.reset((float*)x);
        index = index_pre->index;
    }
    faiss::IndexIVF* index_ivf = dynamic_cast<faiss::IndexIVF*>(index);
    assert(index_ivf);

    size_t nprobe = index_ivf->nprobe;
    std::vector<idx_t> cent_nos (n * nprobe);
    std::vector<float> cent_dis (n * nprobe);
    index_ivf->quantizer->search(
        n, x, nprobe, cent_dis.data(), cent_nos.data());

    if (query_centroid_ids) {
        for (size_t i = 0; i < n; i++)
            query_centroid_ids[i] = cent_nos[i * nprobe];
    }

    index_ivf->search_preassigned (n, x, k,
                                   cent_nos.data(), cent_dis.data(),
                                   distances, labels, true);

    for (size_t i = 0; i < n * k; i++) {
        idx_t label = labels[i];
        if (label < 0) {
            if (result_centroid_ids)
                result_centroid_ids[i] = -1;
        } else {
            long list_no = lo_listno (label);
            long list_index = lo_offset (label);
            if (result_centroid_ids)
                result_centroid_ids[i] = list_no;
            labels[i] = index_ivf->invlists->get_single_id(list_no, list_index);
        }
    }
}

SlidingIndexWindow::SlidingIndexWindow (Index *index): index (index) {
    n_slice = 0;
    IndexIVF* index_ivf = const_cast<IndexIVF*>(extract_index_ivf (index));
    ils = dynamic_cast<ArrayInvertedLists *> (index_ivf->invlists);
    FAISS_THROW_IF_NOT_MSG (ils,
               "only supports indexes with ArrayInvertedLists");
    nlist = ils->nlist;
    sizes.resize(nlist);
}

template<class T>
static void shift_and_add (std::vector<T> & dst,
                           size_t remove,
                           const std::vector<T> & src)
{
    if (remove > 0)
        memmove (dst.data(), dst.data() + remove,
                 (dst.size() - remove) * sizeof (T));
    size_t insert_point = dst.size() - remove;
    dst.resize (insert_point + src.size());
    memcpy (dst.data() + insert_point, src.data (), src.size() * sizeof(T));
}

template<class T>
static void remove_from_begin (std::vector<T> & v,
                               size_t remove)
{
    if (remove > 0)
        v.erase (v.begin(), v.begin() + remove);
}

void SlidingIndexWindow::step(const Index *sub_index, bool remove_oldest) {

    FAISS_THROW_IF_NOT_MSG (!remove_oldest || n_slice > 0,
                            "cannot remove slice: there is none");

    const ArrayInvertedLists *ils2 = nullptr;
    if(sub_index) {
        check_compatible_for_merge (index, sub_index);
        ils2 = dynamic_cast<const ArrayInvertedLists*>(
                                   extract_index_ivf (sub_index)->invlists);
        FAISS_THROW_IF_NOT_MSG (ils2, "supports only ArrayInvertedLists");
    }
    IndexIVF *index_ivf = extract_index_ivf (index);

    if (remove_oldest && ils2) {
        for (int i = 0; i < nlist; i++) {
            std::vector<size_t> & sizesi = sizes[i];
            size_t amount_to_remove = sizesi[0];
            index_ivf->ntotal += ils2->ids[i].size() - amount_to_remove;

            shift_and_add (ils->ids[i], amount_to_remove, ils2->ids[i]);
            shift_and_add (ils->codes[i], amount_to_remove * ils->code_size,
                           ils2->codes[i]);
            for (int j = 0; j + 1 < n_slice; j++) {
                sizesi[j] = sizesi[j + 1] - amount_to_remove;
            }
            sizesi[n_slice - 1] = ils->ids[i].size();
        }
    } else if (ils2) {
        for (int i = 0; i < nlist; i++) {
            index_ivf->ntotal += ils2->ids[i].size();
            shift_and_add (ils->ids[i], 0, ils2->ids[i]);
            shift_and_add (ils->codes[i], 0, ils2->codes[i]);
            sizes[i].push_back(ils->ids[i].size());
        }
        n_slice++;
    } else if (remove_oldest) {
        for (int i = 0; i < nlist; i++) {
            size_t amount_to_remove = sizes[i][0];
            index_ivf->ntotal -= amount_to_remove;
            remove_from_begin (ils->ids[i], amount_to_remove);
            remove_from_begin (ils->codes[i],
                               amount_to_remove * ils->code_size);
            for (int j = 0; j + 1 < n_slice; j++) {
                sizes[i][j] = sizes[i][j + 1] - amount_to_remove;
            }
            sizes[i].pop_back ();
        }
        n_slice--;
    } else {
        FAISS_THROW_MSG ("nothing to do???");
    }
    index->ntotal = index_ivf->ntotal;
}

// Get a subset of inverted lists [i0, i1). Works on IndexIVF's and
// IndexIVF's embedded in a IndexPreTransform

ArrayInvertedLists *
get_invlist_range (const Index *index, long i0, long i1)
{
    const IndexIVF *ivf = extract_index_ivf (index);

    FAISS_THROW_IF_NOT (0 <= i0 && i0 <= i1 && i1 <= ivf->nlist);

    const InvertedLists *src = ivf->invlists;

    ArrayInvertedLists * il = new ArrayInvertedLists(i1 - i0, src->code_size);

    for (long i = i0; i < i1; i++) {
        il->add_entries(i - i0, src->list_size(i),
                        InvertedLists::ScopedIds (src, i).get(),
                        InvertedLists::ScopedCodes (src, i).get());
    }
    return il;
}

void set_invlist_range (Index *index, long i0, long i1,
                        ArrayInvertedLists * src)
{
    IndexIVF *ivf = extract_index_ivf (index);

    FAISS_THROW_IF_NOT (0 <= i0 && i0 <= i1 && i1 <= ivf->nlist);

    ArrayInvertedLists *dst = dynamic_cast<ArrayInvertedLists *>(ivf->invlists);
    FAISS_THROW_IF_NOT_MSG (dst, "only ArrayInvertedLists supported");
    FAISS_THROW_IF_NOT (src->nlist == i1 - i0 &&
                        dst->code_size == src->code_size);

    size_t ntotal = index->ntotal;
    for (long i = i0 ; i < i1; i++) {
        ntotal -= dst->list_size (i);
        ntotal += src->list_size (i - i0);
        std::swap (src->codes[i - i0], dst->codes[i]);
        std::swap (src->ids[i - i0], dst->ids[i]);
    }
    ivf->ntotal = index->ntotal = ntotal;
}

void search_with_parameters (const Index *index,
                             idx_t n, const float *x, idx_t k,
                             float *distances, idx_t *labels,
                             IVFSearchParameters *params,
                             size_t *nb_dis_ptr)
{
    FAISS_THROW_IF_NOT (params);
    const float *prev_x = x;
    ScopeDeleter<float> del;

    if (auto ip = dynamic_cast<const IndexPreTransform *> (index)) {
        x = ip->apply_chain (n, x);
        if (x != prev_x) {
            del.set(x);
        }
        index = ip->index;
    }

    std::vector<idx_t> Iq(params->nprobe * n);
    std::vector<float> Dq(params->nprobe * n);

    const IndexIVF *index_ivf = dynamic_cast<const IndexIVF *>(index);
    FAISS_THROW_IF_NOT (index_ivf);

    index_ivf->quantizer->search(n, x, params->nprobe,
                                 Dq.data(), Iq.data());

    if (nb_dis_ptr) {
        size_t nb_dis = 0;
        const InvertedLists *il = index_ivf->invlists;
        for (idx_t i = 0; i < n * params->nprobe; i++) {
          if (Iq[i] >= 0) {
              nb_dis += il->list_size(Iq[i]);
          }
        }
        *nb_dis_ptr = nb_dis;
    }

    index_ivf->search_preassigned(n, x, k, Iq.data(), Dq.data(),
                                  distances, labels,
                                  false, params);
}

} } // namespace faiss::ivflib
<|endoftext|>


<commit_before>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/midi/midi_manager_mac.h"

#include <iostream>
#include <string>

#include "base/debug/trace_event.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"
#include <CoreAudio/HostTime.h>

using base::IntToString;
using base::SysCFStringRefToUTF8;
using std::string;

// NB: System MIDI types are pointer types in 32-bit and integer types in
// 64-bit. Therefore, the initialization is the simplest one that satisfies both
// (if possible).

namespace media {

MIDIManager* MIDIManager::Create() {
  return new MIDIManagerMac();
}

MIDIManagerMac::MIDIManagerMac()
    : midi_client_(0),
      coremidi_input_(0),
      coremidi_output_(0),
      packet_list_(NULL),
      midi_packet_(NULL) {
}

bool MIDIManagerMac::Initialize() {
  TRACE_EVENT0("midi", "MIDIManagerMac::Initialize");

  // CoreMIDI registration.
  midi_client_ = 0;
  OSStatus result = MIDIClientCreate(
      CFSTR("Google Chrome"),
      NULL,
      NULL,
      &midi_client_);

  if (result != noErr)
    return false;

  coremidi_input_ = 0;

  // Create input and output port.
  result = MIDIInputPortCreate(
      midi_client_,
      CFSTR("MIDI Input"),
      ReadMidiDispatch,
      this,
      &coremidi_input_);
  if (result != noErr)
    return false;

  result = MIDIOutputPortCreate(
      midi_client_,
      CFSTR("MIDI Output"),
      &coremidi_output_);
  if (result != noErr)
    return false;

  int destination_count = MIDIGetNumberOfDestinations();
  destinations_.reserve(destination_count);

  for (int i = 0; i < destination_count ; i++) {
    MIDIEndpointRef destination = MIDIGetDestination(i);

    // Keep track of all destinations (known as outputs by the Web MIDI API).
    // Cache to avoid any possible overhead in calling MIDIGetDestination().
    destinations_[i] = destination;

    MIDIPortInfo info = GetPortInfoFromEndpoint(destination);
    AddOutputPort(info);
  }

  // Open connections from all sources.
  int source_count = MIDIGetNumberOfSources();

  for (int i = 0; i < source_count; ++i)  {
    // Receive from all sources.
    MIDIEndpointRef src = MIDIGetSource(i);
    MIDIPortConnectSource(coremidi_input_, src, reinterpret_cast<void*>(src));

    // Keep track of all sources (known as inputs in Web MIDI API terminology).
    source_map_[src] = i;

    MIDIPortInfo info = GetPortInfoFromEndpoint(src);
    AddInputPort(info);
  }

  // TODO(crogers): Fix the memory management here!
  packet_list_ = reinterpret_cast<MIDIPacketList*>(midi_buffer_);
  midi_packet_ = MIDIPacketListInit(packet_list_);

  return true;
}

MIDIManagerMac::~MIDIManagerMac() {
  if (coremidi_input_)
    MIDIPortDispose(coremidi_input_);
  if (coremidi_output_)
    MIDIPortDispose(coremidi_output_);
}

void MIDIManagerMac::ReadMidiDispatch(const MIDIPacketList* packet_list,
                                      void* read_proc_refcon,
                                      void* src_conn_refcon) {
  MIDIManagerMac* manager = static_cast<MIDIManagerMac*>(read_proc_refcon);
#if __LP64__
  MIDIEndpointRef source = reinterpret_cast<uintptr_t>(src_conn_refcon);
#else
  MIDIEndpointRef source = static_cast<MIDIEndpointRef>(src_conn_refcon);
#endif

  // Dispatch to class method.
  manager->ReadMidi(source, packet_list);
}

void MIDIManagerMac::ReadMidi(MIDIEndpointRef source,
                              const MIDIPacketList* packet_list) {
  // Lookup the port index based on the source.
  SourceMap::iterator j = source_map_.find(source);
  if (j == source_map_.end())
    return;
  int port_index = source_map_[source];

  // Go through each packet and process separately.
  for(size_t i = 0; i < packet_list->numPackets; i++) {
    // Each packet contains MIDI data for one or more messages (like note-on).
    const MIDIPacket &packet = packet_list->packet[i];
    double timestamp_seconds = MIDITimeStampToSeconds(packet.timeStamp);

    ReceiveMIDIData(
        port_index,
        packet.data,
        packet.length,
        timestamp_seconds);
  }
}

void MIDIManagerMac::SendMIDIData(MIDIManagerClient* client,
                                  int port_index,
                                  const uint8* data,
                                  size_t length,
                                  double timestamp) {
  // System Exclusive has already been filtered.
  MIDITimeStamp coremidi_timestamp = SecondsToMIDITimeStamp(timestamp);

  midi_packet_ = MIDIPacketListAdd(
      packet_list_,
      kMaxPacketListSize,
      midi_packet_,
      coremidi_timestamp,
      length,
      data);

  // Lookup the destination based on the port index.
  // TODO(crogers): re-factor |port_index| to use unsigned
  // to avoid the need for this check.
  if (port_index < 0 ||
      static_cast<size_t>(port_index) >= destinations_.size())
    return;

  MIDIEndpointRef destination = destinations_[port_index];

  MIDISend(coremidi_output_, destination, packet_list_);

  // Re-initialize for next time.
  midi_packet_ = MIDIPacketListInit(packet_list_);

  client->AccumulateMIDIBytesSent(length);
}

MIDIPortInfo MIDIManagerMac::GetPortInfoFromEndpoint(
    MIDIEndpointRef endpoint) {
  SInt32 id_number = 0;
  MIDIObjectGetIntegerProperty(endpoint, kMIDIPropertyUniqueID, &id_number);
  string id = IntToString(id_number);

  CFStringRef manufacturer_ref = NULL;
  MIDIObjectGetStringProperty(
      endpoint, kMIDIPropertyManufacturer, &manufacturer_ref);
  string manufacturer = SysCFStringRefToUTF8(manufacturer_ref);

  CFStringRef name_ref = NULL;
  MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &name_ref);
  string name = SysCFStringRefToUTF8(name_ref);

  SInt32 version_number = 0;
  MIDIObjectGetIntegerProperty(
      endpoint, kMIDIPropertyDriverVersion, &version_number);
  string version = IntToString(version_number);

  return MIDIPortInfo(id, manufacturer, name, version);
}

double MIDIManagerMac::MIDITimeStampToSeconds(MIDITimeStamp timestamp) {
  UInt64 nanoseconds = AudioConvertHostTimeToNanos(timestamp);
  return static_cast<double>(nanoseconds) / 1.0e9;
}

MIDITimeStamp MIDIManagerMac::SecondsToMIDITimeStamp(double seconds) {
  UInt64 nanos = UInt64(seconds * 1.0e9);
  return AudioConvertNanosToHostTime(nanos);
}

}  // namespace media
<commit_msg>Web MIDI: bug fix to make send operations work<commit_after>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/midi/midi_manager_mac.h"

#include <iostream>
#include <string>

#include "base/debug/trace_event.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"
#include <CoreAudio/HostTime.h>

using base::IntToString;
using base::SysCFStringRefToUTF8;
using std::string;

// NB: System MIDI types are pointer types in 32-bit and integer types in
// 64-bit. Therefore, the initialization is the simplest one that satisfies both
// (if possible).

namespace media {

MIDIManager* MIDIManager::Create() {
  return new MIDIManagerMac();
}

MIDIManagerMac::MIDIManagerMac()
    : midi_client_(0),
      coremidi_input_(0),
      coremidi_output_(0),
      packet_list_(NULL),
      midi_packet_(NULL) {
}

bool MIDIManagerMac::Initialize() {
  TRACE_EVENT0("midi", "MIDIManagerMac::Initialize");

  // CoreMIDI registration.
  midi_client_ = 0;
  OSStatus result = MIDIClientCreate(
      CFSTR("Google Chrome"),
      NULL,
      NULL,
      &midi_client_);

  if (result != noErr)
    return false;

  coremidi_input_ = 0;

  // Create input and output port.
  result = MIDIInputPortCreate(
      midi_client_,
      CFSTR("MIDI Input"),
      ReadMidiDispatch,
      this,
      &coremidi_input_);
  if (result != noErr)
    return false;

  result = MIDIOutputPortCreate(
      midi_client_,
      CFSTR("MIDI Output"),
      &coremidi_output_);
  if (result != noErr)
    return false;

  int destination_count = MIDIGetNumberOfDestinations();
  destinations_.resize(destination_count);

  for (int i = 0; i < destination_count ; i++) {
    MIDIEndpointRef destination = MIDIGetDestination(i);

    // Keep track of all destinations (known as outputs by the Web MIDI API).
    // Cache to avoid any possible overhead in calling MIDIGetDestination().
    destinations_[i] = destination;

    MIDIPortInfo info = GetPortInfoFromEndpoint(destination);
    AddOutputPort(info);
  }

  // Open connections from all sources.
  int source_count = MIDIGetNumberOfSources();

  for (int i = 0; i < source_count; ++i)  {
    // Receive from all sources.
    MIDIEndpointRef src = MIDIGetSource(i);
    MIDIPortConnectSource(coremidi_input_, src, reinterpret_cast<void*>(src));

    // Keep track of all sources (known as inputs in Web MIDI API terminology).
    source_map_[src] = i;

    MIDIPortInfo info = GetPortInfoFromEndpoint(src);
    AddInputPort(info);
  }

  // TODO(crogers): Fix the memory management here!
  packet_list_ = reinterpret_cast<MIDIPacketList*>(midi_buffer_);
  midi_packet_ = MIDIPacketListInit(packet_list_);

  return true;
}

MIDIManagerMac::~MIDIManagerMac() {
  if (coremidi_input_)
    MIDIPortDispose(coremidi_input_);
  if (coremidi_output_)
    MIDIPortDispose(coremidi_output_);
}

void MIDIManagerMac::ReadMidiDispatch(const MIDIPacketList* packet_list,
                                      void* read_proc_refcon,
                                      void* src_conn_refcon) {
  MIDIManagerMac* manager = static_cast<MIDIManagerMac*>(read_proc_refcon);
#if __LP64__
  MIDIEndpointRef source = reinterpret_cast<uintptr_t>(src_conn_refcon);
#else
  MIDIEndpointRef source = static_cast<MIDIEndpointRef>(src_conn_refcon);
#endif

  // Dispatch to class method.
  manager->ReadMidi(source, packet_list);
}

void MIDIManagerMac::ReadMidi(MIDIEndpointRef source,
                              const MIDIPacketList* packet_list) {
  // Lookup the port index based on the source.
  SourceMap::iterator j = source_map_.find(source);
  if (j == source_map_.end())
    return;
  int port_index = source_map_[source];

  // Go through each packet and process separately.
  for(size_t i = 0; i < packet_list->numPackets; i++) {
    // Each packet contains MIDI data for one or more messages (like note-on).
    const MIDIPacket &packet = packet_list->packet[i];
    double timestamp_seconds = MIDITimeStampToSeconds(packet.timeStamp);

    ReceiveMIDIData(
        port_index,
        packet.data,
        packet.length,
        timestamp_seconds);
  }
}

void MIDIManagerMac::SendMIDIData(MIDIManagerClient* client,
                                  int port_index,
                                  const uint8* data,
                                  size_t length,
                                  double timestamp) {
  // System Exclusive has already been filtered.
  MIDITimeStamp coremidi_timestamp = SecondsToMIDITimeStamp(timestamp);

  midi_packet_ = MIDIPacketListAdd(
      packet_list_,
      kMaxPacketListSize,
      midi_packet_,
      coremidi_timestamp,
      length,
      data);

  // Lookup the destination based on the port index.
  // TODO(crogers): re-factor |port_index| to use unsigned
  // to avoid the need for this check.
  if (port_index < 0 ||
      static_cast<size_t>(port_index) >= destinations_.size())
    return;

  MIDIEndpointRef destination = destinations_[port_index];

  MIDISend(coremidi_output_, destination, packet_list_);

  // Re-initialize for next time.
  midi_packet_ = MIDIPacketListInit(packet_list_);

  client->AccumulateMIDIBytesSent(length);
}

MIDIPortInfo MIDIManagerMac::GetPortInfoFromEndpoint(
    MIDIEndpointRef endpoint) {
  SInt32 id_number = 0;
  MIDIObjectGetIntegerProperty(endpoint, kMIDIPropertyUniqueID, &id_number);
  string id = IntToString(id_number);

  CFStringRef manufacturer_ref = NULL;
  MIDIObjectGetStringProperty(
      endpoint, kMIDIPropertyManufacturer, &manufacturer_ref);
  string manufacturer = SysCFStringRefToUTF8(manufacturer_ref);

  CFStringRef name_ref = NULL;
  MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &name_ref);
  string name = SysCFStringRefToUTF8(name_ref);

  SInt32 version_number = 0;
  MIDIObjectGetIntegerProperty(
      endpoint, kMIDIPropertyDriverVersion, &version_number);
  string version = IntToString(version_number);

  return MIDIPortInfo(id, manufacturer, name, version);
}

double MIDIManagerMac::MIDITimeStampToSeconds(MIDITimeStamp timestamp) {
  UInt64 nanoseconds = AudioConvertHostTimeToNanos(timestamp);
  return static_cast<double>(nanoseconds) / 1.0e9;
}

MIDITimeStamp MIDIManagerMac::SecondsToMIDITimeStamp(double seconds) {
  UInt64 nanos = UInt64(seconds * 1.0e9);
  return AudioConvertNanosToHostTime(nanos);
}

}  // namespace media
<|endoftext|>


<commit_before>//===-- CodeGen/AsmPrinter/DwarfException.cpp - Dwarf Exception Impl ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains support for writing DWARF exception info into asm files.
//
//===----------------------------------------------------------------------===//

#include "DwarfException.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineLocation.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Target/Mangler.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetFrameLowering.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
using namespace llvm;

DwarfCFIException::DwarfCFIException(AsmPrinter *A)
  : DwarfException(A),
    shouldEmitPersonality(false), shouldEmitLSDA(false), shouldEmitMoves(false)
    {}

DwarfCFIException::~DwarfCFIException() {}

/// EndModule - Emit all exception information that should come after the
/// content.
void DwarfCFIException::EndModule() {
  if (moveTypeModule == AsmPrinter::CFI_M_Debug)
    Asm->OutStreamer.EmitCFISections(false, true);

  if (!Asm->MAI->isExceptionHandlingDwarf())
    return;

  const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();

  unsigned PerEncoding = TLOF.getPersonalityEncoding();

  if ((PerEncoding & 0x70) != dwarf::DW_EH_PE_pcrel)
    return;

  // Emit references to all used personality functions
  bool AtLeastOne = false;
  const std::vector<const Function*> &Personalities = MMI->getPersonalities();
  for (size_t i = 0, e = Personalities.size(); i != e; ++i) {
    if (!Personalities[i])
      continue;
    MCSymbol *Sym = Asm->Mang->getSymbol(Personalities[i]);
    TLOF.emitPersonalityValue(Asm->OutStreamer, Asm->TM, Sym);
    AtLeastOne = true;
  }

  if (AtLeastOne && !TLOF.isFunctionEHFrameSymbolPrivate()) {
    // This is a temporary hack to keep sections in the same order they
    // were before. This lets us produce bit identical outputs while
    // transitioning to CFI.
    Asm->OutStreamer.SwitchSection(TLOF.getEHFrameSection());
  }
}

/// BeginFunction - Gather pre-function exception information. Assumes it's
/// being emitted immediately after the function entry point.
void DwarfCFIException::BeginFunction(const MachineFunction *MF) {
  shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false;

  // If any landing pads survive, we need an EH table.
  bool hasLandingPads = !MMI->getLandingPads().empty();

  // See if we need frame move info.
  AsmPrinter::CFIMoveType MoveType = Asm->needsCFIMoves();
  if (MoveType == AsmPrinter::CFI_M_EH ||
      (MoveType == AsmPrinter::CFI_M_Debug &&
       moveTypeModule == AsmPrinter::CFI_M_None))
    moveTypeModule = MoveType;

  shouldEmitMoves = MoveType != AsmPrinter::CFI_M_None;

  const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
  unsigned PerEncoding = TLOF.getPersonalityEncoding();
  const Function *Per = MMI->getPersonalities()[MMI->getPersonalityIndex()];

  shouldEmitPersonality = hasLandingPads &&
    PerEncoding != dwarf::DW_EH_PE_omit && Per;

  unsigned LSDAEncoding = TLOF.getLSDAEncoding();
  shouldEmitLSDA = shouldEmitPersonality &&
    LSDAEncoding != dwarf::DW_EH_PE_omit;

  if (!shouldEmitPersonality && !shouldEmitMoves)
    return;

  Asm->OutStreamer.EmitCFIStartProc();

  // Indicate personality routine, if any.
  if (!shouldEmitPersonality)
    return;

  const MCSymbol *Sym = TLOF.getCFIPersonalitySymbol(Per, Asm->Mang, MMI);
  Asm->OutStreamer.EmitCFIPersonality(Sym, PerEncoding);

  Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_begin",
                                                Asm->getFunctionNumber()));

  // Provide LSDA information.
  if (!shouldEmitLSDA)
    return;

  Asm->OutStreamer.EmitCFILsda(Asm->GetTempSymbol("exception",
                                                  Asm->getFunctionNumber()),
                               LSDAEncoding);
}

/// EndFunction - Gather and emit post-function exception information.
///
void DwarfCFIException::EndFunction() {
  if (!shouldEmitPersonality && !shouldEmitMoves)
    return;

  Asm->OutStreamer.EmitCFIEndProc();

  Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_end",
                                                Asm->getFunctionNumber()));

  // Map all labels and get rid of any dead landing pads.
  MMI->TidyLandingPads();

  if (shouldEmitPersonality)
    EmitExceptionTable();
}
<commit_msg>Initialize moveTypeModule.<commit_after>//===-- CodeGen/AsmPrinter/DwarfException.cpp - Dwarf Exception Impl ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains support for writing DWARF exception info into asm files.
//
//===----------------------------------------------------------------------===//

#include "DwarfException.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineLocation.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Target/Mangler.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetFrameLowering.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
using namespace llvm;

DwarfCFIException::DwarfCFIException(AsmPrinter *A)
  : DwarfException(A),
    shouldEmitPersonality(false), shouldEmitLSDA(false), shouldEmitMoves(false),
    moveTypeModule(AsmPrinter::CFI_M_None) {}

DwarfCFIException::~DwarfCFIException() {}

/// EndModule - Emit all exception information that should come after the
/// content.
void DwarfCFIException::EndModule() {
  if (moveTypeModule == AsmPrinter::CFI_M_Debug)
    Asm->OutStreamer.EmitCFISections(false, true);

  if (!Asm->MAI->isExceptionHandlingDwarf())
    return;

  const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();

  unsigned PerEncoding = TLOF.getPersonalityEncoding();

  if ((PerEncoding & 0x70) != dwarf::DW_EH_PE_pcrel)
    return;

  // Emit references to all used personality functions
  bool AtLeastOne = false;
  const std::vector<const Function*> &Personalities = MMI->getPersonalities();
  for (size_t i = 0, e = Personalities.size(); i != e; ++i) {
    if (!Personalities[i])
      continue;
    MCSymbol *Sym = Asm->Mang->getSymbol(Personalities[i]);
    TLOF.emitPersonalityValue(Asm->OutStreamer, Asm->TM, Sym);
    AtLeastOne = true;
  }

  if (AtLeastOne && !TLOF.isFunctionEHFrameSymbolPrivate()) {
    // This is a temporary hack to keep sections in the same order they
    // were before. This lets us produce bit identical outputs while
    // transitioning to CFI.
    Asm->OutStreamer.SwitchSection(TLOF.getEHFrameSection());
  }
}

/// BeginFunction - Gather pre-function exception information. Assumes it's
/// being emitted immediately after the function entry point.
void DwarfCFIException::BeginFunction(const MachineFunction *MF) {
  shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false;

  // If any landing pads survive, we need an EH table.
  bool hasLandingPads = !MMI->getLandingPads().empty();

  // See if we need frame move info.
  AsmPrinter::CFIMoveType MoveType = Asm->needsCFIMoves();
  if (MoveType == AsmPrinter::CFI_M_EH ||
      (MoveType == AsmPrinter::CFI_M_Debug &&
       moveTypeModule == AsmPrinter::CFI_M_None))
    moveTypeModule = MoveType;

  shouldEmitMoves = MoveType != AsmPrinter::CFI_M_None;

  const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
  unsigned PerEncoding = TLOF.getPersonalityEncoding();
  const Function *Per = MMI->getPersonalities()[MMI->getPersonalityIndex()];

  shouldEmitPersonality = hasLandingPads &&
    PerEncoding != dwarf::DW_EH_PE_omit && Per;

  unsigned LSDAEncoding = TLOF.getLSDAEncoding();
  shouldEmitLSDA = shouldEmitPersonality &&
    LSDAEncoding != dwarf::DW_EH_PE_omit;

  if (!shouldEmitPersonality && !shouldEmitMoves)
    return;

  Asm->OutStreamer.EmitCFIStartProc();

  // Indicate personality routine, if any.
  if (!shouldEmitPersonality)
    return;

  const MCSymbol *Sym = TLOF.getCFIPersonalitySymbol(Per, Asm->Mang, MMI);
  Asm->OutStreamer.EmitCFIPersonality(Sym, PerEncoding);

  Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_begin",
                                                Asm->getFunctionNumber()));

  // Provide LSDA information.
  if (!shouldEmitLSDA)
    return;

  Asm->OutStreamer.EmitCFILsda(Asm->GetTempSymbol("exception",
                                                  Asm->getFunctionNumber()),
                               LSDAEncoding);
}

/// EndFunction - Gather and emit post-function exception information.
///
void DwarfCFIException::EndFunction() {
  if (!shouldEmitPersonality && !shouldEmitMoves)
    return;

  Asm->OutStreamer.EmitCFIEndProc();

  Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_end",
                                                Asm->getFunctionNumber()));

  // Map all labels and get rid of any dead landing pads.
  MMI->TidyLandingPads();

  if (shouldEmitPersonality)
    EmitExceptionTable();
}
<|endoftext|>


<commit_before>//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//

#include "swift/AST/Builtins.h"
#include "swift/SIL/MemAccessUtils.h"
#include "swift/SIL/OwnershipUtils.h"
#include "swift/SIL/SILBasicBlock.h"
#include "swift/SILOptimizer/Utils/CanonicalizeBorrowScope.h"
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"

#define DEBUG_TYPE "copy-propagation"

using namespace swift;

//===----------------------------------------------------------------------===//
//                       MARK: ShrinkBorrowScope
//===----------------------------------------------------------------------===//

class ShrinkBorrowScope {
  // The instruction that begins this borrow scope.
  BeginBorrowInst *introducer;

  InstructionDeleter &deleter;

  SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts;

  /// Instructions which are users of the simple (i.e. not reborrowed) extended
  /// i.e. copied lifetime of the introducer.
  SmallPtrSet<SILInstruction *, 16> users;

  /// Deinit barriers that obstruct hoisting end_borrow instructions.
  llvm::SmallVector<std::pair<SILBasicBlock *, SILInstruction *>>
      barrierInstructions;

  /// Blocks above which the borrow scope cannot be hoisted.
  ///
  /// Consequently, these blocks must begin with end_borrow %borrow.
  ///
  /// Note: These blocks aren't barrier blocks.  Rather the borrow scope is
  ///       barred from being hoisted out of them.  That could happen because
  ///       one of its predecessors is a barrier block (i.e. has a successor
  ///       which is live) or because one of its predecessors has a terminator
  ///       which is itself a deinit barrier.
  SmallPtrSet<SILBasicBlock *, 8> barredBlocks;

  // The list of blocks to look for new points at which to insert end_borrows
  // in.  A block must not be processed if all of its successors have not yet
  // been.  For that reason, it is necessary to allow the same block to be
  // visited multiple times, at most once for each successor.
  SmallVector<SILBasicBlock *, 8> worklist;
  // The instructions from which the shrinking starts, the scope ending
  // instructions, keyed off the block in which they appear.
  llvm::SmallDenseMap<SILBasicBlock *, SILInstruction *> startingInstructions;
  // The end _borrow instructions for this borrow scope that existed before
  // ShrinkBorrowScope ran and which were not modified.
  llvm::SmallPtrSet<SILInstruction *, 8> reusedEndBorrowInsts;

  // Whether ShrinkBorrowScope made any changes to the function.
  //
  // It could have made one of the following sorts of changes:
  // - deleted an end_borrow
  // - created an end_borrow
  // - rewrote the operand of an instruction
  //   - ApplySite
  //   - begin_borrow
  //   - copy_value
  bool madeChange;

public:
  ShrinkBorrowScope(BeginBorrowInst *bbi, InstructionDeleter &deleter,
                    SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts)
      : introducer(bbi), deleter(deleter),
        modifiedCopyValueInsts(modifiedCopyValueInsts), madeChange(false) {}

  bool run();

  bool populateUsers();
  bool initializeWorklist();
  void findBarriers();
  bool rewrite();
  bool createEndBorrow(SILInstruction *insertionPoint);

  bool isBarrierApply(SILInstruction *instruction) {
    // For now, treat every apply (that doesn't use the borrowed value) as a
    // barrier.
    return isa<ApplySite>(instruction);
  }

  bool mayAccessPointer(SILInstruction *instruction) {
    if (!instruction->mayReadOrWriteMemory())
      return false;
    bool fail = false;
    visitAccessedAddress(instruction, [&fail](Operand *operand) {
      auto accessStorage = AccessStorage::compute(operand->get());
      if (accessStorage.getKind() != AccessRepresentation::Kind::Unidentified)
        fail = true;
    });
    return fail;
  }

  bool mayLoadWeakOrUnowned(SILInstruction *instruction) {
    // TODO: It is possible to do better here by looking at the address that is
    //       being loaded.
    return isa<LoadWeakInst>(instruction) || isa<LoadUnownedInst>(instruction);
  }

  bool isDeinitBarrier(SILInstruction *instruction) {
    return isBarrierApply(instruction) || instruction->maySynchronize() ||
           mayAccessPointer(instruction) || mayLoadWeakOrUnowned(instruction);
  }

  bool canReplaceValueWithBorrowee(SILValue value) {
    while (true) {
      auto *instruction = value.getDefiningInstruction();
      if (!instruction)
        return false;
      if (auto *cvi = dyn_cast<CopyValueInst>(instruction)) {
        value = cvi->getOperand();
        continue;
      } else if (auto *bbi = dyn_cast<BeginBorrowInst>(instruction)) {
        if (bbi == introducer) {
          return true;
        }
      }
      return false;
    }
  }

  bool canHoistOverInstruction(SILInstruction *instruction) {
    return tryHoistOverInstruction(instruction, /*rewrite=*/false);
  }

  bool tryHoistOverInstruction(SILInstruction *instruction, bool rewrite = true) {
    if (instruction == introducer) {
      return false;
    }
    if (users.contains(instruction)) {
      if (auto *bbi = dyn_cast<BeginBorrowInst>(instruction)) {
        if (bbi->isLexical() &&
            canReplaceValueWithBorrowee(bbi->getOperand())) {
          if (rewrite) {
            auto borrowee = introducer->getOperand();
            bbi->setOperand(borrowee);
            madeChange = true;
          }
          return true;
        }
      } else if (auto *cvi = dyn_cast<CopyValueInst>(instruction)) {
        if (canReplaceValueWithBorrowee(cvi->getOperand())) {
          if (rewrite) {
            auto borrowee = introducer->getOperand();
            cvi->setOperand(borrowee);
            madeChange = true;
            modifiedCopyValueInsts.push_back(cvi);
          }
          return true;
        }
      }
      return false;
    }
    return !isDeinitBarrier(instruction);
  }
};

//===----------------------------------------------------------------------===//
//                        MARK: Rewrite borrow scopes
//===----------------------------------------------------------------------===//

bool ShrinkBorrowScope::run() {
  if (!BorrowedValue(introducer).isLocalScope())
    return false;
  if (!populateUsers())
    return false;
  if (!initializeWorklist())
    return false;

  findBarriers();

  madeChange |= rewrite();

  return madeChange;
}

bool ShrinkBorrowScope::populateUsers() {
  SmallVector<Operand *, 16> uses;
  if (!findExtendedUsesOfSimpleBorrowedValue(BorrowedValue(introducer),
                                             &uses)) {
    // If the value produced by begin_borrow escapes, don't shrink the borrow
    // scope.
    return false;
  }
  for (auto *use : uses) {
    auto *user = use->getUser();
    users.insert(user);
  }
  return true;
}

bool ShrinkBorrowScope::initializeWorklist() {
  llvm::SmallVector<SILInstruction *, 16> scopeEndingInsts;
  BorrowedValue(introducer).getLocalScopeEndingInstructions(scopeEndingInsts);

  // Form a map of the scopeEndingInsts, keyed off the block they occur in.  If
  // a scope ending instruction is not an end_borrow, bail out.
  for (auto *instruction : scopeEndingInsts) {
    if (!isa<EndBorrowInst>(instruction))
      return false;
    auto *block = instruction->getParent();
    worklist.push_back(block);
    startingInstructions[block] = instruction;
  }

  return true;
}

void ShrinkBorrowScope::findBarriers() {
  // Walk the cfg backwards from the blocks containing scope ending
  // instructions, visiting only the initial blocks (which contained those
  // instructions) and those blocks all of whose successors have already been
  // visited.
  //
  // TODO: Handle loops.

  // Blocks to the top of which the borrow scope has been shrunk.
  SmallPtrSet<SILBasicBlock *, 8> deadBlocks;
  auto hasOnlyDeadSuccessors =
      [&deadBlocks](SILBasicBlock *block) -> bool {
    return llvm::all_of(block->getSuccessorBlocks(), [=](auto *successor) {
      return deadBlocks.contains(successor);
    });
  };

  while (!worklist.empty()) {
    auto *block = worklist.pop_back_val();
    auto *startingInstruction = startingInstructions.lookup(block);
    if (!startingInstruction && !hasOnlyDeadSuccessors(block)) {
      continue;
    }
    for (auto *successor : block->getSuccessorBlocks()) {
      barredBlocks.erase(successor);
    }

    // We either have processed all successors of block or else it is a block
    // which contained one of the original scope-ending instructions.  Scan the
    // block backwards, looking for the first deinit barrier.  If we've visited
    // all successors, start scanning from the terminator.  If the block
    // contained an original scope-ending instruction, start scanning from it.
    SILInstruction *instruction =
        startingInstruction ? startingInstruction : block->getTerminator();
    if (!startingInstruction) {
      // That there's no starting instruction means that this this block did not
      // contain an original introducer.  It was added to the worklist later.
      // At that time, it was checked that this block (along with all that
      // successor's other predecessors) had a terminator over which the borrow
      // scope could be shrunk.  Shrink it now.
      bool hoisted = tryHoistOverInstruction(block->getTerminator());
      assert(hoisted);
      (void)hoisted;
    }
    SILInstruction *barrier = nullptr;
    while ((instruction = instruction->getPreviousInstruction())) {
      if (!tryHoistOverInstruction(instruction)) {
        barrier = instruction;
        break;
      }
    }

    if (barrier) {
      barrierInstructions.push_back({block, barrier});
    } else {
      deadBlocks.insert(block);
      barredBlocks.insert(block);
      // If any of block's predecessor has a terminator over which the scope
      // can't be shrunk, the scope is barred from shrinking out of this block.
      if (llvm::all_of(block->getPredecessorBlocks(), [&](auto *block) {
            return canHoistOverInstruction(block->getTerminator());
            })) {
        // Otherwise, add all predecessors to the worklist and attempt to shrink
        // the borrow scope through them.
        for (auto *predecessor : block->getPredecessorBlocks()) {
          worklist.push_back(predecessor);
        }
      }
    }
  }
}

bool ShrinkBorrowScope::rewrite() {
  bool createdBorrow = false;

  // Insert the new end_borrow instructions that occur after deinit barriers.
  for (auto pair : barrierInstructions) {
    auto *insertionPoint = pair.second->getNextInstruction();
    createdBorrow |= createEndBorrow(insertionPoint);
  }

  // Insert the new end_borrow instructions that occur at the beginning of
  // blocks which we couldn't hoist out of.
  for (auto *block : barredBlocks) {
    auto *insertionPoint = &*block->begin();
    createdBorrow |= createEndBorrow(insertionPoint);
  }

  if (createdBorrow) {
    // Remove all the original end_borrow instructions.
    for (auto pair : startingInstructions) {
      if (reusedEndBorrowInsts.contains(pair.second)) {
        continue;
      }
      deleter.forceDelete(pair.getSecond());
    }
  }

  return createdBorrow;
}

bool ShrinkBorrowScope::createEndBorrow(SILInstruction *insertionPoint) {
  if (auto *ebi = dyn_cast<EndBorrowInst>(insertionPoint)) {
    llvm::SmallDenseMap<SILBasicBlock *, SILInstruction *>::iterator location;
    if ((location = llvm::find_if(startingInstructions, [&](auto pair) -> bool {
           return pair.second == insertionPoint;
         })) != startingInstructions.end()) {
      reusedEndBorrowInsts.insert(location->second);
      return false;
    }
  }
  auto builder = SILBuilderWithScope(insertionPoint);
  builder.createEndBorrow(
      RegularLocation::getAutoGeneratedLocation(insertionPoint->getLoc()),
      introducer);
  return true;
}

bool swift::shrinkBorrowScope(
    BeginBorrowInst *bbi, InstructionDeleter &deleter,
    SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts) {
  ShrinkBorrowScope borrowShrinker(bbi, deleter, modifiedCopyValueInsts);
  return borrowShrinker.run();
}
<commit_msg>[ShrinkBorrowScope] Used extract deinit barrier implementation.<commit_after>//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//

#include "swift/AST/Builtins.h"
#include "swift/SIL/MemAccessUtils.h"
#include "swift/SIL/OwnershipUtils.h"
#include "swift/SIL/SILBasicBlock.h"
#include "swift/SILOptimizer/Utils/CanonicalizeBorrowScope.h"
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"

#define DEBUG_TYPE "copy-propagation"

using namespace swift;

//===----------------------------------------------------------------------===//
//                       MARK: ShrinkBorrowScope
//===----------------------------------------------------------------------===//

class ShrinkBorrowScope {
  // The instruction that begins this borrow scope.
  BeginBorrowInst *introducer;

  InstructionDeleter &deleter;

  SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts;

  /// Instructions which are users of the simple (i.e. not reborrowed) extended
  /// i.e. copied lifetime of the introducer.
  SmallPtrSet<SILInstruction *, 16> users;

  /// Deinit barriers that obstruct hoisting end_borrow instructions.
  llvm::SmallVector<std::pair<SILBasicBlock *, SILInstruction *>>
      barrierInstructions;

  /// Blocks above which the borrow scope cannot be hoisted.
  ///
  /// Consequently, these blocks must begin with end_borrow %borrow.
  ///
  /// Note: These blocks aren't barrier blocks.  Rather the borrow scope is
  ///       barred from being hoisted out of them.  That could happen because
  ///       one of its predecessors is a barrier block (i.e. has a successor
  ///       which is live) or because one of its predecessors has a terminator
  ///       which is itself a deinit barrier.
  SmallPtrSet<SILBasicBlock *, 8> barredBlocks;

  // The list of blocks to look for new points at which to insert end_borrows
  // in.  A block must not be processed if all of its successors have not yet
  // been.  For that reason, it is necessary to allow the same block to be
  // visited multiple times, at most once for each successor.
  SmallVector<SILBasicBlock *, 8> worklist;
  // The instructions from which the shrinking starts, the scope ending
  // instructions, keyed off the block in which they appear.
  llvm::SmallDenseMap<SILBasicBlock *, SILInstruction *> startingInstructions;
  // The end _borrow instructions for this borrow scope that existed before
  // ShrinkBorrowScope ran and which were not modified.
  llvm::SmallPtrSet<SILInstruction *, 8> reusedEndBorrowInsts;

  // Whether ShrinkBorrowScope made any changes to the function.
  //
  // It could have made one of the following sorts of changes:
  // - deleted an end_borrow
  // - created an end_borrow
  // - rewrote the operand of an instruction
  //   - ApplySite
  //   - begin_borrow
  //   - copy_value
  bool madeChange;

public:
  ShrinkBorrowScope(BeginBorrowInst *bbi, InstructionDeleter &deleter,
                    SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts)
      : introducer(bbi), deleter(deleter),
        modifiedCopyValueInsts(modifiedCopyValueInsts), madeChange(false) {}

  bool run();

  bool populateUsers();
  bool initializeWorklist();
  void findBarriers();
  bool rewrite();
  bool createEndBorrow(SILInstruction *insertionPoint);

  bool canReplaceValueWithBorrowee(SILValue value) {
    while (true) {
      auto *instruction = value.getDefiningInstruction();
      if (!instruction)
        return false;
      if (auto *cvi = dyn_cast<CopyValueInst>(instruction)) {
        value = cvi->getOperand();
        continue;
      } else if (auto *bbi = dyn_cast<BeginBorrowInst>(instruction)) {
        if (bbi == introducer) {
          return true;
        }
      }
      return false;
    }
  }

  bool canHoistOverInstruction(SILInstruction *instruction) {
    return tryHoistOverInstruction(instruction, /*rewrite=*/false);
  }

  bool tryHoistOverInstruction(SILInstruction *instruction, bool rewrite = true) {
    if (instruction == introducer) {
      return false;
    }
    if (users.contains(instruction)) {
      if (auto *bbi = dyn_cast<BeginBorrowInst>(instruction)) {
        if (bbi->isLexical() &&
            canReplaceValueWithBorrowee(bbi->getOperand())) {
          if (rewrite) {
            auto borrowee = introducer->getOperand();
            bbi->setOperand(borrowee);
            madeChange = true;
          }
          return true;
        }
      } else if (auto *cvi = dyn_cast<CopyValueInst>(instruction)) {
        if (canReplaceValueWithBorrowee(cvi->getOperand())) {
          if (rewrite) {
            auto borrowee = introducer->getOperand();
            cvi->setOperand(borrowee);
            madeChange = true;
            modifiedCopyValueInsts.push_back(cvi);
          }
          return true;
        }
      }
      return false;
    }
    return !isDeinitBarrier(instruction);
  }
};

//===----------------------------------------------------------------------===//
//                        MARK: Rewrite borrow scopes
//===----------------------------------------------------------------------===//

bool ShrinkBorrowScope::run() {
  if (!BorrowedValue(introducer).isLocalScope())
    return false;
  if (!populateUsers())
    return false;
  if (!initializeWorklist())
    return false;

  findBarriers();

  madeChange |= rewrite();

  return madeChange;
}

bool ShrinkBorrowScope::populateUsers() {
  SmallVector<Operand *, 16> uses;
  if (!findExtendedUsesOfSimpleBorrowedValue(BorrowedValue(introducer),
                                             &uses)) {
    // If the value produced by begin_borrow escapes, don't shrink the borrow
    // scope.
    return false;
  }
  for (auto *use : uses) {
    auto *user = use->getUser();
    users.insert(user);
  }
  return true;
}

bool ShrinkBorrowScope::initializeWorklist() {
  llvm::SmallVector<SILInstruction *, 16> scopeEndingInsts;
  BorrowedValue(introducer).getLocalScopeEndingInstructions(scopeEndingInsts);

  // Form a map of the scopeEndingInsts, keyed off the block they occur in.  If
  // a scope ending instruction is not an end_borrow, bail out.
  for (auto *instruction : scopeEndingInsts) {
    if (!isa<EndBorrowInst>(instruction))
      return false;
    auto *block = instruction->getParent();
    worklist.push_back(block);
    startingInstructions[block] = instruction;
  }

  return true;
}

void ShrinkBorrowScope::findBarriers() {
  // Walk the cfg backwards from the blocks containing scope ending
  // instructions, visiting only the initial blocks (which contained those
  // instructions) and those blocks all of whose successors have already been
  // visited.
  //
  // TODO: Handle loops.

  // Blocks to the top of which the borrow scope has been shrunk.
  SmallPtrSet<SILBasicBlock *, 8> deadBlocks;
  auto hasOnlyDeadSuccessors =
      [&deadBlocks](SILBasicBlock *block) -> bool {
    return llvm::all_of(block->getSuccessorBlocks(), [=](auto *successor) {
      return deadBlocks.contains(successor);
    });
  };

  while (!worklist.empty()) {
    auto *block = worklist.pop_back_val();
    auto *startingInstruction = startingInstructions.lookup(block);
    if (!startingInstruction && !hasOnlyDeadSuccessors(block)) {
      continue;
    }
    for (auto *successor : block->getSuccessorBlocks()) {
      barredBlocks.erase(successor);
    }

    // We either have processed all successors of block or else it is a block
    // which contained one of the original scope-ending instructions.  Scan the
    // block backwards, looking for the first deinit barrier.  If we've visited
    // all successors, start scanning from the terminator.  If the block
    // contained an original scope-ending instruction, start scanning from it.
    SILInstruction *instruction =
        startingInstruction ? startingInstruction : block->getTerminator();
    if (!startingInstruction) {
      // That there's no starting instruction means that this this block did not
      // contain an original introducer.  It was added to the worklist later.
      // At that time, it was checked that this block (along with all that
      // successor's other predecessors) had a terminator over which the borrow
      // scope could be shrunk.  Shrink it now.
      bool hoisted = tryHoistOverInstruction(block->getTerminator());
      assert(hoisted);
      (void)hoisted;
    }
    SILInstruction *barrier = nullptr;
    while ((instruction = instruction->getPreviousInstruction())) {
      if (!tryHoistOverInstruction(instruction)) {
        barrier = instruction;
        break;
      }
    }

    if (barrier) {
      barrierInstructions.push_back({block, barrier});
    } else {
      deadBlocks.insert(block);
      barredBlocks.insert(block);
      // If any of block's predecessor has a terminator over which the scope
      // can't be shrunk, the scope is barred from shrinking out of this block.
      if (llvm::all_of(block->getPredecessorBlocks(), [&](auto *block) {
            return canHoistOverInstruction(block->getTerminator());
            })) {
        // Otherwise, add all predecessors to the worklist and attempt to shrink
        // the borrow scope through them.
        for (auto *predecessor : block->getPredecessorBlocks()) {
          worklist.push_back(predecessor);
        }
      }
    }
  }
}

bool ShrinkBorrowScope::rewrite() {
  bool createdBorrow = false;

  // Insert the new end_borrow instructions that occur after deinit barriers.
  for (auto pair : barrierInstructions) {
    auto *insertionPoint = pair.second->getNextInstruction();
    createdBorrow |= createEndBorrow(insertionPoint);
  }

  // Insert the new end_borrow instructions that occur at the beginning of
  // blocks which we couldn't hoist out of.
  for (auto *block : barredBlocks) {
    auto *insertionPoint = &*block->begin();
    createdBorrow |= createEndBorrow(insertionPoint);
  }

  if (createdBorrow) {
    // Remove all the original end_borrow instructions.
    for (auto pair : startingInstructions) {
      if (reusedEndBorrowInsts.contains(pair.second)) {
        continue;
      }
      deleter.forceDelete(pair.getSecond());
    }
  }

  return createdBorrow;
}

bool ShrinkBorrowScope::createEndBorrow(SILInstruction *insertionPoint) {
  if (auto *ebi = dyn_cast<EndBorrowInst>(insertionPoint)) {
    llvm::SmallDenseMap<SILBasicBlock *, SILInstruction *>::iterator location;
    if ((location = llvm::find_if(startingInstructions, [&](auto pair) -> bool {
           return pair.second == insertionPoint;
         })) != startingInstructions.end()) {
      reusedEndBorrowInsts.insert(location->second);
      return false;
    }
  }
  auto builder = SILBuilderWithScope(insertionPoint);
  builder.createEndBorrow(
      RegularLocation::getAutoGeneratedLocation(insertionPoint->getLoc()),
      introducer);
  return true;
}

bool swift::shrinkBorrowScope(
    BeginBorrowInst *bbi, InstructionDeleter &deleter,
    SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts) {
  ShrinkBorrowScope borrowShrinker(bbi, deleter, modifiedCopyValueInsts);
  return borrowShrinker.run();
}
<|endoftext|>