<commit_before>/***************************************************************************
 *   Copyright (c) Jrgen Riegel          (juergen.riegel@web.de) 2002     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
# include <sstream>
#endif

#include <Base/Exception.h>
#include <Base/Console.h>
#include <Base/FileInfo.h>
#include <App/Application.h>
#include <boost/regex.hpp>
#include <iostream>
#include <iterator>

#include "FeaturePage.h"
#include "FeatureView.h"
#include "FeatureClip.h"

using namespace Drawing;
using namespace std;

//===========================================================================
// FeaturePage
//===========================================================================

PROPERTY_SOURCE(Drawing::FeaturePage, App::DocumentObjectGroup)

const char *group = "Drawing view";

FeaturePage::FeaturePage(void) : numChildren(0)
{
    static const char *group = "Drawing view";

    ADD_PROPERTY_TYPE(PageResult ,(0),group,App::Prop_Output,"Resulting SVG document of that page");
    ADD_PROPERTY_TYPE(Template   ,(""),group,App::Prop_Transient  ,"Template for the page");
    ADD_PROPERTY_TYPE(EditableTexts,(""),group,App::Prop_None,"Substitution values for the editable strings in the template");
}

FeaturePage::~FeaturePage()
{
}

void FeaturePage::onBeforeChange(const App::Property* prop)
{
    if (prop == &Group) {
        numChildren = Group.getSize();
    }

    App::DocumentObjectGroup::onBeforeChange(prop);
}

/// get called by the container when a Property was changed
void FeaturePage::onChanged(const App::Property* prop)
{
    if (prop == &PageResult) {
        if (this->isRestoring()) {
            // When loading a document the included file
            // doesn't need to exist at this point.
            Base::FileInfo fi(PageResult.getValue());
            if (!fi.exists())
                return;
        }
    } else if (prop == &EditableTexts) {
        if (!this->isRestoring()) {
            this->execute();
            return;
        }
    } else if (prop == &Template) {
        if (!this->isRestoring()) {
            EditableTexts.setValues(getEditableTextsFromTemplate());
        }
    } else if (prop == &Group) {
        if (Group.getSize() != numChildren) {
            numChildren = Group.getSize();
            touch();
        }
    }

    App::DocumentObjectGroup::onChanged(prop);
}

void FeaturePage::onDocumentRestored()
{
    Base::FileInfo fi(PageResult.getValue());
    std::string path = App::Application::getResourceDir() + "Mod/Drawing/Templates/" + fi.fileName();
    // try to find the template in user dir/Templates first
    Base::FileInfo tempfi(App::Application::getUserAppDataDir() + "Templates/" + fi.fileName());
    if (tempfi.exists())
        path = tempfi.filePath();
    Template.setValue(path);
}

App::DocumentObjectExecReturn *FeaturePage::execute(void)
{
    std::string temp = Template.getValue();
    if (temp.empty())
        return App::DocumentObject::StdReturn;

    Base::FileInfo fi(temp);
    if (!fi.isReadable()) {
        // if there is a old absolute template file set use a redirect
        fi.setFile(App::Application::getResourceDir() + "Mod/Drawing/Templates/" + fi.fileName());
        // try the redirect
        if (!fi.isReadable()) {
            Base::Console().Log("FeaturePage::execute() not able to open %s!\n",Template.getValue());
            std::string error = std::string("Cannot open file ") + Template.getValue();
            return new App::DocumentObjectExecReturn(error);
        }
    }

    if (std::string(PageResult.getValue()).empty())
        PageResult.setValue(fi.filePath().c_str());

    // open Template file
    string line;
    ifstream file (fi.filePath().c_str());

    // make a temp file for FileIncluded Property
    string tempName = PageResult.getExchangeTempFile();
    ostringstream ofile;
    string tempendl = "--endOfLine--";

    while (!file.eof())
    {
        getline (file,line);
        // check if the marker in the template is found
        if(line.find("<!-- DrawingContent -->") == string::npos)
            // if not -  write through
            ofile << line << tempendl;
        else
        {
            // get through the children and collect all the views
            const std::vector<App::DocumentObject*> &Grp = Group.getValues();
            for (std::vector<App::DocumentObject*>::const_iterator It= Grp.begin();It!=Grp.end();++It) {
                if ( (*It)->getTypeId().isDerivedFrom(Drawing::FeatureView::getClassTypeId()) ) {
                    Drawing::FeatureView *View = dynamic_cast<Drawing::FeatureView *>(*It);
                    if (View->Visible.getValue()) {
                        ofile << View->ViewResult.getValue();
                        ofile << tempendl << tempendl << tempendl;
                    }
                } else if ( (*It)->getTypeId().isDerivedFrom(Drawing::FeatureClip::getClassTypeId()) ) {
                    Drawing::FeatureClip *Clip = dynamic_cast<Drawing::FeatureClip *>(*It);
                    if (Clip->Visible.getValue()) {
                        ofile << Clip->ViewResult.getValue();
                        ofile << tempendl << tempendl << tempendl;
                    }
                } else if ( (*It)->getTypeId().isDerivedFrom(App::DocumentObjectGroup::getClassTypeId()) ) {
                    // getting children inside subgroups too
                    App::DocumentObjectGroup *SubGroup = dynamic_cast<App::DocumentObjectGroup *>(*It);
                    const std::vector<App::DocumentObject*> &SubGrp = SubGroup->Group.getValues();
                    for (std::vector<App::DocumentObject*>::const_iterator Grit= SubGrp.begin();Grit!=SubGrp.end();++Grit) {
                        if ( (*Grit)->getTypeId().isDerivedFrom(Drawing::FeatureView::getClassTypeId()) ) {
                            Drawing::FeatureView *SView = dynamic_cast<Drawing::FeatureView *>(*Grit);
                            if (SView->Visible.getValue()) {
                                ofile << SView->ViewResult.getValue();
                                ofile << tempendl << tempendl << tempendl;
                            }
                        }
                    }
                }
            }
        }
    }

    file.close();

    // checking for freecad editable texts
    string outfragment(ofile.str());
    const std::vector<std::string>& editText = EditableTexts.getValues();
    if (!editText.empty()) {
        boost::regex e1 ("<text.*?freecad:editable=\"(.*?)\".*?<tspan.*?>(.*?)</tspan>");
        string::const_iterator begin, end;
        begin = outfragment.begin();
        end = outfragment.end();
        boost::match_results<std::string::const_iterator> what;
        std::size_t count = 0;
        std::string newfragment;
        newfragment.reserve(outfragment.size());

        while (boost::regex_search(begin, end, what, e1)) {
            if (count < editText.size()) {
                // change values of editable texts
                boost::regex e2 ("(<text.*?freecad:editable=\""+what[1].str()+"\".*?<tspan.*?)>(.*?)(</tspan>)");
                boost::re_detail::string_out_iterator<std::string > out(newfragment);
                boost::regex_replace(out, begin, what[0].second, e2, "$1>"+editText[count]+"$3");
            }
            count++;
            begin = what[0].second;
        }

        // now copy the rest
        newfragment.insert(newfragment.end(), begin, end);
        outfragment = newfragment;
    }

    // restoring linebreaks and saving the file
    boost::regex e3 ("--endOfLine--");
    string fmt = "\\n";
    outfragment = boost::regex_replace(outfragment, e3, fmt);
    ofstream outfinal(tempName.c_str());
    outfinal << outfragment;
    outfinal.close();

    PageResult.setValue(tempName.c_str());

    return App::DocumentObject::StdReturn;
}

std::vector<std::string> FeaturePage::getEditableTextsFromTemplate(void) const {
    //getting editable texts from "freecad:editable" attributes in SVG template

    std::vector<string> eds;

    std::string temp = Template.getValue();
    if (!temp.empty()) {
        Base::FileInfo tfi(temp);
        if (!tfi.isReadable()) {
            // if there is a old absolute template file set use a redirect
            tfi.setFile(App::Application::getResourceDir() + "Mod/Drawing/Templates/" + tfi.fileName());
            // try the redirect
            if (!tfi.isReadable()) {
                return eds;
            }
        }
        string tline, tfrag;
        ifstream tfile (tfi.filePath().c_str());
        while (!tfile.eof()) {
            getline (tfile,tline);
            tfrag += tline;
            tfrag += "--endOfLine--";
        }
        tfile.close();
        boost::regex e ("<text.*?freecad:editable=\"(.*?)\".*?<tspan.*?>(.*?)</tspan>");
        string::const_iterator tbegin, tend;
        tbegin = tfrag.begin();
        tend = tfrag.end();
        boost::match_results<std::string::const_iterator> twhat;
        while (boost::regex_search(tbegin, tend, twhat, e)) {
            eds.push_back(twhat[2]);
            tbegin = twhat[0].second;
        }
    }
    return eds;
}
<commit_msg>+ fixes #0002064: Editable text changes in drawing template not restored.<commit_after>/***************************************************************************
 *   Copyright (c) Jrgen Riegel          (juergen.riegel@web.de) 2002     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
# include <sstream>
#endif

#include <Base/Exception.h>
#include <Base/Console.h>
#include <Base/FileInfo.h>
#include <App/Application.h>
#include <boost/regex.hpp>
#include <iostream>
#include <iterator>

#include "FeaturePage.h"
#include "FeatureView.h"
#include "FeatureClip.h"

using namespace Drawing;
using namespace std;

//===========================================================================
// FeaturePage
//===========================================================================

PROPERTY_SOURCE(Drawing::FeaturePage, App::DocumentObjectGroup)

const char *group = "Drawing view";

FeaturePage::FeaturePage(void) : numChildren(0)
{
    static const char *group = "Drawing view";

    ADD_PROPERTY_TYPE(PageResult ,(0),group,App::Prop_Output,"Resulting SVG document of that page");
    ADD_PROPERTY_TYPE(Template   ,(""),group,App::Prop_Transient  ,"Template for the page");
    ADD_PROPERTY_TYPE(EditableTexts,(""),group,App::Prop_None,"Substitution values for the editable strings in the template");
}

FeaturePage::~FeaturePage()
{
}

void FeaturePage::onBeforeChange(const App::Property* prop)
{
    if (prop == &Group) {
        numChildren = Group.getSize();
    }

    App::DocumentObjectGroup::onBeforeChange(prop);
}

/// get called by the container when a Property was changed
void FeaturePage::onChanged(const App::Property* prop)
{
    if (prop == &PageResult) {
        if (this->isRestoring()) {
            // When loading a document the included file
            // doesn't need to exist at this point.
            Base::FileInfo fi(PageResult.getValue());
            if (!fi.exists())
                return;
        }
    } else if (prop == &EditableTexts) {
        if (!this->isRestoring()) {
            this->execute();
            return;
        }
    } else if (prop == &Template) {
        if (!this->isRestoring()) {
            EditableTexts.setValues(getEditableTextsFromTemplate());
        }
    } else if (prop == &Group) {
        if (Group.getSize() != numChildren) {
            numChildren = Group.getSize();
            touch();
        }
    }

    App::DocumentObjectGroup::onChanged(prop);
}

void FeaturePage::onDocumentRestored()
{
    // Needs to be tmp. set because otherwise the custom text gets overridden (#0002064)
    this->StatusBits.set(4); // the 'Restore' flag

    Base::FileInfo fi(PageResult.getValue());
    std::string path = App::Application::getResourceDir() + "Mod/Drawing/Templates/" + fi.fileName();
    // try to find the template in user dir/Templates first
    Base::FileInfo tempfi(App::Application::getUserAppDataDir() + "Templates/" + fi.fileName());
    if (tempfi.exists())
        path = tempfi.filePath();
    Template.setValue(path);

    this->StatusBits.reset(4); // the 'Restore' flag
}

App::DocumentObjectExecReturn *FeaturePage::execute(void)
{
    std::string temp = Template.getValue();
    if (temp.empty())
        return App::DocumentObject::StdReturn;

    Base::FileInfo fi(temp);
    if (!fi.isReadable()) {
        // if there is a old absolute template file set use a redirect
        fi.setFile(App::Application::getResourceDir() + "Mod/Drawing/Templates/" + fi.fileName());
        // try the redirect
        if (!fi.isReadable()) {
            Base::Console().Log("FeaturePage::execute() not able to open %s!\n",Template.getValue());
            std::string error = std::string("Cannot open file ") + Template.getValue();
            return new App::DocumentObjectExecReturn(error);
        }
    }

    if (std::string(PageResult.getValue()).empty())
        PageResult.setValue(fi.filePath().c_str());

    // open Template file
    string line;
    ifstream file (fi.filePath().c_str());

    // make a temp file for FileIncluded Property
    string tempName = PageResult.getExchangeTempFile();
    ostringstream ofile;
    string tempendl = "--endOfLine--";

    while (!file.eof())
    {
        getline (file,line);
        // check if the marker in the template is found
        if(line.find("<!-- DrawingContent -->") == string::npos)
            // if not -  write through
            ofile << line << tempendl;
        else
        {
            // get through the children and collect all the views
            const std::vector<App::DocumentObject*> &Grp = Group.getValues();
            for (std::vector<App::DocumentObject*>::const_iterator It= Grp.begin();It!=Grp.end();++It) {
                if ( (*It)->getTypeId().isDerivedFrom(Drawing::FeatureView::getClassTypeId()) ) {
                    Drawing::FeatureView *View = dynamic_cast<Drawing::FeatureView *>(*It);
                    if (View->Visible.getValue()) {
                        ofile << View->ViewResult.getValue();
                        ofile << tempendl << tempendl << tempendl;
                    }
                } else if ( (*It)->getTypeId().isDerivedFrom(Drawing::FeatureClip::getClassTypeId()) ) {
                    Drawing::FeatureClip *Clip = dynamic_cast<Drawing::FeatureClip *>(*It);
                    if (Clip->Visible.getValue()) {
                        ofile << Clip->ViewResult.getValue();
                        ofile << tempendl << tempendl << tempendl;
                    }
                } else if ( (*It)->getTypeId().isDerivedFrom(App::DocumentObjectGroup::getClassTypeId()) ) {
                    // getting children inside subgroups too
                    App::DocumentObjectGroup *SubGroup = dynamic_cast<App::DocumentObjectGroup *>(*It);
                    const std::vector<App::DocumentObject*> &SubGrp = SubGroup->Group.getValues();
                    for (std::vector<App::DocumentObject*>::const_iterator Grit= SubGrp.begin();Grit!=SubGrp.end();++Grit) {
                        if ( (*Grit)->getTypeId().isDerivedFrom(Drawing::FeatureView::getClassTypeId()) ) {
                            Drawing::FeatureView *SView = dynamic_cast<Drawing::FeatureView *>(*Grit);
                            if (SView->Visible.getValue()) {
                                ofile << SView->ViewResult.getValue();
                                ofile << tempendl << tempendl << tempendl;
                            }
                        }
                    }
                }
            }
        }
    }

    file.close();

    // checking for freecad editable texts
    string outfragment(ofile.str());
    const std::vector<std::string>& editText = EditableTexts.getValues();
    if (!editText.empty()) {
        boost::regex e1 ("<text.*?freecad:editable=\"(.*?)\".*?<tspan.*?>(.*?)</tspan>");
        string::const_iterator begin, end;
        begin = outfragment.begin();
        end = outfragment.end();
        boost::match_results<std::string::const_iterator> what;
        std::size_t count = 0;
        std::string newfragment;
        newfragment.reserve(outfragment.size());

        while (boost::regex_search(begin, end, what, e1)) {
            if (count < editText.size()) {
                // change values of editable texts
                boost::regex e2 ("(<text.*?freecad:editable=\""+what[1].str()+"\".*?<tspan.*?)>(.*?)(</tspan>)");
                boost::re_detail::string_out_iterator<std::string > out(newfragment);
                boost::regex_replace(out, begin, what[0].second, e2, "$1>"+editText[count]+"$3");
            }
            count++;
            begin = what[0].second;
        }

        // now copy the rest
        newfragment.insert(newfragment.end(), begin, end);
        outfragment = newfragment;
    }

    // restoring linebreaks and saving the file
    boost::regex e3 ("--endOfLine--");
    string fmt = "\\n";
    outfragment = boost::regex_replace(outfragment, e3, fmt);
    ofstream outfinal(tempName.c_str());
    outfinal << outfragment;
    outfinal.close();

    PageResult.setValue(tempName.c_str());

    return App::DocumentObject::StdReturn;
}

std::vector<std::string> FeaturePage::getEditableTextsFromTemplate(void) const {
    //getting editable texts from "freecad:editable" attributes in SVG template

    std::vector<string> eds;

    std::string temp = Template.getValue();
    if (!temp.empty()) {
        Base::FileInfo tfi(temp);
        if (!tfi.isReadable()) {
            // if there is a old absolute template file set use a redirect
            tfi.setFile(App::Application::getResourceDir() + "Mod/Drawing/Templates/" + tfi.fileName());
            // try the redirect
            if (!tfi.isReadable()) {
                return eds;
            }
        }
        string tline, tfrag;
        ifstream tfile (tfi.filePath().c_str());
        while (!tfile.eof()) {
            getline (tfile,tline);
            tfrag += tline;
            tfrag += "--endOfLine--";
        }
        tfile.close();
        boost::regex e ("<text.*?freecad:editable=\"(.*?)\".*?<tspan.*?>(.*?)</tspan>");
        string::const_iterator tbegin, tend;
        tbegin = tfrag.begin();
        tend = tfrag.end();
        boost::match_results<std::string::const_iterator> twhat;
        while (boost::regex_search(tbegin, tend, twhat, e)) {
            eds.push_back(twhat[2]);
            tbegin = twhat[0].second;
        }
    }
    return eds;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <thread>
#include "msg_filter.hpp"
#include "sub_dir.hpp"
#include "io_policy/line.hpp"
#include "io_policy/sysv_mq.hpp"
#include "io_policy/tcp.hpp"
#include "util.hpp"

using namespace wissbi;
using namespace std;

int main(int argc, char* argv[]) {
    SubDir sub_dir("/var/lib/wissbi", argv[1]);
    for(string conn_str : sub_dir.GetSubList()) {
        thread([conn_str]{
            sockaddr sock_addr;
            util::ConnectStringToSockaddr(conn_str, reinterpret_cast<sockaddr_in*>(&sock_addr));
            MsgFilter<io_policy::SysvMq, io_policy::TCP> producerFilter;
            producerFilter.Connect(&sock_addr);
            producerFilter.FilterLoop();
        }).detach();
    }

    MsgFilter<io_policy::Line, io_policy::SysvMq> input_filter;
    input_filter.FilterLoop();

    int wait_cnt = 0;
    while(input_filter.GetCount() > 0 && wait_cnt++ < 100) {
        this_thread::sleep_for(chrono::milliseconds(10));
    }

	return 0;
}
<commit_msg>disable sigint and sigterm in pub currently<commit_after>#include <signal.h>
#include <iostream>
#include <thread>
#include "msg_filter.hpp"
#include "sub_dir.hpp"
#include "io_policy/line.hpp"
#include "io_policy/sysv_mq.hpp"
#include "io_policy/tcp.hpp"
#include "util.hpp"

using namespace wissbi;
using namespace std;

void exit_signal_handler(int signum) {
}

int main(int argc, char* argv[]) {
    signal(SIGINT, exit_signal_handler);
    signal(SIGTERM, exit_signal_handler);

    SubDir sub_dir("/var/lib/wissbi", argv[1]);
    for(string conn_str : sub_dir.GetSubList()) {
        thread([conn_str]{
            sockaddr sock_addr;
            util::ConnectStringToSockaddr(conn_str, reinterpret_cast<sockaddr_in*>(&sock_addr));
            MsgFilter<io_policy::SysvMq, io_policy::TCP> producerFilter;
            producerFilter.Connect(&sock_addr);
            producerFilter.FilterLoop();
        }).detach();
    }

    MsgFilter<io_policy::Line, io_policy::SysvMq> input_filter;
    input_filter.FilterLoop();

    int wait_cnt = 0;
    while(input_filter.GetCount() > 0 && wait_cnt++ < 100) {
        this_thread::sleep_for(chrono::milliseconds(10));
    }

	return 0;
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2015 Stefan Tröger <stefantroeger@gmx.net>              *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
# include <SMESH_Mesh.hxx>
# include <vtkDataSetReader.h>
# include <vtkGeometryFilter.h>
# include <vtkStructuredGrid.h>
# include <vtkUnstructuredGrid.h>
# include <vtkImageData.h>
# include <vtkRectilinearGrid.h>
# include <vtkAppendFilter.h>
# include <vtkXMLUnstructuredGridReader.h>
# include <vtkXMLPolyDataReader.h>
# include <vtkXMLStructuredGridReader.h>
# include <vtkXMLRectilinearGridReader.h>
# include <vtkXMLImageDataReader.h>
#endif

#include "FemPostPipeline.h"
#include "FemMesh.h"
#include "FemMeshObject.h"
#include "FemVTKTools.h"

#include <Base/Console.h>
#include <App/Document.h>

#include <App/DocumentObjectPy.h>
#include <Mod/Fem/App/FemPostPipelinePy.h>

using namespace Fem;
using namespace App;

PROPERTY_SOURCE(Fem::FemPostPipeline, Fem::FemPostObject)
const char* FemPostPipeline::ModeEnums[]= {"Serial","Parallel",NULL};

FemPostPipeline::FemPostPipeline()
{
    ADD_PROPERTY_TYPE(Filter, (0), "Pipeline", App::Prop_None, "The filter used in in this pipeline");
    ADD_PROPERTY_TYPE(Functions, (0), "Pipeline", App::Prop_Hidden, "The function provider which groups all pipeline functions");
    ADD_PROPERTY_TYPE(Mode,(long(0)), "Pipeline", App::Prop_None, "Selects the pipeline data transition mode. In serial every filter"
                                                              "gets the output of the previous one as input, in parallel every"
                                                              "filter gets the pipelien source as input.");
    Mode.setEnums(ModeEnums);
}

FemPostPipeline::~FemPostPipeline()
{
}

short FemPostPipeline::mustExecute(void) const
{
    if(Mode.isTouched())
        return 1;

    return FemPostFilter::mustExecute();
}

DocumentObjectExecReturn* FemPostPipeline::execute(void) {

    //if we are the toplevel pipeline our data object is not created by filters, we are the main source!
    if(!Input.getValue())
        return StdReturn;

    //now if we are a filter than our data object is created by the filter we hold

    //if we are in serial mode we just copy over the data of the last filter,
    //but if we are in parallel we need to combine all filter results
    if(Mode.getValue() == 0) {

        //serial
        Data.setValue(getLastPostObject()->Data.getValue());
    }
    else {

        //parallel. go through all filters and append the result
        const std::vector<App::DocumentObject*>& filters = Filter.getValues();
        std::vector<App::DocumentObject*>::const_iterator it = filters.begin();

        vtkSmartPointer<vtkAppendFilter> append = vtkSmartPointer<vtkAppendFilter>::New();
        for(;it != filters.end(); ++it) {

            append->AddInputDataObject(static_cast<FemPostObject*>(*it)->Data.getValue());
        }

        append->Update();
        Data.setValue(append->GetOutputDataObject(0));
    }

    return Fem::FemPostObject::execute();
}

bool FemPostPipeline::canRead(Base::FileInfo File) {

    if (File.hasExtension("vtk") ||
        // from FemResult only unstructural mesh is supported in femvtktoools.cpp
        File.hasExtension("vtp") ||
        File.hasExtension("vts") ||
        File.hasExtension("vtr") ||
        File.hasExtension("vti") ||
        File.hasExtension("vtu"))
        return true;

    return false;
}

void FemPostPipeline::read(Base::FileInfo File) {

    // checking on the file
    if (!File.isReadable())
        throw Base::FileException("File to load not existing or not readable", File);

    if (File.hasExtension("vtu"))
        readXMLFile<vtkXMLUnstructuredGridReader>(File.filePath());
    else if (File.hasExtension("vtp"))
        readXMLFile<vtkXMLPolyDataReader>(File.filePath());
    else if (File.hasExtension("vts"))
        readXMLFile<vtkXMLStructuredGridReader>(File.filePath());
    else if (File.hasExtension("vtr"))
        readXMLFile<vtkXMLRectilinearGridReader>(File.filePath());
    else if (File.hasExtension("vti"))
        readXMLFile<vtkXMLImageDataReader>(File.filePath());
    else if (File.hasExtension("vtk"))
        readXMLFile<vtkDataSetReader>(File.filePath());
    else
        throw Base::FileException("Unknown extension");
}

// PyObject *FemPostPipeline::getPyObject()
// {
//     if (PythonObject.is(Py::_None())){
//         // ref counter is set to 1
//         PythonObject = Py::Object(new DocumentObjectPy(this),true);
//     }
//     return Py::new_reference_to(PythonObject);
// }

void FemPostPipeline::onChanged(const Property* prop)
{
    if(prop == &Filter || prop == &Mode) {

        //we check if all connections are right and add new ones if needed
        std::vector<App::DocumentObject*> objs = Filter.getValues();

        if(objs.empty())
            return;

        std::vector<App::DocumentObject*>::iterator it = objs.begin();
        FemPostFilter* filter = static_cast<FemPostFilter*>(*it);

        //If we have a Input we need to ensure our filters are connected correctly
        if(Input.getValue()) {

            //the first filter is always connected to the input
            if(filter->Input.getValue() != Input.getValue())
                filter->Input.setValue(Input.getValue());

            //all the others need to be connected to the previous filter or the source, dependent on the mode
            ++it;
            for(; it != objs.end(); ++it) {
                FemPostFilter* nextFilter = static_cast<FemPostFilter*>(*it);

                if(Mode.getValue() == 0) { //serial mode
                    if( nextFilter->Input.getValue() != filter)
                        nextFilter->Input.setValue(filter);
                }
                else { //Parallel mode
                    if( nextFilter->Input.getValue() != Input.getValue())
                        nextFilter->Input.setValue(Input.getValue());
                }

                filter = nextFilter;
            };
        }
        //if we have no input the filters are responsible of grabbing the pipeline data themself
        else {
            //the first filter must always grab the data
            if(filter->Input.getValue() != NULL)
                filter->Input.setValue(NULL);

            //all the others need to be connected to the previous filter or grab the data, dependent on mode
            ++it;
            for(; it != objs.end(); ++it) {
                FemPostFilter* nextFilter = static_cast<FemPostFilter*>(*it);

                if(Mode.getValue() == 0) { //serial mode
                    if( nextFilter->Input.getValue() != filter)
                        nextFilter->Input.setValue(filter);
                }
                else { //Parallel mode
                    if( nextFilter->Input.getValue() != NULL)
                        nextFilter->Input.setValue(NULL);
                }

                filter = nextFilter;
            };
        }
    }

    App::GeoFeature::onChanged(prop);

}

FemPostObject* FemPostPipeline::getLastPostObject() {

    if(Filter.getValues().empty())
        return this;

    return static_cast<FemPostObject*>(Filter.getValues().back());
}

bool FemPostPipeline::holdsPostObject(FemPostObject* obj) {

    std::vector<App::DocumentObject*>::const_iterator it = Filter.getValues().begin();
    for(; it != Filter.getValues().end(); ++it) {

        if(*it == obj)
            return true;
    }
    return false;
}

void FemPostPipeline::load(FemResultObject* res) {
    if(!res->Mesh.getValue() || !res->Mesh.getValue()->isDerivedFrom(Fem::FemMeshObject::getClassTypeId())) {
        Base::Console().Warning("Mesh of result object is empty or not derived from Fem::FemMeshObject\n");
        return;
    }

    //first copy the mesh over
    // ***************************
    const FemMesh& mesh = static_cast<FemMeshObject*>(res->Mesh.getValue())->FemMesh.getValue();
    vtkSmartPointer<vtkUnstructuredGrid> grid = vtkSmartPointer<vtkUnstructuredGrid>::New();
    FemVTKTools::exportVTKMesh(&mesh, grid);

    //Now copy the point data over
    // ***************************
    FemVTKTools::exportFreeCADResult(res, grid);

    Data.setValue(grid);
}

PyObject* FemPostPipeline::getPyObject(void)
{
    if (PythonObject.is(Py::_None())) {
        // ref counter is set to 1
        PythonObject = Py::Object(new FemPostPipelinePy(this),true);
    }
    return Py::new_reference_to(PythonObject);
}
<commit_msg>FEM: post result mesh, better log<commit_after>/***************************************************************************
 *   Copyright (c) 2015 Stefan Tröger <stefantroeger@gmx.net>              *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
# include <SMESH_Mesh.hxx>
# include <vtkDataSetReader.h>
# include <vtkGeometryFilter.h>
# include <vtkStructuredGrid.h>
# include <vtkUnstructuredGrid.h>
# include <vtkImageData.h>
# include <vtkRectilinearGrid.h>
# include <vtkAppendFilter.h>
# include <vtkXMLUnstructuredGridReader.h>
# include <vtkXMLPolyDataReader.h>
# include <vtkXMLStructuredGridReader.h>
# include <vtkXMLRectilinearGridReader.h>
# include <vtkXMLImageDataReader.h>
#endif

#include "FemPostPipeline.h"
#include "FemMesh.h"
#include "FemMeshObject.h"
#include "FemVTKTools.h"

#include <Base/Console.h>
#include <App/Document.h>

#include <App/DocumentObjectPy.h>
#include <Mod/Fem/App/FemPostPipelinePy.h>

using namespace Fem;
using namespace App;

PROPERTY_SOURCE(Fem::FemPostPipeline, Fem::FemPostObject)
const char* FemPostPipeline::ModeEnums[]= {"Serial","Parallel",NULL};

FemPostPipeline::FemPostPipeline()
{
    ADD_PROPERTY_TYPE(Filter, (0), "Pipeline", App::Prop_None, "The filter used in in this pipeline");
    ADD_PROPERTY_TYPE(Functions, (0), "Pipeline", App::Prop_Hidden, "The function provider which groups all pipeline functions");
    ADD_PROPERTY_TYPE(Mode,(long(0)), "Pipeline", App::Prop_None, "Selects the pipeline data transition mode. In serial every filter"
                                                              "gets the output of the previous one as input, in parallel every"
                                                              "filter gets the pipelien source as input.");
    Mode.setEnums(ModeEnums);
}

FemPostPipeline::~FemPostPipeline()
{
}

short FemPostPipeline::mustExecute(void) const
{
    if(Mode.isTouched())
        return 1;

    return FemPostFilter::mustExecute();
}

DocumentObjectExecReturn* FemPostPipeline::execute(void) {

    //if we are the toplevel pipeline our data object is not created by filters, we are the main source!
    if(!Input.getValue())
        return StdReturn;

    //now if we are a filter than our data object is created by the filter we hold

    //if we are in serial mode we just copy over the data of the last filter,
    //but if we are in parallel we need to combine all filter results
    if(Mode.getValue() == 0) {

        //serial
        Data.setValue(getLastPostObject()->Data.getValue());
    }
    else {

        //parallel. go through all filters and append the result
        const std::vector<App::DocumentObject*>& filters = Filter.getValues();
        std::vector<App::DocumentObject*>::const_iterator it = filters.begin();

        vtkSmartPointer<vtkAppendFilter> append = vtkSmartPointer<vtkAppendFilter>::New();
        for(;it != filters.end(); ++it) {

            append->AddInputDataObject(static_cast<FemPostObject*>(*it)->Data.getValue());
        }

        append->Update();
        Data.setValue(append->GetOutputDataObject(0));
    }

    return Fem::FemPostObject::execute();
}

bool FemPostPipeline::canRead(Base::FileInfo File) {

    if (File.hasExtension("vtk") ||
        // from FemResult only unstructural mesh is supported in femvtktoools.cpp
        File.hasExtension("vtp") ||
        File.hasExtension("vts") ||
        File.hasExtension("vtr") ||
        File.hasExtension("vti") ||
        File.hasExtension("vtu"))
        return true;

    return false;
}

void FemPostPipeline::read(Base::FileInfo File) {

    // checking on the file
    if (!File.isReadable())
        throw Base::FileException("File to load not existing or not readable", File);

    if (File.hasExtension("vtu"))
        readXMLFile<vtkXMLUnstructuredGridReader>(File.filePath());
    else if (File.hasExtension("vtp"))
        readXMLFile<vtkXMLPolyDataReader>(File.filePath());
    else if (File.hasExtension("vts"))
        readXMLFile<vtkXMLStructuredGridReader>(File.filePath());
    else if (File.hasExtension("vtr"))
        readXMLFile<vtkXMLRectilinearGridReader>(File.filePath());
    else if (File.hasExtension("vti"))
        readXMLFile<vtkXMLImageDataReader>(File.filePath());
    else if (File.hasExtension("vtk"))
        readXMLFile<vtkDataSetReader>(File.filePath());
    else
        throw Base::FileException("Unknown extension");
}

// PyObject *FemPostPipeline::getPyObject()
// {
//     if (PythonObject.is(Py::_None())){
//         // ref counter is set to 1
//         PythonObject = Py::Object(new DocumentObjectPy(this),true);
//     }
//     return Py::new_reference_to(PythonObject);
// }

void FemPostPipeline::onChanged(const Property* prop)
{
    if(prop == &Filter || prop == &Mode) {

        //we check if all connections are right and add new ones if needed
        std::vector<App::DocumentObject*> objs = Filter.getValues();

        if(objs.empty())
            return;

        std::vector<App::DocumentObject*>::iterator it = objs.begin();
        FemPostFilter* filter = static_cast<FemPostFilter*>(*it);

        //If we have a Input we need to ensure our filters are connected correctly
        if(Input.getValue()) {

            //the first filter is always connected to the input
            if(filter->Input.getValue() != Input.getValue())
                filter->Input.setValue(Input.getValue());

            //all the others need to be connected to the previous filter or the source, dependent on the mode
            ++it;
            for(; it != objs.end(); ++it) {
                FemPostFilter* nextFilter = static_cast<FemPostFilter*>(*it);

                if(Mode.getValue() == 0) { //serial mode
                    if( nextFilter->Input.getValue() != filter)
                        nextFilter->Input.setValue(filter);
                }
                else { //Parallel mode
                    if( nextFilter->Input.getValue() != Input.getValue())
                        nextFilter->Input.setValue(Input.getValue());
                }

                filter = nextFilter;
            };
        }
        //if we have no input the filters are responsible of grabbing the pipeline data themself
        else {
            //the first filter must always grab the data
            if(filter->Input.getValue() != NULL)
                filter->Input.setValue(NULL);

            //all the others need to be connected to the previous filter or grab the data, dependent on mode
            ++it;
            for(; it != objs.end(); ++it) {
                FemPostFilter* nextFilter = static_cast<FemPostFilter*>(*it);

                if(Mode.getValue() == 0) { //serial mode
                    if( nextFilter->Input.getValue() != filter)
                        nextFilter->Input.setValue(filter);
                }
                else { //Parallel mode
                    if( nextFilter->Input.getValue() != NULL)
                        nextFilter->Input.setValue(NULL);
                }

                filter = nextFilter;
            };
        }
    }

    App::GeoFeature::onChanged(prop);

}

FemPostObject* FemPostPipeline::getLastPostObject() {

    if(Filter.getValues().empty())
        return this;

    return static_cast<FemPostObject*>(Filter.getValues().back());
}

bool FemPostPipeline::holdsPostObject(FemPostObject* obj) {

    std::vector<App::DocumentObject*>::const_iterator it = Filter.getValues().begin();
    for(; it != Filter.getValues().end(); ++it) {

        if(*it == obj)
            return true;
    }
    return false;
}

void FemPostPipeline::load(FemResultObject* res) {
    if (!res->Mesh.getValue()) {
        Base::Console().Log("Result mesh object is empty.\n");
        return;
    }
    if(!res->Mesh.getValue()->isDerivedFrom(Fem::FemMeshObject::getClassTypeId())) {
        Base::Console().Log("Result mesh object is not derived from Fem::FemMeshObject.\n");
        return;
    }

    //first copy the mesh over
    // ***************************
    const FemMesh& mesh = static_cast<FemMeshObject*>(res->Mesh.getValue())->FemMesh.getValue();
    vtkSmartPointer<vtkUnstructuredGrid> grid = vtkSmartPointer<vtkUnstructuredGrid>::New();
    FemVTKTools::exportVTKMesh(&mesh, grid);

    //Now copy the point data over
    // ***************************
    FemVTKTools::exportFreeCADResult(res, grid);

    Data.setValue(grid);
}

PyObject* FemPostPipeline::getPyObject(void)
{
    if (PythonObject.is(Py::_None())) {
        // ref counter is set to 1
        PythonObject = Py::Object(new FemPostPipelinePy(this),true);
    }
    return Py::new_reference_to(PythonObject);
}
<|endoftext|>


<commit_before><commit_msg>Path: [skip ci] fix memory leak in TooltablePy::getTools() For some background information see: https://forum.freecadweb.org/viewtopic.php?f=15&t=50583&start=20#p457516<commit_after><|endoftext|>


<commit_before><commit_msg>new version<commit_after><|endoftext|>


<commit_before>//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.

#include <vector>

#include "llvm/IR/DataLayout.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"

#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/LoopPass.h"

using namespace llvm;

bool CloneMetadata(const llvm::Instruction *, llvm::Instruction *);

class InstrumentNontermination : public LoopPass {
  bool checkFunction(Function *F);
  bool instrumentLoop(Loop *L);
  bool instrumentLoop(Loop *L, const std::set<llvm::Value *>& variables);

  llvm::Value *getOperand(llvm::Value *v) {
      if (isa<Constant>(v) ||
          isa<AllocaInst>(v) || isa<GlobalVariable>(v)) {
          return v;
      }
      return nullptr;
  }

  Function *_assert{nullptr};

  public:
    static char ID;

    InstrumentNontermination() : LoopPass(ID) {}

    bool runOnLoop(Loop *L, LPPassManager &LPM) override {
      // for now, we detect only nested loops
      if (L->getParentLoop()) {
          // run on non-nested loops for now
          return false;
      }

      return instrumentLoop(L);
    }
};

bool InstrumentNontermination::checkFunction(Function *F) {
  if (!F) // call via pointer
      return false;

  if (F->getName().equals("__VERIFIER_assume") ||
      F->getName().equals("__VERIFIER_assert"))
    return true;
  return false;
}

bool InstrumentNontermination::instrumentLoop(Loop *L) {
  std::set<llvm::Value *> usedValues;

  for (auto *block : L->blocks()) {
    // check that the loop reads and writes only to known
    // locations (allocas and global variables)
    for (auto& I : *block) {
      if (auto *CI = dyn_cast<CallInst>(&I)) {
          if (!checkFunction(CI->getCalledFunction())) {
            return false;
          }
      } else if (auto LI = dyn_cast<LoadInst>(&I)) {
        if (auto v = getOperand(LI->getPointerOperand())) {
          if (!isa<ConstantInt>(v)) {
            usedValues.insert(v);
          }
        } else {
          return false;
        }
      } else if (auto SI = dyn_cast<StoreInst>(&I)) {
        if (auto p = getOperand(SI->getPointerOperand())) {
          if (!isa<ConstantInt>(p)) {
            usedValues.insert(p);
          }
        } else {
          return false;
        }
      } else {
        if (I.mayReadOrWriteMemory()) {
          llvm::errs() << "WARNING: Unhandled instr: " << I << "\n";
          return false;
        }
      }
    }
  }

  return instrumentLoop(L, usedValues);
}

bool InstrumentNontermination::instrumentLoop(Loop *L, const std::set<llvm::Value *>& variables) {
  auto *header = L->getHeader();
  assert(header);

  // mapping of old to new ones
  std::map<Value *, Value *> mapping;

  // for each variable, create its copy in the header
  // and store the last recent value from the original
  // variable
  for (auto *v : variables) {
    //errs() << "INFO: variable: " << *v << "\n";
    Instruction *newVal = nullptr;
    if (auto *I = dyn_cast<Instruction>(v)) {
        newVal = I->clone();
        newVal->insertAfter(I);
    } else if (auto *G = dyn_cast<GlobalValue>(v)) {
        // create a new alloca that
        // is going to be inserted at the beginning of the header
        newVal = new AllocaInst(G->getType()->getContainedType(0)
#if (LLVM_VERSION_MAJOR >= 5)
        , G->getType()->getAddressSpace()
#endif
        );

        // puth the alloca on the beginning of the function
        newVal->insertBefore(header->getParent()->getBasicBlockList().front().getTerminator());
    } else {
      llvm::errs() << "ERROR: Unhandled copying: " << *v << "\n";
      return false;
    }

    assert(newVal);
    mapping[v] = newVal;
  }

  // store the state of variables at the loop head
  for (auto& it : mapping) {
    auto *LI = new LoadInst(it.first);
    auto *SI = new StoreInst(LI, it.second);

    header->getInstList().push_front(SI);
    header->getInstList().push_front(LI);
  }

  // compare the old and new values after the iteration of the loop
  for (auto I = pred_begin(header), E = pred_end(header); I != E; ++I) {
    auto *term = (*I)->getTerminator();

    // the state must be stored before any enter ofer,
    // but the assertions are inserted only before the
    // jumps that come from the loop
    if (!L->contains(*I))
      continue;

    // create an assertion that the values are not all the same
    // as the old values (if this assert fails, we found
    // a cycle in the state space)
    Instruction *lastCond = nullptr;
    for (auto& it : mapping) {
      auto *newVal = new LoadInst(it.first);
      auto *oldVal = new LoadInst(it.second);
      auto *cmp = new ICmpInst(ICmpInst::ICMP_EQ, newVal, oldVal);
      newVal->insertBefore(term);
      oldVal->insertBefore(term);
      cmp->insertBefore(term);

      if (lastCond) {
        assert(mapping.size() > 1); // we can get here only after 1 iteration
        auto *And = BinaryOperator::Create(Instruction::And, lastCond, cmp);
        And->insertBefore(term);
        lastCond = And;
      } else {
        lastCond = cmp;
      }
    }

    assert(lastCond);

    if (!_assert) {
      auto M = header->getParent()->getParent();
      auto& Ctx = M->getContext();
      auto F = M->getOrInsertFunction("__INSTR_check_nontermination",
                                      Type::getVoidTy(Ctx), // retval
                                      Type::getInt1Ty(Ctx)  // condition
#if LLVM_VERSION_MAJOR < 5
                                      , nullptr
#endif
                                      );
#if LLVM_VERSION_MAJOR >= 9
      _assert = cast<Function>(F.getCallee()->stripPointerCasts());
#else
      _assert = cast<Function>(F);
#endif
    }

    // insert the assertion that all the values are the same
    assert(_assert);
    auto *CI = CallInst::Create(_assert, {lastCond});
    CloneMetadata(lastCond, CI);
    CI->insertBefore(term);
  }

  llvm::errs() << "Instrumented a loop with non-termination checks\n";
  return true;
}

static RegisterPass<InstrumentNontermination> CL("instrument-nontermination",
                                                  "Insert trivial checks for state space cycles");
char InstrumentNontermination::ID;

<commit_msg>Improve non-termination check<commit_after>//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.

#include <vector>

#include "llvm/IR/DataLayout.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"

#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/LoopPass.h"

using namespace llvm;

bool CloneMetadata(const llvm::Instruction *, llvm::Instruction *);

class InstrumentNontermination : public LoopPass {
  bool checkFunction(Function *F);
  bool instrumentLoop(Loop *L);
  bool instrumentLoop(Loop *L, const std::set<llvm::Value *>& variables);

  llvm::Value *getOperand(llvm::Value *v) {
      if (isa<Constant>(v) ||
          isa<AllocaInst>(v) || isa<GlobalVariable>(v)) {
          return v;
      }
      return nullptr;
  }

  Function *_assert{nullptr};

  public:
    static char ID;

    InstrumentNontermination() : LoopPass(ID) {}

    bool runOnLoop(Loop *L, LPPassManager &LPM) override {
      // for now, we detect only nested loops
      if (L->getParentLoop()) {
          // run on non-nested loops for now
          return false;
      }

      return instrumentLoop(L);
    }
};

bool InstrumentNontermination::checkFunction(Function *F) {
  if (!F) // call via pointer
      return false;

  if (F->getName().equals("__VERIFIER_assume") ||
      F->getName().equals("__VERIFIER_assert") ||
      F->getName().startswith("__VERIFIER_nondet_"))
    return true;
  return false;
}

bool InstrumentNontermination::instrumentLoop(Loop *L) {
  std::set<llvm::Value *> usedValues;

  for (auto *block : L->blocks()) {
    // check that the loop reads and writes only to known
    // locations (allocas and global variables)
    for (auto& I : *block) {
      if (auto *CI = dyn_cast<CallInst>(&I)) {
          if (!checkFunction(CI->getCalledFunction())) {
            return false;
          }
      } else if (auto LI = dyn_cast<LoadInst>(&I)) {
        if (auto v = getOperand(LI->getPointerOperand())) {
          if (!isa<ConstantInt>(v)) {
            usedValues.insert(v);
          }
        } else {
          return false;
        }
      } else if (auto SI = dyn_cast<StoreInst>(&I)) {
        if (auto p = getOperand(SI->getPointerOperand())) {
          if (!isa<ConstantInt>(p)) {
            usedValues.insert(p);
          }
        } else {
          return false;
        }
      } else {
        if (I.mayReadOrWriteMemory()) {
          llvm::errs() << "WARNING: Unhandled instr: " << I << "\n";
          return false;
        }
      }
    }
  }

  return instrumentLoop(L, usedValues);
}

bool InstrumentNontermination::instrumentLoop(Loop *L, const std::set<llvm::Value *>& variables) {
  auto *header = L->getHeader();
  assert(header);

  // mapping of old to new ones
  std::map<Value *, Value *> mapping;

  // for each variable, create its copy in the header
  // and store the last recent value from the original
  // variable
  for (auto *v : variables) {
    //errs() << "INFO: variable: " << *v << "\n";
    Instruction *newVal = nullptr;
    if (auto *I = dyn_cast<Instruction>(v)) {
        newVal = I->clone();
        newVal->insertAfter(I);
    } else if (auto *G = dyn_cast<GlobalValue>(v)) {
        // create a new alloca that
        // is going to be inserted at the beginning of the header
        newVal = new AllocaInst(G->getType()->getContainedType(0)
#if (LLVM_VERSION_MAJOR >= 5)
        , G->getType()->getAddressSpace()
#endif
        );

        // puth the alloca on the beginning of the function
        newVal->insertBefore(header->getParent()->getBasicBlockList().front().getTerminator());
    } else {
      llvm::errs() << "ERROR: Unhandled copying: " << *v << "\n";
      return false;
    }

    assert(newVal);
    mapping[v] = newVal;
  }

  // store the state of variables at the loop head
  for (auto& it : mapping) {
    auto *LI = new LoadInst(it.first);
    auto *SI = new StoreInst(LI, it.second);

    header->getInstList().push_front(SI);
    header->getInstList().push_front(LI);
  }

  // compare the old and new values after the iteration of the loop
  for (auto I = pred_begin(header), E = pred_end(header); I != E; ++I) {
    auto *term = (*I)->getTerminator();

    // the state must be stored before any enter ofer,
    // but the assertions are inserted only before the
    // jumps that come from the loop
    if (!L->contains(*I))
      continue;

    // create an assertion that the values are not all the same
    // as the old values (if this assert fails, we found
    // a cycle in the state space)
    Instruction *lastCond = nullptr;
    for (auto& it : mapping) {
      auto *newVal = new LoadInst(it.first);
      auto *oldVal = new LoadInst(it.second);
      auto *cmp = new ICmpInst(ICmpInst::ICMP_EQ, newVal, oldVal);
      newVal->insertBefore(term);
      oldVal->insertBefore(term);
      cmp->insertBefore(term);

      if (lastCond) {
        assert(mapping.size() > 1); // we can get here only after 1 iteration
        auto *And = BinaryOperator::Create(Instruction::And, lastCond, cmp);
        And->insertBefore(term);
        lastCond = And;
      } else {
        lastCond = cmp;
      }
    }

    assert(lastCond);

    if (!_assert) {
      auto M = header->getParent()->getParent();
      auto& Ctx = M->getContext();
      auto F = M->getOrInsertFunction("__INSTR_check_nontermination",
                                      Type::getVoidTy(Ctx), // retval
                                      Type::getInt1Ty(Ctx)  // condition
#if LLVM_VERSION_MAJOR < 5
                                      , nullptr
#endif
                                      );
#if LLVM_VERSION_MAJOR >= 9
      _assert = cast<Function>(F.getCallee()->stripPointerCasts());
#else
      _assert = cast<Function>(F);
#endif
    }

    // insert the assertion that all the values are the same
    assert(_assert);
    auto *CI = CallInst::Create(_assert, {lastCond});
    CloneMetadata(lastCond, CI);
    CI->insertBefore(term);
  }

  llvm::errs() << "Instrumented a loop with non-termination checks\n";
  return true;
}

static RegisterPass<InstrumentNontermination> CL("instrument-nontermination",
                                                  "Insert trivial checks for state space cycles");
char InstrumentNontermination::ID;

<|endoftext|>


<commit_before>/// \file RPageStorageFile.cxx
/// \ingroup NTuple ROOT7
/// \author Jakob Blomer <jblomer@cern.ch>
/// \date 2019-11-25
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include <ROOT/RField.hxx>
#include <ROOT/RLogger.hxx>
#include <ROOT/RNTupleDescriptor.hxx>
#include <ROOT/RNTupleModel.hxx>
#include <ROOT/RNTupleZip.hxx>
#include <ROOT/RPage.hxx>
#include <ROOT/RPageAllocator.hxx>
#include <ROOT/RPagePool.hxx>
#include <ROOT/RPageStorageFile.hxx>
#include <ROOT/RRawFile.hxx>

#include <RVersion.h>
#include <TError.h>

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <utility>

ROOT::Experimental::Detail::RPageSinkFile::RPageSinkFile(std::string_view ntupleName, std::string_view path,
   const RNTupleWriteOptions &options)
   : RPageSink(ntupleName, options)
   , fMetrics("RPageSinkRoot")
   , fPageAllocator(std::make_unique<RPageAllocatorHeap>())
{
   R__WARNING_HERE("NTuple") << "The RNTuple file format will change. " <<
      "Do not store real data with this version of RNTuple!";

   fWriter = std::unique_ptr<Internal::RMiniFileWriter>(Internal::RMiniFileWriter::Recreate(
      ntupleName, path, options.GetCompression(), options.GetContainerFormat()));
}

ROOT::Experimental::Detail::RPageSinkFile::RPageSinkFile(std::string_view ntupleName, TFile &file,
   const RNTupleWriteOptions &options)
   : RPageSink(ntupleName, options)
   , fMetrics("RPageSinkRoot")
   , fPageAllocator(std::make_unique<RPageAllocatorHeap>())
{
   R__WARNING_HERE("NTuple") << "The RNTuple file format will change. " <<
      "Do not store real data with this version of RNTuple!";

   fWriter = std::unique_ptr<Internal::RMiniFileWriter>(Internal::RMiniFileWriter::Append(ntupleName, file));
}

ROOT::Experimental::Detail::RPageSinkFile::RPageSinkFile(std::string_view ntupleName, std::string_view path,
   const RNTupleWriteOptions &options, std::unique_ptr<TFile> &file)
   : RPageSink(ntupleName, options)
   , fMetrics("RPageSinkRoot")
   , fPageAllocator(std::make_unique<RPageAllocatorHeap>())
{
   R__WARNING_HERE("NTuple") << "The RNTuple file format will change. " <<
      "Do not store real data with this version of RNTuple!";
   fWriter = std::unique_ptr<Internal::RMiniFileWriter>(Internal::RMiniFileWriter::Recreate(ntupleName, path, file));
}

ROOT::Experimental::Detail::RPageSinkFile::~RPageSinkFile()
{
}

void ROOT::Experimental::Detail::RPageSinkFile::DoCreate(const RNTupleModel & /* model */)
{
   const auto &descriptor = fDescriptorBuilder.GetDescriptor();
   auto szHeader = descriptor.SerializeHeader(nullptr);
   auto buffer = std::unique_ptr<unsigned char[]>(new unsigned char[szHeader]);
   descriptor.SerializeHeader(buffer.get());

   auto zipBuffer = std::unique_ptr<unsigned char[]>(new unsigned char[szHeader]);
   auto szZipHeader = fCompressor(buffer.get(), szHeader, fOptions.GetCompression(),
      [&zipBuffer](const void *b, size_t n, size_t o){ memcpy(zipBuffer.get() + o, b, n); } );
   fWriter->WriteNTupleHeader(zipBuffer.get(), szZipHeader, szHeader);
}

ROOT::Experimental::RClusterDescriptor::RLocator
ROOT::Experimental::Detail::RPageSinkFile::DoCommitPage(ColumnHandle_t columnHandle, const RPage &page)
{
   unsigned char *buffer = reinterpret_cast<unsigned char *>(page.GetBuffer());
   bool isAdoptedBuffer = true;
   auto packedBytes = page.GetSize();
   auto element = columnHandle.fColumn->GetElement();
   const auto isMappable = element->IsMappable();

   if (!isMappable) {
      packedBytes = (page.GetNElements() * element->GetBitsOnStorage() + 7) / 8;
      buffer = new unsigned char[packedBytes];
      isAdoptedBuffer = false;
      element->Pack(buffer, page.GetBuffer(), page.GetNElements());
   }
   auto zippedBytes = packedBytes;

   if (fOptions.GetCompression() != 0) {
      zippedBytes = fCompressor(buffer, packedBytes, fOptions.GetCompression());
      if (!isAdoptedBuffer)
         delete[] buffer;
      buffer = const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(fCompressor.GetZipBuffer()));
      isAdoptedBuffer = true;
   }

   auto offsetData = fWriter->WriteBlob(buffer, zippedBytes, packedBytes);
   fClusterMinOffset = std::min(offsetData, fClusterMinOffset);
   fClusterMaxOffset = std::max(offsetData, fClusterMaxOffset);

   if (!isAdoptedBuffer)
      delete[] buffer;

   RClusterDescriptor::RLocator result;
   result.fPosition = offsetData;
   result.fBytesOnStorage = zippedBytes;
   return result;
}

ROOT::Experimental::RClusterDescriptor::RLocator
ROOT::Experimental::Detail::RPageSinkFile::DoCommitCluster(ROOT::Experimental::NTupleSize_t /* nEntries */)
{
   RClusterDescriptor::RLocator result;
   result.fPosition = fClusterMinOffset;
   result.fBytesOnStorage = fClusterMaxOffset - fClusterMinOffset;
   fClusterMinOffset = std::uint64_t(-1);
   fClusterMaxOffset = 0;
   return result;
}

void ROOT::Experimental::Detail::RPageSinkFile::DoCommitDataset()
{
   const auto &descriptor = fDescriptorBuilder.GetDescriptor();
   auto szFooter = descriptor.SerializeFooter(nullptr);
   auto buffer = std::unique_ptr<unsigned char []>(new unsigned char[szFooter]);
   descriptor.SerializeFooter(buffer.get());

   auto zipBuffer = std::unique_ptr<unsigned char[]>(new unsigned char[szFooter]);
   auto szZipFooter = fCompressor(buffer.get(), szFooter, fOptions.GetCompression(),
      [&zipBuffer](const void *b, size_t n, size_t o){ memcpy(zipBuffer.get() + o, b, n); } );
   fWriter->WriteNTupleFooter(zipBuffer.get(), szZipFooter, szFooter);
   fWriter->Commit();
}

ROOT::Experimental::Detail::RPage
ROOT::Experimental::Detail::RPageSinkFile::ReservePage(ColumnHandle_t columnHandle, std::size_t nElements)
{
   if (nElements == 0)
      nElements = kDefaultElementsPerPage;
   auto elementSize = columnHandle.fColumn->GetElement()->GetSize();
   return fPageAllocator->NewPage(columnHandle.fId, elementSize, nElements);
}

void ROOT::Experimental::Detail::RPageSinkFile::ReleasePage(RPage &page)
{
   fPageAllocator->DeletePage(page);
}

////////////////////////////////////////////////////////////////////////////////

ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageAllocatorFile::NewPage(
   ColumnId_t columnId, void *mem, std::size_t elementSize, std::size_t nElements)
{
   RPage newPage(columnId, mem, elementSize * nElements, elementSize);
   newPage.TryGrow(nElements);
   return newPage;
}

void ROOT::Experimental::Detail::RPageAllocatorFile::DeletePage(const RPage& page)
{
   if (page.IsNull())
      return;
   delete[] reinterpret_cast<unsigned char *>(page.GetBuffer());
}

////////////////////////////////////////////////////////////////////////////////

ROOT::Experimental::Detail::RPageSourceFile::RPageSourceFile(std::string_view ntupleName,
   const RNTupleReadOptions &options)
   : RPageSource(ntupleName, options)
   , fMetrics("RPageSourceFile")
   , fPageAllocator(std::make_unique<RPageAllocatorFile>())
   , fPagePool(std::make_shared<RPagePool>())
{
}

ROOT::Experimental::Detail::RPageSourceFile::RPageSourceFile(std::string_view ntupleName, std::string_view path,
   const RNTupleReadOptions &options)
   : RPageSourceFile(ntupleName, options)
{
   fFile = std::unique_ptr<RRawFile>(RRawFile::Create(path));
   R__ASSERT(fFile);
   fReader = Internal::RMiniFileReader(fFile.get());
}

ROOT::Experimental::Detail::RPageSourceFile::~RPageSourceFile()
{
}

ROOT::Experimental::RNTupleDescriptor ROOT::Experimental::Detail::RPageSourceFile::DoAttach()
{
   RNTupleDescriptorBuilder descBuilder;
   auto fNTuple = fReader.GetNTuple(fNTupleName);

   auto buffer = std::unique_ptr<unsigned char[]>(new unsigned char[fNTuple.fLenHeader]);
   auto zipBuffer = std::unique_ptr<unsigned char[]>(new unsigned char[fNTuple.fNBytesHeader]);
   fReader.ReadBlob(zipBuffer.get(), fNTuple.fNBytesHeader, fNTuple.fSeekHeader);
   fDecompressor(zipBuffer.get(), fNTuple.fNBytesHeader, fNTuple.fLenHeader, buffer.get());
   descBuilder.SetFromHeader(buffer.get());

   buffer = std::unique_ptr<unsigned char[]>(new unsigned char[fNTuple.fLenFooter]);
   zipBuffer = std::unique_ptr<unsigned char[]>(new unsigned char[fNTuple.fNBytesFooter]);
   fReader.ReadBlob(zipBuffer.get(), fNTuple.fNBytesFooter, fNTuple.fSeekFooter);
   fDecompressor(zipBuffer.get(), fNTuple.fNBytesFooter, fNTuple.fLenFooter, buffer.get());
   descBuilder.AddClustersFromFooter(buffer.get());

   return descBuilder.MoveDescriptor();
}

ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceFile::PopulatePageFromCluster(
   ColumnHandle_t columnHandle, const RClusterDescriptor &clusterDescriptor, ClusterSize_t::ValueType clusterIndex)
{
   auto columnId = columnHandle.fId;
   auto clusterId = clusterDescriptor.GetId();
   const auto &pageRange = clusterDescriptor.GetPageRange(columnId);

   // TODO(jblomer): binary search
   RClusterDescriptor::RPageRange::RPageInfo pageInfo;
   decltype(clusterIndex) firstInPage = 0;
   for (const auto &pi : pageRange.fPageInfos) {
      if (firstInPage + pi.fNElements > clusterIndex) {
         pageInfo = pi;
         break;
      }
      firstInPage += pi.fNElements;
   }
   R__ASSERT(firstInPage <= clusterIndex);
   R__ASSERT((firstInPage + pageInfo.fNElements) > clusterIndex);

   auto element = columnHandle.fColumn->GetElement();
   auto elementSize = element->GetSize();

   auto pageSize = pageInfo.fLocator.fBytesOnStorage;
   auto pageBuffer = new unsigned char[
      std::max(pageSize, static_cast<std::uint32_t>(elementSize * pageInfo.fNElements))];
   fReader.ReadBlob(pageBuffer, pageInfo.fLocator.fBytesOnStorage, pageInfo.fLocator.fPosition);

   auto bytesOnStorage = (element->GetBitsOnStorage() * pageInfo.fNElements + 7) / 8;
   if (pageSize != bytesOnStorage) {
      fDecompressor(pageBuffer, pageSize, bytesOnStorage);
      pageSize = bytesOnStorage;
   }

   if (!element->IsMappable()) {
      pageSize = elementSize * pageInfo.fNElements;
      auto unpackedBuffer = new unsigned char[pageSize];
      element->Unpack(unpackedBuffer, pageBuffer, pageInfo.fNElements);
      delete[] pageBuffer;
      pageBuffer = unpackedBuffer;
   }

   auto indexOffset = clusterDescriptor.GetColumnRange(columnId).fFirstElementIndex;
   auto newPage = fPageAllocator->NewPage(columnId, pageBuffer, elementSize, pageInfo.fNElements);
   newPage.SetWindow(indexOffset + firstInPage, RPage::RClusterInfo(clusterId, indexOffset));
   fPagePool->RegisterPage(newPage,
      RPageDeleter([](const RPage &page, void */*userData*/)
      {
         RPageAllocatorFile::DeletePage(page);
      }, nullptr));
   return newPage;
}

ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceFile::PopulatePage(
   ColumnHandle_t columnHandle, NTupleSize_t globalIndex)
{
   auto columnId = columnHandle.fId;
   auto cachedPage = fPagePool->GetPage(columnId, globalIndex);
   if (!cachedPage.IsNull())
      return cachedPage;

   auto clusterId = fDescriptor.FindClusterId(columnId, globalIndex);
   R__ASSERT(clusterId != kInvalidDescriptorId);
   const auto &clusterDescriptor = fDescriptor.GetClusterDescriptor(clusterId);
   auto selfOffset = clusterDescriptor.GetColumnRange(columnId).fFirstElementIndex;
   R__ASSERT(selfOffset <= globalIndex);
   return PopulatePageFromCluster(columnHandle, clusterDescriptor, globalIndex - selfOffset);
}

ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceFile::PopulatePage(
   ColumnHandle_t columnHandle, const RClusterIndex &clusterIndex)
{
   auto clusterId = clusterIndex.GetClusterId();
   auto index = clusterIndex.GetIndex();
   auto columnId = columnHandle.fId;
   auto cachedPage = fPagePool->GetPage(columnId, clusterIndex);
   if (!cachedPage.IsNull())
      return cachedPage;

   R__ASSERT(clusterId != kInvalidDescriptorId);
   const auto &clusterDescriptor = fDescriptor.GetClusterDescriptor(clusterId);
   return PopulatePageFromCluster(columnHandle, clusterDescriptor, index);
}

void ROOT::Experimental::Detail::RPageSourceFile::ReleasePage(RPage &page)
{
   fPagePool->ReturnPage(page);
}

std::unique_ptr<ROOT::Experimental::Detail::RPageSource> ROOT::Experimental::Detail::RPageSourceFile::Clone() const
{
   auto clone = new RPageSourceFile(fNTupleName, fOptions);
   clone->fFile = fFile->Clone();
   clone->fReader = Internal::RMiniFileReader(clone->fFile.get());
   return std::unique_ptr<RPageSourceFile>(clone);
}
<commit_msg>[ntuple] minor code improvement (NFC)<commit_after>/// \file RPageStorageFile.cxx
/// \ingroup NTuple ROOT7
/// \author Jakob Blomer <jblomer@cern.ch>
/// \date 2019-11-25
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include <ROOT/RField.hxx>
#include <ROOT/RLogger.hxx>
#include <ROOT/RNTupleDescriptor.hxx>
#include <ROOT/RNTupleModel.hxx>
#include <ROOT/RNTupleZip.hxx>
#include <ROOT/RPage.hxx>
#include <ROOT/RPageAllocator.hxx>
#include <ROOT/RPagePool.hxx>
#include <ROOT/RPageStorageFile.hxx>
#include <ROOT/RRawFile.hxx>

#include <RVersion.h>
#include <TError.h>

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <utility>

ROOT::Experimental::Detail::RPageSinkFile::RPageSinkFile(std::string_view ntupleName, std::string_view path,
   const RNTupleWriteOptions &options)
   : RPageSink(ntupleName, options)
   , fMetrics("RPageSinkRoot")
   , fPageAllocator(std::make_unique<RPageAllocatorHeap>())
{
   R__WARNING_HERE("NTuple") << "The RNTuple file format will change. " <<
      "Do not store real data with this version of RNTuple!";

   fWriter = std::unique_ptr<Internal::RMiniFileWriter>(Internal::RMiniFileWriter::Recreate(
      ntupleName, path, options.GetCompression(), options.GetContainerFormat()));
}

ROOT::Experimental::Detail::RPageSinkFile::RPageSinkFile(std::string_view ntupleName, TFile &file,
   const RNTupleWriteOptions &options)
   : RPageSink(ntupleName, options)
   , fMetrics("RPageSinkRoot")
   , fPageAllocator(std::make_unique<RPageAllocatorHeap>())
{
   R__WARNING_HERE("NTuple") << "The RNTuple file format will change. " <<
      "Do not store real data with this version of RNTuple!";

   fWriter = std::unique_ptr<Internal::RMiniFileWriter>(Internal::RMiniFileWriter::Append(ntupleName, file));
}

ROOT::Experimental::Detail::RPageSinkFile::RPageSinkFile(std::string_view ntupleName, std::string_view path,
   const RNTupleWriteOptions &options, std::unique_ptr<TFile> &file)
   : RPageSink(ntupleName, options)
   , fMetrics("RPageSinkRoot")
   , fPageAllocator(std::make_unique<RPageAllocatorHeap>())
{
   R__WARNING_HERE("NTuple") << "The RNTuple file format will change. " <<
      "Do not store real data with this version of RNTuple!";
   fWriter = std::unique_ptr<Internal::RMiniFileWriter>(Internal::RMiniFileWriter::Recreate(ntupleName, path, file));
}

ROOT::Experimental::Detail::RPageSinkFile::~RPageSinkFile()
{
}

void ROOT::Experimental::Detail::RPageSinkFile::DoCreate(const RNTupleModel & /* model */)
{
   const auto &descriptor = fDescriptorBuilder.GetDescriptor();
   auto szHeader = descriptor.SerializeHeader(nullptr);
   auto buffer = std::unique_ptr<unsigned char[]>(new unsigned char[szHeader]);
   descriptor.SerializeHeader(buffer.get());

   auto zipBuffer = std::unique_ptr<unsigned char[]>(new unsigned char[szHeader]);
   auto szZipHeader = fCompressor(buffer.get(), szHeader, fOptions.GetCompression(),
      [&zipBuffer](const void *b, size_t n, size_t o){ memcpy(zipBuffer.get() + o, b, n); } );
   fWriter->WriteNTupleHeader(zipBuffer.get(), szZipHeader, szHeader);
}

ROOT::Experimental::RClusterDescriptor::RLocator
ROOT::Experimental::Detail::RPageSinkFile::DoCommitPage(ColumnHandle_t columnHandle, const RPage &page)
{
   unsigned char *buffer = reinterpret_cast<unsigned char *>(page.GetBuffer());
   bool isAdoptedBuffer = true;
   auto packedBytes = page.GetSize();
   auto element = columnHandle.fColumn->GetElement();
   const auto isMappable = element->IsMappable();

   if (!isMappable) {
      packedBytes = (page.GetNElements() * element->GetBitsOnStorage() + 7) / 8;
      buffer = new unsigned char[packedBytes];
      isAdoptedBuffer = false;
      element->Pack(buffer, page.GetBuffer(), page.GetNElements());
   }
   auto zippedBytes = packedBytes;

   if (fOptions.GetCompression() != 0) {
      zippedBytes = fCompressor(buffer, packedBytes, fOptions.GetCompression());
      if (!isAdoptedBuffer)
         delete[] buffer;
      buffer = const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(fCompressor.GetZipBuffer()));
      isAdoptedBuffer = true;
   }

   auto offsetData = fWriter->WriteBlob(buffer, zippedBytes, packedBytes);
   fClusterMinOffset = std::min(offsetData, fClusterMinOffset);
   fClusterMaxOffset = std::max(offsetData, fClusterMaxOffset);

   if (!isAdoptedBuffer)
      delete[] buffer;

   RClusterDescriptor::RLocator result;
   result.fPosition = offsetData;
   result.fBytesOnStorage = zippedBytes;
   return result;
}

ROOT::Experimental::RClusterDescriptor::RLocator
ROOT::Experimental::Detail::RPageSinkFile::DoCommitCluster(ROOT::Experimental::NTupleSize_t /* nEntries */)
{
   RClusterDescriptor::RLocator result;
   result.fPosition = fClusterMinOffset;
   result.fBytesOnStorage = fClusterMaxOffset - fClusterMinOffset;
   fClusterMinOffset = std::uint64_t(-1);
   fClusterMaxOffset = 0;
   return result;
}

void ROOT::Experimental::Detail::RPageSinkFile::DoCommitDataset()
{
   const auto &descriptor = fDescriptorBuilder.GetDescriptor();
   auto szFooter = descriptor.SerializeFooter(nullptr);
   auto buffer = std::unique_ptr<unsigned char []>(new unsigned char[szFooter]);
   descriptor.SerializeFooter(buffer.get());

   auto zipBuffer = std::unique_ptr<unsigned char[]>(new unsigned char[szFooter]);
   auto szZipFooter = fCompressor(buffer.get(), szFooter, fOptions.GetCompression(),
      [&zipBuffer](const void *b, size_t n, size_t o){ memcpy(zipBuffer.get() + o, b, n); } );
   fWriter->WriteNTupleFooter(zipBuffer.get(), szZipFooter, szFooter);
   fWriter->Commit();
}

ROOT::Experimental::Detail::RPage
ROOT::Experimental::Detail::RPageSinkFile::ReservePage(ColumnHandle_t columnHandle, std::size_t nElements)
{
   if (nElements == 0)
      nElements = kDefaultElementsPerPage;
   auto elementSize = columnHandle.fColumn->GetElement()->GetSize();
   return fPageAllocator->NewPage(columnHandle.fId, elementSize, nElements);
}

void ROOT::Experimental::Detail::RPageSinkFile::ReleasePage(RPage &page)
{
   fPageAllocator->DeletePage(page);
}

////////////////////////////////////////////////////////////////////////////////

ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageAllocatorFile::NewPage(
   ColumnId_t columnId, void *mem, std::size_t elementSize, std::size_t nElements)
{
   RPage newPage(columnId, mem, elementSize * nElements, elementSize);
   newPage.TryGrow(nElements);
   return newPage;
}

void ROOT::Experimental::Detail::RPageAllocatorFile::DeletePage(const RPage& page)
{
   if (page.IsNull())
      return;
   delete[] reinterpret_cast<unsigned char *>(page.GetBuffer());
}

////////////////////////////////////////////////////////////////////////////////

ROOT::Experimental::Detail::RPageSourceFile::RPageSourceFile(std::string_view ntupleName,
   const RNTupleReadOptions &options)
   : RPageSource(ntupleName, options)
   , fMetrics("RPageSourceFile")
   , fPageAllocator(std::make_unique<RPageAllocatorFile>())
   , fPagePool(std::make_shared<RPagePool>())
{
}

ROOT::Experimental::Detail::RPageSourceFile::RPageSourceFile(std::string_view ntupleName, std::string_view path,
   const RNTupleReadOptions &options)
   : RPageSourceFile(ntupleName, options)
{
   fFile = std::unique_ptr<RRawFile>(RRawFile::Create(path));
   R__ASSERT(fFile);
   fReader = Internal::RMiniFileReader(fFile.get());
}

ROOT::Experimental::Detail::RPageSourceFile::~RPageSourceFile()
{
}

ROOT::Experimental::RNTupleDescriptor ROOT::Experimental::Detail::RPageSourceFile::DoAttach()
{
   RNTupleDescriptorBuilder descBuilder;
   const auto fNTuple = fReader.GetNTuple(fNTupleName);

   auto buffer = std::unique_ptr<unsigned char[]>(new unsigned char[fNTuple.fLenHeader]);
   auto zipBuffer = std::unique_ptr<unsigned char[]>(new unsigned char[fNTuple.fNBytesHeader]);
   fReader.ReadBlob(zipBuffer.get(), fNTuple.fNBytesHeader, fNTuple.fSeekHeader);
   fDecompressor(zipBuffer.get(), fNTuple.fNBytesHeader, fNTuple.fLenHeader, buffer.get());
   descBuilder.SetFromHeader(buffer.get());

   buffer = std::unique_ptr<unsigned char[]>(new unsigned char[fNTuple.fLenFooter]);
   zipBuffer = std::unique_ptr<unsigned char[]>(new unsigned char[fNTuple.fNBytesFooter]);
   fReader.ReadBlob(zipBuffer.get(), fNTuple.fNBytesFooter, fNTuple.fSeekFooter);
   fDecompressor(zipBuffer.get(), fNTuple.fNBytesFooter, fNTuple.fLenFooter, buffer.get());
   descBuilder.AddClustersFromFooter(buffer.get());

   return descBuilder.MoveDescriptor();
}

ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceFile::PopulatePageFromCluster(
   ColumnHandle_t columnHandle, const RClusterDescriptor &clusterDescriptor, ClusterSize_t::ValueType clusterIndex)
{
   const auto columnId = columnHandle.fId;
   const auto clusterId = clusterDescriptor.GetId();
   const auto &pageRange = clusterDescriptor.GetPageRange(columnId);

   // TODO(jblomer): binary search
   RClusterDescriptor::RPageRange::RPageInfo pageInfo;
   decltype(clusterIndex) firstInPage = 0;
   for (const auto &pi : pageRange.fPageInfos) {
      if (firstInPage + pi.fNElements > clusterIndex) {
         pageInfo = pi;
         break;
      }
      firstInPage += pi.fNElements;
   }
   R__ASSERT(firstInPage <= clusterIndex);
   R__ASSERT((firstInPage + pageInfo.fNElements) > clusterIndex);

   const auto element = columnHandle.fColumn->GetElement();
   const auto elementSize = element->GetSize();

   auto pageSize = pageInfo.fLocator.fBytesOnStorage;
   auto pageBuffer = new unsigned char[
      std::max(pageSize, static_cast<std::uint32_t>(elementSize * pageInfo.fNElements))];
   fReader.ReadBlob(pageBuffer, pageInfo.fLocator.fBytesOnStorage, pageInfo.fLocator.fPosition);

   const auto bytesOnStorage = (element->GetBitsOnStorage() * pageInfo.fNElements + 7) / 8;
   if (pageSize != bytesOnStorage) {
      fDecompressor(pageBuffer, pageSize, bytesOnStorage);
      pageSize = bytesOnStorage;
   }

   if (!element->IsMappable()) {
      pageSize = elementSize * pageInfo.fNElements;
      auto unpackedBuffer = new unsigned char[pageSize];
      element->Unpack(unpackedBuffer, pageBuffer, pageInfo.fNElements);
      delete[] pageBuffer;
      pageBuffer = unpackedBuffer;
   }

   const auto indexOffset = clusterDescriptor.GetColumnRange(columnId).fFirstElementIndex;
   auto newPage = fPageAllocator->NewPage(columnId, pageBuffer, elementSize, pageInfo.fNElements);
   newPage.SetWindow(indexOffset + firstInPage, RPage::RClusterInfo(clusterId, indexOffset));
   fPagePool->RegisterPage(newPage,
      RPageDeleter([](const RPage &page, void */*userData*/)
      {
         RPageAllocatorFile::DeletePage(page);
      }, nullptr));
   return newPage;
}

ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceFile::PopulatePage(
   ColumnHandle_t columnHandle, NTupleSize_t globalIndex)
{
   const auto columnId = columnHandle.fId;
   auto cachedPage = fPagePool->GetPage(columnId, globalIndex);
   if (!cachedPage.IsNull())
      return cachedPage;

   const auto clusterId = fDescriptor.FindClusterId(columnId, globalIndex);
   R__ASSERT(clusterId != kInvalidDescriptorId);
   const auto &clusterDescriptor = fDescriptor.GetClusterDescriptor(clusterId);
   const auto selfOffset = clusterDescriptor.GetColumnRange(columnId).fFirstElementIndex;
   R__ASSERT(selfOffset <= globalIndex);
   return PopulatePageFromCluster(columnHandle, clusterDescriptor, globalIndex - selfOffset);
}

ROOT::Experimental::Detail::RPage ROOT::Experimental::Detail::RPageSourceFile::PopulatePage(
   ColumnHandle_t columnHandle, const RClusterIndex &clusterIndex)
{
   const auto clusterId = clusterIndex.GetClusterId();
   const auto index = clusterIndex.GetIndex();
   const auto columnId = columnHandle.fId;
   auto cachedPage = fPagePool->GetPage(columnId, clusterIndex);
   if (!cachedPage.IsNull())
      return cachedPage;

   R__ASSERT(clusterId != kInvalidDescriptorId);
   const auto &clusterDescriptor = fDescriptor.GetClusterDescriptor(clusterId);
   return PopulatePageFromCluster(columnHandle, clusterDescriptor, index);
}

void ROOT::Experimental::Detail::RPageSourceFile::ReleasePage(RPage &page)
{
   fPagePool->ReturnPage(page);
}

std::unique_ptr<ROOT::Experimental::Detail::RPageSource> ROOT::Experimental::Detail::RPageSourceFile::Clone() const
{
   auto clone = new RPageSourceFile(fNTupleName, fOptions);
   clone->fFile = fFile->Clone();
   clone->fReader = Internal::RMiniFileReader(clone->fFile.get());
   return std::unique_ptr<RPageSourceFile>(clone);
}
<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * Razor - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2012 Razor team
 * Authors:
 *   Kuzma Shapran <kuzma.shapran@gmail.com>
 *   Luís Pereira <luis.artur.pereira@gmail.com>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "calendar_utils.h"
#include "config.h"

#include <QtCore/QtGlobal>

#if QT_VERSION < 0x040800

#ifdef CAN_USE_BOOST

#include <boost/locale/date_time.hpp>

Qt::DayOfWeek firstDayOfWeek(void)
{
    return (boost::locale::calendar().first_day_of_week() + 6) % 7;
}

#else // use C

#ifdef HAVE__NL_TIME_FIRST_WEEKDAY
#include <langinfo.h>
#include <QtCore/QDebug>
#endif

Qt::DayOfWeek firstDayOfWeek(void)
{
    #ifdef HAVE__NL_TIME_FIRST_WEEKDAY
    int first_weekday, week_1stday, week_start;
    long week_1stday_l;

    first_weekday = nl_langinfo(_NL_TIME_FIRST_WEEKDAY)[0];
    week_1stday_l = (long) nl_langinfo(_NL_TIME_WEEK_1STDAY);
    if (week_1stday_l == 19971130L)  // Sunday
    {
        week_1stday = 0;
    }
    else if (week_1stday_l== 19971201L) // Monday
    {
        week_1stday = 1;
    }
    else
    {
        qDebug() << Q_FUNC_INFO <<
            "nl_langinfo(_NL_TIME_WEEK_1STDAY) returned an unknown value.";
    }

    week_start = (week_1stday + first_weekday - 1) % 7;
    if (week_start == 0)
    {
        return Qt::Sunday;
    }
    else
    {
        return static_cast<Qt::DayOfWeek>(week_start);
    }
    #else
    return Qt::Sunday;
    #endif // HAVE__NL_TIME_FIRST_WEEKDAY
}

#endif

#else // use Qt >= 4.8

Qt::DayOfWeek firstDayOfWeek(void)
{
    return QLocale::system().firstDayOfWeek();
}

#endif
<commit_msg>plugin-clock: Use camelCase style for variables<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * Razor - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2012 Razor team
 * Authors:
 *   Kuzma Shapran <kuzma.shapran@gmail.com>
 *   Luís Pereira <luis.artur.pereira@gmail.com>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "calendar_utils.h"
#include "config.h"

#include <QtCore/QtGlobal>

#if QT_VERSION < 0x040800

#ifdef CAN_USE_BOOST

#include <boost/locale/date_time.hpp>

Qt::DayOfWeek firstDayOfWeek(void)
{
    return (boost::locale::calendar().first_day_of_week() + 6) % 7;
}

#else // use C

#ifdef HAVE__NL_TIME_FIRST_WEEKDAY
#include <langinfo.h>
#include <QtCore/QDebug>
#endif

Qt::DayOfWeek firstDayOfWeek(void)
{
    #ifdef HAVE__NL_TIME_FIRST_WEEKDAY
    int firstWeekDay, weekFirstDay, weekStart;
    long weekFirstDayLong;

    firstWeekDay = nl_langinfo(_NL_TIME_FIRST_WEEKDAY)[0];
    weekFirstDayLong = (long) nl_langinfo(_NL_TIME_WEEK_1STDAY);
    if (weekFirstDayLong == 19971130L)  // Sunday
    {
        weekFirstDay = 0;
    }
    else if (weekFirstDayLong == 19971201L) // Monday
    {
        weekFirstDay = 1;
    }
    else
    {
        qDebug() << Q_FUNC_INFO <<
            "nl_langinfo(_NL_TIME_WEEK_1STDAY) returned an unknown value.";
    }

    weekStart = (weekFirstDay + firstWeekDay - 1) % 7;
    if (weekStart == 0)
    {
        return Qt::Sunday;
    }
    else
    {
        return static_cast<Qt::DayOfWeek>(weekStart);
    }
    #else
    return Qt::Sunday;
    #endif // HAVE__NL_TIME_FIRST_WEEKDAY
}

#endif

#else // use Qt >= 4.8

Qt::DayOfWeek firstDayOfWeek(void)
{
    return QLocale::system().firstDayOfWeek();
}

#endif
<|endoftext|>


<commit_before><commit_msg>Initialize widget placement in Widget contructor.<commit_after><|endoftext|>


<commit_before><commit_msg>mysql8.0: it seems that TEXT type is treated by MYSQL_TYPE_BLOB<commit_after><|endoftext|>


<commit_before><commit_msg>Ubuntu: Detect "xubuntu" as DESKTOP_SESSION.<commit_after><|endoftext|>


<commit_before>#include "../std/target_os.hpp"

#if !defined(OMIM_OS_BADA) && !defined(OMIM_OS_WINDOWS_NATIVE)

#include "condition.hpp"
#include "mutex.hpp"

#include "../std/stdint.hpp"
#include <sys/time.h>
#include <sys/errno.h>

#include <pthread.h>

namespace threads
{
  namespace impl
  {
    class ConditionImpl
    {
    public:
      Mutex m_Mutex;
      pthread_cond_t m_Condition;
    };
  }

  Condition::Condition() : m_pImpl(new impl::ConditionImpl)
  {
    ::pthread_cond_init(&m_pImpl->m_Condition, 0);
  }

  Condition::~Condition()
  {
    ::pthread_cond_destroy(&m_pImpl->m_Condition);
    delete m_pImpl;
  }

  void Condition::Signal(bool broadcast)
  {
    if (broadcast)
      ::pthread_cond_broadcast(&m_pImpl->m_Condition);
    else
      ::pthread_cond_signal(&m_pImpl->m_Condition);
  }

  void Condition::Wait(unsigned ms)
  {
    if (ms == -1)
      ::pthread_cond_wait(&m_pImpl->m_Condition, &m_pImpl->m_Mutex.m_Mutex);
    else
    {
      ::timeval curtv;
      ::gettimeofday(&curtv, 0);

      ::timespec ts;

      uint64_t deltaNanoSec = curtv.tv_usec * 1000 + ms * 1000000;

      ts.tv_sec = curtv.tv_sec + deltaNanoSec / 1000000000;
      ts.tv_nsec = deltaNanoSec % 1000000000;

      ::pthread_cond_timedwait(&m_pImpl->m_Condition, &m_pImpl->m_Mutex.m_Mutex, &ts);
    }
  }

  void Condition::Lock()
  {
    m_pImpl->m_Mutex.Lock();
  }

  void Condition::Unlock()
  {
    m_pImpl->m_Mutex.Unlock();
  }
}

#endif
<commit_msg>fixed includes.<commit_after>#include "../std/target_os.hpp"

#if !defined(OMIM_OS_BADA) && !defined(OMIM_OS_WINDOWS_NATIVE)

#include "condition.hpp"
#include "mutex.hpp"

#include "../std/stdint.hpp"
#include "../std/systime.hpp"

#include <pthread.h>

namespace threads
{
  namespace impl
  {
    class ConditionImpl
    {
    public:
      Mutex m_Mutex;
      pthread_cond_t m_Condition;
    };
  }

  Condition::Condition() : m_pImpl(new impl::ConditionImpl)
  {
    ::pthread_cond_init(&m_pImpl->m_Condition, 0);
  }

  Condition::~Condition()
  {
    ::pthread_cond_destroy(&m_pImpl->m_Condition);
    delete m_pImpl;
  }

  void Condition::Signal(bool broadcast)
  {
    if (broadcast)
      ::pthread_cond_broadcast(&m_pImpl->m_Condition);
    else
      ::pthread_cond_signal(&m_pImpl->m_Condition);
  }

  void Condition::Wait(unsigned ms)
  {
    if (ms == -1)
      ::pthread_cond_wait(&m_pImpl->m_Condition, &m_pImpl->m_Mutex.m_Mutex);
    else
    {
      ::timeval curtv;
      ::gettimeofday(&curtv, 0);

      ::timespec ts;

      uint64_t deltaNanoSec = curtv.tv_usec * 1000 + ms * 1000000;

      ts.tv_sec = curtv.tv_sec + deltaNanoSec / 1000000000;
      ts.tv_nsec = deltaNanoSec % 1000000000;

      ::pthread_cond_timedwait(&m_pImpl->m_Condition, &m_pImpl->m_Mutex.m_Mutex, &ts);
    }
  }

  void Condition::Lock()
  {
    m_pImpl->m_Mutex.Lock();
  }

  void Condition::Unlock()
  {
    m_pImpl->m_Mutex.Unlock();
  }
}

#endif
<|endoftext|>