<commit_before>/*
 * Create on: Jun 6, 2019
 * Author: KmolYuan
 * These functions make writing constraint easier
 */

#include "solve.h"

Constraint PointOnPointConstraint(Point *point1, Point *point2) {
    Constraint con{};
    con.type = PointOnPoint;
    con.point1 = point1;
    con.point2 = point2;
    return con;
}

static Constraint _P2PDistanceConstraint(int type, Point *point1, Point *point2,
                                         double *value) {
    Constraint con{};
    con.type = type;
    con.point1 = point1;
    con.point2 = point2;
    con.parameter = value;
    return con;
}

Constraint P2PDistanceConstraint(Point *point1, Point *point2, double *value) {
    return _P2PDistanceConstraint(P2PDistance, point1, point2, value);
}

Constraint P2PDistanceVertConstraint(Point *point1, Point *point2,
                                     double *value) {
    return _P2PDistanceConstraint(P2PDistanceVert, point1, point2, value);
}

Constraint P2PDistanceHorzConstraint(Point *point1, Point *point2,
                                     double *value) {
    return _P2PDistanceConstraint(P2PDistanceHorz, point1, point2, value);
}

static Constraint _PointLineConstraint(int type, Point *point1, Line *line1) {
    Constraint con{};
    con.type = type;
    con.point1 = point1;
    con.line1 = line1;
    return con;
}

Constraint PointOnLineConstraint(Point *point1, Line *line1) {
    return _PointLineConstraint(PointOnLine, point1, line1);
}

static Constraint _P2LDistanceConstraint(int type, Point *point1, Line *line1,
                                         double *value) {
    Constraint con{};
    con.type = type;
    con.point1 = point1;
    con.line1 = line1;
    con.parameter = value;
    return con;
}

Constraint P2LDistanceConstraint(Point *point1, Line *line1, double *value) {
    return _P2LDistanceConstraint(P2LDistance, point1, line1, value);
}

Constraint P2LDistanceVertConstraint(Point *point1, Line *line1,
                                     double *value) {
    return _P2LDistanceConstraint(P2LDistanceVert, point1, line1, value);
}

Constraint P2LDistanceHorzConstraint(Point *point1, Line *line1,
                                     double *value) {
    return _P2LDistanceConstraint(P2LDistanceHorz, point1, line1, value);
}

static Constraint _VerticalHorizontalConstraint(int type, Line *line1) {
    Constraint con{};
    con.type = type;
    con.line1 = line1;
    return con;
}

Constraint VerticalConstraint(Line *line1) {
    return _VerticalHorizontalConstraint(Vertical, line1);
}

Constraint HorizontalConstraint(Line *line1) {
    return _VerticalHorizontalConstraint(Horizontal, line1);
}

Constraint TangentToCircleConstraint(Line *line1, Circle *circle1) {
    Constraint con{};
    con.type = TangentToCircle;
    con.line1 = line1;
    con.circle1 = circle1;
    return con;
}

Constraint TangentToArcConstraint(Line *line1, Arc *arc1) {
    Constraint con{};
    con.type = TangentToCircle;
    con.line1 = line1;
    con.arc1 = arc1;
    return con;
}

Constraint ArcRulesConstraint(Arc *arc1) {
    Constraint con{};
    con.type = ArcRules;
    con.arc1 = arc1;
    return con;
}

static Constraint _LineConstraint(int type, Line *line1, double *value) {
    Constraint con{};
    con.type = type;
    con.line1 = line1;
    con.parameter = value;
    return con;
}

Constraint LineLengthConstraint(Line *line1, double *value) {
    return _LineConstraint(LineLength, line1, value);
}

static Constraint _LinesConstraint(int type, Line *line1, Line *line2) {
    Constraint con{};
    con.type = type;
    con.line1 = line1;
    con.line2 = line2;
    return con;
}

Constraint EqualLegnthConstraint(Line *line1, Line *line2) {
    return _LinesConstraint(EqualLegnth, line1, line2);
}

Constraint ArcRadiusConstraint(Arc *arc1, double *value) {
    Constraint con{};
    con.type = ArcRadius;
    con.arc1 = arc1;
    con.parameter = value;
    return con;
}

static Constraint _ArcsConstraint(int type, Arc *arc1, Arc *arc2) {
    Constraint con{};
    con.type = type;
    con.arc1 = arc1;
    con.arc2 = arc2;
    return con;
}

Constraint EqualRadiusArcsConstraint(Arc *arc1, Arc *arc2) {
    return _ArcsConstraint(EqualRadiusArcs, arc1, arc2);
}

static Constraint _CirclesConstraint(int type, Circle *circle1,
                                     Circle *circle2) {
    Constraint con{};
    con.type = type;
    con.circle1 = circle1;
    con.circle2 = circle2;
    return con;
}

static Constraint _CircArcConstraint(int type, Circle *circle1, Arc *arc1) {
    Constraint con{};
    con.type = type;
    con.circle1 = circle1;
    con.arc1 = arc1;
    return con;
}

Constraint EqualRadiusCirclesConstraint(Circle *circle1, Circle *circle2) {
    return _CirclesConstraint(EqualRadiusCircles, circle1, circle2);
}

Constraint EqualRadiusCircArcConstraint(Circle *circle1, Arc *arc1) {
    return _CircArcConstraint(EqualRadiusCircles, circle1, arc1);
}

Constraint ConcentricArcsConstraint(Arc *arc1, Arc *arc2) {
    return _ArcsConstraint(ConcentricArcs, arc1, arc2);
}

Constraint ConcentricCirclesConstraint(Circle *circle1, Circle *circle2) {
    return _CirclesConstraint(ConcentricCircles, circle1, circle2);
}

Constraint ConcentricCircArcConstraint(Circle *circle1, Arc *arc1) {
    return _CircArcConstraint(ConcentricCircArc, circle1, arc1);
}

Constraint CircleRadiusConstraint(Circle *circle1, double *value) {
    Constraint con{};
    con.type = CircleRadius;
    con.circle1 = circle1;
    con.parameter = value;
    return con;
}

static Constraint _AngleConstraint(int type, Line *line1, Line *line2,
                                   double *value) {
    Constraint con{};
    con.type = type;
    con.line1 = line1;
    con.line2 = line2;
    con.parameter = value;
    return con;
}

Constraint InternalAngleConstraint(Line *line1, Line *line2, double *value) {
    return _AngleConstraint(InternalAngle, line1, line2, value);
}

Constraint ExternalAngleConstraint(Line *line1, Line *line2, double *value) {
    return _AngleConstraint(ExternalAngle, line1, line2, value);
}

Constraint PerpendicularConstraint(Line *line1, Line *line2) {
    return _LinesConstraint(Perpendicular, line1, line2);
}

Constraint ParallelConstraint(Line *line1, Line *line2) {
    return _LinesConstraint(Parallel, line1, line2);
}

Constraint ColinearConstraint(Line *line1, Line *line2) {
    return _LinesConstraint(Colinear, line1, line2);
}

static Constraint _PointCircleConstraint(int type, Point *point1,
                                         Circle *circle1) {
    Constraint con{};
    con.type = type;
    con.point1 = point1;
    con.circle1 = circle1;
    return con;
}

Constraint PointOnCircleConstraint(Point *point1, Circle *circle1) {
    return _PointCircleConstraint(PointOnCircle, point1, circle1);
}

static Constraint _PointArcConstraint(int type, Point *point1, Arc *arc1) {
    Constraint con{};
    con.type = type;
    con.point1 = point1;
    con.arc1 = arc1;
    return con;
}

Constraint PointOnArcConstraint(Point *point1, Arc *arc1) {
    return _PointArcConstraint(PointOnCircle, point1, arc1);
}

Constraint PointOnLineMidpointConstraint(Point *point1, Line *line1) {
    return _PointLineConstraint(PointOnLineMidpoint, point1, line1);
}

Constraint PointOnArcMidpointConstraint(Point *point1, Arc *arc1) {
    return _PointArcConstraint(PointOnArcMidpoint, point1, arc1);
}

Constraint PointOnCircleQuadConstraint(Point *point1, Circle *circle1,
                                       double *value) {
    Constraint con{};
    con.type = PointOnCircleQuad;
    con.point1 = point1;
    con.circle1 = circle1;
    con.parameter = value;  // value only can be 0, 1, 2, 3, default 0.
    return con;
}

Constraint SymmetricPointsConstraint(Point *point1, Point *point2, Line *sym) {
    Constraint con{};
    con.type = SymmetricPoints;
    con.point1 = point1;
    con.point2 = point2;
    con.SymLine = sym;
    return con;
}

Constraint SymmetricLinesConstraint(Line *line1, Line *line2, Line *sym) {
    Constraint con{};
    con.type = SymmetricLines;
    con.line1 = line1;
    con.line2 = line2;
    con.SymLine = sym;
    return con;
}

Constraint SymmetricCirclesConstraint(Circle *circle1, Circle *circle2,
                                      Line *sym) {
    Constraint con{};
    con.type = SymmetricCircles;
    con.circle1 = circle1;
    con.circle2 = circle2;
    con.SymLine = sym;
    return con;
}

Constraint SymmetricArcsConstraint(Arc *arc1, Arc *arc2, Line *sym) {
    Constraint con{};
    con.type = SymmetricArcs;
    con.arc1 = arc1;
    con.arc2 = arc2;
    con.SymLine = sym;
    return con;
}

Constraint LineInternalAngleConstraint(Line *line1, double *value) {
    return _LineConstraint(LineInternalAngle, line1, value);
}

Constraint LineExternalAngleConstraint(Line *line1, double *value) {
    return _LineConstraint(LineExternalAngle, line1, value);
}
<commit_msg>Unify the type of constraint types.<commit_after>/*
 * Create on: Jun 6, 2019
 * Author: KmolYuan
 * These functions make writing constraint easier
 */

#include "solve.h"

Constraint PointOnPointConstraint(Point *point1, Point *point2) {
    Constraint con{};
    con.type = PointOnPoint;
    con.point1 = point1;
    con.point2 = point2;
    return con;
}

static Constraint _P2PDistanceConstraint(unsigned long type, Point *point1,
                                         Point *point2, double *value) {
    Constraint con{};
    con.type = type;
    con.point1 = point1;
    con.point2 = point2;
    con.parameter = value;
    return con;
}

Constraint P2PDistanceConstraint(Point *point1, Point *point2, double *value) {
    return _P2PDistanceConstraint(P2PDistance, point1, point2, value);
}

Constraint P2PDistanceVertConstraint(Point *point1, Point *point2,
                                     double *value) {
    return _P2PDistanceConstraint(P2PDistanceVert, point1, point2, value);
}

Constraint P2PDistanceHorzConstraint(Point *point1, Point *point2,
                                     double *value) {
    return _P2PDistanceConstraint(P2PDistanceHorz, point1, point2, value);
}

static Constraint _PointLineConstraint(unsigned long type, Point *point1,
                                       Line *line1) {
    Constraint con{};
    con.type = type;
    con.point1 = point1;
    con.line1 = line1;
    return con;
}

Constraint PointOnLineConstraint(Point *point1, Line *line1) {
    return _PointLineConstraint(PointOnLine, point1, line1);
}

static Constraint _P2LDistanceConstraint(unsigned long type, Point *point1,
                                         Line *line1, double *value) {
    Constraint con{};
    con.type = type;
    con.point1 = point1;
    con.line1 = line1;
    con.parameter = value;
    return con;
}

Constraint P2LDistanceConstraint(Point *point1, Line *line1, double *value) {
    return _P2LDistanceConstraint(P2LDistance, point1, line1, value);
}

Constraint P2LDistanceVertConstraint(Point *point1, Line *line1,
                                     double *value) {
    return _P2LDistanceConstraint(P2LDistanceVert, point1, line1, value);
}

Constraint P2LDistanceHorzConstraint(Point *point1, Line *line1,
                                     double *value) {
    return _P2LDistanceConstraint(P2LDistanceHorz, point1, line1, value);
}

static Constraint _VerticalHorizontalConstraint(unsigned long type,
                                                Line *line1) {
    Constraint con{};
    con.type = type;
    con.line1 = line1;
    return con;
}

Constraint VerticalConstraint(Line *line1) {
    return _VerticalHorizontalConstraint(Vertical, line1);
}

Constraint HorizontalConstraint(Line *line1) {
    return _VerticalHorizontalConstraint(Horizontal, line1);
}

Constraint TangentToCircleConstraint(Line *line1, Circle *circle1) {
    Constraint con{};
    con.type = TangentToCircle;
    con.line1 = line1;
    con.circle1 = circle1;
    return con;
}

Constraint TangentToArcConstraint(Line *line1, Arc *arc1) {
    Constraint con{};
    con.type = TangentToCircle;
    con.line1 = line1;
    con.arc1 = arc1;
    return con;
}

Constraint ArcRulesConstraint(Arc *arc1) {
    Constraint con{};
    con.type = ArcRules;
    con.arc1 = arc1;
    return con;
}

static Constraint _LineConstraint(unsigned long type, Line *line1,
                                  double *value) {
    Constraint con{};
    con.type = type;
    con.line1 = line1;
    con.parameter = value;
    return con;
}

Constraint LineLengthConstraint(Line *line1, double *value) {
    return _LineConstraint(LineLength, line1, value);
}

static Constraint _LinesConstraint(unsigned long type, Line *line1,
                                   Line *line2) {
    Constraint con{};
    con.type = type;
    con.line1 = line1;
    con.line2 = line2;
    return con;
}

Constraint EqualLegnthConstraint(Line *line1, Line *line2) {
    return _LinesConstraint(EqualLegnth, line1, line2);
}

Constraint ArcRadiusConstraint(Arc *arc1, double *value) {
    Constraint con{};
    con.type = ArcRadius;
    con.arc1 = arc1;
    con.parameter = value;
    return con;
}

static Constraint _ArcsConstraint(unsigned long type, Arc *arc1, Arc *arc2) {
    Constraint con{};
    con.type = type;
    con.arc1 = arc1;
    con.arc2 = arc2;
    return con;
}

Constraint EqualRadiusArcsConstraint(Arc *arc1, Arc *arc2) {
    return _ArcsConstraint(EqualRadiusArcs, arc1, arc2);
}

static Constraint _CirclesConstraint(unsigned long type, Circle *circle1,
                                     Circle *circle2) {
    Constraint con{};
    con.type = type;
    con.circle1 = circle1;
    con.circle2 = circle2;
    return con;
}

static Constraint _CircArcConstraint(unsigned long type, Circle *circle1,
                                     Arc *arc1) {
    Constraint con{};
    con.type = type;
    con.circle1 = circle1;
    con.arc1 = arc1;
    return con;
}

Constraint EqualRadiusCirclesConstraint(Circle *circle1, Circle *circle2) {
    return _CirclesConstraint(EqualRadiusCircles, circle1, circle2);
}

Constraint EqualRadiusCircArcConstraint(Circle *circle1, Arc *arc1) {
    return _CircArcConstraint(EqualRadiusCircles, circle1, arc1);
}

Constraint ConcentricArcsConstraint(Arc *arc1, Arc *arc2) {
    return _ArcsConstraint(ConcentricArcs, arc1, arc2);
}

Constraint ConcentricCirclesConstraint(Circle *circle1, Circle *circle2) {
    return _CirclesConstraint(ConcentricCircles, circle1, circle2);
}

Constraint ConcentricCircArcConstraint(Circle *circle1, Arc *arc1) {
    return _CircArcConstraint(ConcentricCircArc, circle1, arc1);
}

Constraint CircleRadiusConstraint(Circle *circle1, double *value) {
    Constraint con{};
    con.type = CircleRadius;
    con.circle1 = circle1;
    con.parameter = value;
    return con;
}

static Constraint _AngleConstraint(unsigned long type, Line *line1, Line *line2,
                                   double *value) {
    Constraint con{};
    con.type = type;
    con.line1 = line1;
    con.line2 = line2;
    con.parameter = value;
    return con;
}

Constraint InternalAngleConstraint(Line *line1, Line *line2, double *value) {
    return _AngleConstraint(InternalAngle, line1, line2, value);
}

Constraint ExternalAngleConstraint(Line *line1, Line *line2, double *value) {
    return _AngleConstraint(ExternalAngle, line1, line2, value);
}

Constraint PerpendicularConstraint(Line *line1, Line *line2) {
    return _LinesConstraint(Perpendicular, line1, line2);
}

Constraint ParallelConstraint(Line *line1, Line *line2) {
    return _LinesConstraint(Parallel, line1, line2);
}

Constraint ColinearConstraint(Line *line1, Line *line2) {
    return _LinesConstraint(Colinear, line1, line2);
}

static Constraint _PointCircleConstraint(unsigned long type, Point *point1,
                                         Circle *circle1) {
    Constraint con{};
    con.type = type;
    con.point1 = point1;
    con.circle1 = circle1;
    return con;
}

Constraint PointOnCircleConstraint(Point *point1, Circle *circle1) {
    return _PointCircleConstraint(PointOnCircle, point1, circle1);
}

static Constraint _PointArcConstraint(unsigned long type, Point *point1,
                                      Arc *arc1) {
    Constraint con{};
    con.type = type;
    con.point1 = point1;
    con.arc1 = arc1;
    return con;
}

Constraint PointOnArcConstraint(Point *point1, Arc *arc1) {
    return _PointArcConstraint(PointOnCircle, point1, arc1);
}

Constraint PointOnLineMidpointConstraint(Point *point1, Line *line1) {
    return _PointLineConstraint(PointOnLineMidpoint, point1, line1);
}

Constraint PointOnArcMidpointConstraint(Point *point1, Arc *arc1) {
    return _PointArcConstraint(PointOnArcMidpoint, point1, arc1);
}

Constraint PointOnCircleQuadConstraint(Point *point1, Circle *circle1,
                                       double *value) {
    Constraint con{};
    con.type = PointOnCircleQuad;
    con.point1 = point1;
    con.circle1 = circle1;
    con.parameter = value;  // value only can be 0, 1, 2, 3, default 0.
    return con;
}

Constraint SymmetricPointsConstraint(Point *point1, Point *point2, Line *sym) {
    Constraint con{};
    con.type = SymmetricPoints;
    con.point1 = point1;
    con.point2 = point2;
    con.SymLine = sym;
    return con;
}

Constraint SymmetricLinesConstraint(Line *line1, Line *line2, Line *sym) {
    Constraint con{};
    con.type = SymmetricLines;
    con.line1 = line1;
    con.line2 = line2;
    con.SymLine = sym;
    return con;
}

Constraint SymmetricCirclesConstraint(Circle *circle1, Circle *circle2,
                                      Line *sym) {
    Constraint con{};
    con.type = SymmetricCircles;
    con.circle1 = circle1;
    con.circle2 = circle2;
    con.SymLine = sym;
    return con;
}

Constraint SymmetricArcsConstraint(Arc *arc1, Arc *arc2, Line *sym) {
    Constraint con{};
    con.type = SymmetricArcs;
    con.arc1 = arc1;
    con.arc2 = arc2;
    con.SymLine = sym;
    return con;
}

Constraint LineInternalAngleConstraint(Line *line1, double *value) {
    return _LineConstraint(LineInternalAngle, line1, value);
}

Constraint LineExternalAngleConstraint(Line *line1, double *value) {
    return _LineConstraint(LineExternalAngle, line1, value);
}
<|endoftext|>


<commit_before>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "Backend.h"
#include "SccLiveness.h"

extern const IRType RegTypes[RegNumCount];

LinearScanMD::LinearScanMD(Func *func)
    : helperSpillSlots(nullptr),
      maxOpHelperSpilledLiveranges(0),
      func(func)
{
}

void
LinearScanMD::Init(LinearScan *linearScan)
{
    LinearScanMDShared::Init(linearScan);
    Func *func = linearScan->func;
    RegNum localsReg = func->GetLocalsPointer();
    if (localsReg != RegSP)
    {
        func->m_regsUsed.Set(localsReg);
    }

    memset(this->vfpSymTable, 0, sizeof(this->vfpSymTable));
}

StackSym *
LinearScanMD::EnsureSpillSymForVFPReg(RegNum reg, Func *func)
{
    Assert(REGNUM_ISVFPREG(reg));

    __analysis_assume(reg - RegD0 < VFP_REGCOUNT);
    StackSym *sym = this->vfpSymTable[reg - RegD0];

    if (sym == nullptr)
    {
        sym = StackSym::New(TyFloat64, func);
        func->StackAllocate(sym, MachRegDouble);

        __analysis_assume(reg - RegD0 < VFP_REGCOUNT);
        this->vfpSymTable[reg - RegD0] = sym;
    }

    return sym;
}

bool
LinearScanMD::IsAllocatable(RegNum reg, Func *func) const
{
    return reg != func->GetLocalsPointer();
}

BitVector
LinearScanMD::FilterRegIntSizeConstraints(BitVector regsBv, BitVector sizeUsageBv) const
{
    return regsBv;
}

bool
LinearScanMD::FitRegIntSizeConstraints(RegNum reg, BitVector sizeUsageBv) const
{
    return true;
}

bool
LinearScanMD::FitRegIntSizeConstraints(RegNum reg, IRType type) const
{
    return true;
}

void
LinearScanMD::InsertOpHelperSpillAndRestores(SList<OpHelperBlock> *opHelperBlockList)
{
    if (maxOpHelperSpilledLiveranges)
    {
        Assert(!helperSpillSlots);
        helperSpillSlots = AnewArrayZ(linearScan->GetTempAlloc(), StackSym *, maxOpHelperSpilledLiveranges);
    }

    FOREACH_SLIST_ENTRY(OpHelperBlock, opHelperBlock, opHelperBlockList)
    {
        InsertOpHelperSpillsAndRestores(opHelperBlock);
    }
    NEXT_SLIST_ENTRY;
}

void
LinearScanMD::InsertOpHelperSpillsAndRestores(const OpHelperBlock& opHelperBlock)
{
    uint32 index = 0;

    FOREACH_SLIST_ENTRY(OpHelperSpilledLifetime, opHelperSpilledLifetime, &opHelperBlock.spilledLifetime)
    {
        // Use the original sym as spill slot if this is an inlinee arg
        StackSym* sym = nullptr;
        if (opHelperSpilledLifetime.spillAsArg)
        {
            sym = opHelperSpilledLifetime.lifetime->sym;
            AnalysisAssert(sym);
            Assert(sym->IsAllocated());
        }

        if (RegTypes[opHelperSpilledLifetime.reg] == TyFloat64)
        {
            IR::RegOpnd * regOpnd = IR::RegOpnd::New(nullptr, opHelperSpilledLifetime.reg, TyMachDouble, this->func);

            if (!sym)
            {
                sym = EnsureSpillSymForVFPReg(regOpnd->GetReg(), this->func);
            }
            IR::Instr * pushInstr = IR::Instr::New(Js::OpCode::FSTR, IR::SymOpnd::New(sym, TyMachDouble, this->func), regOpnd, this->func);
            opHelperBlock.opHelperLabel->InsertAfter(pushInstr);
            pushInstr->CopyNumber(opHelperBlock.opHelperLabel);
            if (opHelperSpilledLifetime.reload)
            {
                IR::Instr * popInstr = IR::Instr::New(Js::OpCode::FLDR, regOpnd, IR::SymOpnd::New(sym, TyMachDouble, this->func), this->func);
                opHelperBlock.opHelperEndInstr->InsertBefore(popInstr);
                popInstr->CopyNumber(opHelperBlock.opHelperEndInstr);
            }
        }
        else
        {
            Assert(helperSpillSlots);
            Assert(index < maxOpHelperSpilledLiveranges);

            if (!sym)
            {
                // Lazily allocate only as many slots as we really need.
                if (!helperSpillSlots[index])
                {
                    helperSpillSlots[index] = StackSym::New(TyMachReg, func);
                }

                sym = helperSpillSlots[index];
                index++;

                Assert(sym);
                func->StackAllocate(sym, MachRegInt);
            }

            IR::RegOpnd * regOpnd = IR::RegOpnd::New(sym, opHelperSpilledLifetime.reg, sym->GetType(), func);
            IR::Instr * saveInstr = IR::Instr::New(Js::OpCode::STR, IR::SymOpnd::New(sym, sym->GetType(), func), regOpnd, func);
            opHelperBlock.opHelperLabel->InsertAfter(saveInstr);
            saveInstr->CopyNumber(opHelperBlock.opHelperLabel);
            this->LegalizeDef(saveInstr);

            if (opHelperSpilledLifetime.reload)
            {
                IR::Instr * restoreInstr = IR::Instr::New(Js::OpCode::LDR, regOpnd, IR::SymOpnd::New(sym, sym->GetType(), func), func);
                opHelperBlock.opHelperEndInstr->InsertBefore(restoreInstr);
                restoreInstr->CopyNumber(opHelperBlock.opHelperEndInstr);
                this->LegalizeUse(restoreInstr, restoreInstr->GetSrc1());
            }
        }
    }
    NEXT_SLIST_ENTRY;
}

void
LinearScanMD::EndOfHelperBlock(uint32 helperSpilledLiveranges)
{
    if (helperSpilledLiveranges > maxOpHelperSpilledLiveranges)
    {
        maxOpHelperSpilledLiveranges = helperSpilledLiveranges;
    }
}

void
LinearScanMD::LegalizeDef(IR::Instr * instr)
{
    if (instr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn)
    {
        // ArgOut_A_InlineBuiltIn pseudo instruction is kept through register allocator only to use for bailout as is,
        // and thus it must not be changed here by legalization.
        // It is removed in peeps, so only place to special case it is in register allocator.
        return;
    }

    // Legalize opcodes, etc., but do not expand symbol/indirs with large offsets
    // because we can't safely do this until all loads and stores are in place.
    LegalizeMD::LegalizeDst(instr, false);
}

void
LinearScanMD::LegalizeUse(IR::Instr * instr, IR::Opnd * opnd)
{
    if (instr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn)
    {
        // ArgOut_A_InlineBuiltIn pseudo instruction is kept through register allocator only to use for bailout as is,
        // and thus it must not be changed here by legalization.
        // It is removed in peeps, so only place to special case it is in register allocator.
        return;
    }

    // Legalize opcodes, etc., but do not expand symbol/indirs with large offsets
    // because we can't safely do this until all loads and stores are in place.
    if (opnd == instr->GetSrc1())
    {
        LegalizeMD::LegalizeSrc(instr, opnd, 1, false);
    }
    else
    {
        LegalizeMD::LegalizeSrc(instr, opnd, 2, false);
    }
}

void
LinearScanMD::GenerateBailOut(
    IR::Instr * instr,
    __in_ecount(registerSaveSymsCount) StackSym ** registerSaveSyms,
    uint registerSaveSymsCount)
{
    Func *const func = instr->m_func;
    BailOutInfo *const bailOutInfo = instr->GetBailOutInfo();
    IR::Instr *firstInstr = instr->m_prev;
    Js::Var *const registerSaveSpace = (Js::Var*)func->GetThreadContextInfo()->GetBailOutRegisterSaveSpaceAddr();

    const auto LoadRegSaveSpaceIntoScratch = [&](const RegNum reg)
    {
        // Load the register save space address for the specified register into the scratch register:
        //     ldimm SCRATCH_REG, regSaveSpace
        LinearScan::InsertMove(
            IR::RegOpnd::New(nullptr, SCRATCH_REG, TyMachPtr, func),
            IR::AddrOpnd::New(&registerSaveSpace[reg - 1], IR::AddrOpndKindDynamicMisc, func),
            instr);
    };

    const auto SaveReg = [&](const RegNum reg)
    {
        Assert(registerSaveSyms[reg - 1]);

        //     LoadRegSaveSpaceIntoScratch(reg)
        //     mov  [SCRATCH_REG], reg
        LoadRegSaveSpaceIntoScratch(reg);
        const IRType regType = RegTypes[reg];
        LinearScan::InsertMove(
            IR::IndirOpnd::New(
                IR::RegOpnd::New(nullptr, SCRATCH_REG, TyMachPtr, func),
                0,
                regType,
                func),
            IR::RegOpnd::New(registerSaveSyms[reg - 1], reg, regType, func),
            instr);
    };

    // Save registers used for parameters, and lr, if necessary, into the register save space
    if(bailOutInfo->branchConditionOpnd && registerSaveSyms[RegR1 - 1] && registerSaveSyms[RegR0 - 1])
    {
        // ARM64_WORKITEM: Needs looking at
        __debugbreak();
#if 0
        // Save r1 and r0 with one push:
        //     LoadRegSaveSpaceIntoScratch(RegR2)
        //     push [SCRATCH_REG], {r0 - r1}
        LoadRegSaveSpaceIntoScratch(RegR2);
        IR::Instr *instrPush = IR::Instr::New(
            Js::OpCode::PUSH,
            IR::IndirOpnd::New(
            IR::RegOpnd::New(nullptr, SCRATCH_REG, TyMachPtr, func),
            0,
            TyMachReg,
            func),
            IR::RegBVOpnd::New(BVUnit32((1 << RegR1) - 1), TyMachReg, func),
            func);

        instr->InsertBefore(instrPush);
        instrPush->CopyNumber(instr);
#endif
    }
    else if(bailOutInfo->branchConditionOpnd && registerSaveSyms[RegR1 - 1])
    {
        SaveReg(RegR1);
    }
    else if(registerSaveSyms[RegR0 - 1])
    {
        SaveReg(RegR0);
    }
    if(registerSaveSyms[RegLR - 1])
    {
        SaveReg(RegLR);
    }

    if(bailOutInfo->branchConditionOpnd)
    {
        // Pass in the branch condition
        //     mov  r1, condition
        IR::Instr *const newInstr =
            LinearScan::InsertMove(
                IR::RegOpnd::New(nullptr, RegR1, bailOutInfo->branchConditionOpnd->GetType(), func),
                bailOutInfo->branchConditionOpnd,
                instr);
        linearScan->SetSrcRegs(newInstr);
    }

    if (func->IsOOPJIT())
    {
        // ldimm r0, dataAddr
        intptr_t nativeDataAddr = func->GetWorkItem()->GetWorkItemData()->nativeDataAddr;
        IR::RegOpnd * r0 = IR::RegOpnd::New(nullptr, RegR0, TyMachPtr, func);
        LinearScan::InsertMove(r0, IR::AddrOpnd::New(nativeDataAddr, IR::AddrOpndKindDynamicNativeCodeDataRef, func), instr);

        // mov r0, [r0]
        LinearScan::InsertMove(r0, IR::IndirOpnd::New(r0, 0, TyMachPtr, func), instr);

        // lea r0, [r0 + bailoutRecord_offset]
        unsigned int bailoutRecordOffset = NativeCodeData::GetDataTotalOffset(bailOutInfo->bailOutRecord);
        LinearScan::InsertLea(
            r0,
            IR::IndirOpnd::New(r0, bailoutRecordOffset, TyUint32,
#if DBG
                NativeCodeData::GetDataDescription(bailOutInfo->bailOutRecord, func->m_alloc),
#endif
                this->func), instr);
    }
    else
    {
        // Pass in the bailout record
        //     ldimm r0, bailOutRecord
        LinearScan::InsertMove(
            IR::RegOpnd::New(nullptr, RegR0, TyMachPtr, func),
            IR::AddrOpnd::New(bailOutInfo->bailOutRecord, IR::AddrOpndKindDynamicBailOutRecord, func, true),
            instr);
    }

    firstInstr = firstInstr->m_next;
    for(uint i = 0; i < registerSaveSymsCount; i++)
    {
        StackSym *const stackSym = registerSaveSyms[i];
        if(!stackSym)
        {
            continue;
        }

        // Record the use on the lifetime in case it spilled afterwards. Spill loads will be inserted before 'firstInstr', that
        // is, before the register saves are done.
        this->linearScan->RecordUse(stackSym->scratch.linearScan.lifetime, firstInstr, nullptr, true);
    }

    // Load the bailout target into lr
    //     ldimm lr, BailOut
    //     blx  lr
    Assert(instr->GetSrc1()->IsHelperCallOpnd());
    LinearScan::InsertMove(IR::RegOpnd::New(nullptr, RegLR, TyMachPtr, func), instr->GetSrc1(), instr);
    instr->ReplaceSrc1(IR::RegOpnd::New(nullptr, RegLR, TyMachPtr, func));
}

IR::Instr *
LinearScanMD::GenerateBailInForGeneratorYield(IR::Instr * resumeLabelInstr, BailOutInfo * bailOutInfo)
{
    Js::Throw::NotImplemented();
}

uint LinearScanMD::GetRegisterSaveIndex(RegNum reg)
{
    if (RegTypes[reg] == TyFloat64)
    {
        Assert(reg+1 >= RegD0);
        return (reg - RegD0) * 2 + RegD0;
    }
    else
    {
        return reg;
    }
}

// static
RegNum LinearScanMD::GetRegisterFromSaveIndex(uint offset)
{
    return (RegNum)(offset >= RegD0 ? (offset - RegD0) / 2  + RegD0 : offset);
}

RegNum LinearScanMD::GetParamReg(IR::SymOpnd *symOpnd, Func *func)
{
    /* TODO - Add ARM32 support according to register calling convention */
    return RegNOREG;
}
<commit_msg>[MERGE #4134 @sigatrev] ARM64: fix bail out double values<commit_after>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "Backend.h"
#include "SccLiveness.h"

extern const IRType RegTypes[RegNumCount];

LinearScanMD::LinearScanMD(Func *func)
    : helperSpillSlots(nullptr),
      maxOpHelperSpilledLiveranges(0),
      func(func)
{
}

void
LinearScanMD::Init(LinearScan *linearScan)
{
    LinearScanMDShared::Init(linearScan);
    Func *func = linearScan->func;
    RegNum localsReg = func->GetLocalsPointer();
    if (localsReg != RegSP)
    {
        func->m_regsUsed.Set(localsReg);
    }

    memset(this->vfpSymTable, 0, sizeof(this->vfpSymTable));
}

StackSym *
LinearScanMD::EnsureSpillSymForVFPReg(RegNum reg, Func *func)
{
    Assert(REGNUM_ISVFPREG(reg));

    __analysis_assume(reg - RegD0 < VFP_REGCOUNT);
    StackSym *sym = this->vfpSymTable[reg - RegD0];

    if (sym == nullptr)
    {
        sym = StackSym::New(TyFloat64, func);
        func->StackAllocate(sym, MachRegDouble);

        __analysis_assume(reg - RegD0 < VFP_REGCOUNT);
        this->vfpSymTable[reg - RegD0] = sym;
    }

    return sym;
}

bool
LinearScanMD::IsAllocatable(RegNum reg, Func *func) const
{
    return reg != func->GetLocalsPointer();
}

BitVector
LinearScanMD::FilterRegIntSizeConstraints(BitVector regsBv, BitVector sizeUsageBv) const
{
    return regsBv;
}

bool
LinearScanMD::FitRegIntSizeConstraints(RegNum reg, BitVector sizeUsageBv) const
{
    return true;
}

bool
LinearScanMD::FitRegIntSizeConstraints(RegNum reg, IRType type) const
{
    return true;
}

void
LinearScanMD::InsertOpHelperSpillAndRestores(SList<OpHelperBlock> *opHelperBlockList)
{
    if (maxOpHelperSpilledLiveranges)
    {
        Assert(!helperSpillSlots);
        helperSpillSlots = AnewArrayZ(linearScan->GetTempAlloc(), StackSym *, maxOpHelperSpilledLiveranges);
    }

    FOREACH_SLIST_ENTRY(OpHelperBlock, opHelperBlock, opHelperBlockList)
    {
        InsertOpHelperSpillsAndRestores(opHelperBlock);
    }
    NEXT_SLIST_ENTRY;
}

void
LinearScanMD::InsertOpHelperSpillsAndRestores(const OpHelperBlock& opHelperBlock)
{
    uint32 index = 0;

    FOREACH_SLIST_ENTRY(OpHelperSpilledLifetime, opHelperSpilledLifetime, &opHelperBlock.spilledLifetime)
    {
        // Use the original sym as spill slot if this is an inlinee arg
        StackSym* sym = nullptr;
        if (opHelperSpilledLifetime.spillAsArg)
        {
            sym = opHelperSpilledLifetime.lifetime->sym;
            AnalysisAssert(sym);
            Assert(sym->IsAllocated());
        }

        if (RegTypes[opHelperSpilledLifetime.reg] == TyFloat64)
        {
            IR::RegOpnd * regOpnd = IR::RegOpnd::New(nullptr, opHelperSpilledLifetime.reg, TyMachDouble, this->func);

            if (!sym)
            {
                sym = EnsureSpillSymForVFPReg(regOpnd->GetReg(), this->func);
            }
            IR::Instr * pushInstr = IR::Instr::New(Js::OpCode::FSTR, IR::SymOpnd::New(sym, TyMachDouble, this->func), regOpnd, this->func);
            opHelperBlock.opHelperLabel->InsertAfter(pushInstr);
            pushInstr->CopyNumber(opHelperBlock.opHelperLabel);
            if (opHelperSpilledLifetime.reload)
            {
                IR::Instr * popInstr = IR::Instr::New(Js::OpCode::FLDR, regOpnd, IR::SymOpnd::New(sym, TyMachDouble, this->func), this->func);
                opHelperBlock.opHelperEndInstr->InsertBefore(popInstr);
                popInstr->CopyNumber(opHelperBlock.opHelperEndInstr);
            }
        }
        else
        {
            Assert(helperSpillSlots);
            Assert(index < maxOpHelperSpilledLiveranges);

            if (!sym)
            {
                // Lazily allocate only as many slots as we really need.
                if (!helperSpillSlots[index])
                {
                    helperSpillSlots[index] = StackSym::New(TyMachReg, func);
                }

                sym = helperSpillSlots[index];
                index++;

                Assert(sym);
                func->StackAllocate(sym, MachRegInt);
            }

            IR::RegOpnd * regOpnd = IR::RegOpnd::New(sym, opHelperSpilledLifetime.reg, sym->GetType(), func);
            IR::Instr * saveInstr = IR::Instr::New(Js::OpCode::STR, IR::SymOpnd::New(sym, sym->GetType(), func), regOpnd, func);
            opHelperBlock.opHelperLabel->InsertAfter(saveInstr);
            saveInstr->CopyNumber(opHelperBlock.opHelperLabel);
            this->LegalizeDef(saveInstr);

            if (opHelperSpilledLifetime.reload)
            {
                IR::Instr * restoreInstr = IR::Instr::New(Js::OpCode::LDR, regOpnd, IR::SymOpnd::New(sym, sym->GetType(), func), func);
                opHelperBlock.opHelperEndInstr->InsertBefore(restoreInstr);
                restoreInstr->CopyNumber(opHelperBlock.opHelperEndInstr);
                this->LegalizeUse(restoreInstr, restoreInstr->GetSrc1());
            }
        }
    }
    NEXT_SLIST_ENTRY;
}

void
LinearScanMD::EndOfHelperBlock(uint32 helperSpilledLiveranges)
{
    if (helperSpilledLiveranges > maxOpHelperSpilledLiveranges)
    {
        maxOpHelperSpilledLiveranges = helperSpilledLiveranges;
    }
}

void
LinearScanMD::LegalizeDef(IR::Instr * instr)
{
    if (instr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn)
    {
        // ArgOut_A_InlineBuiltIn pseudo instruction is kept through register allocator only to use for bailout as is,
        // and thus it must not be changed here by legalization.
        // It is removed in peeps, so only place to special case it is in register allocator.
        return;
    }

    // Legalize opcodes, etc., but do not expand symbol/indirs with large offsets
    // because we can't safely do this until all loads and stores are in place.
    LegalizeMD::LegalizeDst(instr, false);
}

void
LinearScanMD::LegalizeUse(IR::Instr * instr, IR::Opnd * opnd)
{
    if (instr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn)
    {
        // ArgOut_A_InlineBuiltIn pseudo instruction is kept through register allocator only to use for bailout as is,
        // and thus it must not be changed here by legalization.
        // It is removed in peeps, so only place to special case it is in register allocator.
        return;
    }

    // Legalize opcodes, etc., but do not expand symbol/indirs with large offsets
    // because we can't safely do this until all loads and stores are in place.
    if (opnd == instr->GetSrc1())
    {
        LegalizeMD::LegalizeSrc(instr, opnd, 1, false);
    }
    else
    {
        LegalizeMD::LegalizeSrc(instr, opnd, 2, false);
    }
}

void
LinearScanMD::GenerateBailOut(
    IR::Instr * instr,
    __in_ecount(registerSaveSymsCount) StackSym ** registerSaveSyms,
    uint registerSaveSymsCount)
{
    Func *const func = instr->m_func;
    BailOutInfo *const bailOutInfo = instr->GetBailOutInfo();
    IR::Instr *firstInstr = instr->m_prev;
    Js::Var *const registerSaveSpace = (Js::Var*)func->GetThreadContextInfo()->GetBailOutRegisterSaveSpaceAddr();

    const auto LoadRegSaveSpaceIntoScratch = [&](const RegNum reg)
    {
        // Load the register save space address for the specified register into the scratch register:
        //     ldimm SCRATCH_REG, regSaveSpace
        LinearScan::InsertMove(
            IR::RegOpnd::New(nullptr, SCRATCH_REG, TyMachPtr, func),
            IR::AddrOpnd::New(&registerSaveSpace[reg - 1], IR::AddrOpndKindDynamicMisc, func),
            instr);
    };

    const auto SaveReg = [&](const RegNum reg)
    {
        Assert(registerSaveSyms[reg - 1]);

        //     LoadRegSaveSpaceIntoScratch(reg)
        //     mov  [SCRATCH_REG], reg
        LoadRegSaveSpaceIntoScratch(reg);
        const IRType regType = RegTypes[reg];
        LinearScan::InsertMove(
            IR::IndirOpnd::New(
                IR::RegOpnd::New(nullptr, SCRATCH_REG, TyMachPtr, func),
                0,
                regType,
                func),
            IR::RegOpnd::New(registerSaveSyms[reg - 1], reg, regType, func),
            instr);
    };

    // Save registers used for parameters, and lr, if necessary, into the register save space
    if(bailOutInfo->branchConditionOpnd && registerSaveSyms[RegR1 - 1] && registerSaveSyms[RegR0 - 1])
    {
        // ARM64_WORKITEM: Needs looking at
        __debugbreak();
#if 0
        // Save r1 and r0 with one push:
        //     LoadRegSaveSpaceIntoScratch(RegR2)
        //     push [SCRATCH_REG], {r0 - r1}
        LoadRegSaveSpaceIntoScratch(RegR2);
        IR::Instr *instrPush = IR::Instr::New(
            Js::OpCode::PUSH,
            IR::IndirOpnd::New(
            IR::RegOpnd::New(nullptr, SCRATCH_REG, TyMachPtr, func),
            0,
            TyMachReg,
            func),
            IR::RegBVOpnd::New(BVUnit32((1 << RegR1) - 1), TyMachReg, func),
            func);

        instr->InsertBefore(instrPush);
        instrPush->CopyNumber(instr);
#endif
    }
    else if(bailOutInfo->branchConditionOpnd && registerSaveSyms[RegR1 - 1])
    {
        SaveReg(RegR1);
    }
    else if(registerSaveSyms[RegR0 - 1])
    {
        SaveReg(RegR0);
    }
    if(registerSaveSyms[RegLR - 1])
    {
        SaveReg(RegLR);
    }

    if(bailOutInfo->branchConditionOpnd)
    {
        // Pass in the branch condition
        //     mov  r1, condition
        IR::Instr *const newInstr =
            LinearScan::InsertMove(
                IR::RegOpnd::New(nullptr, RegR1, bailOutInfo->branchConditionOpnd->GetType(), func),
                bailOutInfo->branchConditionOpnd,
                instr);
        linearScan->SetSrcRegs(newInstr);
    }

    if (func->IsOOPJIT())
    {
        // ldimm r0, dataAddr
        intptr_t nativeDataAddr = func->GetWorkItem()->GetWorkItemData()->nativeDataAddr;
        IR::RegOpnd * r0 = IR::RegOpnd::New(nullptr, RegR0, TyMachPtr, func);
        LinearScan::InsertMove(r0, IR::AddrOpnd::New(nativeDataAddr, IR::AddrOpndKindDynamicNativeCodeDataRef, func), instr);

        // mov r0, [r0]
        LinearScan::InsertMove(r0, IR::IndirOpnd::New(r0, 0, TyMachPtr, func), instr);

        // lea r0, [r0 + bailoutRecord_offset]
        unsigned int bailoutRecordOffset = NativeCodeData::GetDataTotalOffset(bailOutInfo->bailOutRecord);
        LinearScan::InsertLea(
            r0,
            IR::IndirOpnd::New(r0, bailoutRecordOffset, TyUint32,
#if DBG
                NativeCodeData::GetDataDescription(bailOutInfo->bailOutRecord, func->m_alloc),
#endif
                this->func), instr);
    }
    else
    {
        // Pass in the bailout record
        //     ldimm r0, bailOutRecord
        LinearScan::InsertMove(
            IR::RegOpnd::New(nullptr, RegR0, TyMachPtr, func),
            IR::AddrOpnd::New(bailOutInfo->bailOutRecord, IR::AddrOpndKindDynamicBailOutRecord, func, true),
            instr);
    }

    firstInstr = firstInstr->m_next;
    for(uint i = 0; i < registerSaveSymsCount; i++)
    {
        StackSym *const stackSym = registerSaveSyms[i];
        if(!stackSym)
        {
            continue;
        }

        // Record the use on the lifetime in case it spilled afterwards. Spill loads will be inserted before 'firstInstr', that
        // is, before the register saves are done.
        this->linearScan->RecordUse(stackSym->scratch.linearScan.lifetime, firstInstr, nullptr, true);
    }

    // Load the bailout target into lr
    //     ldimm lr, BailOut
    //     blx  lr
    Assert(instr->GetSrc1()->IsHelperCallOpnd());
    LinearScan::InsertMove(IR::RegOpnd::New(nullptr, RegLR, TyMachPtr, func), instr->GetSrc1(), instr);
    instr->ReplaceSrc1(IR::RegOpnd::New(nullptr, RegLR, TyMachPtr, func));
}

IR::Instr *
LinearScanMD::GenerateBailInForGeneratorYield(IR::Instr * resumeLabelInstr, BailOutInfo * bailOutInfo)
{
    Js::Throw::NotImplemented();
}

uint LinearScanMD::GetRegisterSaveIndex(RegNum reg)
{
    return reg;
}

// static
RegNum LinearScanMD::GetRegisterFromSaveIndex(uint offset)
{
    return (RegNum)offset;
}

RegNum LinearScanMD::GetParamReg(IR::SymOpnd *symOpnd, Func *func)
{
    /* TODO - Add ARM32 support according to register calling convention */
    return RegNOREG;
}
<|endoftext|>


<commit_before>/*
 * DynPLM.cpp
 *
 *  Created on: 03.01.2014
 *      Author: cls
 */

#include "DynPLM.h"

namespace	 NetworKit {

DynPLM::DynPLM(bool refine, double gamma, std::string par) : parallelism(par), refine(refine), gamma(gamma), plm2(refine, gamma, par) {

}

void DynPLM::update(std::vector<GraphEvent>& stream) {
	DEBUG("processing event stream");

	auto isolate = [&](node u) {
		edgeweight vol = G->volume(u);
		// volCommunity[zeta[u]] -= vol;
		zeta[u] = zeta.addCluster();
		// volCommunity[zeta[u]] = vol;
	};

	for (GraphEvent ev : stream) {
		TRACE("event: " << ev.toString());
		switch (ev.type) {
			case GraphEvent::NODE_ADDITION : {
				zeta.append(ev.u);
				zeta[ev.u] = zeta.addCluster();
				// volCommunity[zeta[ev.u]] = G.volume(ev.u);
				break;
			}
			case GraphEvent::NODE_REMOVAL : {
				// volCommunity[zeta[ev.u]] -= G.volume(ev.u);
				zeta[ev.u] = none;
				break;
			}
			case GraphEvent::EDGE_ADDITION : {
				isolate(ev.u);
				isolate(ev.v);
				break;
			}
			case GraphEvent::EDGE_REMOVAL : {
				isolate(ev.u);
				isolate(ev.v);
				break;
			}
			case GraphEvent::EDGE_WEIGHT_UPDATE : {
				isolate(ev.u);
				isolate(ev.v);
				break;
			}
			case GraphEvent::TIME_STEP : {
				break;
			}
			default: {
				throw std::runtime_error("unknown event type");
			}
		}
	} // end event loop
}

Clustering DynPLM::detect() {
	DEBUG("retrieving solution");
	return this->run(*this->G);
}

Clustering DynPLM::run(Graph& G) {
	INFO("calling run method on " << G.toString());

	edgeweight total = G.totalEdgeWeight();
	edgeweight divisor = (2 * total * total); // needed in modularity calculation

	// init community-dependent temporaries
	std::map<cluster, double> volCommunity;
	// std::vector<double> volCommunity(zeta.upperBound(), 0.0);
	zeta.forEntries([&](node u, cluster C) { 	// set volume for all communities
		volCommunity[C] += G.volume(u);
	});

	bool moved = false; // indicates whether any node has been moved

	// try to improve modularity by moving a node to neighboring clusters
	auto tryMove = [&](node u) {
		// TRACE("trying to move node " << u);

		// collect edge weight to neighbor clusters
		std::map<cluster, edgeweight> affinity;
		G.forWeightedNeighborsOf(u, [&](node v, edgeweight weight) {
			if (u != v) {
				cluster C = zeta[v];
				affinity[C] += weight;
			}
		});

		// sub-functions

		// $\vol(C \ {x})$ - volume of cluster C excluding node x
		auto volCommunityMinusNode = [&](cluster C, node x) {
			double volC = 0.0;
			volC = volCommunity[C];
			if (zeta[x] == C) {
				return volC - G.volume(x);
			} else {
				return volC;
			}
		};

		auto modGain = [&](node u, cluster C, cluster D) {
			double delta = (affinity[D] - affinity[C]) / total + this->gamma * ((volCommunityMinusNode(C, u) - volCommunityMinusNode(D, u)) * G.volume(u)) / divisor;
			//TRACE("(" << affinity[D] << " - " << affinity[C] << ") / " << total << " + " << this->gamma << " * ((" << volCommunityMinusNode(C, u) << " - " << volCommunityMinusNode(D, u) << ") *" << volN << ") / 2 * " << (total * total));
			return delta;
		};

		auto modUpdate = [&](node u, cluster C, cluster D) {
			double volN = 0.0;
			volN = G.volume(u);
			// update the volume of the two clusters
			#pragma omp atomic update
			volCommunity[C] -= volN;
			#pragma omp atomic update
			volCommunity[D] += volN;
		};

		cluster best = none;
		cluster C = none;
		cluster D = none;
		double deltaBest = -1;

		C = zeta[u];

//			TRACE("Processing neighborhood of node " << u << ", which is in cluster " << C);
		G.forNeighborsOf(u, [&](node v) {
			D = zeta[v];
			if (D != C) { // consider only nodes in other clusters (and implicitly only nodes other than u)
				double delta = modGain(u, C, D);
				// TRACE("mod gain: " << delta); // FIXME: all mod gains are negative
				if (delta > deltaBest) {
					deltaBest = delta;
					best = D;
				}
			}
		});

		// TRACE("deltaBest=" << deltaBest); // FIXME: best mod gain is negative
		if (deltaBest > 0) { // if modularity improvement possible
			assert (best != C && best != none);// do not "move" to original cluster

			zeta[u] = best; // move to best cluster
			// TRACE("node " << u << " moved");
			modUpdate(u, C, best);

			moved = true; // change to clustering has been made

		} else {
			// TRACE("node " << u << " not moved");
		}
	};

	// first move phase

	// apply node movement according to parallelization strategy
	if (this->parallelism == "none") {
		G.forNodes(tryMove);
	} else if (this->parallelism == "simple") {
		G.parallelForNodes(tryMove);
	} else if (this->parallelism == "balanced") {
		G.balancedParallelForNodes(tryMove);
	} else {
		ERROR("unknown parallelization strategy: " << this->parallelism);
		throw std::runtime_error("unknown parallelization strategy");
	}

	if (moved) {
		DEBUG("nodes moved, so begin coarsening and recursive call");
		std::pair<Graph, std::vector<node>> coarsened = plm2.coarsen(G, zeta);	// coarsen graph according to communitites
		Clustering zetaCoarse = plm2.run(coarsened.first);

		zeta = plm2.prolong(coarsened.first, zetaCoarse, G, coarsened.second); // unpack communities in coarse graph onto fine graph
		// refinement phase
		if (refine) {
			INFO("refinement phase");
			// reinit community-dependent temporaries
			cluster o = zeta.upperBound();
			volCommunity.clear();
			zeta.forEntries([&](node u, cluster C) { 	// set volume for all communities
				volCommunity[C] += G.volume(u);
			});

			// second move phase
			moved = false;
			// apply node movement according to parallelization strategy
			if (this->parallelism == "none") {
				G.forNodes(tryMove);
			} else if (this->parallelism == "simple") {
				G.parallelForNodes(tryMove);
			} else if (this->parallelism == "balanced") {
				G.balancedParallelForNodes(tryMove);
			} else {
				ERROR("unknown parallelization strategy: " << this->parallelism);
				throw std::runtime_error("unknown parallelization strategy");
			}
		}
	}

	return zeta;
}

} /* namespace NetworKit */

<commit_msg>minor edits to DynPLM<commit_after>/*
 * DynPLM.cpp
 *
 *  Created on: 03.01.2014
 *      Author: cls
 */

#include "DynPLM.h"

namespace	 NetworKit {

DynPLM::DynPLM(bool refine, double gamma, std::string par) : parallelism(par), refine(refine), gamma(gamma), plm2(refine, gamma, par) {

}

void DynPLM::update(std::vector<GraphEvent>& stream) {
	DEBUG("processing event stream");

	// turn a node into a singleton
	auto isolate = [&](node u) {
		zeta[u] = zeta.addCluster();
	};

	for (GraphEvent ev : stream) {
		TRACE("event: " << ev.toString());
		switch (ev.type) {
			case GraphEvent::NODE_ADDITION : {
				zeta.append(ev.u);
				isolate(ev.u)
				break;
			}
			case GraphEvent::NODE_REMOVAL : {
				zeta[ev.u] = none;
				break;
			}
			case GraphEvent::EDGE_ADDITION : {
				isolate(ev.u);
				isolate(ev.v);
				break;
			}
			case GraphEvent::EDGE_REMOVAL : {
				isolate(ev.u);
				isolate(ev.v);
				break;
			}
			case GraphEvent::EDGE_WEIGHT_UPDATE : {
				isolate(ev.u);
				isolate(ev.v);
				break;
			}
			case GraphEvent::TIME_STEP : {
				break;
			}
			default: {
				throw std::runtime_error("unknown event type");
			}
		}
	} // end event loop
}

Clustering DynPLM::detect() {
	DEBUG("retrieving solution");
	return this->run(*this->G);
}

Clustering DynPLM::run(Graph& G) {
	INFO("calling run method on " << G.toString());

	edgeweight total = G.totalEdgeWeight();
	edgeweight divisor = (2 * total * total); // needed in modularity calculation

	// init community-dependent temporaries
	//
	std::map<cluster, double> volCommunity; // a map to save memory
	zeta.forEntries([&](node u, cluster C) { 	// set volume for all communities
		volCommunity[C] += G.volume(u);
	});

	bool moved = false; // indicates whether any node has been moved

	// try to improve modularity by moving a node to neighboring clusters
	auto tryMove = [&](node u) {
		// TRACE("trying to move node " << u);
		// collect edge weight to neighbor clusters
		std::map<cluster, edgeweight> affinity;
		G.forWeightedNeighborsOf(u, [&](node v, edgeweight weight) {
			if (u != v) {
				cluster C = zeta[v];
				affinity[C] += weight;
			}
		});

		// sub-functions

		// $\vol(C \ {x})$ - volume of cluster C excluding node x
		auto volCommunityMinusNode = [&](cluster C, node x) {
			double volC = 0.0;
			volC = volCommunity[C];
			if (zeta[x] == C) {
				return volC - G.volume(x);
			} else {
				return volC;
			}
		};

		auto modGain = [&](node u, cluster C, cluster D) {
			double delta = (affinity[D] - affinity[C]) / total + this->gamma * ((volCommunityMinusNode(C, u) - volCommunityMinusNode(D, u)) * G.volume(u)) / divisor;
			//TRACE("(" << affinity[D] << " - " << affinity[C] << ") / " << total << " + " << this->gamma << " * ((" << volCommunityMinusNode(C, u) << " - " << volCommunityMinusNode(D, u) << ") *" << volN << ") / 2 * " << (total * total));
			return delta;
		};

		auto modUpdate = [&](node u, cluster C, cluster D) {
			double volN = 0.0;
			volN = G.volume(u);
			// update the volume of the two clusters
			#pragma omp atomic update
			volCommunity[C] -= volN;
			#pragma omp atomic update
			volCommunity[D] += volN;
		};

		cluster best = none;
		cluster C = none;
		cluster D = none;
		double deltaBest = -1;

		C = zeta[u];

//			TRACE("Processing neighborhood of node " << u << ", which is in cluster " << C);
		G.forNeighborsOf(u, [&](node v) {
			D = zeta[v];
			if (D != C) { // consider only nodes in other clusters (and implicitly only nodes other than u)
				double delta = modGain(u, C, D);
				// TRACE("mod gain: " << delta); // FIXME: all mod gains are negative
				if (delta > deltaBest) {
					deltaBest = delta;
					best = D;
				}
			}
		});

		// TRACE("deltaBest=" << deltaBest); // FIXME: best mod gain is negative
		if (deltaBest > 0) { // if modularity improvement possible
			assert (best != C && best != none);// do not "move" to original cluster
			zeta[u] = best; // move to best cluster
			// TRACE("node " << u << " moved");
			modUpdate(u, C, best);
			moved = true; // change to clustering has been made

		} else {
			// TRACE("node " << u << " not moved");
		}
	};

	// first move phase

	// apply node movement according to parallelization strategy
	if (this->parallelism == "none") {
		G.forNodes(tryMove);
	} else if (this->parallelism == "simple") {
		G.parallelForNodes(tryMove);
	} else if (this->parallelism == "balanced") {
		G.balancedParallelForNodes(tryMove);
	} else {
		ERROR("unknown parallelization strategy: " << this->parallelism);
		throw std::runtime_error("unknown parallelization strategy");
	}

	if (moved) {
		DEBUG("nodes moved, so begin coarsening and recursive call");
		std::pair<Graph, std::vector<node>> coarsened = plm2.coarsen(G, zeta);	// coarsen graph according to communitites
		Clustering zetaCoarse = plm2.run(coarsened.first);

		zeta = plm2.prolong(coarsened.first, zetaCoarse, G, coarsened.second); // unpack communities in coarse graph onto fine graph
		// refinement phase
		if (refine) {
			INFO("refinement phase");
			// reinit community-dependent temporaries
			cluster o = zeta.upperBound();
			volCommunity.clear();
			zeta.forEntries([&](node u, cluster C) { 	// set volume for all communities
				volCommunity[C] += G.volume(u);
			});

			// second move phase
			moved = false;
			// apply node movement according to parallelization strategy
			if (this->parallelism == "none") {
				G.forNodes(tryMove);
			} else if (this->parallelism == "simple") {
				G.parallelForNodes(tryMove);
			} else if (this->parallelism == "balanced") {
				G.balancedParallelForNodes(tryMove);
			} else {
				ERROR("unknown parallelization strategy: " << this->parallelism);
				throw std::runtime_error("unknown parallelization strategy");
			}
		}
	}

	return zeta;
}

} /* namespace NetworKit */

<|endoftext|>


<commit_before>#include "Algorithm2A.hpp"

std::vector<index_type> Algorithm2A::calculateLCP(std::string BWT) {
    std::vector<index_type> LCP;

    LCP.push_back(1);
    for(int i=0; i<BWT.size()-1; i++) {
        LCP.push_back(-2);
    }
    LCP.push_back(-1);

    Interval firstInterval;
    firstInterval.startIndex = 1;
    firstInterval.endIndex = BWT.size();

    QueueElement firstElement;
    firstElement.interval = firstInterval;
    firstElement.l = 0;

    queue<QueueElement> queueLCP;
    queueLCP.push(firstElement);

    while(!queueLCP.empty()) {
        QueueElement element;
        element = queueLCP.front();
        queueLCP.pop();

        vector<Interval> intervals = getIntervals(element.interval.startIndex,
                                                  element.interval.endIndex);

        for(vector<Interval>::iterator it = intervals.begin(); it != intervals.end(); ++it) {
            if(LCP[it->endIndex] == -2) {
                QueueElement newElement;
                newElement.interval = *it;
                newElement.l = element.l + 1;
                queueLCP.push(newElement);
                LCP[it->endIndex] = element.l;
            }
        }
    }
    return LCP;
}
<commit_msg>Update<commit_after>#include "Algorithm2A.hpp"

std::vector<index_type> Algorithm2A::calculateLCP(std::string BWT) {
    std::vector<index_type> LCP;

    LCP.push_back(-1);
    for(int i=0; i<BWT.size()-1; i++) {
        LCP.push_back(-2);
    }
    LCP.push_back(-1);

    Interval firstInterval;
    firstInterval.startIndex = 1;
    firstInterval.endIndex = BWT.size();

    QueueElement firstElement;
    firstElement.interval = firstInterval;
    firstElement.l = 0;

    queue<QueueElement> queueLCP;
    queueLCP.push(firstElement);

    while(!queueLCP.empty()) {
        QueueElement element;
        element = queueLCP.front();
        queueLCP.pop();

        vector<Interval> intervals = getIntervals(element.interval.startIndex,
                                                  element.interval.endIndex);

        for(vector<Interval>::iterator it = intervals.begin(); it != intervals.end(); ++it) {
            if(LCP[it->endIndex] == -2) {
                QueueElement newElement;
                newElement.interval = *it;
                newElement.l = element.l + 1;
                queueLCP.push(newElement);
                LCP[it->endIndex] = element.l;
            }
        }
    }
    return LCP;
}
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include <px4_platform_common/px4_work_queue/WorkQueueManager.hpp>

#include <px4_platform_common/px4_work_queue/WorkQueue.hpp>

#include <drivers/drv_hrt.h>
#include <px4_posix.h>
#include <px4_tasks.h>
#include <px4_time.h>
#include <px4_atomic.h>
#include <containers/BlockingList.hpp>
#include <containers/BlockingQueue.hpp>
#include <lib/drivers/device/Device.hpp>
#include <lib/mathlib/mathlib.h>

#include <limits.h>
#include <string.h>

using namespace time_literals;

namespace px4
{

// list of current work queues
static BlockingList<WorkQueue *> *_wq_manager_wqs_list{nullptr};

// queue of WorkQueues to be created (as threads in the wq manager task)
static BlockingQueue<const wq_config_t *, 1> *_wq_manager_create_queue{nullptr};

static px4::atomic_bool _wq_manager_should_exit{false};

static WorkQueue *FindWorkQueueByName(const char *name)
{
	if (_wq_manager_wqs_list == nullptr) {
		PX4_ERR("not running");
		return nullptr;
	}

	auto lg = _wq_manager_wqs_list->getLockGuard();

	// search list
	for (WorkQueue *wq : *_wq_manager_wqs_list) {
		if (strcmp(wq->get_name(), name) == 0) {
			return wq;
		}
	}

	return nullptr;
}

WorkQueue *WorkQueueFindOrCreate(const wq_config_t &new_wq)
{
	if (_wq_manager_create_queue == nullptr) {
		PX4_ERR("not running");
		return nullptr;
	}

	// search list for existing work queue
	WorkQueue *wq = FindWorkQueueByName(new_wq.name);

	// create work queue if it doesn't already exist
	if (wq == nullptr) {
		// add WQ config to list
		//  main thread wakes up, creates the thread
		_wq_manager_create_queue->push(&new_wq);

		// we wait until new wq is created, then return
		uint64_t t = 0;

		while (wq == nullptr && t < 10_s) {
			// Wait up to 10 seconds, checking every 1 ms
			t += 1_ms;
			px4_usleep(1_ms);

			wq = FindWorkQueueByName(new_wq.name);
		}

		if (wq == nullptr) {
			PX4_ERR("failed to create %s", new_wq.name);
		}
	}

	return wq;
}

const wq_config_t &device_bus_to_wq(uint32_t device_id_int)
{
	union device::Device::DeviceId device_id;
	device_id.devid = device_id_int;

	const device::Device::DeviceBusType bus_type = device_id.devid_s.bus_type;
	const uint8_t bus = device_id.devid_s.bus;

	if (bus_type == device::Device::DeviceBusType_I2C) {
		switch (bus) {
		case 1: return wq_configurations::I2C1;

		case 2: return wq_configurations::I2C2;

		case 3: return wq_configurations::I2C3;

		case 4: return wq_configurations::I2C4;
		}

	} else if (bus_type == device::Device::DeviceBusType_SPI) {
		switch (bus) {
		case 1: return wq_configurations::SPI1;

		case 2: return wq_configurations::SPI2;

		case 3: return wq_configurations::SPI3;

		case 4: return wq_configurations::SPI4;

		case 5: return wq_configurations::SPI5;

		case 6: return wq_configurations::SPI6;
		}
	}

	// otherwise use high priority
	return wq_configurations::hp_default;
};

static void *WorkQueueRunner(void *context)
{
	wq_config_t *config = static_cast<wq_config_t *>(context);
	WorkQueue wq(*config);

	// add to work queue list
	_wq_manager_wqs_list->add(&wq);

	wq.Run();

	// remove from work queue list
	_wq_manager_wqs_list->remove(&wq);

	return nullptr;
}

static void WorkQueueManagerRun()
{
	_wq_manager_wqs_list = new BlockingList<WorkQueue *>();
	_wq_manager_create_queue = new BlockingQueue<const wq_config_t *, 1>();

	while (!_wq_manager_should_exit.load()) {
		// create new work queues as needed
		const wq_config_t *wq = _wq_manager_create_queue->pop();

		if (wq != nullptr) {
			// create new work queue

			pthread_attr_t attr;
			int ret_attr_init = pthread_attr_init(&attr);

			if (ret_attr_init != 0) {
				PX4_ERR("attr init for %s failed (%i)", wq->name, ret_attr_init);
			}

			sched_param param;
			int ret_getschedparam = pthread_attr_getschedparam(&attr, &param);

			if (ret_getschedparam != 0) {
				PX4_ERR("getting sched param for %s failed (%i)", wq->name, ret_getschedparam);
			}

			// stack size
#ifndef __PX4_QURT
			const size_t stacksize = math::max(PTHREAD_STACK_MIN, PX4_STACK_ADJUSTED(wq->stacksize));
#else
			const size_t stacksize = math::max(8 * 1024, PX4_STACK_ADJUSTED(wq->stacksize));
#endif
			int ret_setstacksize = pthread_attr_setstacksize(&attr, stacksize);

			if (ret_setstacksize != 0) {
				PX4_ERR("setting stack size for %s failed (%i)", wq->name, ret_setstacksize);
			}

#ifndef __PX4_QURT
			// schedule policy FIFO
			int ret_setschedpolicy = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);

			if (ret_setschedpolicy != 0) {
				PX4_ERR("failed to set sched policy SCHED_FIFO (%i)", ret_setschedpolicy);
			}

#endif // ! QuRT

			// priority
			param.sched_priority = sched_get_priority_max(SCHED_FIFO) + wq->relative_priority;
			int ret_setschedparam = pthread_attr_setschedparam(&attr, &param);

			if (ret_setschedparam != 0) {
				PX4_ERR("setting sched params for %s failed (%i)", wq->name, ret_setschedparam);
			}

			// create thread
			pthread_t thread;
			int ret_create = pthread_create(&thread, &attr, WorkQueueRunner, (void *)wq);

			if (ret_create == 0) {
				PX4_INFO("creating: %s, priority: %d, stack: %zu bytes", wq->name, param.sched_priority, stacksize);

			} else {
				PX4_ERR("failed to create thread for %s (%i): %s", wq->name, ret_create, strerror(ret_create));
			}

			// destroy thread attributes
			int ret_destroy = pthread_attr_destroy(&attr);

			if (ret_destroy != 0) {
				PX4_ERR("failed to destroy thread attributes for %s (%i)", wq->name, ret_create);
			}
		}
	}
}

int WorkQueueManagerStart()
{
	int task_id = px4_task_spawn_cmd("wq:manager",
					 SCHED_DEFAULT,
					 PX4_WQ_HP_BASE,
					 1200,
					 (px4_main_t)&WorkQueueManagerRun,
					 nullptr);

	if (task_id < 0) {
		PX4_ERR("task start failed (%i)", task_id);
		return -errno;
	}

	return 0;
}

int WorkQueueManagerStop()
{
	if (_wq_manager_wqs_list != nullptr) {
		auto lg = _wq_manager_wqs_list->getLockGuard();

		// ask all work queues (threads) to stop
		// NOTE: not currently safe without all WorkItems stopping first
		for (WorkQueue *wq : *_wq_manager_wqs_list) {
			wq->request_stop();
		}

		delete _wq_manager_wqs_list;
	}

	_wq_manager_should_exit.store(true);

	if (_wq_manager_create_queue != nullptr) {
		// push nullptr to wake the wq manager task
		_wq_manager_create_queue->push(nullptr);

		px4_usleep(1000);

		delete _wq_manager_create_queue;
	}

	return PX4_OK;
}

} // namespace px4
<commit_msg>platforms: fix main function signature<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include <px4_platform_common/px4_work_queue/WorkQueueManager.hpp>

#include <px4_platform_common/px4_work_queue/WorkQueue.hpp>

#include <drivers/drv_hrt.h>
#include <px4_posix.h>
#include <px4_tasks.h>
#include <px4_time.h>
#include <px4_atomic.h>
#include <containers/BlockingList.hpp>
#include <containers/BlockingQueue.hpp>
#include <lib/drivers/device/Device.hpp>
#include <lib/mathlib/mathlib.h>

#include <limits.h>
#include <string.h>

using namespace time_literals;

namespace px4
{

// list of current work queues
static BlockingList<WorkQueue *> *_wq_manager_wqs_list{nullptr};

// queue of WorkQueues to be created (as threads in the wq manager task)
static BlockingQueue<const wq_config_t *, 1> *_wq_manager_create_queue{nullptr};

static px4::atomic_bool _wq_manager_should_exit{false};

static WorkQueue *FindWorkQueueByName(const char *name)
{
	if (_wq_manager_wqs_list == nullptr) {
		PX4_ERR("not running");
		return nullptr;
	}

	auto lg = _wq_manager_wqs_list->getLockGuard();

	// search list
	for (WorkQueue *wq : *_wq_manager_wqs_list) {
		if (strcmp(wq->get_name(), name) == 0) {
			return wq;
		}
	}

	return nullptr;
}

WorkQueue *WorkQueueFindOrCreate(const wq_config_t &new_wq)
{
	if (_wq_manager_create_queue == nullptr) {
		PX4_ERR("not running");
		return nullptr;
	}

	// search list for existing work queue
	WorkQueue *wq = FindWorkQueueByName(new_wq.name);

	// create work queue if it doesn't already exist
	if (wq == nullptr) {
		// add WQ config to list
		//  main thread wakes up, creates the thread
		_wq_manager_create_queue->push(&new_wq);

		// we wait until new wq is created, then return
		uint64_t t = 0;

		while (wq == nullptr && t < 10_s) {
			// Wait up to 10 seconds, checking every 1 ms
			t += 1_ms;
			px4_usleep(1_ms);

			wq = FindWorkQueueByName(new_wq.name);
		}

		if (wq == nullptr) {
			PX4_ERR("failed to create %s", new_wq.name);
		}
	}

	return wq;
}

const wq_config_t &device_bus_to_wq(uint32_t device_id_int)
{
	union device::Device::DeviceId device_id;
	device_id.devid = device_id_int;

	const device::Device::DeviceBusType bus_type = device_id.devid_s.bus_type;
	const uint8_t bus = device_id.devid_s.bus;

	if (bus_type == device::Device::DeviceBusType_I2C) {
		switch (bus) {
		case 1: return wq_configurations::I2C1;

		case 2: return wq_configurations::I2C2;

		case 3: return wq_configurations::I2C3;

		case 4: return wq_configurations::I2C4;
		}

	} else if (bus_type == device::Device::DeviceBusType_SPI) {
		switch (bus) {
		case 1: return wq_configurations::SPI1;

		case 2: return wq_configurations::SPI2;

		case 3: return wq_configurations::SPI3;

		case 4: return wq_configurations::SPI4;

		case 5: return wq_configurations::SPI5;

		case 6: return wq_configurations::SPI6;
		}
	}

	// otherwise use high priority
	return wq_configurations::hp_default;
};

static void *WorkQueueRunner(void *context)
{
	wq_config_t *config = static_cast<wq_config_t *>(context);
	WorkQueue wq(*config);

	// add to work queue list
	_wq_manager_wqs_list->add(&wq);

	wq.Run();

	// remove from work queue list
	_wq_manager_wqs_list->remove(&wq);

	return nullptr;
}

static int WorkQueueManagerRun(int, char **)
{
	_wq_manager_wqs_list = new BlockingList<WorkQueue *>();
	_wq_manager_create_queue = new BlockingQueue<const wq_config_t *, 1>();

	while (!_wq_manager_should_exit.load()) {
		// create new work queues as needed
		const wq_config_t *wq = _wq_manager_create_queue->pop();

		if (wq != nullptr) {
			// create new work queue

			pthread_attr_t attr;
			int ret_attr_init = pthread_attr_init(&attr);

			if (ret_attr_init != 0) {
				PX4_ERR("attr init for %s failed (%i)", wq->name, ret_attr_init);
			}

			sched_param param;
			int ret_getschedparam = pthread_attr_getschedparam(&attr, &param);

			if (ret_getschedparam != 0) {
				PX4_ERR("getting sched param for %s failed (%i)", wq->name, ret_getschedparam);
			}

			// stack size
#ifndef __PX4_QURT
			const size_t stacksize = math::max(PTHREAD_STACK_MIN, PX4_STACK_ADJUSTED(wq->stacksize));
#else
			const size_t stacksize = math::max(8 * 1024, PX4_STACK_ADJUSTED(wq->stacksize));
#endif
			int ret_setstacksize = pthread_attr_setstacksize(&attr, stacksize);

			if (ret_setstacksize != 0) {
				PX4_ERR("setting stack size for %s failed (%i)", wq->name, ret_setstacksize);
			}

#ifndef __PX4_QURT
			// schedule policy FIFO
			int ret_setschedpolicy = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);

			if (ret_setschedpolicy != 0) {
				PX4_ERR("failed to set sched policy SCHED_FIFO (%i)", ret_setschedpolicy);
			}

#endif // ! QuRT

			// priority
			param.sched_priority = sched_get_priority_max(SCHED_FIFO) + wq->relative_priority;
			int ret_setschedparam = pthread_attr_setschedparam(&attr, &param);

			if (ret_setschedparam != 0) {
				PX4_ERR("setting sched params for %s failed (%i)", wq->name, ret_setschedparam);
			}

			// create thread
			pthread_t thread;
			int ret_create = pthread_create(&thread, &attr, WorkQueueRunner, (void *)wq);

			if (ret_create == 0) {
				PX4_INFO("creating: %s, priority: %d, stack: %zu bytes", wq->name, param.sched_priority, stacksize);

			} else {
				PX4_ERR("failed to create thread for %s (%i): %s", wq->name, ret_create, strerror(ret_create));
			}

			// destroy thread attributes
			int ret_destroy = pthread_attr_destroy(&attr);

			if (ret_destroy != 0) {
				PX4_ERR("failed to destroy thread attributes for %s (%i)", wq->name, ret_create);
			}
		}
	}

	return 0;
}

int WorkQueueManagerStart()
{
	int task_id = px4_task_spawn_cmd("wq:manager",
					 SCHED_DEFAULT,
					 PX4_WQ_HP_BASE,
					 1200,
					 (px4_main_t)&WorkQueueManagerRun,
					 nullptr);

	if (task_id < 0) {
		PX4_ERR("task start failed (%i)", task_id);
		return -errno;
	}

	return 0;
}

int WorkQueueManagerStop()
{
	if (_wq_manager_wqs_list != nullptr) {
		auto lg = _wq_manager_wqs_list->getLockGuard();

		// ask all work queues (threads) to stop
		// NOTE: not currently safe without all WorkItems stopping first
		for (WorkQueue *wq : *_wq_manager_wqs_list) {
			wq->request_stop();
		}

		delete _wq_manager_wqs_list;
	}

	_wq_manager_should_exit.store(true);

	if (_wq_manager_create_queue != nullptr) {
		// push nullptr to wake the wq manager task
		_wq_manager_create_queue->push(nullptr);

		px4_usleep(1000);

		delete _wq_manager_create_queue;
	}

	return PX4_OK;
}

} // namespace px4
<|endoftext|>


<commit_before>/*
* OSPRayStructuredVolume.cpp
* Copyright (C) 2009-2017 by MegaMol Team
* Alle Rechte vorbehalten.
*/

#include "stdafx.h"
#include "OSPRayStructuredVolume.h"
#include "mmcore/moldyn/VolumeDataCall.h"
#include "mmcore/param/BoolParam.h"
#include "mmcore/param/Vector3fParam.h"
#include "mmcore/param/FloatParam.h"
#include "mmcore/param/EnumParam.h"
#include "vislib/sys/Log.h"
#include "mmcore/Call.h"
#include "mmcore/view/CallGetTransferFunction.h"

using namespace megamol::ospray;

OSPRayStructuredVolume::OSPRayStructuredVolume(void) :
    AbstractOSPRayStructure(),

    clippingBoxActive("ClippingBox::Active", "Activates the clipping Box"),
    clippingBoxLower("ClippingBox::Left", "Left corner of the clipping Box"),
    clippingBoxUpper("ClippingBox::Right", "Right corner of the clipping Box"),
    repType("Representation", "Activates one of the three different volume representations: Volume, Isosurfae, Slice"),
    sliceNormal("Slice::sliceNormal", "Direction of the slice normal"),
    sliceDist("Slice::sliceDist", "Distance of the slice in the direction of the normal vector"),
    IsoValue("Isosurface::Isovalue","Sets the isovalue of the isosurface"),
    getTFSlot("gettransferfunction", "Connects to a color transfer function module"),

    getDataSlot("getdata", "Connects to the data source")
 {
    core::param::EnumParam *rt = new core::param::EnumParam(VOLUMEREP);
    rt->SetTypePair(VOLUMEREP, "Volume");
    rt->SetTypePair(ISOSURFACE, "Isosurface");
    rt->SetTypePair(SLICE, "Slice");
    this->repType << rt;
    this->MakeSlotAvailable(&this->repType);

    this->clippingBoxActive << new core::param::BoolParam(false);
    this->clippingBoxLower << new core::param::Vector3fParam({ -5.0f, -5.0f, -5.0f });
    this->clippingBoxUpper << new core::param::Vector3fParam({ 0.0f, 5.0f, 5.0f });
    this->MakeSlotAvailable(&this->clippingBoxActive);
    this->MakeSlotAvailable(&this->clippingBoxLower);
    this->MakeSlotAvailable(&this->clippingBoxUpper);

    this->sliceNormal << new core::param::Vector3fParam({ 1.0f, 0.0f, 0.0f });
    this->sliceDist << new core::param::FloatParam(0.0f);
    this->MakeSlotAvailable(&this->sliceNormal);
    this->MakeSlotAvailable(&this->sliceDist);

    this->IsoValue << new core::param::FloatParam(0.0f);
    this->MakeSlotAvailable(&this->IsoValue);

    this->getDataSlot.SetCompatibleCall<megamol::core::moldyn::VolumeDataCallDescription>();
    this->MakeSlotAvailable(&this->getDataSlot);

    this->getTFSlot.SetCompatibleCall<core::view::CallGetTransferFunctionDescription>();
    this->MakeSlotAvailable(&this->getTFSlot);

    //this->SetSlotUnavailable(&this->getMaterialSlot);
}

bool OSPRayStructuredVolume::readData(megamol::core::Call &call) {

    // fill material container
    this->processMaterial();

    // read Data, calculate  shape parameters, fill data vectors
    CallOSPRayStructure *os = dynamic_cast<CallOSPRayStructure*>(&call);
    megamol::core::moldyn::VolumeDataCall *cd = this->getDataSlot.CallAs<megamol::core::moldyn::VolumeDataCall>();

    this->structureContainer.dataChanged = false;
    if (cd == NULL) return false;
    if (os->getTime() > cd->FrameCount()) {
        cd->SetFrameID(cd->FrameCount() - 1, true); // isTimeForced flag set to true
    } else {
        cd->SetFrameID(os->getTime(), true); // isTimeForced flag set to true
    }
    if (this->datahash != cd->DataHash() || this->time != os->getTime() || this->InterfaceIsDirty()) {
        this->datahash = cd->DataHash();
        this->time = os->getTime();
        this->structureContainer.dataChanged = true;
    } else {
        return true;
    }

    if (!(*cd)(1)) return false;
    if (!(*cd)(0)) return false;

    unsigned int voxelCount = cd->VolumeDimension().GetDepth() * cd->VolumeDimension().GetHeight() * cd->VolumeDimension().GetWidth();
    unsigned int maxDim = vislib::math::Max<unsigned int>(cd->VolumeDimension().Depth(), vislib::math::Max<unsigned int>(cd->VolumeDimension().Height(), cd->VolumeDimension().Width()));
    float scale = 2.0f;
    std::vector<float> gridOrigin = { -0.5f*scale, -0.5f*scale, -0.5f*scale };
    std::vector<float> gridSpacing = { scale / (float)maxDim, scale / (float)maxDim, scale / (float)maxDim };
    std::vector<int> dimensions = { (int)cd->VolumeDimension().GetWidth(), (int)cd->VolumeDimension().GetHeight(), (int)cd->VolumeDimension().GetDepth() };

    std::vector<float> voxels(voxelCount);
    voxels.assign(cd->VoxelMap(), cd->VoxelMap() + voxelCount);

    // get color transfer function
    std::vector<float> rgb;
    std::vector<float> a;
    core::view::CallGetTransferFunction *cgtf = this->getTFSlot.CallAs<core::view::CallGetTransferFunction>();
    if (cgtf != NULL && ((*cgtf)())) {
        if (cgtf->OpenGLTextureFormat() == megamol::core::view::CallGetTransferFunction::TextureFormat::TEXTURE_FORMAT_RGBA) {
            auto numColors = cgtf->TextureSize() / 4;
            rgb.resize(3 * numColors);
            a.resize(numColors);
            auto texture = cgtf->GetTextureData();

            for (unsigned int i = 0; i < numColors; i++) {
                rgb[i + 0] = texture[i + 0];
                rgb[i + 1] = texture[i + 1];
                rgb[i + 2] = texture[i + 2];
                a[i]       = texture[i + 3];
            }
        } else {
            vislib::sys::Log::DefaultLog.WriteError("No color transfer function connected to OSPRayStructuredVolume module");
            return false;
        }
    }

    // Write stuff into the structureContainer

    this->structureContainer.type = structureTypeEnum::VOLUME;
    this->structureContainer.volumeType = volumeTypeEnum::STRUCTUREDVOLUME;
    this->structureContainer.volRepType = (volumeRepresentationType)this->repType.Param<core::param::EnumParam>()->Value();
    this->structureContainer.voxels = std::make_shared<std::vector<float>>(std::move(voxels));
    this->structureContainer.gridOrigin = std::make_shared<std::vector<float>>(std::move(gridOrigin));
    this->structureContainer.gridSpacing = std::make_shared<std::vector<float>>(std::move(gridSpacing));
    this->structureContainer.dimensions = std::make_shared<std::vector<int>>(std::move(dimensions));
    this->structureContainer.voxelCount = voxelCount;
    this->structureContainer.maxDim = maxDim;
    this->structureContainer.tfRGB = std::make_shared<std::vector<float>>(std::move(rgb));
    this->structureContainer.tfA = std::make_shared<std::vector<float>>(std::move(a));

    this->structureContainer.clippingBoxActive = this->clippingBoxActive.Param<core::param::BoolParam>()->Value();
    std::vector<float> cbl = { this->clippingBoxLower.Param<core::param::Vector3fParam>()->Value().GetX(), this->clippingBoxLower.Param<core::param::Vector3fParam>()->Value().GetY(), this->clippingBoxLower.Param<core::param::Vector3fParam>()->Value().GetZ() };
    this->structureContainer.clippingBoxLower = std::make_shared<std::vector<float>>(std::move(cbl));
    std::vector<float> cbu = { this->clippingBoxUpper.Param<core::param::Vector3fParam>()->Value().GetX(), this->clippingBoxUpper.Param<core::param::Vector3fParam>()->Value().GetY(), this->clippingBoxUpper.Param<core::param::Vector3fParam>()->Value().GetZ() };
    this->structureContainer.clippingBoxUpper = std::make_shared<std::vector<float>>(std::move(cbu));

    std::vector<float> sData = { this->sliceNormal.Param<core::param::Vector3fParam>()->Value().GetX(), this->sliceNormal.Param<core::param::Vector3fParam>()->Value().GetY(), this->sliceNormal.Param<core::param::Vector3fParam>()->Value().GetZ(), this->sliceDist.Param<core::param::FloatParam>()->Value() };
    this->structureContainer.sliceData = std::make_shared<std::vector<float>>(std::move(sData));

    std::vector<float> iValue = { this->IsoValue.Param<core::param::FloatParam>()->Value() };
    this->structureContainer.isoValue = std::make_shared<std::vector<float>>(std::move(iValue));

    return true;
}

OSPRayStructuredVolume::~OSPRayStructuredVolume() {
    this->Release();
}

bool OSPRayStructuredVolume::create() {
    return true;
}

void OSPRayStructuredVolume::release() {

}

/*
ospray::OSPRaySphereGeometry::InterfaceIsDirty()
*/
bool OSPRayStructuredVolume::InterfaceIsDirty() {
    if (
        this->clippingBoxActive.IsDirty() ||
        this->clippingBoxLower.IsDirty() ||
        this->clippingBoxUpper.IsDirty() ||
        this->sliceDist.IsDirty() ||
        this->sliceNormal.IsDirty() ||
        this->IsoValue.IsDirty() ||
        this->repType.IsDirty()
        ) {
        this->clippingBoxActive.ResetDirty();
        this->clippingBoxLower.ResetDirty();
        this->clippingBoxUpper.ResetDirty();
        this->sliceDist.ResetDirty();
        this->sliceNormal.ResetDirty();
        this->IsoValue.ResetDirty();
        this->repType.ResetDirty();
        return true;
    } else {
        return false;
    }
}

bool OSPRayStructuredVolume::getExtends(megamol::core::Call &call) {
    CallOSPRayStructure *os = dynamic_cast<CallOSPRayStructure*>(&call);
    megamol::core::moldyn::VolumeDataCall *cd = this->getDataSlot.CallAs<megamol::core::moldyn::VolumeDataCall>();

    if (cd == NULL) return false;
    if (os->getTime() > cd->FrameCount()) {
        cd->SetFrameID(cd->FrameCount() - 1, true);  // isTimeForced flag set to true
    } else {
        cd->SetFrameID(os->getTime(), true); // isTimeForced flag set to true
    }

    if (!(*cd)(1)) return false;

    this->extendContainer.boundingBox = std::make_shared<megamol::core::BoundingBoxes>(cd->AccessBoundingBoxes());
    this->extendContainer.timeFramesCount = cd->FrameCount();
    this->extendContainer.isValid = true;

    return true;
}<commit_msg>small fixes for OSPRayStructuredVolume<commit_after>/*
* OSPRayStructuredVolume.cpp
* Copyright (C) 2009-2017 by MegaMol Team
* Alle Rechte vorbehalten.
*/

#include "stdafx.h"
#include "OSPRayStructuredVolume.h"
#include "mmcore/moldyn/VolumeDataCall.h"
#include "mmcore/param/BoolParam.h"
#include "mmcore/param/Vector3fParam.h"
#include "mmcore/param/FloatParam.h"
#include "mmcore/param/EnumParam.h"
#include "vislib/sys/Log.h"
#include "mmcore/Call.h"
#include "mmcore/view/CallGetTransferFunction.h"

using namespace megamol::ospray;

OSPRayStructuredVolume::OSPRayStructuredVolume(void) :
    AbstractOSPRayStructure(),

    clippingBoxActive("ClippingBox::Active", "Activates the clipping Box"),
    clippingBoxLower("ClippingBox::Left", "Left corner of the clipping Box"),
    clippingBoxUpper("ClippingBox::Right", "Right corner of the clipping Box"),
    repType("Representation", "Activates one of the three different volume representations: Volume, Isosurfae, Slice"),
    sliceNormal("Slice::sliceNormal", "Direction of the slice normal"),
    sliceDist("Slice::sliceDist", "Distance of the slice in the direction of the normal vector"),
    IsoValue("Isosurface::Isovalue","Sets the isovalue of the isosurface"),
    getTFSlot("gettransferfunction", "Connects to a color transfer function module"),

    getDataSlot("getdata", "Connects to the data source")
 {
    core::param::EnumParam *rt = new core::param::EnumParam(VOLUMEREP);
    rt->SetTypePair(VOLUMEREP, "Volume");
    rt->SetTypePair(ISOSURFACE, "Isosurface");
    rt->SetTypePair(SLICE, "Slice");
    this->repType << rt;
    this->MakeSlotAvailable(&this->repType);

    this->clippingBoxActive << new core::param::BoolParam(false);
    this->clippingBoxLower << new core::param::Vector3fParam({ -5.0f, -5.0f, -5.0f });
    this->clippingBoxUpper << new core::param::Vector3fParam({ 0.0f, 5.0f, 5.0f });
    this->MakeSlotAvailable(&this->clippingBoxActive);
    this->MakeSlotAvailable(&this->clippingBoxLower);
    this->MakeSlotAvailable(&this->clippingBoxUpper);

    this->sliceNormal << new core::param::Vector3fParam({ 1.0f, 0.0f, 0.0f });
    this->sliceDist << new core::param::FloatParam(0.0f);
    this->MakeSlotAvailable(&this->sliceNormal);
    this->MakeSlotAvailable(&this->sliceDist);

    this->IsoValue << new core::param::FloatParam(0.0f);
    this->MakeSlotAvailable(&this->IsoValue);

    this->getDataSlot.SetCompatibleCall<megamol::core::moldyn::VolumeDataCallDescription>();
    this->MakeSlotAvailable(&this->getDataSlot);

    this->getTFSlot.SetCompatibleCall<core::view::CallGetTransferFunctionDescription>();
    this->MakeSlotAvailable(&this->getTFSlot);

    //this->SetSlotUnavailable(&this->getMaterialSlot);
}

bool OSPRayStructuredVolume::readData(megamol::core::Call &call) {

    // fill material container
    this->processMaterial();

    // read Data, calculate  shape parameters, fill data vectors
    CallOSPRayStructure *os = dynamic_cast<CallOSPRayStructure*>(&call);
    megamol::core::moldyn::VolumeDataCall *cd = this->getDataSlot.CallAs<megamol::core::moldyn::VolumeDataCall>();

    this->structureContainer.dataChanged = false;
    if (cd == NULL) return false;
    if (os->getTime() > cd->FrameCount()) {
        cd->SetFrameID(cd->FrameCount() - 1, true); // isTimeForced flag set to true
    } else {
        cd->SetFrameID(os->getTime(), true); // isTimeForced flag set to true
    }
    if (this->datahash != cd->DataHash() || this->time != os->getTime() || this->InterfaceIsDirty()) {
        this->datahash = cd->DataHash();
        this->time = os->getTime();
        this->structureContainer.dataChanged = true;
    } else {
        return true;
    }

    if (!(*cd)(1)) return false;
    if (!(*cd)(0)) return false;

    unsigned int voxelCount = cd->VolumeDimension().GetDepth() * cd->VolumeDimension().GetHeight() * cd->VolumeDimension().GetWidth();
    unsigned int maxDim = vislib::math::Max<unsigned int>(cd->VolumeDimension().Depth(), vislib::math::Max<unsigned int>(cd->VolumeDimension().Height(), cd->VolumeDimension().Width()));
    float scale = 2.0f;
    std::vector<float> gridOrigin = { -0.5f*scale, -0.5f*scale, -0.5f*scale };
    std::vector<float> gridSpacing = { scale / (float)maxDim, scale / (float)maxDim, scale / (float)maxDim };
    std::vector<int> dimensions = { (int)cd->VolumeDimension().GetWidth(), (int)cd->VolumeDimension().GetHeight(), (int)cd->VolumeDimension().GetDepth() };

    std::vector<float> voxels(voxelCount);
    voxels.assign(cd->VoxelMap(), cd->VoxelMap() + voxelCount);

    // get color transfer function
    std::vector<float> rgb;
    std::vector<float> a;
    core::view::CallGetTransferFunction *cgtf = this->getTFSlot.CallAs<core::view::CallGetTransferFunction>();
    if (cgtf != NULL && ((*cgtf)())) {
        if (cgtf->OpenGLTextureFormat() == megamol::core::view::CallGetTransferFunction::TextureFormat::TEXTURE_FORMAT_RGBA) {
            auto numColors = cgtf->TextureSize() / 4;
            rgb.resize(3 * numColors);
            a.resize(numColors);
            auto texture = cgtf->GetTextureData();

            for (unsigned int i = 0; i < numColors; i++) {
                rgb[i + 0] = texture[i + 0];
                rgb[i + 1] = texture[i + 1];
                rgb[i + 2] = texture[i + 2];
                a[i]       = texture[i + 3];
            }
        } else {
            vislib::sys::Log::DefaultLog.WriteError("No alpha channel in transfer function connected to OSPRayStructuredVolume module");
            return false;
        }
    } else {
        vislib::sys::Log::DefaultLog.WriteError(
            "No transfer function connected to OSPRayStructuredVolume module");
        return false;
    }

    // Write stuff into the structureContainer

    this->structureContainer.type = structureTypeEnum::VOLUME;
    this->structureContainer.volumeType = volumeTypeEnum::STRUCTUREDVOLUME;
    this->structureContainer.volRepType = (volumeRepresentationType)this->repType.Param<core::param::EnumParam>()->Value();
    this->structureContainer.voxels = std::make_shared<std::vector<float>>(std::move(voxels));
    this->structureContainer.gridOrigin = std::make_shared<std::vector<float>>(std::move(gridOrigin));
    this->structureContainer.gridSpacing = std::make_shared<std::vector<float>>(std::move(gridSpacing));
    this->structureContainer.dimensions = std::make_shared<std::vector<int>>(std::move(dimensions));
    this->structureContainer.voxelCount = voxelCount;
    this->structureContainer.maxDim = maxDim;
    this->structureContainer.valueRange = std::make_shared<std::pair<float, float>>(cd->MinimumDensity(), cd->MaximumDensity());
    this->structureContainer.tfRGB = std::make_shared<std::vector<float>>(std::move(rgb));
    this->structureContainer.tfA = std::make_shared<std::vector<float>>(std::move(a));

    this->structureContainer.clippingBoxActive = this->clippingBoxActive.Param<core::param::BoolParam>()->Value();
    std::vector<float> cbl = { this->clippingBoxLower.Param<core::param::Vector3fParam>()->Value().GetX(), this->clippingBoxLower.Param<core::param::Vector3fParam>()->Value().GetY(), this->clippingBoxLower.Param<core::param::Vector3fParam>()->Value().GetZ() };
    this->structureContainer.clippingBoxLower = std::make_shared<std::vector<float>>(std::move(cbl));
    std::vector<float> cbu = { this->clippingBoxUpper.Param<core::param::Vector3fParam>()->Value().GetX(), this->clippingBoxUpper.Param<core::param::Vector3fParam>()->Value().GetY(), this->clippingBoxUpper.Param<core::param::Vector3fParam>()->Value().GetZ() };
    this->structureContainer.clippingBoxUpper = std::make_shared<std::vector<float>>(std::move(cbu));

    std::vector<float> sData = { this->sliceNormal.Param<core::param::Vector3fParam>()->Value().GetX(), this->sliceNormal.Param<core::param::Vector3fParam>()->Value().GetY(), this->sliceNormal.Param<core::param::Vector3fParam>()->Value().GetZ(), this->sliceDist.Param<core::param::FloatParam>()->Value() };
    this->structureContainer.sliceData = std::make_shared<std::vector<float>>(std::move(sData));

    std::vector<float> iValue = { this->IsoValue.Param<core::param::FloatParam>()->Value() };
    this->structureContainer.isoValue = std::make_shared<std::vector<float>>(std::move(iValue));

    return true;
}

OSPRayStructuredVolume::~OSPRayStructuredVolume() {
    this->Release();
}

bool OSPRayStructuredVolume::create() {
    return true;
}

void OSPRayStructuredVolume::release() {

}

/*
ospray::OSPRaySphereGeometry::InterfaceIsDirty()
*/
bool OSPRayStructuredVolume::InterfaceIsDirty() {
    if (
        this->clippingBoxActive.IsDirty() ||
        this->clippingBoxLower.IsDirty() ||
        this->clippingBoxUpper.IsDirty() ||
        this->sliceDist.IsDirty() ||
        this->sliceNormal.IsDirty() ||
        this->IsoValue.IsDirty() ||
        this->repType.IsDirty()
        ) {
        this->clippingBoxActive.ResetDirty();
        this->clippingBoxLower.ResetDirty();
        this->clippingBoxUpper.ResetDirty();
        this->sliceDist.ResetDirty();
        this->sliceNormal.ResetDirty();
        this->IsoValue.ResetDirty();
        this->repType.ResetDirty();
        return true;
    } else {
        return false;
    }
}

bool OSPRayStructuredVolume::getExtends(megamol::core::Call &call) {
    CallOSPRayStructure *os = dynamic_cast<CallOSPRayStructure*>(&call);
    megamol::core::moldyn::VolumeDataCall *cd = this->getDataSlot.CallAs<megamol::core::moldyn::VolumeDataCall>();

    if (cd == NULL) return false;
    if (os->getTime() > cd->FrameCount()) {
        cd->SetFrameID(cd->FrameCount() - 1, true);  // isTimeForced flag set to true
    } else {
        cd->SetFrameID(os->getTime(), true); // isTimeForced flag set to true
    }

    if (!(*cd)(1)) return false;

    this->extendContainer.boundingBox = std::make_shared<megamol::core::BoundingBoxes>(cd->AccessBoundingBoxes());
    this->extendContainer.timeFramesCount = cd->FrameCount();
    this->extendContainer.isValid = true;

    return true;
}<|endoftext|>