<commit_before>// Copyright (C) 2017 - 2018 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and University of
// of Connecticut School of Medicine.
// All rights reserved.

/*!
    \file CDataContainer.cpp
    \brief Implementation file of class CDataContainer
 */

/**
 * Class CDataContainer
 *
 * This class is the is used to group CDataObjects logically. It itself is
 * an object. Contained objects are still globally accessible.
 *
 * Copyright Stefan Hoops 2002
 */

#include "copasi/copasi.h"

#include "copasi/core/CDataContainer.h"
#include "copasi/core/CDataVector.h"
#include "copasi/core/CRootContainer.h"
#include "copasi/core/CRegisteredCommonName.h"
#include "copasi/core/CDataTimer.h"
#include "copasi/core/CDataString.h"

#include "copasi/utilities/CUnit.h"
#include "copasi/undo/CUndoData.h"
#include "copasi/model/CModel.h"
#include "copasi/function/CFunctionDB.h"
#include "copasi/CopasiDataModel/CDataModel.h"

const CObjectInterface::ContainerList CDataContainer::EmptyList;

// static
CDataContainer * CDataContainer::fromData(const CData & data, CUndoObjectInterface * pParent)
{
  return new CDataContainer(data.getProperty(CData::OBJECT_NAME).toString(),
                            NO_PARENT,
                            data.getProperty(CData::OBJECT_TYPE).toString(),
                            CFlags< Flag >(data.getProperty(CData::OBJECT_FLAG).toString()));
}

// virtual
CData CDataContainer::toData() const
{
  return CDataObject::toData();
}

// virtual
bool CDataContainer::applyData(const CData & data, CUndoData::ChangeSet & changes)
{
  return CDataObject::applyData(data, changes);
}

// virtual
void CDataContainer::createUndoData(CUndoData & undoData,
                                    const CUndoData::Type & type,
                                    const CData & oldData,
                                    const CCore::Framework & framework) const
{
  CDataObject::createUndoData(undoData, type, oldData, framework);

  if (type == CUndoData::Type::REMOVE)
    {
      appendDeletedDependentData(undoData);
    }

  return;
}

// virtual
bool CDataContainer::appendDeletedDependentData(CUndoData & undoData) const
{
  bool dataAppended = false;

  const CFunctionDB * pFunctionDB = dynamic_cast< const CFunctionDB * >(getObjectAncestor("FunctionDB"));
  const CDataModel * pDataModel = getObjectDataModel();

  if (pFunctionDB == NULL &&
      pDataModel == NULL)
    {
      return dataAppended;
    }

  CDataObject::DataObjectSet Reactions;
  CDataObject::DataObjectSet Metabolites;
  CDataObject::DataObjectSet Values;
  CDataObject::DataObjectSet Compartments;
  CDataObject::DataObjectSet Events;
  CDataObject::DataObjectSet EventAssignments;
  CDataObject::DataObjectSet Tasks;

  if (pFunctionDB != NULL)
    {
      CDataObject::ObjectSet DeletedObjects;
      DeletedObjects.insert(this);
      CDataObject::DataObjectSet Functions;

      pFunctionDB->appendDependentFunctions(DeletedObjects, Functions);

      CDataObject::DataObjectSet::const_iterator it = Functions.begin();
      CDataObject::DataObjectSet::const_iterator end = Functions.end();

      for (; it != end; ++it)
        {
          dataAppended |= undoData.addPreProcessData(CUndoData(CUndoData::Type::REMOVE, *it));
        }
    }

  if (pDataModel != NULL)
    {
      const CModel * pModel = pDataModel->getModel();

      DataObjectSet dependentReactions;
      DataObjectSet dependentMetabolites;
      DataObjectSet dependentCompartments;
      DataObjectSet dependentModelValues;
      DataObjectSet dependentEvents;
      DataObjectSet dependentEventAssignments;

      dataAppended |= pModel->appendAllDependents(*this,
                      dependentReactions,
                      dependentMetabolites,
                      dependentCompartments,
                      dependentModelValues,
                      dependentEvents,
                      dependentEventAssignments);

      DataObjectSet::const_iterator it = dependentEventAssignments.begin();
      DataObjectSet::const_iterator end = dependentEventAssignments.end();

      for (; it != end; ++it)
        {
          undoData.addPreProcessData(CUndoData(CUndoData::Type::REMOVE, *it, undoData.getAuthorID()));
        }

      it = dependentEvents.begin();
      end = dependentEvents.end();

      for (; it != end; ++it)
        {
          undoData.addPreProcessData(CUndoData(CUndoData::Type::REMOVE, *it, undoData.getAuthorID()));
        }

      it = dependentReactions.begin();
      end = dependentReactions.end();

      for (; it != end; ++it)
        {
          undoData.addPreProcessData(CUndoData(CUndoData::Type::REMOVE, *it, undoData.getAuthorID()));
        }

      it = dependentModelValues.begin();
      end = dependentModelValues.end();

      for (; it != end; ++it)
        {
          undoData.addPreProcessData(CUndoData(CUndoData::Type::REMOVE, *it, undoData.getAuthorID()));
        }

      it = dependentMetabolites.begin();
      end = dependentMetabolites.end();

      for (; it != end; ++it)
        {
          undoData.addPreProcessData(CUndoData(CUndoData::Type::REMOVE, *it, undoData.getAuthorID()));
        }

      it = dependentCompartments.begin();
      end = dependentCompartments.end();

      for (; it != end; ++it)
        {
          undoData.addPreProcessData(CUndoData(CUndoData::Type::REMOVE, *it, undoData.getAuthorID()));
        }
    }

  return dataAppended;
}

CDataContainer::CDataContainer() :
  CDataObject(),
  mObjects()
{addObjectReference("Name", *const_cast<std::string *>(&getObjectName()));}

CDataContainer::CDataContainer(const std::string & name,
                               const CDataContainer * pParent,
                               const std::string & type,
                               const CFlags< Flag > & flag):
  CDataObject(name, pParent, type, flag | CDataObject::Container),
  mObjects()
{addObjectReference("Name", *const_cast<std::string *>(&getObjectName()));}

CDataContainer::CDataContainer(const CDataContainer & src,
                               const CDataContainer * pParent):
  CDataObject(src, pParent),
  mObjects()
{addObjectReference("Name", *const_cast<std::string *>(&getObjectName()));}

CDataContainer::~CDataContainer()
{
  objectMap::iterator it = mObjects.begin();
  objectMap::iterator end = mObjects.end();

  for (; it != end; ++it)
    if (*it != NULL)
      {
        if ((*it)->getObjectParent() == this)
          {
            (*it)->setObjectParent(NULL);

            if (*it != NULL) delete(*it);
          }
        else
          {
            (*it)->removeReference(this);
          }
      }
}

const CObjectInterface * CDataContainer::getObject(const CCommonName & cn) const
{
  if (cn == "")
    {
      if (hasFlag(Root))
        return NULL;
      else
        return this;
    }

  if (cn == "Property=DisplayName")
    {
      return CDataObject::getObject(cn);
    }

  std::string Name = cn.getObjectName();
  std::string Type = cn.getObjectType();

  if (getObjectName() == Name && getObjectType() == Type)
    return getObject(cn.getRemainder());

  //check if the first part of the cn matches one of the children (by name and type)
  objectMap::range range = mObjects.equal_range(Name);

  while (range.first != range.second && (*range.first)->getObjectType() != Type) ++range.first;

  if (range.first == range.second) //not found in the list of children
    {
      if (Type == "String")
        return new CDataString(Name, this);
      else if (Type == "Separator")
        return new CCopasiReportSeparator(Name, this);
      else if (getObjectName() == "Root" && Type == "Vector")
        return CRootContainer::getRoot()->getObject(cn);
      else
        return NULL;
    }

  const CObjectInterface * pObject = NULL;

  //handle objects where the array flag is set. Currently this applies to the
  //CArrayAnnotation object. Since this is also a container, we have to do this
  //before handling general containers.
  if ((*range.first)->hasFlag(Array))
    {
      //we need to call the getObject() method of the child array with the
      //remainder of the cn, with the indices in square brackets, or with an empty string

      //if there are no indices there could still be a remainder (since the array can also be
      //a container)
      if (cn.getElementName(0, false) == "") //no indices
        return (*range.first)->getObject(cn.getRemainder());

      return (*range.first)->getObject(cn);
    }

  //handle generic containers.
  if ((*range.first)->hasFlag(Container))
    return (*range.first)->getObject(cn.getRemainder());

  if ((*range.first)->hasFlag(Matrix))
    {
      if (cn.getElementName(0, false) == "")
        return *range.first;

      pObject = (*range.first)->getObject("[" + cn.getElementName(0, false) + "]" +                   //TODO really?
                                          "[" + cn.getElementName(1, false) + "]");

      if ((*range.first)->getObjectType() == "Reference" || !pObject)
        return pObject;
      else
        return pObject->getObject(cn.getRemainder());
    }

  return (*range.first)->getObject(cn.getRemainder());
}

const CDataContainer::objectMap & CDataContainer::getObjects() const
{return mObjects;}

CDataContainer::objectMap & CDataContainer::getObjects()
{return mObjects;}

const CDataObject * CDataContainer::getValueObject() const
{
  void * ptr = getValuePointer();

  if (ptr == NULL) return NULL;

  objectMap::const_iterator it = mObjects.begin();
  objectMap::const_iterator end = mObjects.end();

  for (; it != end; ++it)
    if (ptr == (*it)->getValuePointer()) return *it;

  return NULL;
}

void CDataContainer::initObjects() {}

// virtual
bool CDataContainer::add(CDataObject * pObject,
                         const bool & adopt)
{
  if (pObject == NULL)
    {
      return false;
    }

  bool success = mObjects.insert(pObject).second;

  if (adopt)
    pObject->setObjectParent(this);
  else
    pObject->addReference(this);

  validityChanged(pObject->getValidity());

  return success;
}

// virtual
bool CDataContainer::remove(CDataObject * pObject)
{
  if (pObject != NULL)
    {
      validityRemoved(pObject->getValidity());
      pObject->removeReference(this);
    }

  return mObjects.erase(pObject);
}

// virtual
size_t CDataContainer::getIndex(const CDataObject * pObject) const
{
  return C_INVALID_INDEX;
}

void CDataContainer::getDescendants(CDataObject::DataObjectSet & descendants, const bool & recursive) const
{
  const CDataContainer * pContainer;
  objectMap::const_iterator it = mObjects.begin();
  objectMap::const_iterator end = mObjects.end();

  for (; it != end; ++it)
    if ((*it)->getObjectParent() == this)
      {
        descendants.insert(*it);

        if (recursive &&
            (pContainer = dynamic_cast< const CDataContainer * >(*it)) != NULL)
          {
            pContainer->getDescendants(descendants, recursive);
          }
      }
}

void CDataContainer::objectRenamed(CDataObject * pObject, const std::string & oldName)
{
  mObjects.objectRenamed(pObject, oldName);
}

// virtual
const std::string CDataContainer::getUnits() const
{return "?";}

// virtual
std::string CDataContainer::getChildObjectUnits(const CDataObject * /* pObject */) const
{return "?";}

// virtual
CUndoObjectInterface * CDataContainer::insert(const CData & data)
{
  return NULL;
}
<commit_msg>- issue 2725: be a bit more stringent as to when to defer to the root container<commit_after>// Copyright (C) 2017 - 2018 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and University of
// of Connecticut School of Medicine.
// All rights reserved.

/*!
    \file CDataContainer.cpp
    \brief Implementation file of class CDataContainer
 */

/**
 * Class CDataContainer
 *
 * This class is the is used to group CDataObjects logically. It itself is
 * an object. Contained objects are still globally accessible.
 *
 * Copyright Stefan Hoops 2002
 */

#include "copasi/copasi.h"

#include "copasi/core/CDataContainer.h"
#include "copasi/core/CDataVector.h"
#include "copasi/core/CRootContainer.h"
#include "copasi/core/CRegisteredCommonName.h"
#include "copasi/core/CDataTimer.h"
#include "copasi/core/CDataString.h"

#include "copasi/utilities/CUnit.h"
#include "copasi/undo/CUndoData.h"
#include "copasi/model/CModel.h"
#include "copasi/function/CFunctionDB.h"
#include "copasi/CopasiDataModel/CDataModel.h"

const CObjectInterface::ContainerList CDataContainer::EmptyList;

// static
CDataContainer * CDataContainer::fromData(const CData & data, CUndoObjectInterface * pParent)
{
  return new CDataContainer(data.getProperty(CData::OBJECT_NAME).toString(),
                            NO_PARENT,
                            data.getProperty(CData::OBJECT_TYPE).toString(),
                            CFlags< Flag >(data.getProperty(CData::OBJECT_FLAG).toString()));
}

// virtual
CData CDataContainer::toData() const
{
  return CDataObject::toData();
}

// virtual
bool CDataContainer::applyData(const CData & data, CUndoData::ChangeSet & changes)
{
  return CDataObject::applyData(data, changes);
}

// virtual
void CDataContainer::createUndoData(CUndoData & undoData,
                                    const CUndoData::Type & type,
                                    const CData & oldData,
                                    const CCore::Framework & framework) const
{
  CDataObject::createUndoData(undoData, type, oldData, framework);

  if (type == CUndoData::Type::REMOVE)
    {
      appendDeletedDependentData(undoData);
    }

  return;
}

// virtual
bool CDataContainer::appendDeletedDependentData(CUndoData & undoData) const
{
  bool dataAppended = false;

  const CFunctionDB * pFunctionDB = dynamic_cast< const CFunctionDB * >(getObjectAncestor("FunctionDB"));
  const CDataModel * pDataModel = getObjectDataModel();

  if (pFunctionDB == NULL &&
      pDataModel == NULL)
    {
      return dataAppended;
    }

  CDataObject::DataObjectSet Reactions;
  CDataObject::DataObjectSet Metabolites;
  CDataObject::DataObjectSet Values;
  CDataObject::DataObjectSet Compartments;
  CDataObject::DataObjectSet Events;
  CDataObject::DataObjectSet EventAssignments;
  CDataObject::DataObjectSet Tasks;

  if (pFunctionDB != NULL)
    {
      CDataObject::ObjectSet DeletedObjects;
      DeletedObjects.insert(this);
      CDataObject::DataObjectSet Functions;

      pFunctionDB->appendDependentFunctions(DeletedObjects, Functions);

      CDataObject::DataObjectSet::const_iterator it = Functions.begin();
      CDataObject::DataObjectSet::const_iterator end = Functions.end();

      for (; it != end; ++it)
        {
          dataAppended |= undoData.addPreProcessData(CUndoData(CUndoData::Type::REMOVE, *it));
        }
    }

  if (pDataModel != NULL)
    {
      const CModel * pModel = pDataModel->getModel();

      DataObjectSet dependentReactions;
      DataObjectSet dependentMetabolites;
      DataObjectSet dependentCompartments;
      DataObjectSet dependentModelValues;
      DataObjectSet dependentEvents;
      DataObjectSet dependentEventAssignments;

      dataAppended |= pModel->appendAllDependents(*this,
                      dependentReactions,
                      dependentMetabolites,
                      dependentCompartments,
                      dependentModelValues,
                      dependentEvents,
                      dependentEventAssignments);

      DataObjectSet::const_iterator it = dependentEventAssignments.begin();
      DataObjectSet::const_iterator end = dependentEventAssignments.end();

      for (; it != end; ++it)
        {
          undoData.addPreProcessData(CUndoData(CUndoData::Type::REMOVE, *it, undoData.getAuthorID()));
        }

      it = dependentEvents.begin();
      end = dependentEvents.end();

      for (; it != end; ++it)
        {
          undoData.addPreProcessData(CUndoData(CUndoData::Type::REMOVE, *it, undoData.getAuthorID()));
        }

      it = dependentReactions.begin();
      end = dependentReactions.end();

      for (; it != end; ++it)
        {
          undoData.addPreProcessData(CUndoData(CUndoData::Type::REMOVE, *it, undoData.getAuthorID()));
        }

      it = dependentModelValues.begin();
      end = dependentModelValues.end();

      for (; it != end; ++it)
        {
          undoData.addPreProcessData(CUndoData(CUndoData::Type::REMOVE, *it, undoData.getAuthorID()));
        }

      it = dependentMetabolites.begin();
      end = dependentMetabolites.end();

      for (; it != end; ++it)
        {
          undoData.addPreProcessData(CUndoData(CUndoData::Type::REMOVE, *it, undoData.getAuthorID()));
        }

      it = dependentCompartments.begin();
      end = dependentCompartments.end();

      for (; it != end; ++it)
        {
          undoData.addPreProcessData(CUndoData(CUndoData::Type::REMOVE, *it, undoData.getAuthorID()));
        }
    }

  return dataAppended;
}

CDataContainer::CDataContainer() :
  CDataObject(),
  mObjects()
{addObjectReference("Name", *const_cast<std::string *>(&getObjectName()));}

CDataContainer::CDataContainer(const std::string & name,
                               const CDataContainer * pParent,
                               const std::string & type,
                               const CFlags< Flag > & flag):
  CDataObject(name, pParent, type, flag | CDataObject::Container),
  mObjects()
{addObjectReference("Name", *const_cast<std::string *>(&getObjectName()));}

CDataContainer::CDataContainer(const CDataContainer & src,
                               const CDataContainer * pParent):
  CDataObject(src, pParent),
  mObjects()
{addObjectReference("Name", *const_cast<std::string *>(&getObjectName()));}

CDataContainer::~CDataContainer()
{
  objectMap::iterator it = mObjects.begin();
  objectMap::iterator end = mObjects.end();

  for (; it != end; ++it)
    if (*it != NULL)
      {
        if ((*it)->getObjectParent() == this)
          {
            (*it)->setObjectParent(NULL);

            if (*it != NULL) delete(*it);
          }
        else
          {
            (*it)->removeReference(this);
          }
      }
}

const CObjectInterface * CDataContainer::getObject(const CCommonName & cn) const
{
  if (cn == "")
    {
      if (hasFlag(Root))
        return NULL;
      else
        return this;
    }

  if (cn == "Property=DisplayName")
    {
      return CDataObject::getObject(cn);
    }

  std::string Name = cn.getObjectName();
  std::string Type = cn.getObjectType();

  if (getObjectName() == Name && getObjectType() == Type)
    return getObject(cn.getRemainder());

  //check if the first part of the cn matches one of the children (by name and type)
  objectMap::range range = mObjects.equal_range(Name);

  while (range.first != range.second && (*range.first)->getObjectType() != Type) ++range.first;

  if (range.first == range.second) //not found in the list of children
    {
      if (Type == "String")
        return new CDataString(Name, this);
      else if (Type == "Separator")
        return new CCopasiReportSeparator(Name, this);
      else if (getObjectName() == "Root" && Type == "Vector" && CRootContainer::getRoot() != this)
        return CRootContainer::getRoot()->getObject(cn);
      else
        return NULL;
    }

  const CObjectInterface * pObject = NULL;

  //handle objects where the array flag is set. Currently this applies to the
  //CArrayAnnotation object. Since this is also a container, we have to do this
  //before handling general containers.
  if ((*range.first)->hasFlag(Array))
    {
      //we need to call the getObject() method of the child array with the
      //remainder of the cn, with the indices in square brackets, or with an empty string

      //if there are no indices there could still be a remainder (since the array can also be
      //a container)
      if (cn.getElementName(0, false) == "") //no indices
        return (*range.first)->getObject(cn.getRemainder());

      return (*range.first)->getObject(cn);
    }

  //handle generic containers.
  if ((*range.first)->hasFlag(Container))
    return (*range.first)->getObject(cn.getRemainder());

  if ((*range.first)->hasFlag(Matrix))
    {
      if (cn.getElementName(0, false) == "")
        return *range.first;

      pObject = (*range.first)->getObject("[" + cn.getElementName(0, false) + "]" +                   //TODO really?
                                          "[" + cn.getElementName(1, false) + "]");

      if ((*range.first)->getObjectType() == "Reference" || !pObject)
        return pObject;
      else
        return pObject->getObject(cn.getRemainder());
    }

  return (*range.first)->getObject(cn.getRemainder());
}

const CDataContainer::objectMap & CDataContainer::getObjects() const
{return mObjects;}

CDataContainer::objectMap & CDataContainer::getObjects()
{return mObjects;}

const CDataObject * CDataContainer::getValueObject() const
{
  void * ptr = getValuePointer();

  if (ptr == NULL) return NULL;

  objectMap::const_iterator it = mObjects.begin();
  objectMap::const_iterator end = mObjects.end();

  for (; it != end; ++it)
    if (ptr == (*it)->getValuePointer()) return *it;

  return NULL;
}

void CDataContainer::initObjects() {}

// virtual
bool CDataContainer::add(CDataObject * pObject,
                         const bool & adopt)
{
  if (pObject == NULL)
    {
      return false;
    }

  bool success = mObjects.insert(pObject).second;

  if (adopt)
    pObject->setObjectParent(this);
  else
    pObject->addReference(this);

  validityChanged(pObject->getValidity());

  return success;
}

// virtual
bool CDataContainer::remove(CDataObject * pObject)
{
  if (pObject != NULL)
    {
      validityRemoved(pObject->getValidity());
      pObject->removeReference(this);
    }

  return mObjects.erase(pObject);
}

// virtual
size_t CDataContainer::getIndex(const CDataObject * pObject) const
{
  return C_INVALID_INDEX;
}

void CDataContainer::getDescendants(CDataObject::DataObjectSet & descendants, const bool & recursive) const
{
  const CDataContainer * pContainer;
  objectMap::const_iterator it = mObjects.begin();
  objectMap::const_iterator end = mObjects.end();

  for (; it != end; ++it)
    if ((*it)->getObjectParent() == this)
      {
        descendants.insert(*it);

        if (recursive &&
            (pContainer = dynamic_cast< const CDataContainer * >(*it)) != NULL)
          {
            pContainer->getDescendants(descendants, recursive);
          }
      }
}

void CDataContainer::objectRenamed(CDataObject * pObject, const std::string & oldName)
{
  mObjects.objectRenamed(pObject, oldName);
}

// virtual
const std::string CDataContainer::getUnits() const
{return "?";}

// virtual
std::string CDataContainer::getChildObjectUnits(const CDataObject * /* pObject */) const
{return "?";}

// virtual
CUndoObjectInterface * CDataContainer::insert(const CData & data)
{
  return NULL;
}
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstring>
#include <climits>
#include <algorithm>
#include <vector>

#include <mpi.h>

using namespace std;

#define MAXN 100
#define MAXM 10000

int p,rank;
int n,m;

struct edge{
	int u,v,w;
	int id;

	bool operator < (edge e) const{
		return w < e.w;
	}
}e[MAXM],e_local[MAXM];

bool in_tree[MAXM];

// Union - Find

int parent[MAXN + 1],uf_rank[MAXN + 1];
int Find(int x){
	if(parent[x] == x) return x;
	parent[x] = Find(parent[x]);
	return parent[x];
}

void Union(int x, int y){
	x = Find(x);
	y = Find(y);

	if(uf_rank[x] < uf_rank[y]){
		parent[x] = y;
	}else{
		parent[y] = x;

		if(uf_rank[x] == uf_rank[y])
			++uf_rank[x];
	}
}

// dfs to find a path between two nodes in the MST

vector<int> L[MAXN],edge_id[MAXN],path,path_edges;
bool visited[MAXN];

bool dfs(int u, int v){
	path.push_back(u);

	if(u == v) return true;

	bool ret = false;

	if(!visited[u]){
		visited[u] = true;

		for(int i = 0;i < L[u].size();++i){
			int to = L[u][i];
			path_edges.push_back(edge_id[u][i]);

			if(dfs(to,v)){
				ret = true;
				break;
			}else{
				path_edges.pop_back();
			}
		}
	}

	if(!ret)
		path.pop_back();

	return ret;
}

// dfs to mark edges in a subtree after erasing an edge

int mark[MAXN];

void dfs2(int u, int v, int cur){
	if(visited[cur]) return;
	visited[cur] = true;

	mark[cur] = u;

	for(int i = 0;i < L[cur].size();++i){
		int to = L[cur][i];

		if(to != u && to != v)
			dfs2(u,v,to);
	}
}

int main(int argc, char *argv[]){
	MPI_Init(&argc,&argv);
	MPI_Comm_size(MPI_COMM_WORLD,&p);
	MPI_Comm_rank(MPI_COMM_WORLD,&rank);

	if(rank == 0){
		n = m = 0;

		while(scanf("%d,%d,%d",&e[m].u,&e[m].v,&e[m].w) == 3){
			n = max(n,max(e[m].u,e[m].v));
			e[m].id = m;
			++m;
		}
	}

	MPI_Bcast(&n,1,MPI_INT,0,MPI_COMM_WORLD);
	MPI_Bcast(&m,1,MPI_INT,0,MPI_COMM_WORLD);

	int blocklengths[] = {1,1,1,1};
	MPI_Aint displacements[] = {offsetof(edge,u), offsetof(edge,v), offsetof(edge,w), offsetof(edge,id)};
	MPI_Datatype types[] = {MPI_INT, MPI_INT, MPI_INT, MPI_INT};
	MPI_Datatype MPI_EDGE;

	MPI_Type_create_struct(4,blocklengths,displacements,types,&MPI_EDGE);
	MPI_Type_commit(&MPI_EDGE);

	MPI_Bcast(e,m,MPI_EDGE,0,MPI_COMM_WORLD);

	// Find minimum spanning tree using Kruskal's algorithm

	for(int i = 1;i <= n;++i){
		parent[i] = i;
		uf_rank[i] = 0;
	}

	int start = (m + p - 1) / p * rank,end = min(m,(m + p - 1) / p * (rank + 1));
	int m_local = 0;

	for(int i = start;i < end;++i)
		e_local[i - start] = e[i];

	sort(e_local,e_local + (end - start));

	for(int i = 0;i < end - start;++i){
		if(Find(e_local[i].u) != Find(e_local[i].v)){
			Union(e_local[i].u,e_local[i].v);
			e_local[m_local] = e_local[i];
			m_local++;
		}
	}

	int curP = p;

	while(curP > 1){
		if(rank < curP){
			//printf("%d %d\n",rank,curP);
			int m1 = 0,m2 = 0;
			MPI_Status status;

			//printf("%d %d send\n",rank,curP);
			MPI_Send(&m_local,1,MPI_INT,rank / 2,0,MPI_COMM_WORLD);
			//printf("%d %d send\n",rank,curP);
			MPI_Send(e_local,m_local,MPI_EDGE,rank / 2,1,MPI_COMM_WORLD);
			//printf("%d %d send\n",rank,curP);

			if(2 * rank < curP){
				//printf("%d %d receive\n",rank,curP);
				MPI_Recv(&m1,1,MPI_INT,2 * rank,0,MPI_COMM_WORLD,&status);
				//printf("%d %d receive\n",rank,curP);
				MPI_Recv(e_local,m1,MPI_EDGE,2 * rank,1,MPI_COMM_WORLD,&status);
				//printf("%d %d receive\n",rank,curP);

				if(2 * rank + 1 < curP){
					//printf("%d %d receive\n",rank,curP);
					MPI_Recv(&m2,1,MPI_INT,2 * rank + 1,0,MPI_COMM_WORLD,&status);
					//printf("%d %d receive\n",rank,curP);
					MPI_Recv(e_local + m1,m2,MPI_EDGE,2 * rank + 1,1,MPI_COMM_WORLD,&status);
					//printf("%d %d receive\n",rank,curP);
				}

				int m_aux = m1 + m2;
				sort(e_local,e_local + m_aux);

				for(int i = 1;i <= n;++i){
					parent[i] = i;
					uf_rank[i] = 0;
				}

				m_local = 0;

				for(int i = 0;i < m_aux;++i){
					if(Find(e_local[i].u) != Find(e_local[i].v)){
						Union(e_local[i].u,e_local[i].v);
						e_local[m_local] = e_local[i];
						m_local++;
					}
				}
			}
		}

		curP = (curP + 1) / 2;
	}

	if(rank == 0){
		int total = 0;

		for(int i = 0;i < m_local;++i){
			L[ e_local[i].u ].push_back(e_local[i].v);
			edge_id[ e_local[i].u ].push_back(e_local[i].id);

			L[ e_local[i].v ].push_back(e_local[i].u);
			edge_id[ e_local[i].v ].push_back(e_local[i].id);

			in_tree[ e_local[i].id ] = true;

			printf("%d - %d (%d)\n",e_local[i].u,e_local[i].v,e_local[i].w);
			total += e_local[i].w;
		}

		printf("Total weight = %d\n\n",total);
	}

	for(int i = 1;i <= n;++i){
		int list_size;

		if(rank == 0)
			list_size = L[i].size();

		MPI_Bcast(&list_size,1,MPI_INT,0,MPI_COMM_WORLD);

		L[i].resize(list_size);
		MPI_Bcast(&L[i].front(),list_size,MPI_INT,0,MPI_COMM_WORLD);

		edge_id[i].resize(list_size);
		MPI_Bcast(&edge_id[i].front(),list_size,MPI_INT,0,MPI_COMM_WORLD);
	}

	MPI_Bcast(in_tree,m,MPI_C_BOOL,0,MPI_COMM_WORLD);

	// Find the path int T that connect two endpoint of an edge

	bool verified_local = true;

	for(int i = (m + p - 1) / p * rank;i < min(m,(m + p - 1) / p * (rank + 1));++i){
		if(!in_tree[i]){
			memset(visited,false,sizeof visited);
			path.clear();
			dfs(e[i].u,e[i].v);

			printf("process %d, (%d, %d) : ",rank,e[i].u,e[i].v);

			for(int j = 0;j < path.size();++j){
				if(j > 0) printf(" -> ");
				printf("%d",path[j]);
			}

			printf("\n");

			// Verify MST

			for(int j = 0;j < path_edges.size();++j){
				if(e[i].w < e[ path_edges[j] ].w)
					verified_local = false;
			}
		}
	}

	printf("\n");

	bool verified_global;
	MPI_Reduce(&verified_local,&verified_global,1,MPI_C_BOOL,MPI_LAND,0,MPI_COMM_WORLD);

	if(rank == 0){
		printf("Verification: ");
		if(verified_global) printf("It is an MST\n\n");
		else printf("It is not an MST\n\n");
	}

	// Find edges that can replace an edge in the MST

	int most_vital_edge_local[p];
	int max_increase_local[p];
	most_vital_edge_local[rank] = -1;
	max_increase_local[rank] = -1;

	for(int i = (m + p - 1) / p * rank;i < min(m,(m + p - 1) / p * (rank + 1));++i){
		if(in_tree[i]){
			memset(visited,false,sizeof visited);
			dfs2(e[i].u,e[i].v,e[i].u);
			dfs2(e[i].v,e[i].u,e[i].v);

			printf("process %d, (%d, %d) :",rank,e[i].u,e[i].v);

			int rep = -1;

			for(int j = 0;j < m;++j)
				if(j != i && ((mark[ e[j].u ] == e[i].u && mark[ e[j].v ] == e[i].v) || (mark[ e[j].v ] == e[i].u && mark[ e[j].u ] == e[i].v))){
					printf(" (%d, %d)",e[j].u,e[j].v);

					if(rep == -1 || e[j].w < e[rep].w)
						rep = j;
				}

			printf(", replacement : (%d, %d)\n",e[rep].u,e[rep].v);

			if(e[rep].w - e[i].w > max_increase_local[rank]){
				max_increase_local[rank] = e[rep].w - e[i].w;
				most_vital_edge_local[rank] = i;
			}
		}
	}

	if(rank != 0){
		MPI_Send(&max_increase_local[rank],1,MPI_INT,0,2,MPI_COMM_WORLD);
		MPI_Send(&most_vital_edge_local[rank],1,MPI_INT,0,3,MPI_COMM_WORLD);
	}else{
		int most_vital_edge = most_vital_edge_local[0],max_increase = max_increase_local[0];
		MPI_Status status;

		for(int i = 1;i < p;++i){
			MPI_Recv(&max_increase_local[i],1,MPI_INT,i,2,MPI_COMM_WORLD,&status);
			MPI_Recv(&most_vital_edge_local[i],1,MPI_INT,i,3,MPI_COMM_WORLD,&status);

			if(max_increase_local[i] > max_increase){
				max_increase = max_increase_local[i];
				most_vital_edge = most_vital_edge_local[i];
			}
		}

		printf("\n");
		printf("Most vital edge = (%d, %d)\n",e[most_vital_edge].u,e[most_vital_edge].v);
		printf("Increase = %d\n",max_increase);
	}

	MPI_Finalize();

	return 0;
}<commit_msg>erase debug prints<commit_after>#include <cstdio>
#include <cstring>
#include <climits>
#include <algorithm>
#include <vector>

#include <mpi.h>

using namespace std;

#define MAXN 100
#define MAXM 10000

int p,rank;
int n,m;

struct edge{
	int u,v,w;
	int id;

	bool operator < (edge e) const{
		return w < e.w;
	}
}e[MAXM],e_local[MAXM];

bool in_tree[MAXM];

// Union - Find

int parent[MAXN + 1],uf_rank[MAXN + 1];
int Find(int x){
	if(parent[x] == x) return x;
	parent[x] = Find(parent[x]);
	return parent[x];
}

void Union(int x, int y){
	x = Find(x);
	y = Find(y);

	if(uf_rank[x] < uf_rank[y]){
		parent[x] = y;
	}else{
		parent[y] = x;

		if(uf_rank[x] == uf_rank[y])
			++uf_rank[x];
	}
}

// dfs to find a path between two nodes in the MST

vector<int> L[MAXN],edge_id[MAXN],path,path_edges;
bool visited[MAXN];

bool dfs(int u, int v){
	path.push_back(u);

	if(u == v) return true;

	bool ret = false;

	if(!visited[u]){
		visited[u] = true;

		for(int i = 0;i < L[u].size();++i){
			int to = L[u][i];
			path_edges.push_back(edge_id[u][i]);

			if(dfs(to,v)){
				ret = true;
				break;
			}else{
				path_edges.pop_back();
			}
		}
	}

	if(!ret)
		path.pop_back();

	return ret;
}

// dfs to mark edges in a subtree after erasing an edge

int mark[MAXN];

void dfs2(int u, int v, int cur){
	if(visited[cur]) return;
	visited[cur] = true;

	mark[cur] = u;

	for(int i = 0;i < L[cur].size();++i){
		int to = L[cur][i];

		if(to != u && to != v)
			dfs2(u,v,to);
	}
}

int main(int argc, char *argv[]){
	MPI_Init(&argc,&argv);
	MPI_Comm_size(MPI_COMM_WORLD,&p);
	MPI_Comm_rank(MPI_COMM_WORLD,&rank);

	if(rank == 0){
		n = m = 0;

		while(scanf("%d,%d,%d",&e[m].u,&e[m].v,&e[m].w) == 3){
			n = max(n,max(e[m].u,e[m].v));
			e[m].id = m;
			++m;
		}
	}

	MPI_Bcast(&n,1,MPI_INT,0,MPI_COMM_WORLD);
	MPI_Bcast(&m,1,MPI_INT,0,MPI_COMM_WORLD);

	int blocklengths[] = {1,1,1,1};
	MPI_Aint displacements[] = {offsetof(edge,u), offsetof(edge,v), offsetof(edge,w), offsetof(edge,id)};
	MPI_Datatype types[] = {MPI_INT, MPI_INT, MPI_INT, MPI_INT};
	MPI_Datatype MPI_EDGE;

	MPI_Type_create_struct(4,blocklengths,displacements,types,&MPI_EDGE);
	MPI_Type_commit(&MPI_EDGE);

	MPI_Bcast(e,m,MPI_EDGE,0,MPI_COMM_WORLD);

	// Find minimum spanning tree using Kruskal's algorithm

	for(int i = 1;i <= n;++i){
		parent[i] = i;
		uf_rank[i] = 0;
	}

	int start = (m + p - 1) / p * rank,end = min(m,(m + p - 1) / p * (rank + 1));
	int m_local = 0;

	for(int i = start;i < end;++i)
		e_local[i - start] = e[i];

	sort(e_local,e_local + (end - start));

	for(int i = 0;i < end - start;++i){
		if(Find(e_local[i].u) != Find(e_local[i].v)){
			Union(e_local[i].u,e_local[i].v);
			e_local[m_local] = e_local[i];
			m_local++;
		}
	}

	int curP = p;

	while(curP > 1){
		if(rank < curP){
			int m1 = 0,m2 = 0;
			MPI_Status status;

			MPI_Send(&m_local,1,MPI_INT,rank / 2,0,MPI_COMM_WORLD);
			MPI_Send(e_local,m_local,MPI_EDGE,rank / 2,1,MPI_COMM_WORLD);

			if(2 * rank < curP){
				MPI_Recv(&m1,1,MPI_INT,2 * rank,0,MPI_COMM_WORLD,&status);
				MPI_Recv(e_local,m1,MPI_EDGE,2 * rank,1,MPI_COMM_WORLD,&status);

				if(2 * rank + 1 < curP){
					MPI_Recv(&m2,1,MPI_INT,2 * rank + 1,0,MPI_COMM_WORLD,&status);
					MPI_Recv(e_local + m1,m2,MPI_EDGE,2 * rank + 1,1,MPI_COMM_WORLD,&status);
				}

				int m_aux = m1 + m2;
				sort(e_local,e_local + m_aux);

				for(int i = 1;i <= n;++i){
					parent[i] = i;
					uf_rank[i] = 0;
				}

				m_local = 0;

				for(int i = 0;i < m_aux;++i){
					if(Find(e_local[i].u) != Find(e_local[i].v)){
						Union(e_local[i].u,e_local[i].v);
						e_local[m_local] = e_local[i];
						m_local++;
					}
				}
			}
		}

		curP = (curP + 1) / 2;
	}

	if(rank == 0){
		int total = 0;

		for(int i = 0;i < m_local;++i){
			L[ e_local[i].u ].push_back(e_local[i].v);
			edge_id[ e_local[i].u ].push_back(e_local[i].id);

			L[ e_local[i].v ].push_back(e_local[i].u);
			edge_id[ e_local[i].v ].push_back(e_local[i].id);

			in_tree[ e_local[i].id ] = true;

			printf("%d - %d (%d)\n",e_local[i].u,e_local[i].v,e_local[i].w);
			total += e_local[i].w;
		}

		printf("Total weight = %d\n\n",total);
	}

	for(int i = 1;i <= n;++i){
		int list_size;

		if(rank == 0)
			list_size = L[i].size();

		MPI_Bcast(&list_size,1,MPI_INT,0,MPI_COMM_WORLD);

		L[i].resize(list_size);
		MPI_Bcast(&L[i].front(),list_size,MPI_INT,0,MPI_COMM_WORLD);

		edge_id[i].resize(list_size);
		MPI_Bcast(&edge_id[i].front(),list_size,MPI_INT,0,MPI_COMM_WORLD);
	}

	MPI_Bcast(in_tree,m,MPI_C_BOOL,0,MPI_COMM_WORLD);

	// Find the path int T that connect two endpoint of an edge

	bool verified_local = true;

	for(int i = (m + p - 1) / p * rank;i < min(m,(m + p - 1) / p * (rank + 1));++i){
		if(!in_tree[i]){
			memset(visited,false,sizeof visited);
			path.clear();
			dfs(e[i].u,e[i].v);

			printf("process %d, (%d, %d) : ",rank,e[i].u,e[i].v);

			for(int j = 0;j < path.size();++j){
				if(j > 0) printf(" -> ");
				printf("%d",path[j]);
			}

			printf("\n");

			// Verify MST

			for(int j = 0;j < path_edges.size();++j){
				if(e[i].w < e[ path_edges[j] ].w)
					verified_local = false;
			}
		}
	}

	printf("\n");

	bool verified_global;
	MPI_Reduce(&verified_local,&verified_global,1,MPI_C_BOOL,MPI_LAND,0,MPI_COMM_WORLD);

	if(rank == 0){
		printf("Verification: ");
		if(verified_global) printf("It is an MST\n\n");
		else printf("It is not an MST\n\n");
	}

	// Find edges that can replace an edge in the MST

	int most_vital_edge_local[p];
	int max_increase_local[p];
	most_vital_edge_local[rank] = -1;
	max_increase_local[rank] = -1;

	for(int i = (m + p - 1) / p * rank;i < min(m,(m + p - 1) / p * (rank + 1));++i){
		if(in_tree[i]){
			memset(visited,false,sizeof visited);
			dfs2(e[i].u,e[i].v,e[i].u);
			dfs2(e[i].v,e[i].u,e[i].v);

			printf("process %d, (%d, %d) :",rank,e[i].u,e[i].v);

			int rep = -1;

			for(int j = 0;j < m;++j)
				if(j != i && ((mark[ e[j].u ] == e[i].u && mark[ e[j].v ] == e[i].v) || (mark[ e[j].v ] == e[i].u && mark[ e[j].u ] == e[i].v))){
					printf(" (%d, %d)",e[j].u,e[j].v);

					if(rep == -1 || e[j].w < e[rep].w)
						rep = j;
				}

			printf(", replacement : (%d, %d)\n",e[rep].u,e[rep].v);

			if(e[rep].w - e[i].w > max_increase_local[rank]){
				max_increase_local[rank] = e[rep].w - e[i].w;
				most_vital_edge_local[rank] = i;
			}
		}
	}

	if(rank != 0){
		MPI_Send(&max_increase_local[rank],1,MPI_INT,0,2,MPI_COMM_WORLD);
		MPI_Send(&most_vital_edge_local[rank],1,MPI_INT,0,3,MPI_COMM_WORLD);
	}else{
		int most_vital_edge = most_vital_edge_local[0],max_increase = max_increase_local[0];
		MPI_Status status;

		for(int i = 1;i < p;++i){
			MPI_Recv(&max_increase_local[i],1,MPI_INT,i,2,MPI_COMM_WORLD,&status);
			MPI_Recv(&most_vital_edge_local[i],1,MPI_INT,i,3,MPI_COMM_WORLD,&status);

			if(max_increase_local[i] > max_increase){
				max_increase = max_increase_local[i];
				most_vital_edge = most_vital_edge_local[i];
			}
		}

		printf("\n");
		printf("Most vital edge = (%d, %d)\n",e[most_vital_edge].u,e[most_vital_edge].v);
		printf("Increase = %d\n",max_increase);
	}

	MPI_Finalize();

	return 0;
}<|endoftext|>


<commit_before>#ifndef INCLUDED_TOBY_MULTIVISITOR_H
#define INCLUDED_TOBY_MULTIVISITOR_H

#include "overload_set.hpp"

#include <tuple>

namespace toby {

namespace detail {
template <typename Callable, typename Tuple,
          size_t... I>
auto apply_impl(Callable&& f, Tuple&& t,
                std::index_sequence<I...>) {
  return f(std::get<I>(t)...);
}
}

template <typename Callable, typename Tuple>
auto apply(Callable&& f, Tuple&& t) {
  using is = std::make_index_sequence<
      std::tuple_size<std::decay_t<Tuple>>::value>;
  return detail::apply_impl(std::forward<Callable>(f),
                            std::forward<Tuple>(t),
                            is());
}

template <typename R, typename F>
class multivisitor {
 private:
  F m_f;

 public:
  explicit multivisitor(F&& f) : m_f(f) {}

  template <typename... Vs>
  auto operator()(const Vs&... args) {
    return collect(std::tuple<>(), args...);
  }

 private:
  template <typename T>
  auto collect(const T& t) {
    return apply(m_f, t);
  }

  template <typename T, typename V, typename... Vs>
  auto collect(const T& t, const V& arg,
               const Vs&... args) {
    return arg.template visit<R>([&](auto v) {
      return this->collect(
          std::tuple_cat(t, std::make_tuple(v)),
          args...);
    });
  }
};

template <typename T, typename F>
auto make_multivisitor(F&& f) {
  return multivisitor<T, F>(std::forward<F>(f));
}

template <typename T, typename... Fs>
auto make_multivisitor(Fs&&... fs) {
  return make_multivisitor<T>(
      make_overload_set(std::forward<Fs>(fs)...));
}

}  // namespace toby

#endif
<commit_msg>multivisitor: avoid a copy when collecting values<commit_after>#ifndef INCLUDED_TOBY_MULTIVISITOR_H
#define INCLUDED_TOBY_MULTIVISITOR_H

#include "overload_set.hpp"

#include <tuple>

namespace toby {

namespace detail {
template <typename Callable, typename Tuple,
          size_t... I>
auto apply_impl(Callable&& f, Tuple&& t,
                std::index_sequence<I...>) {
  return f(std::get<I>(t)...);
}
}

template <typename Callable, typename Tuple>
auto apply(Callable&& f, Tuple&& t) {
  using is = std::make_index_sequence<
      std::tuple_size<std::decay_t<Tuple>>::value>;
  return detail::apply_impl(std::forward<Callable>(f),
                            std::forward<Tuple>(t),
                            is());
}

template <typename R, typename F>
class multivisitor {
 private:
  F m_f;

 public:
  explicit multivisitor(F&& f) : m_f(f) {}

  template <typename... Vs>
  auto operator()(const Vs&... args) {
    return collect(std::tuple<>(), args...);
  }

 private:
  template <typename T>
  auto collect(const T& t) {
    return apply(m_f, t);
  }

  template <typename T, typename V, typename... Vs>
  auto collect(const T& t, const V& arg,
               const Vs&... args) {
    return arg.template visit<R>([&](const auto& v) {
      return this->collect(
          std::tuple_cat(t, std::tuple<decltype(v)>(v)),
          args...);
    });
  }
};

template <typename T, typename F>
auto make_multivisitor(F&& f) {
  return multivisitor<T, F>(std::forward<F>(f));
}

template <typename T, typename... Fs>
auto make_multivisitor(Fs&&... fs) {
  return make_multivisitor<T>(
      make_overload_set(std::forward<Fs>(fs)...));
}

}  // namespace toby

#endif
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <stdio.h>
#ifndef _WIN32
#include <unistd.h>
#endif

#include <list>

#include <unotools/streamwrap.hxx>
#include <unotools/ucbstreamhelper.hxx>

#include <comphelper/processfactory.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/registry/XSimpleRegistry.hpp>
#include <com/sun/star/ucb/UniversalContentBroker.hpp>

#include <tools/urlobj.hxx>
#include <vcl/vclmain.hxx>

#include <osl/file.hxx>
#include <osl/process.h>
#include <rtl/bootstrap.hxx>
#include <vcl/svapp.hxx>

#include <svx/galtheme.hxx>
#include <svx/gallery1.hxx>

using namespace ::com::sun::star;

typedef ::std::list<OUString> FileNameList;

class GalApp : public Application
{
    bool mbInBuildTree;
    bool mbRelativeURLs;
public:
    GalApp() : mbInBuildTree( false ), mbRelativeURLs( false ) {}
    virtual int Main();

protected:
    uno::Reference<lang::XMultiServiceFactory> xMSF;
    void Init();
};

Gallery* createGallery( const OUString& rURL )
{
    return new Gallery( rURL );
}

void disposeGallery( Gallery* pGallery )
{
    delete pGallery;
}

static void createTheme( OUString aThemeName, OUString aGalleryURL,
                         OUString aDestDir, FileNameList &rFiles,
                         bool bRelativeURLs )
{
    Gallery* pGallery;

    pGallery = createGallery( aGalleryURL );
    if (!pGallery ) {
            fprintf( stderr, "Could't create '%s'\n",
                     OUStringToOString( aGalleryURL, RTL_TEXTENCODING_UTF8 ).getStr() );
            exit( 1 );
    }
    fprintf( stderr, "Work on gallery '%s'\n",
             OUStringToOString( aGalleryURL, RTL_TEXTENCODING_UTF8 ).getStr() );

    fprintf( stderr, "Existing themes: %" SAL_PRI_SIZET "u\n",
             pGallery->GetThemeCount() );

    GalleryTheme *pGalTheme;
    if( !pGallery->HasTheme( aThemeName) ) {
            if( !pGallery->CreateTheme( aThemeName ) ) {
                    fprintf( stderr, "Failed to create theme\n" );
                    exit( 1 );
            }
    }

    fprintf( stderr, "Existing themes: %" SAL_PRI_SIZET "u\n",
             pGallery->GetThemeCount() );

    SfxListener aListener;

    if ( !( pGalTheme = pGallery->AcquireTheme( aThemeName, aListener ) ) ) {
            fprintf( stderr, "Failed to acquire theme\n" );
            exit( 1 );
    }

    fprintf( stderr, "Using DestDir: %s\n",
             OUStringToOString( aDestDir, RTL_TEXTENCODING_UTF8 ).getStr() );
    pGalTheme->SetDestDir( String( aDestDir ), bRelativeURLs );

    FileNameList::const_iterator aIter;

    for( aIter = rFiles.begin(); aIter != rFiles.end(); ++aIter )
    {
//  Should/could use:
//    if ( ! pGalTheme->InsertFileOrDirURL( aURL ) ) {
//    Requires a load more components ...

        Graphic aGraphic;

        if ( ! pGalTheme->InsertURL( *aIter ) )
            fprintf( stderr, "Failed to import '%s'\n",
                     OUStringToOString( *aIter, RTL_TEXTENCODING_UTF8 ).getStr() );
        else
            fprintf( stderr, "Imported file '%s' (%" SAL_PRI_SIZET "u)\n",
                     OUStringToOString( *aIter, RTL_TEXTENCODING_UTF8 ).getStr(),
                     pGalTheme->GetObjectCount() );
    }

    pGallery->ReleaseTheme( pGalTheme, aListener );

    disposeGallery( pGallery );
}

static int PrintHelp()
{
    fprintf( stdout, "Utility to generate LibreOffice gallery files\n\n" );

    fprintf( stdout, "using: gengal --name <name> --path <dir> [ --destdir <path> ]\n");
    fprintf( stdout, "              [ files ... ]\n\n" );

    fprintf( stdout, "options:\n");
    fprintf( stdout, " --name <theme>\t\tdefines the user visible name of the created or updated theme.\n");

    fprintf( stdout, " --path <dir>\t\tdefines directory where the gallery files are created\n");
    fprintf( stdout, "\t\t\tor updated.\n");

    fprintf( stdout, " --destdir <dir>\tdefines a path prefix to be removed from the paths\n");
    fprintf( stdout, "\t\t\tstored in the gallery files. It is useful to create\n");
    fprintf( stdout, "\t\t\tRPM packages using the BuildRoot feature.\n");

    fprintf( stdout, " --relative-urls\t\tflags that after removing the destdir, the URL should be a path relative to the gallery folder in the install\n");
    fprintf( stdout, "\t\t\tprimarily used for internal gallery generation at compile time.\n");
    fprintf( stdout, "\t\t\ttheme files.\n");
    fprintf( stdout, " files\t\t\tlists files to be added to the gallery. Absolute paths\n");
    fprintf( stdout, "\t\t\tare required.\n");
    // --build-tree not documented - only useful during the build ...

    return EXIT_SUCCESS;
}

static OUString Smartify( const OUString &rPath )
{
    INetURLObject aURL;
    aURL.SetSmartURL( rPath );
    return aURL.GetMainURL( INetURLObject::NO_DECODE );
}

void GalApp::Init()
{
    try {
        if( !mbInBuildTree && getenv( "OOO_INSTALL_PREFIX" ) == NULL ) {
            OUString fileName = GetAppFileName();
            int lastSlash = fileName.lastIndexOf( '/' );
#ifdef WNT
        // Don't know which directory separators GetAppFileName() returns on Windows.
        // Be safe and take into consideration they might be backslashes.
            if( fileName.lastIndexOf( '\\' ) > lastSlash )
                lastSlash = fileName.lastIndexOf( '\\' );
#endif
            OUString baseBinDir = fileName.copy( 0, lastSlash );
            OUString installPrefix = baseBinDir + OUString::createFromAscii( "/../.." );

            OUString envVar( "OOO_INSTALL_PREFIX");
            osl_setEnvironment(envVar.pData, installPrefix.pData);
        }
        OSL_TRACE( "OOO_INSTALL_PREFIX=%s", getenv( "OOO_INSTALL_PREFIX" ) );

        uno::Reference<uno::XComponentContext> xComponentContext
            = ::cppu::defaultBootstrap_InitialComponentContext();
        xMSF = uno::Reference<lang::XMultiServiceFactory>
            ( xComponentContext->getServiceManager(), uno::UNO_QUERY );
        if( !xMSF.is() )
        {
            fprintf( stderr, "Failed to bootstrap\n" );
            exit( 1 );
        }
        ::comphelper::setProcessServiceFactory( xMSF );

        // For backwards compatibility, in case some code still uses plain
        // createInstance w/o args directly to obtain an instance:
        com::sun::star::ucb::UniversalContentBroker::create(xComponentContext);
    } catch (const uno::Exception &e) {
        fprintf( stderr, "Bootstrap exception '%s'\n",
                 rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
        exit( 1 );
    }
}

int GalApp::Main()
{
    OUString aPath, aDestDir;
    OUString aName( "Default name" );
    FileNameList aFiles;

    for( sal_uInt32 i = 0; i < GetCommandLineParamCount(); i++ )
    {
        OUString aParam = GetCommandLineParam( i );

        if ( aParam.startsWith( "-env:" ) )
            continue;
        else if ( aParam == "--help" || aParam == "-h"  )
            return PrintHelp();
        else if ( aParam == "--build-tree" )
        {
            mbRelativeURLs = true;
            mbInBuildTree = true;
        }
        else if ( aParam == "--name" )
            aName = GetCommandLineParam( ++i );
        else if ( aParam == "--path" )
            aPath = Smartify( GetCommandLineParam( ++i ) );
        else if ( aParam == "--destdir" )
            aDestDir = GetCommandLineParam( ++i );
        else if ( aParam == "--relative-urls" )
            mbRelativeURLs = true;
        else if ( aParam == "--number-from" )
            fprintf ( stderr, "--number-from is deprecated, themes now "
                      "have filenames based on their names\n" );
        else
            aFiles.push_back( Smartify( aParam ) );
    }

    if( aFiles.size() < 1 )
        return PrintHelp();

    createTheme( aName, aPath, aDestDir, aFiles, mbRelativeURLs );

    // Without this we get extraordinary crashes from the
    // drawinglayer VirtualDevice cache when importing svg
    uno::Reference< lang::XComponent >(
        comphelper::getProcessComponentContext(),
        uno::UNO_QUERY_THROW )-> dispose();
    ::comphelper::setProcessServiceFactory( NULL );

    return EXIT_SUCCESS;
}

void vclmain::createApplication()
{
    static GalApp aGalApp;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Do not dispose component context too early (DeInitVCL might still need it)<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <stdio.h>
#ifndef _WIN32
#include <unistd.h>
#endif

#include <list>

#include <unotools/streamwrap.hxx>
#include <unotools/ucbstreamhelper.hxx>

#include <comphelper/processfactory.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/registry/XSimpleRegistry.hpp>
#include <com/sun/star/ucb/UniversalContentBroker.hpp>

#include <tools/urlobj.hxx>
#include <vcl/vclmain.hxx>

#include <osl/file.hxx>
#include <osl/process.h>
#include <rtl/bootstrap.hxx>
#include <vcl/svapp.hxx>

#include <svx/galtheme.hxx>
#include <svx/gallery1.hxx>

using namespace ::com::sun::star;

typedef ::std::list<OUString> FileNameList;

class GalApp : public Application
{
    bool mbInBuildTree;
    bool mbRelativeURLs;
public:
    GalApp() : mbInBuildTree( false ), mbRelativeURLs( false ) {}
    virtual int Main();

protected:
    uno::Reference<lang::XMultiServiceFactory> xMSF;
    void Init();
    void DeInit();
};

Gallery* createGallery( const OUString& rURL )
{
    return new Gallery( rURL );
}

void disposeGallery( Gallery* pGallery )
{
    delete pGallery;
}

static void createTheme( OUString aThemeName, OUString aGalleryURL,
                         OUString aDestDir, FileNameList &rFiles,
                         bool bRelativeURLs )
{
    Gallery* pGallery;

    pGallery = createGallery( aGalleryURL );
    if (!pGallery ) {
            fprintf( stderr, "Could't create '%s'\n",
                     OUStringToOString( aGalleryURL, RTL_TEXTENCODING_UTF8 ).getStr() );
            exit( 1 );
    }
    fprintf( stderr, "Work on gallery '%s'\n",
             OUStringToOString( aGalleryURL, RTL_TEXTENCODING_UTF8 ).getStr() );

    fprintf( stderr, "Existing themes: %" SAL_PRI_SIZET "u\n",
             pGallery->GetThemeCount() );

    GalleryTheme *pGalTheme;
    if( !pGallery->HasTheme( aThemeName) ) {
            if( !pGallery->CreateTheme( aThemeName ) ) {
                    fprintf( stderr, "Failed to create theme\n" );
                    exit( 1 );
            }
    }

    fprintf( stderr, "Existing themes: %" SAL_PRI_SIZET "u\n",
             pGallery->GetThemeCount() );

    SfxListener aListener;

    if ( !( pGalTheme = pGallery->AcquireTheme( aThemeName, aListener ) ) ) {
            fprintf( stderr, "Failed to acquire theme\n" );
            exit( 1 );
    }

    fprintf( stderr, "Using DestDir: %s\n",
             OUStringToOString( aDestDir, RTL_TEXTENCODING_UTF8 ).getStr() );
    pGalTheme->SetDestDir( String( aDestDir ), bRelativeURLs );

    FileNameList::const_iterator aIter;

    for( aIter = rFiles.begin(); aIter != rFiles.end(); ++aIter )
    {
//  Should/could use:
//    if ( ! pGalTheme->InsertFileOrDirURL( aURL ) ) {
//    Requires a load more components ...

        Graphic aGraphic;

        if ( ! pGalTheme->InsertURL( *aIter ) )
            fprintf( stderr, "Failed to import '%s'\n",
                     OUStringToOString( *aIter, RTL_TEXTENCODING_UTF8 ).getStr() );
        else
            fprintf( stderr, "Imported file '%s' (%" SAL_PRI_SIZET "u)\n",
                     OUStringToOString( *aIter, RTL_TEXTENCODING_UTF8 ).getStr(),
                     pGalTheme->GetObjectCount() );
    }

    pGallery->ReleaseTheme( pGalTheme, aListener );

    disposeGallery( pGallery );
}

static int PrintHelp()
{
    fprintf( stdout, "Utility to generate LibreOffice gallery files\n\n" );

    fprintf( stdout, "using: gengal --name <name> --path <dir> [ --destdir <path> ]\n");
    fprintf( stdout, "              [ files ... ]\n\n" );

    fprintf( stdout, "options:\n");
    fprintf( stdout, " --name <theme>\t\tdefines the user visible name of the created or updated theme.\n");

    fprintf( stdout, " --path <dir>\t\tdefines directory where the gallery files are created\n");
    fprintf( stdout, "\t\t\tor updated.\n");

    fprintf( stdout, " --destdir <dir>\tdefines a path prefix to be removed from the paths\n");
    fprintf( stdout, "\t\t\tstored in the gallery files. It is useful to create\n");
    fprintf( stdout, "\t\t\tRPM packages using the BuildRoot feature.\n");

    fprintf( stdout, " --relative-urls\t\tflags that after removing the destdir, the URL should be a path relative to the gallery folder in the install\n");
    fprintf( stdout, "\t\t\tprimarily used for internal gallery generation at compile time.\n");
    fprintf( stdout, "\t\t\ttheme files.\n");
    fprintf( stdout, " files\t\t\tlists files to be added to the gallery. Absolute paths\n");
    fprintf( stdout, "\t\t\tare required.\n");
    // --build-tree not documented - only useful during the build ...

    return EXIT_SUCCESS;
}

static OUString Smartify( const OUString &rPath )
{
    INetURLObject aURL;
    aURL.SetSmartURL( rPath );
    return aURL.GetMainURL( INetURLObject::NO_DECODE );
}

void GalApp::Init()
{
    try {
        if( !mbInBuildTree && getenv( "OOO_INSTALL_PREFIX" ) == NULL ) {
            OUString fileName = GetAppFileName();
            int lastSlash = fileName.lastIndexOf( '/' );
#ifdef WNT
        // Don't know which directory separators GetAppFileName() returns on Windows.
        // Be safe and take into consideration they might be backslashes.
            if( fileName.lastIndexOf( '\\' ) > lastSlash )
                lastSlash = fileName.lastIndexOf( '\\' );
#endif
            OUString baseBinDir = fileName.copy( 0, lastSlash );
            OUString installPrefix = baseBinDir + OUString::createFromAscii( "/../.." );

            OUString envVar( "OOO_INSTALL_PREFIX");
            osl_setEnvironment(envVar.pData, installPrefix.pData);
        }
        OSL_TRACE( "OOO_INSTALL_PREFIX=%s", getenv( "OOO_INSTALL_PREFIX" ) );

        uno::Reference<uno::XComponentContext> xComponentContext
            = ::cppu::defaultBootstrap_InitialComponentContext();
        xMSF = uno::Reference<lang::XMultiServiceFactory>
            ( xComponentContext->getServiceManager(), uno::UNO_QUERY );
        if( !xMSF.is() )
        {
            fprintf( stderr, "Failed to bootstrap\n" );
            exit( 1 );
        }
        ::comphelper::setProcessServiceFactory( xMSF );

        // For backwards compatibility, in case some code still uses plain
        // createInstance w/o args directly to obtain an instance:
        com::sun::star::ucb::UniversalContentBroker::create(xComponentContext);
    } catch (const uno::Exception &e) {
        fprintf( stderr, "Bootstrap exception '%s'\n",
                 rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
        exit( 1 );
    }
}

int GalApp::Main()
{
    OUString aPath, aDestDir;
    OUString aName( "Default name" );
    FileNameList aFiles;

    for( sal_uInt32 i = 0; i < GetCommandLineParamCount(); i++ )
    {
        OUString aParam = GetCommandLineParam( i );

        if ( aParam.startsWith( "-env:" ) )
            continue;
        else if ( aParam == "--help" || aParam == "-h"  )
            return PrintHelp();
        else if ( aParam == "--build-tree" )
        {
            mbRelativeURLs = true;
            mbInBuildTree = true;
        }
        else if ( aParam == "--name" )
            aName = GetCommandLineParam( ++i );
        else if ( aParam == "--path" )
            aPath = Smartify( GetCommandLineParam( ++i ) );
        else if ( aParam == "--destdir" )
            aDestDir = GetCommandLineParam( ++i );
        else if ( aParam == "--relative-urls" )
            mbRelativeURLs = true;
        else if ( aParam == "--number-from" )
            fprintf ( stderr, "--number-from is deprecated, themes now "
                      "have filenames based on their names\n" );
        else
            aFiles.push_back( Smartify( aParam ) );
    }

    if( aFiles.size() < 1 )
        return PrintHelp();

    createTheme( aName, aPath, aDestDir, aFiles, mbRelativeURLs );

    return EXIT_SUCCESS;
}

void GalApp::DeInit()
{
    uno::Reference< lang::XComponent >(
        comphelper::getProcessComponentContext(),
        uno::UNO_QUERY_THROW )-> dispose();
    ::comphelper::setProcessServiceFactory( NULL );
}

void vclmain::createApplication()
{
    static GalApp aGalApp;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: linenum.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: fme $ $Date: 2001-06-01 10:20:44 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _SWLINENUM_HXX
#define _SWLINENUM_HXX

#ifndef _BASEDLGS_HXX //autogen
#include <sfx2/basedlgs.hxx>
#endif

#ifndef _SFXTABDLG_HXX //autogen
#include <sfx2/tabdlg.hxx>
#endif

#ifndef _SV_FIXED_HXX //autogen
#include <vcl/fixed.hxx>
#endif

#ifndef _SV_FIELD_HXX //autogen
#include <vcl/field.hxx>
#endif
#ifndef _NUMBERINGTYPELISTBOX_HXX
#include <numberingtypelistbox.hxx>
#endif

#ifndef _LSTBOX_HXX //autogen
#include <vcl/lstbox.hxx>
#endif

class Window;
class SfxItemSet;
class SwView;
class SwWrtShell;

/*--------------------------------------------------------------------
   Beschreibung: SingleTabDialog
 --------------------------------------------------------------------*/

class SwLineNumberingDlg : public SfxSingleTabDialog
{
    SwWrtShell* pSh;

    DECL_LINK( OKHdl, Button * );

public:
    inline SwWrtShell* GetWrtShell() const { return pSh; }

     SwLineNumberingDlg(SwView *pVw);
    ~SwLineNumberingDlg();
};

/*--------------------------------------------------------------------
   Beschreibung: TabPage
 --------------------------------------------------------------------*/

class SwLineNumberingPage : public SfxTabPage
{
    CheckBox        aNumberingOnCB;
    FixedText       aCharStyleFT;
    ListBox         aCharStyleLB;
    FixedText       aFormatFT;
    SwNumberingTypeListBox   aFormatLB;
    FixedText       aPosFT;
    ListBox         aPosLB;
    FixedText       aOffsetFT;
    MetricField     aOffsetMF;
    FixedText       aNumIntervalFT;
    NumericField    aNumIntervalNF;
    FixedText       aNumRowsFT;
    FixedLine        aDisplayFL;
    FixedText       aDivisorFT;
    Edit            aDivisorED;
    FixedText       aDivIntervalFT;
    NumericField    aDivIntervalNF;
    FixedText       aDivRowsFT;
    FixedLine        aDivisorFL;
    CheckBox        aCountEmptyLinesCB;
    CheckBox        aCountFrameLinesCB;
    CheckBox        aRestartEachPageCB;
    FixedLine        aCountFL;

    SwWrtShell*     pSh;

    SwLineNumberingPage( Window* pParent, const SfxItemSet& rSet );
    ~SwLineNumberingPage();

    DECL_LINK( LineOnOffHdl, CheckBox *pCB = 0 );
    DECL_LINK( ModifyHdl, Edit *pED = 0 );

public:

    static SfxTabPage*  Create( Window* pParent, const SfxItemSet& rAttrSet );

    virtual BOOL        FillItemSet( SfxItemSet& rSet );
    virtual void        Reset( const SfxItemSet& rSet );
};

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.3.1448); FILE MERGED 2005/09/05 13:45:20 rt 1.3.1448.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: linenum.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 09:24:44 $
 *
 *  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 _SWLINENUM_HXX
#define _SWLINENUM_HXX

#ifndef _BASEDLGS_HXX //autogen
#include <sfx2/basedlgs.hxx>
#endif

#ifndef _SFXTABDLG_HXX //autogen
#include <sfx2/tabdlg.hxx>
#endif

#ifndef _SV_FIXED_HXX //autogen
#include <vcl/fixed.hxx>
#endif

#ifndef _SV_FIELD_HXX //autogen
#include <vcl/field.hxx>
#endif
#ifndef _NUMBERINGTYPELISTBOX_HXX
#include <numberingtypelistbox.hxx>
#endif

#ifndef _LSTBOX_HXX //autogen
#include <vcl/lstbox.hxx>
#endif

class Window;
class SfxItemSet;
class SwView;
class SwWrtShell;

/*--------------------------------------------------------------------
   Beschreibung: SingleTabDialog
 --------------------------------------------------------------------*/

class SwLineNumberingDlg : public SfxSingleTabDialog
{
    SwWrtShell* pSh;

    DECL_LINK( OKHdl, Button * );

public:
    inline SwWrtShell* GetWrtShell() const { return pSh; }

     SwLineNumberingDlg(SwView *pVw);
    ~SwLineNumberingDlg();
};

/*--------------------------------------------------------------------
   Beschreibung: TabPage
 --------------------------------------------------------------------*/

class SwLineNumberingPage : public SfxTabPage
{
    CheckBox        aNumberingOnCB;
    FixedText       aCharStyleFT;
    ListBox         aCharStyleLB;
    FixedText       aFormatFT;
    SwNumberingTypeListBox   aFormatLB;
    FixedText       aPosFT;
    ListBox         aPosLB;
    FixedText       aOffsetFT;
    MetricField     aOffsetMF;
    FixedText       aNumIntervalFT;
    NumericField    aNumIntervalNF;
    FixedText       aNumRowsFT;
    FixedLine        aDisplayFL;
    FixedText       aDivisorFT;
    Edit            aDivisorED;
    FixedText       aDivIntervalFT;
    NumericField    aDivIntervalNF;
    FixedText       aDivRowsFT;
    FixedLine        aDivisorFL;
    CheckBox        aCountEmptyLinesCB;
    CheckBox        aCountFrameLinesCB;
    CheckBox        aRestartEachPageCB;
    FixedLine        aCountFL;

    SwWrtShell*     pSh;

    SwLineNumberingPage( Window* pParent, const SfxItemSet& rSet );
    ~SwLineNumberingPage();

    DECL_LINK( LineOnOffHdl, CheckBox *pCB = 0 );
    DECL_LINK( ModifyHdl, Edit *pED = 0 );

public:

    static SfxTabPage*  Create( Window* pParent, const SfxItemSet& rAttrSet );

    virtual BOOL        FillItemSet( SfxItemSet& rSet );
    virtual void        Reset( const SfxItemSet& rSet );
};

#endif

<|endoftext|>


<commit_before>/**
 * \file
 * \brief SignalsCatcherControlBlock class header
 *
 * \author Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-04-18
 */

#ifndef INCLUDE_DISTORTOS_SYNCHRONIZATION_SIGNALSCATCHERCONTROLBLOCK_HPP_
#define INCLUDE_DISTORTOS_SYNCHRONIZATION_SIGNALSCATCHERCONTROLBLOCK_HPP_

#include "distortos/SignalAction.hpp"

namespace distortos
{

namespace synchronization
{

/// SignalsCatcherControlBlock class is a structure required by threads for "catching" and "handling" of signals
class SignalsCatcherControlBlock
{
public:

	/// association of signal number with SignalAction
	using Association = std::pair<uint8_t, SignalAction>;

	/// type of uninitialized storage for Association objects
	using Storage = std::aligned_storage<sizeof(Association), alignof(Association)>::type;

	/**
	 * \brief SignalsCatcherControlBlock's constructor
	 *
	 * \param [in] storageBegin is a pointer to first element of storage for Association objects
	 * \param [in] storageEnd is a pointer to "one past the last" element of storage for Association objects
	 */

	constexpr SignalsCatcherControlBlock(Storage* const storageBegin, Storage* const storageEnd) :
			signalMask_{SignalSet::empty},
			associationsBegin_{reinterpret_cast<decltype(associationsBegin_)>(storageBegin)},
			storageBegin_{storageBegin},
			storageEnd_{storageEnd}
	{

	}

private:

	/// SignalSet with signal mask for associated thread
	SignalSet signalMask_;

	/// pointer to first element of range of Association objects
	Association* associationsBegin_;

	/// union binds \a associationsEnd_ and \a storageBegin_ - these point to the same address
	union
	{
		/// pointer to "one past the last" element of range of Association objects
		Association* associationsEnd_;

		/// pointer to first element of range of Storage objects
		Storage* storageBegin_;
	};

	/// pointer to "one past the last" element of range of Storage objects
	Storage* storageEnd_;
};

}	// namespace synchronization

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_SYNCHRONIZATION_SIGNALSCATCHERCONTROLBLOCK_HPP_
<commit_msg>SignalsCatcherControlBlock: add SignalsCatcherControlBlock::getSignalMask()<commit_after>/**
 * \file
 * \brief SignalsCatcherControlBlock class header
 *
 * \author Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-04-18
 */

#ifndef INCLUDE_DISTORTOS_SYNCHRONIZATION_SIGNALSCATCHERCONTROLBLOCK_HPP_
#define INCLUDE_DISTORTOS_SYNCHRONIZATION_SIGNALSCATCHERCONTROLBLOCK_HPP_

#include "distortos/SignalAction.hpp"

namespace distortos
{

namespace synchronization
{

/// SignalsCatcherControlBlock class is a structure required by threads for "catching" and "handling" of signals
class SignalsCatcherControlBlock
{
public:

	/// association of signal number with SignalAction
	using Association = std::pair<uint8_t, SignalAction>;

	/// type of uninitialized storage for Association objects
	using Storage = std::aligned_storage<sizeof(Association), alignof(Association)>::type;

	/**
	 * \brief SignalsCatcherControlBlock's constructor
	 *
	 * \param [in] storageBegin is a pointer to first element of storage for Association objects
	 * \param [in] storageEnd is a pointer to "one past the last" element of storage for Association objects
	 */

	constexpr SignalsCatcherControlBlock(Storage* const storageBegin, Storage* const storageEnd) :
			signalMask_{SignalSet::empty},
			associationsBegin_{reinterpret_cast<decltype(associationsBegin_)>(storageBegin)},
			storageBegin_{storageBegin},
			storageEnd_{storageEnd}
	{

	}

	/**
	 * \return SignalSet with signal mask for associated thread
	 */

	SignalSet getSignalMask() const
	{
		return signalMask_;
	}

private:

	/// SignalSet with signal mask for associated thread
	SignalSet signalMask_;

	/// pointer to first element of range of Association objects
	Association* associationsBegin_;

	/// union binds \a associationsEnd_ and \a storageBegin_ - these point to the same address
	union
	{
		/// pointer to "one past the last" element of range of Association objects
		Association* associationsEnd_;

		/// pointer to first element of range of Storage objects
		Storage* storageBegin_;
	};

	/// pointer to "one past the last" element of range of Storage objects
	Storage* storageEnd_;
};

}	// namespace synchronization

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_SYNCHRONIZATION_SIGNALSCATCHERCONTROLBLOCK_HPP_
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "ValueExtractionSynthesizer.h"

#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"

using namespace clang;

namespace cling {
  ValueExtractionSynthesizer::ValueExtractionSynthesizer(clang::Sema* S)
    : TransactionTransformer(S), m_Context(&S->getASTContext()), m_gClingVD(0),
      m_UnresolvedNoAlloc(0), m_UnresolvedWithAlloc(0),
      m_UnresolvedCopyArray(0) { }

  // pin the vtable here.
  ValueExtractionSynthesizer::~ValueExtractionSynthesizer()
  { }

  namespace {
    class ReturnStmtCollector : public StmtVisitor<ReturnStmtCollector> {
    private:
      llvm::SmallVectorImpl<Stmt**>& m_Stmts;
    public:
      ReturnStmtCollector(llvm::SmallVectorImpl<Stmt**>& S)
        : m_Stmts(S) {}

      void VisitStmt(Stmt* S) {
        for(Stmt::child_iterator I = S->child_begin(), E = S->child_end();
            I != E; ++I) {
          if (!*I)
            continue;
          Visit(*I);
          if (isa<ReturnStmt>(*I))
            m_Stmts.push_back(&*I);
        }
      }
    };
  }

  void ValueExtractionSynthesizer::Transform() {
    if (!getTransaction()->getCompilationOpts().ResultEvaluation)
      return;

    FunctionDecl* FD = getTransaction()->getWrapperFD();

    int foundAtPos = -1;
    Expr* lastExpr = utils::Analyze::GetOrCreateLastExpr(FD, &foundAtPos,
                                                         /*omitDS*/false,
                                                         m_Sema);
    if (foundAtPos < 0)
      return;

    typedef llvm::SmallVector<Stmt**, 4> StmtIters;
    StmtIters returnStmts;
    ReturnStmtCollector collector(returnStmts);
    CompoundStmt* CS = cast<CompoundStmt>(FD->getBody());
    collector.VisitStmt(CS);

    if (isa<Expr>(*(CS->body_begin() + foundAtPos)))
      returnStmts.push_back(CS->body_begin() + foundAtPos);

    // We want to support cases such as:
    // gCling->evaluate("if() return 'A' else return 12", V), that puts in V,
    // either A or 12.
    // In this case the void wrapper is compiled with the stmts returning
    // values. Sema would cast them to void, but the code will still be
    // executed. For example:
    // int g(); void f () { return g(); } will still call g().
    //
    for (StmtIters::iterator I = returnStmts.begin(), E = returnStmts.end();
         I != E; ++I) {
      ReturnStmt* RS = dyn_cast<ReturnStmt>(**I);
      if (RS) {
        if (Expr* RetV = RS->getRetValue()) {
          QualType RetTy = RetV->getType();
          assert (RetTy->isVoidType() && "Must be void type.");
          // Any return statement will have been "healed" by Sema
          // to correspond to the original void return type of the
          // wrapper, using a ImplicitCastExpr 'void' <ToVoid>.
          // Remove that.
          if (ImplicitCastExpr* VoidCast = dyn_cast<ImplicitCastExpr>(RetV)) {
            lastExpr = VoidCast->getSubExpr();
          }
        }
      }
      else
        lastExpr = cast<Expr>(**I);

      if (lastExpr) {
        QualType lastExprTy = lastExpr->getType();
        // Set up lastExpr properly.
        if (!lastExprTy->isVoidType()) {
          // Change the void function's return type
          // We can't PushDeclContext, because we don't have scope.
          Sema::ContextRAII pushedDC(*m_Sema, FD);

          if (lastExprTy->isFunctionType()) {
            // A return type of function needs to be converted to
            // pointer to function.
            lastExprTy = m_Context->getPointerType(lastExprTy);
            lastExpr = m_Sema->ImpCastExprToType(lastExpr, lastExprTy,
                                                 CK_FunctionToPointerDecay,
                                                 VK_RValue).take();
          }

          //
          // Here we don't want to depend on the JIT runFunction, because of its
          // limitations, when it comes to return value handling. There it is
          // not clear who provides the storage and who cleans it up in a
          // platform independent way.
          //
          // Depending on the type we need to synthesize a call to cling:
          // 0) void : do nothing;
          // 1) enum, integral, float, double, referece, pointer types :
          //      call to cling::internal::setValueNoAlloc(...);
          // 2) object type (alloc on the stack) :
          //      cling::internal::setValueWithAlloc
          //   2.1) constant arrays:
          //          call to cling::runtime::internal::copyArray(...)
          //
          // We need to synthesize later:
          // Wrapper has signature: void w(cling::StoredValueRef SVR)
          // case 1):
          //   setValueNoAlloc(gCling, &SVR, lastExprTy, lastExpr())
          // case 2):
          //   new (setValueWithAlloc(gCling, &SVR, lastExprTy)) (lastExpr)
          // case 2.1):
          //   copyArray(src, placement, size)

          if (lastExprTy->isVoidType()) {
            // do nothing;
            return;
          }

          if (!m_gClingVD)
            FindAndCacheRuntimeDecls();

          Expr* SVRInit = SynthesizeSVRInit(lastExpr);
          // if we had return stmt update to execute the SVR init, even if the
          // wrapper returns void.
          if (RS) {
            if (ImplicitCastExpr* VoidCast
                = dyn_cast<ImplicitCastExpr>(RS->getRetValue()))
              VoidCast->setSubExpr(SVRInit);
          }
          else
            **I = SVRInit;
        }
      }
    }
  }

  Expr* ValueExtractionSynthesizer::SynthesizeSVRInit(Expr* E) const {
    // Build a reference to gCling
    ExprResult gClingDRE
      = m_Sema->BuildDeclRefExpr(m_gClingVD, m_Context->VoidPtrTy,
                                 VK_RValue, SourceLocation());
    // We have the wrapper as Sema's CurContext
    FunctionDecl* FD = cast<FunctionDecl>(m_Sema->CurContext);

    // Build a reference to StoredValueRef* in the wrapper, should be
    // the only argument of the wrapper.
    ExprResult wrapperSVRDRE
      = m_Sema->BuildDeclRefExpr(FD->getParamDecl(0), m_Context->VoidPtrTy,
                                 VK_RValue, E->getLocStart());
    QualType ETy = E->getType();
    Expr* ETyVP
      = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy,
                                             (uint64_t)ETy.getAsOpaquePtr());

    llvm::SmallVector<Expr*, 4> CallArgs;
    CallArgs.push_back(gClingDRE.take());
    CallArgs.push_back(wrapperSVRDRE.take());
    CallArgs.push_back(ETyVP);

    ExprResult Call;
    SourceLocation noLoc;
    const Type* desugaredTy = ETy->getUnqualifiedDesugaredType();
    if (desugaredTy->isRecordType() || desugaredTy->isConstantArrayType()) {
      // 2) object types :
      // call new (setValueWithAlloc(gCling, &SVR, ETy)) (E)
      Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedWithAlloc,
                                   E->getLocStart(), CallArgs,
                                   E->getLocEnd());
      Expr* placement = Call.take();
      if (const ConstantArrayType* constArray
          = dyn_cast<ConstantArrayType>(desugaredTy)) {
        CallArgs.clear();
        CallArgs.push_back(E);
        CallArgs.push_back(placement);
        uint64_t arrSize
          = m_Context->getConstantArrayElementCount(constArray);
        Expr* arrSizeExpr
          = utils::Synthesize::IntegerLiteralExpr(*m_Context, arrSize);

        CallArgs.push_back(arrSizeExpr);
        // 2.1) arrays:
        // call copyArray(T* src, void* placement, int size)
        Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedCopyArray,
                                     E->getLocStart(), CallArgs,
                                     E->getLocEnd());

      }
      else {
        TypeSourceInfo* ETSI
          = m_Context->getTrivialTypeSourceInfo(ETy, noLoc);

        Call = m_Sema->BuildCXXNew(E->getSourceRange(),
                                   /*useGlobal ::*/true,
                                   /*placementLParen*/ noLoc,
                                   MultiExprArg(placement),
                                   /*placementRParen*/ noLoc,
                                   /*TypeIdParens*/ SourceRange(),
                                   /*allocType*/ ETSI->getType(),
                                   /*allocTypeInfo*/ETSI,
                                   /*arraySize*/0,
                                   /*directInitRange*/E->getSourceRange(),
                                   /*initializer*/E,
                                   /*mayContainAuto*/false
                                   );
      }
    }
    else if (desugaredTy->isIntegralOrEnumerationType()
             || desugaredTy->isReferenceType()
             || desugaredTy->isPointerType()
             || desugaredTy->isFloatingType()) {
      if (desugaredTy->isIntegralOrEnumerationType()) {
        // 1)  enum, integral, float, double, referece, pointer types :
        //      call to cling::internal::setValueNoAlloc(...);

        // If the type is enum or integral we need to force-cast it into
        // uint64 in order to pick up the correct overload.
        if (desugaredTy->isIntegralOrEnumerationType()) {
          QualType UInt64Ty = m_Context->UnsignedLongLongTy;
          TypeSourceInfo* TSI
            = m_Context->getTrivialTypeSourceInfo(UInt64Ty, noLoc);
          Expr* castedE
            = m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).take();
          CallArgs.push_back(castedE);
        }
      }
      else if (desugaredTy->isReferenceType()) {
        // we need to get the address of the references
        Expr* E = m_Sema->BuildUnaryOp(/*Scope*/0, noLoc, UO_AddrOf,
                                       E).take();
        CallArgs.push_back(E);
      }
      else if (desugaredTy->isPointerType()) {
        // function pointers need explicit void* cast.
        QualType VoidPtrTy = m_Context->VoidPtrTy;
        TypeSourceInfo* TSI
          = m_Context->getTrivialTypeSourceInfo(VoidPtrTy, noLoc);
        Expr* castedE
          = m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).take();
        CallArgs.push_back(castedE);
      }
      else if (desugaredTy->isFloatingType()) {
        // floats and double will fall naturally in the correct
        // case, because of the overload resolution.
        CallArgs.push_back(E);
      }
      Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc,
                                   E->getLocStart(), CallArgs,
                                   E->getLocEnd());
    }
    else
      assert(0 && "Unhandled code path?");

    assert(!Call.isInvalid() && "Invalid Call");
    return Call.take();
  }

  void ValueExtractionSynthesizer::FindAndCacheRuntimeDecls() {
    assert(!m_gClingVD && "Called multiple times!?");
    NamespaceDecl* NSD = utils::Lookup::Namespace(m_Sema, "cling");
    NSD = utils::Lookup::Namespace(m_Sema, "runtime", NSD);
    m_gClingVD = cast<VarDecl>(utils::Lookup::Named(m_Sema, "gCling", NSD));
    NSD = utils::Lookup::Namespace(m_Sema, "internal",NSD);

    SourceLocation NoSLoc = SourceLocation();
    LookupResult R(*m_Sema, &m_Context->Idents.get("setValueNoAlloc"),
                   SourceLocation(), Sema::LookupOrdinaryName,
                   Sema::ForRedeclaration);

    m_Sema->LookupQualifiedName(R, NSD);
    assert(!R.empty()
           && "Cannot find cling::runtime::internal::setValueNoAlloc");

    CXXScopeSpec CSS;
    m_UnresolvedNoAlloc
      = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).take();

    R.clear();
    R.setLookupName(&m_Context->Idents.get("setValueWithAlloc"));
    m_Sema->LookupQualifiedName(R, NSD);
    assert(!R.empty()
           && "Cannot find cling::runtime::internal::setValueWithAlloc");
    m_UnresolvedWithAlloc
      = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).take();

    R.clear();
    R.setLookupName(&m_Context->Idents.get("copyArray"));
    m_Sema->LookupQualifiedName(R, NSD);
    assert(!R.empty() && "Cannot find cling::runtime::internal::copyArray");
    m_UnresolvedCopyArray
      = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).take();
  }
} // end namespace cling
<commit_msg>Remove unused var.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "ValueExtractionSynthesizer.h"

#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"

using namespace clang;

namespace cling {
  ValueExtractionSynthesizer::ValueExtractionSynthesizer(clang::Sema* S)
    : TransactionTransformer(S), m_Context(&S->getASTContext()), m_gClingVD(0),
      m_UnresolvedNoAlloc(0), m_UnresolvedWithAlloc(0),
      m_UnresolvedCopyArray(0) { }

  // pin the vtable here.
  ValueExtractionSynthesizer::~ValueExtractionSynthesizer()
  { }

  namespace {
    class ReturnStmtCollector : public StmtVisitor<ReturnStmtCollector> {
    private:
      llvm::SmallVectorImpl<Stmt**>& m_Stmts;
    public:
      ReturnStmtCollector(llvm::SmallVectorImpl<Stmt**>& S)
        : m_Stmts(S) {}

      void VisitStmt(Stmt* S) {
        for(Stmt::child_iterator I = S->child_begin(), E = S->child_end();
            I != E; ++I) {
          if (!*I)
            continue;
          Visit(*I);
          if (isa<ReturnStmt>(*I))
            m_Stmts.push_back(&*I);
        }
      }
    };
  }

  void ValueExtractionSynthesizer::Transform() {
    if (!getTransaction()->getCompilationOpts().ResultEvaluation)
      return;

    FunctionDecl* FD = getTransaction()->getWrapperFD();

    int foundAtPos = -1;
    Expr* lastExpr = utils::Analyze::GetOrCreateLastExpr(FD, &foundAtPos,
                                                         /*omitDS*/false,
                                                         m_Sema);
    if (foundAtPos < 0)
      return;

    typedef llvm::SmallVector<Stmt**, 4> StmtIters;
    StmtIters returnStmts;
    ReturnStmtCollector collector(returnStmts);
    CompoundStmt* CS = cast<CompoundStmt>(FD->getBody());
    collector.VisitStmt(CS);

    if (isa<Expr>(*(CS->body_begin() + foundAtPos)))
      returnStmts.push_back(CS->body_begin() + foundAtPos);

    // We want to support cases such as:
    // gCling->evaluate("if() return 'A' else return 12", V), that puts in V,
    // either A or 12.
    // In this case the void wrapper is compiled with the stmts returning
    // values. Sema would cast them to void, but the code will still be
    // executed. For example:
    // int g(); void f () { return g(); } will still call g().
    //
    for (StmtIters::iterator I = returnStmts.begin(), E = returnStmts.end();
         I != E; ++I) {
      ReturnStmt* RS = dyn_cast<ReturnStmt>(**I);
      if (RS) {
        if (Expr* RetV = RS->getRetValue()) {
          QualType RetTy = RetV->getType();
          assert (RetTy->isVoidType() && "Must be void type.");
          // Any return statement will have been "healed" by Sema
          // to correspond to the original void return type of the
          // wrapper, using a ImplicitCastExpr 'void' <ToVoid>.
          // Remove that.
          if (ImplicitCastExpr* VoidCast = dyn_cast<ImplicitCastExpr>(RetV)) {
            lastExpr = VoidCast->getSubExpr();
          }
        }
      }
      else
        lastExpr = cast<Expr>(**I);

      if (lastExpr) {
        QualType lastExprTy = lastExpr->getType();
        // Set up lastExpr properly.
        if (!lastExprTy->isVoidType()) {
          // Change the void function's return type
          // We can't PushDeclContext, because we don't have scope.
          Sema::ContextRAII pushedDC(*m_Sema, FD);

          if (lastExprTy->isFunctionType()) {
            // A return type of function needs to be converted to
            // pointer to function.
            lastExprTy = m_Context->getPointerType(lastExprTy);
            lastExpr = m_Sema->ImpCastExprToType(lastExpr, lastExprTy,
                                                 CK_FunctionToPointerDecay,
                                                 VK_RValue).take();
          }

          //
          // Here we don't want to depend on the JIT runFunction, because of its
          // limitations, when it comes to return value handling. There it is
          // not clear who provides the storage and who cleans it up in a
          // platform independent way.
          //
          // Depending on the type we need to synthesize a call to cling:
          // 0) void : do nothing;
          // 1) enum, integral, float, double, referece, pointer types :
          //      call to cling::internal::setValueNoAlloc(...);
          // 2) object type (alloc on the stack) :
          //      cling::internal::setValueWithAlloc
          //   2.1) constant arrays:
          //          call to cling::runtime::internal::copyArray(...)
          //
          // We need to synthesize later:
          // Wrapper has signature: void w(cling::StoredValueRef SVR)
          // case 1):
          //   setValueNoAlloc(gCling, &SVR, lastExprTy, lastExpr())
          // case 2):
          //   new (setValueWithAlloc(gCling, &SVR, lastExprTy)) (lastExpr)
          // case 2.1):
          //   copyArray(src, placement, size)

          if (lastExprTy->isVoidType()) {
            // do nothing;
            return;
          }

          if (!m_gClingVD)
            FindAndCacheRuntimeDecls();

          Expr* SVRInit = SynthesizeSVRInit(lastExpr);
          // if we had return stmt update to execute the SVR init, even if the
          // wrapper returns void.
          if (RS) {
            if (ImplicitCastExpr* VoidCast
                = dyn_cast<ImplicitCastExpr>(RS->getRetValue()))
              VoidCast->setSubExpr(SVRInit);
          }
          else
            **I = SVRInit;
        }
      }
    }
  }

  Expr* ValueExtractionSynthesizer::SynthesizeSVRInit(Expr* E) const {
    // Build a reference to gCling
    ExprResult gClingDRE
      = m_Sema->BuildDeclRefExpr(m_gClingVD, m_Context->VoidPtrTy,
                                 VK_RValue, SourceLocation());
    // We have the wrapper as Sema's CurContext
    FunctionDecl* FD = cast<FunctionDecl>(m_Sema->CurContext);

    // Build a reference to StoredValueRef* in the wrapper, should be
    // the only argument of the wrapper.
    ExprResult wrapperSVRDRE
      = m_Sema->BuildDeclRefExpr(FD->getParamDecl(0), m_Context->VoidPtrTy,
                                 VK_RValue, E->getLocStart());
    QualType ETy = E->getType();
    Expr* ETyVP
      = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy,
                                             (uint64_t)ETy.getAsOpaquePtr());

    llvm::SmallVector<Expr*, 4> CallArgs;
    CallArgs.push_back(gClingDRE.take());
    CallArgs.push_back(wrapperSVRDRE.take());
    CallArgs.push_back(ETyVP);

    ExprResult Call;
    SourceLocation noLoc;
    const Type* desugaredTy = ETy->getUnqualifiedDesugaredType();
    if (desugaredTy->isRecordType() || desugaredTy->isConstantArrayType()) {
      // 2) object types :
      // call new (setValueWithAlloc(gCling, &SVR, ETy)) (E)
      Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedWithAlloc,
                                   E->getLocStart(), CallArgs,
                                   E->getLocEnd());
      Expr* placement = Call.take();
      if (const ConstantArrayType* constArray
          = dyn_cast<ConstantArrayType>(desugaredTy)) {
        CallArgs.clear();
        CallArgs.push_back(E);
        CallArgs.push_back(placement);
        uint64_t arrSize
          = m_Context->getConstantArrayElementCount(constArray);
        Expr* arrSizeExpr
          = utils::Synthesize::IntegerLiteralExpr(*m_Context, arrSize);

        CallArgs.push_back(arrSizeExpr);
        // 2.1) arrays:
        // call copyArray(T* src, void* placement, int size)
        Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedCopyArray,
                                     E->getLocStart(), CallArgs,
                                     E->getLocEnd());

      }
      else {
        TypeSourceInfo* ETSI
          = m_Context->getTrivialTypeSourceInfo(ETy, noLoc);

        Call = m_Sema->BuildCXXNew(E->getSourceRange(),
                                   /*useGlobal ::*/true,
                                   /*placementLParen*/ noLoc,
                                   MultiExprArg(placement),
                                   /*placementRParen*/ noLoc,
                                   /*TypeIdParens*/ SourceRange(),
                                   /*allocType*/ ETSI->getType(),
                                   /*allocTypeInfo*/ETSI,
                                   /*arraySize*/0,
                                   /*directInitRange*/E->getSourceRange(),
                                   /*initializer*/E,
                                   /*mayContainAuto*/false
                                   );
      }
    }
    else if (desugaredTy->isIntegralOrEnumerationType()
             || desugaredTy->isReferenceType()
             || desugaredTy->isPointerType()
             || desugaredTy->isFloatingType()) {
      if (desugaredTy->isIntegralOrEnumerationType()) {
        // 1)  enum, integral, float, double, referece, pointer types :
        //      call to cling::internal::setValueNoAlloc(...);

        // If the type is enum or integral we need to force-cast it into
        // uint64 in order to pick up the correct overload.
        if (desugaredTy->isIntegralOrEnumerationType()) {
          QualType UInt64Ty = m_Context->UnsignedLongLongTy;
          TypeSourceInfo* TSI
            = m_Context->getTrivialTypeSourceInfo(UInt64Ty, noLoc);
          Expr* castedE
            = m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).take();
          CallArgs.push_back(castedE);
        }
      }
      else if (desugaredTy->isReferenceType()) {
        // we need to get the address of the references
        Expr* E = m_Sema->BuildUnaryOp(/*Scope*/0, noLoc, UO_AddrOf,
                                       E).take();
        CallArgs.push_back(E);
      }
      else if (desugaredTy->isPointerType()) {
        // function pointers need explicit void* cast.
        QualType VoidPtrTy = m_Context->VoidPtrTy;
        TypeSourceInfo* TSI
          = m_Context->getTrivialTypeSourceInfo(VoidPtrTy, noLoc);
        Expr* castedE
          = m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).take();
        CallArgs.push_back(castedE);
      }
      else if (desugaredTy->isFloatingType()) {
        // floats and double will fall naturally in the correct
        // case, because of the overload resolution.
        CallArgs.push_back(E);
      }
      Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc,
                                   E->getLocStart(), CallArgs,
                                   E->getLocEnd());
    }
    else
      assert(0 && "Unhandled code path?");

    assert(!Call.isInvalid() && "Invalid Call");
    return Call.take();
  }

  void ValueExtractionSynthesizer::FindAndCacheRuntimeDecls() {
    assert(!m_gClingVD && "Called multiple times!?");
    NamespaceDecl* NSD = utils::Lookup::Namespace(m_Sema, "cling");
    NSD = utils::Lookup::Namespace(m_Sema, "runtime", NSD);
    m_gClingVD = cast<VarDecl>(utils::Lookup::Named(m_Sema, "gCling", NSD));
    NSD = utils::Lookup::Namespace(m_Sema, "internal",NSD);

    LookupResult R(*m_Sema, &m_Context->Idents.get("setValueNoAlloc"),
                   SourceLocation(), Sema::LookupOrdinaryName,
                   Sema::ForRedeclaration);

    m_Sema->LookupQualifiedName(R, NSD);
    assert(!R.empty()
           && "Cannot find cling::runtime::internal::setValueNoAlloc");

    CXXScopeSpec CSS;
    m_UnresolvedNoAlloc
      = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).take();

    R.clear();
    R.setLookupName(&m_Context->Idents.get("setValueWithAlloc"));
    m_Sema->LookupQualifiedName(R, NSD);
    assert(!R.empty()
           && "Cannot find cling::runtime::internal::setValueWithAlloc");
    m_UnresolvedWithAlloc
      = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).take();

    R.clear();
    R.setLookupName(&m_Context->Idents.get("copyArray"));
    m_Sema->LookupQualifiedName(R, NSD);
    assert(!R.empty() && "Cannot find cling::runtime::internal::copyArray");
    m_UnresolvedCopyArray
      = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).take();
  }
} // end namespace cling
<|endoftext|>