<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkCellTypes.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * 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.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

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 AUTHORS 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 "vtkCellTypes.h"
#include "vtkObjectFactory.h"

//------------------------------------------------------------------------------
vtkCellTypes* vtkCellTypes::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkCellTypes");
  if(ret)
    {
    return (vtkCellTypes*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkCellTypes;
}

vtkCellTypes::vtkCellTypes ()
{

  this->TypeArray = NULL;
  this->LocationArray = NULL;
  this->Size = 0;
  this->MaxId = -1;
  this->Extend = 1000;
  this->Allocate(1000,this->Extend);

}

vtkCellTypes::~vtkCellTypes()
{

  if ( this->TypeArray )
    {
    this->TypeArray->UnRegister(this);
    this->TypeArray = NULL;
    }

  if ( this->LocationArray )
    {
    this->LocationArray->UnRegister(this);
    this->LocationArray = NULL;
    }

}

// Allocate memory for this array. Delete old storage only if necessary.
int vtkCellTypes::Allocate(int sz, int ext)
{

  this->Size = ( sz > 0 ? sz : 1);
  this->Extend = ( ext > 0 ? ext : 1);
  this->MaxId = -1;

  if ( this->TypeArray )
    {
    this->TypeArray->UnRegister(this);
    }
  this->TypeArray = vtkUnsignedCharArray::New();
  this->TypeArray->Allocate(sz,ext);
  this->TypeArray->Register(this);
  this->TypeArray->Delete();

  if ( this->LocationArray )
    {
    this->LocationArray->UnRegister(this);
    }
  this->LocationArray = vtkIntArray::New();
  this->LocationArray->Allocate(sz,ext);
  this->LocationArray->Register(this);
  this->LocationArray->Delete();

  return 1;
}

// Add a cell at specified id.
void vtkCellTypes::InsertCell(int cellId, unsigned char type, int loc)
{
  vtkDebugMacro(<<"Insert Cell id: " << cellId << " at location " << loc);
  TypeArray->InsertValue(cellId, type);

  LocationArray->InsertValue(cellId, loc);

  if ( cellId > this->MaxId )
    {
    this->MaxId = cellId;
    }
  return;
}

// Add a cell to the object in the next available slot.
int vtkCellTypes::InsertNextCell(unsigned char type, int loc)
{
  vtkDebugMacro(<<"Insert Next Cell " << type << " location " << loc);
  this->InsertCell (++this->MaxId,type,loc);
  return this->MaxId;
}

// Specify a group of cell types.
void vtkCellTypes::SetCellTypes(int ncells, vtkUnsignedCharArray *cellTypes, vtkIntArray *cellLocations)
{
  this->Size = ncells;
  this->TypeArray = cellTypes;
  this->LocationArray = cellLocations;
  this->Extend = 1;
  this->MaxId = -1;

}

// Reclaim any extra memory.
void vtkCellTypes::Squeeze()
{
  this->TypeArray->Squeeze();
  this->LocationArray->Squeeze();
}

// Initialize object without releasing memory.
void vtkCellTypes::Reset()
{
  this->MaxId = -1;
}

unsigned long vtkCellTypes::GetActualMemorySize()
{
  unsigned long size=0;

  if ( this->TypeArray )
    {
    size += this->TypeArray->GetActualMemorySize();
    }

  if ( this->LocationArray )
    {
    size += this->LocationArray->GetActualMemorySize();
    }

  return (unsigned long) ceil((float)size/1000.0); //kilobytes
}

void vtkCellTypes::DeepCopy(vtkCellTypes *src)
{
  if (this->TypeArray)
    {
      this->TypeArray->UnRegister(this);
      this->TypeArray = NULL;
    }
  if (src->TypeArray)
    {
      this->TypeArray = vtkUnsignedCharArray::New();
      this->TypeArray->DeepCopy(src->TypeArray);
      this->TypeArray->Register(this);
      this->TypeArray->Delete();
    }

  if (this->LocationArray)
    {
      this->LocationArray->UnRegister(this);
      this->LocationArray = NULL;
    }
  if (src->LocationArray)
    {
      this->LocationArray = vtkIntArray::New();
      this->LocationArray->DeepCopy(src->LocationArray);
      this->LocationArray->Register(this);
      this->LocationArray->Delete();
    }

  this->Allocate(src->Size, src->Extend);
  this->MaxId = src->MaxId;
}

<commit_msg>ERR: was not registering cellTypes and cellLocations.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkCellTypes.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * 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.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

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 AUTHORS 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 "vtkCellTypes.h"
#include "vtkObjectFactory.h"

//------------------------------------------------------------------------------
vtkCellTypes* vtkCellTypes::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkCellTypes");
  if(ret)
    {
    return (vtkCellTypes*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkCellTypes;
}

vtkCellTypes::vtkCellTypes ()
{

  this->TypeArray = NULL;
  this->LocationArray = NULL;
  this->Size = 0;
  this->MaxId = -1;
  this->Extend = 1000;
  this->Allocate(1000,this->Extend);

}

vtkCellTypes::~vtkCellTypes()
{

  if ( this->TypeArray )
    {
    this->TypeArray->UnRegister(this);
    this->TypeArray = NULL;
    }

  if ( this->LocationArray )
    {
    this->LocationArray->UnRegister(this);
    this->LocationArray = NULL;
    }

}

// Allocate memory for this array. Delete old storage only if necessary.
int vtkCellTypes::Allocate(int sz, int ext)
{

  this->Size = ( sz > 0 ? sz : 1);
  this->Extend = ( ext > 0 ? ext : 1);
  this->MaxId = -1;

  if ( this->TypeArray )
    {
    this->TypeArray->UnRegister(this);
    }
  this->TypeArray = vtkUnsignedCharArray::New();
  this->TypeArray->Allocate(sz,ext);
  this->TypeArray->Register(this);
  this->TypeArray->Delete();

  if ( this->LocationArray )
    {
    this->LocationArray->UnRegister(this);
    }
  this->LocationArray = vtkIntArray::New();
  this->LocationArray->Allocate(sz,ext);
  this->LocationArray->Register(this);
  this->LocationArray->Delete();

  return 1;
}

// Add a cell at specified id.
void vtkCellTypes::InsertCell(int cellId, unsigned char type, int loc)
{
  vtkDebugMacro(<<"Insert Cell id: " << cellId << " at location " << loc);
  TypeArray->InsertValue(cellId, type);

  LocationArray->InsertValue(cellId, loc);

  if ( cellId > this->MaxId )
    {
    this->MaxId = cellId;
    }
  return;
}

// Add a cell to the object in the next available slot.
int vtkCellTypes::InsertNextCell(unsigned char type, int loc)
{
  vtkDebugMacro(<<"Insert Next Cell " << type << " location " << loc);
  this->InsertCell (++this->MaxId,type,loc);
  return this->MaxId;
}

// Specify a group of cell types.
void vtkCellTypes::SetCellTypes(int ncells, vtkUnsignedCharArray *cellTypes, vtkIntArray *cellLocations)
{
  this->Size = ncells;

  this->TypeArray = cellTypes;
  cellTypes->Register(this);

  this->LocationArray = cellLocations;
  cellLocations->Register(this);
  this->Extend = 1;
  this->MaxId = -1;

}

// Reclaim any extra memory.
void vtkCellTypes::Squeeze()
{
  this->TypeArray->Squeeze();
  this->LocationArray->Squeeze();
}

// Initialize object without releasing memory.
void vtkCellTypes::Reset()
{
  this->MaxId = -1;
}

unsigned long vtkCellTypes::GetActualMemorySize()
{
  unsigned long size=0;

  if ( this->TypeArray )
    {
    size += this->TypeArray->GetActualMemorySize();
    }

  if ( this->LocationArray )
    {
    size += this->LocationArray->GetActualMemorySize();
    }

  return (unsigned long) ceil((float)size/1000.0); //kilobytes
}

void vtkCellTypes::DeepCopy(vtkCellTypes *src)
{
  if (this->TypeArray)
    {
      this->TypeArray->UnRegister(this);
      this->TypeArray = NULL;
    }
  if (src->TypeArray)
    {
      this->TypeArray = vtkUnsignedCharArray::New();
      this->TypeArray->DeepCopy(src->TypeArray);
      this->TypeArray->Register(this);
      this->TypeArray->Delete();
    }

  if (this->LocationArray)
    {
      this->LocationArray->UnRegister(this);
      this->LocationArray = NULL;
    }
  if (src->LocationArray)
    {
      this->LocationArray = vtkIntArray::New();
      this->LocationArray->DeepCopy(src->LocationArray);
      this->LocationArray->Register(this);
      this->LocationArray->Delete();
    }

  this->Allocate(src->Size, src->Extend);
  this->MaxId = src->MaxId;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: b3dvector.hxx,v $
 * $Revision: 1.11 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _BGFX_VECTOR_B3DVECTOR_HXX
#define _BGFX_VECTOR_B3DVECTOR_HXX

#include <basegfx/tuple/b3dtuple.hxx>

namespace basegfx
{
    // predeclaration
    class B3DHomMatrix;

    /** Base Point class with three double values

        This class derives all operators and common handling for
        a 3D data class from B3DTuple. All necessary extensions
        which are special for 3D Vectors are added here.

        @see B3DTuple
    */
    class B3DVector : public ::basegfx::B3DTuple
    {
    public:
        /** Create a 3D Vector

            The vector is initialized to (0.0, 0.0, 0.0)
        */
        B3DVector()
        :   B3DTuple()
        {}

        /** Create a 3D Vector

            @param fX
            This parameter is used to initialize the X-coordinate
            of the 3D Vector.

            @param fY
            This parameter is used to initialize the Y-coordinate
            of the 3D Vector.

            @param fZ
            This parameter is used to initialize the Z-coordinate
            of the 3D Vector.
        */
        B3DVector(double fX, double fY, double fZ)
        :   B3DTuple(fX, fY, fZ)
        {}

        /** Create a copy of a 3D Vector

            @param rVec
            The 3D Vector which will be copied.
        */
        B3DVector(const B3DVector& rVec)
        :   B3DTuple(rVec)
        {}

        /** constructor with tuple to allow copy-constructing
            from B3DTuple-based classes
        */
        B3DVector(const ::basegfx::B3DTuple& rTuple)
        :   B3DTuple(rTuple)
        {}

        ~B3DVector()
        {}

        /** *=operator to allow usage from B3DVector, too
        */
        B3DVector& operator*=( const B3DVector& rPnt )
        {
            mfX *= rPnt.mfX;
            mfY *= rPnt.mfY;
            mfZ *= rPnt.mfZ;
            return *this;
        }

        /** *=operator to allow usage from B3DVector, too
        */
        B3DVector& operator*=(double t)
        {
            mfX *= t;
            mfY *= t;
            mfZ *= t;
            return *this;
        }

        /** assignment operator to allow assigning the results
            of B3DTuple calculations
        */
        B3DVector& operator=( const ::basegfx::B3DTuple& rVec )
        {
            mfX = rVec.getX();
            mfY = rVec.getY();
            mfZ = rVec.getZ();
            return *this;
        }

        /** Calculate the length of this 3D Vector

            @return The Length of the 3D Vector
        */
        double getLength(void) const
        {
            double fLen(scalar(*this));
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Calculate the length in the XY-Plane for this 3D Vector

            @return The XY-Plane Length of the 3D Vector
        */
        double getXYLength(void) const
        {
            double fLen((mfX * mfX) + (mfY * mfY));
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Calculate the length in the XZ-Plane for this 3D Vector

            @return The XZ-Plane Length of the 3D Vector
        */
        double getXZLength(void) const
        {
            double fLen((mfX * mfX) + (mfZ * mfZ)); // #i73040#
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Calculate the length in the YZ-Plane for this 3D Vector

            @return The YZ-Plane Length of the 3D Vector
        */
        double getYZLength(void) const
        {
            double fLen((mfY * mfY) + (mfZ * mfZ));
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Set the length of this 3D Vector

            @param fLen
            The to be achieved length of the 3D Vector
        */
        B3DVector& setLength(double fLen)
        {
            double fLenNow(scalar(*this));

            if(!::basegfx::fTools::equalZero(fLenNow))
            {
                const double fOne(1.0);

                if(!::basegfx::fTools::equal(fOne, fLenNow))
                {
                    fLen /= sqrt(fLenNow);
                }

                mfX *= fLen;
                mfY *= fLen;
                mfZ *= fLen;
            }

            return *this;
        }

        /** Normalize this 3D Vector

            The length of the 3D Vector is set to 1.0
        */
        B3DVector& normalize();

        /** Test if this 3D Vector is normalized

            @return
            true if lenth of vector is equal to 1.0
            false else
        */
        bool isNormalized() const
        {
            const double fOne(1.0);
            const double fScalar(scalar(*this));

            return (::basegfx::fTools::equal(fOne, fScalar));
        }

        /** get a 3D Vector which is perpendicular to this and a given 3D Vector

            @attention This only works if this and the given 3D Vector are
            both normalized.

            @param rNormalizedVec
            A normalized 3D Vector.

            @return
            A 3D Vector perpendicular to this and the given one
        */
        B3DVector getPerpendicular(const B3DVector& rNormalizedVec) const;

        /** get the projection of this Vector on the given Plane

            @attention This only works if the given 3D Vector defining
            the Plane is normalized.

            @param rNormalizedPlane
            A normalized 3D Vector defining a Plane.

            @return
            The projected 3D Vector
        */
        B3DVector getProjectionOnPlane(const B3DVector& rNormalizedPlane) const;

        /** Calculate the Scalar product

            This method calculates the Scalar product between this
            and the given 3D Vector.

            @param rVec
            A second 3D Vector.

            @return
            The Scalar Product of two 3D Vectors
        */
        double scalar(const B3DVector& rVec) const
        {
            return ((mfX * rVec.mfX) + (mfY * rVec.mfY) + (mfZ * rVec.mfZ));
        }

        /** Transform vector by given transformation matrix.

            Since this is a vector, translational components of the
            matrix are disregarded.
        */
        B3DVector& operator*=( const B3DHomMatrix& rMat );

        static const B3DVector& getEmptyVector()
        {
            return (const B3DVector&) ::basegfx::B3DTuple::getEmptyTuple();
        }
    };

    // external operators
    //////////////////////////////////////////////////////////////////////////

    /** get a 3D Vector which is in 2D (ignoring
        the Z-Coordinate) perpendicular to a given 3D Vector

        @attention This only works if the given 3D Vector is normalized.

        @param rNormalizedVec
        A normalized 3D Vector.

        @return
        A 3D Vector perpendicular to the given one in X,Y (2D).
    */
    inline B3DVector getPerpendicular2D( const B3DVector& rNormalizedVec )
    {
        B3DVector aPerpendicular(-rNormalizedVec.getY(), rNormalizedVec.getX(), rNormalizedVec.getZ());
        return aPerpendicular;
    }

    /** Transform vector by given transformation matrix.

        Since this is a vector, translational components of the
        matrix are disregarded.
    */
    B3DVector operator*( const B3DHomMatrix& rMat, const B3DVector& rVec );

    /** Calculate the Cross Product of two 3D Vectors

        @param rVecA
        A first 3D Vector.

        @param rVecB
        A second 3D Vector.

        @return
        The Cross Product of both 3D Vectors
    */
    inline B3DVector cross(const B3DVector& rVecA, const B3DVector& rVecB)
    {
        B3DVector aVec(
            rVecA.getY() * rVecB.getZ() - rVecA.getZ() * rVecB.getY(),
            rVecA.getZ() * rVecB.getX() - rVecA.getX() * rVecB.getZ(),
            rVecA.getX() * rVecB.getY() - rVecA.getY() * rVecB.getX());
        return aVec;
    }
} // end of namespace basegfx

#endif /* _BGFX_VECTOR_B3DVECTOR_HXX */
<commit_msg>INTEGRATION: CWS aw033 (1.9.2); FILE MERGED 2008/05/14 14:43:16 aw 1.9.2.5: RESYNC: (1.10-1.11); FILE MERGED 2008/05/14 09:16:13 aw 1.9.2.4: #i39532# aw033 progresses from git 2008/04/16 04:50:23 aw 1.9.2.3: #i39532# moved 3D default raster converter to basegfx 2007/03/20 15:21:24 aw 1.9.2.2: RESYNC: (1.9-1.10); FILE MERGED 2006/05/12 11:39:25 aw 1.9.2.1: code changes for primitive support<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: b3dvector.hxx,v $
 * $Revision: 1.12 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _BGFX_VECTOR_B3DVECTOR_HXX
#define _BGFX_VECTOR_B3DVECTOR_HXX

#include <basegfx/tuple/b3dtuple.hxx>

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

namespace basegfx
{
    // predeclaration
    class B3DHomMatrix;

    /** Base Point class with three double values

        This class derives all operators and common handling for
        a 3D data class from B3DTuple. All necessary extensions
        which are special for 3D Vectors are added here.

        @see B3DTuple
    */
    class B3DVector : public ::basegfx::B3DTuple
    {
    public:
        /** Create a 3D Vector

            The vector is initialized to (0.0, 0.0, 0.0)
        */
        B3DVector()
        :   B3DTuple()
        {}

        /** Create a 3D Vector

            @param fX
            This parameter is used to initialize the X-coordinate
            of the 3D Vector.

            @param fY
            This parameter is used to initialize the Y-coordinate
            of the 3D Vector.

            @param fZ
            This parameter is used to initialize the Z-coordinate
            of the 3D Vector.
        */
        B3DVector(double fX, double fY, double fZ)
        :   B3DTuple(fX, fY, fZ)
        {}

        /** Create a copy of a 3D Vector

            @param rVec
            The 3D Vector which will be copied.
        */
        B3DVector(const B3DVector& rVec)
        :   B3DTuple(rVec)
        {}

        /** constructor with tuple to allow copy-constructing
            from B3DTuple-based classes
        */
        B3DVector(const ::basegfx::B3DTuple& rTuple)
        :   B3DTuple(rTuple)
        {}

        ~B3DVector()
        {}

        /** *=operator to allow usage from B3DVector, too
        */
        B3DVector& operator*=( const B3DVector& rPnt )
        {
            mfX *= rPnt.mfX;
            mfY *= rPnt.mfY;
            mfZ *= rPnt.mfZ;
            return *this;
        }

        /** *=operator to allow usage from B3DVector, too
        */
        B3DVector& operator*=(double t)
        {
            mfX *= t;
            mfY *= t;
            mfZ *= t;
            return *this;
        }

        /** assignment operator to allow assigning the results
            of B3DTuple calculations
        */
        B3DVector& operator=( const ::basegfx::B3DTuple& rVec )
        {
            mfX = rVec.getX();
            mfY = rVec.getY();
            mfZ = rVec.getZ();
            return *this;
        }

        /** Calculate the length of this 3D Vector

            @return The Length of the 3D Vector
        */
        double getLength(void) const
        {
            double fLen(scalar(*this));
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Calculate the length in the XY-Plane for this 3D Vector

            @return The XY-Plane Length of the 3D Vector
        */
        double getXYLength(void) const
        {
            double fLen((mfX * mfX) + (mfY * mfY));
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Calculate the length in the XZ-Plane for this 3D Vector

            @return The XZ-Plane Length of the 3D Vector
        */
        double getXZLength(void) const
        {
            double fLen((mfX * mfX) + (mfZ * mfZ)); // #i73040#
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Calculate the length in the YZ-Plane for this 3D Vector

            @return The YZ-Plane Length of the 3D Vector
        */
        double getYZLength(void) const
        {
            double fLen((mfY * mfY) + (mfZ * mfZ));
            if((0.0 == fLen) || (1.0 == fLen))
                return fLen;
            return sqrt(fLen);
        }

        /** Set the length of this 3D Vector

            @param fLen
            The to be achieved length of the 3D Vector
        */
        B3DVector& setLength(double fLen)
        {
            double fLenNow(scalar(*this));

            if(!::basegfx::fTools::equalZero(fLenNow))
            {
                const double fOne(1.0);

                if(!::basegfx::fTools::equal(fOne, fLenNow))
                {
                    fLen /= sqrt(fLenNow);
                }

                mfX *= fLen;
                mfY *= fLen;
                mfZ *= fLen;
            }

            return *this;
        }

        /** Normalize this 3D Vector

            The length of the 3D Vector is set to 1.0
        */
        B3DVector& normalize();

        /** Test if this 3D Vector is normalized

            @return
            true if lenth of vector is equal to 1.0
            false else
        */
        bool isNormalized() const
        {
            const double fOne(1.0);
            const double fScalar(scalar(*this));

            return (::basegfx::fTools::equal(fOne, fScalar));
        }

        /** get a 3D Vector which is perpendicular to this and a given 3D Vector

            @attention This only works if this and the given 3D Vector are
            both normalized.

            @param rNormalizedVec
            A normalized 3D Vector.

            @return
            A 3D Vector perpendicular to this and the given one
        */
        B3DVector getPerpendicular(const B3DVector& rNormalizedVec) const;

        /** get the projection of this Vector on the given Plane

            @attention This only works if the given 3D Vector defining
            the Plane is normalized.

            @param rNormalizedPlane
            A normalized 3D Vector defining a Plane.

            @return
            The projected 3D Vector
        */
        B3DVector getProjectionOnPlane(const B3DVector& rNormalizedPlane) const;

        /** Calculate the Scalar product

            This method calculates the Scalar product between this
            and the given 3D Vector.

            @param rVec
            A second 3D Vector.

            @return
            The Scalar Product of two 3D Vectors
        */
        double scalar(const B3DVector& rVec) const
        {
            return ((mfX * rVec.mfX) + (mfY * rVec.mfY) + (mfZ * rVec.mfZ));
        }

        /** Transform vector by given transformation matrix.

            Since this is a vector, translational components of the
            matrix are disregarded.
        */
        B3DVector& operator*=( const B3DHomMatrix& rMat );

        static const B3DVector& getEmptyVector()
        {
            return (const B3DVector&) ::basegfx::B3DTuple::getEmptyTuple();
        }
    };

    // external operators
    //////////////////////////////////////////////////////////////////////////

    /** get a 3D Vector which is in 2D (ignoring
        the Z-Coordinate) perpendicular to a given 3D Vector

        @attention This only works if the given 3D Vector is normalized.

        @param rNormalizedVec
        A normalized 3D Vector.

        @return
        A 3D Vector perpendicular to the given one in X,Y (2D).
    */
    inline B3DVector getPerpendicular2D( const B3DVector& rNormalizedVec )
    {
        B3DVector aPerpendicular(-rNormalizedVec.getY(), rNormalizedVec.getX(), rNormalizedVec.getZ());
        return aPerpendicular;
    }

    /** Transform vector by given transformation matrix.

        Since this is a vector, translational components of the
        matrix are disregarded.
    */
    B3DVector operator*( const B3DHomMatrix& rMat, const B3DVector& rVec );

    /** Calculate the Cross Product of two 3D Vectors

        @param rVecA
        A first 3D Vector.

        @param rVecB
        A second 3D Vector.

        @return
        The Cross Product of both 3D Vectors
    */
    inline B3DVector cross(const B3DVector& rVecA, const B3DVector& rVecB)
    {
        B3DVector aVec(
            rVecA.getY() * rVecB.getZ() - rVecA.getZ() * rVecB.getY(),
            rVecA.getZ() * rVecB.getX() - rVecA.getX() * rVecB.getZ(),
            rVecA.getX() * rVecB.getY() - rVecA.getY() * rVecB.getX());
        return aVec;
    }
} // end of namespace basegfx

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

#endif /* _BGFX_VECTOR_B3DVECTOR_HXX */
<|endoftext|>


<commit_before>class Solution {
protected:
    string calculateEncodedString(const string& str) {
        const int n = str.length();
        string ans;
        for (int i = 1; i < n; ++i) {
            int last = (int)str[i - 1];
            int current = (int)str[i];
            int diff = 0;
            if (current >= last) {
                diff = current - last;
            } else {
                diff = 26 - (last - current);
            }
            ans += (char)('a' + diff);
        }
        return ans;
    }
public:
    vector<vector<string>> groupStrings(vector<string>& strings) {
        unordered_map<string, vector<int>> M;
        const int n = strings.size();
        for (int i = 0; i < n; ++i) {
            string encoded = calculateEncodedString(strings[i]);
            M[encoded].push_back(i);
        }

        vector<vector<string>> ans;

        for (auto it = M.begin(); it != M.end(); ++it) {
            vector<string> seq;
            const vector<int>& indices = it->second;
            for (int i = 0; i < indices.size(); ++i) {
                seq.push_back(strings[indices[i]]);
            }
            sort(seq.begin(), seq.end());
            ans.push_back(seq);
        }
        return ans;
   }
};<commit_msg>added solutions<commit_after>class Solution {
private:
    string getOriginalString(const string& word) {
        if (word.empty()) {
            return "";
        }
        int diff = word[0] - 'a';
        string result = word;
        for (int i = 0; i < result.length(); ++i) {
            result[i] = shift(result[i], 26 - diff);
        }
        return result;
    }

    char shift(char ch, int diff) {
        if (diff > 0) {
            return 'a' + (((int)(ch - 'a') + diff) % 26);
        }

        return shift(ch, 26 - (diff % 26));
    }
public:
    vector<vector<string>> groupStrings(vector<string>& strings) {
        unordered_map<string, vector<string>> dict;
        for (int i = 0; i < strings.size(); ++i) {
            const string& str = strings[i];
            dict[getOriginalString(str)].push_back(str);
        }
        vector<vector<string>> result;
        for (auto it = dict.begin(); it != dict.end(); ++it) {
            result.push_back(it->second);
        }
        return result;
    }
};<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkTimeStamp.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
//
// Initialize static member
//
#include "vtkTimeStamp.h"

#include "vtkCriticalSection.h"
#include "vtkObjectFactory.h"
#include "vtkWindows.h"
#if defined(__APPLE__)
  #include <libkern/OSAtomic.h>
#endif

//-------------------------------------------------------------------------
vtkTimeStamp* vtkTimeStamp::New()
{
  // If the factory was unable to create the object, then create it here.
  return new vtkTimeStamp;
}

//-------------------------------------------------------------------------
void vtkTimeStamp::Modified()
{
// Windows optimization
#if defined(WIN32) || defined(_WIN32)
  static LONG vtkTimeStampTime = 0;
  this->ModifiedTime = (unsigned long)InterlockedIncrement(&vtkTimeStampTime);

// Mac optimization (64 bit)
#elif defined(__APPLE__) && __LP64__
  // "ModifiedTime" is "unsigned long", a type that changess sizes
  // depending on architecture.  The atomic increment is safe, since it
  // operates on a variable of the exact type needed.  The cast does not
  // change the size, but does change signedness, which is not ideal.
  static volatile int64_t vtkTimeStampTime = 0;
  this->ModifiedTime = (unsigned long)OSAtomicIncrement64Barrier(&vtkTimeStampTime);

// Mac optimization (32 bit, 10.4 or later)
#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1040)
  static volatile int32_t vtkTimeStampTime = 0;
  this->ModifiedTime = (unsigned long)OSAtomicIncrement32Barrier(&vtkTimeStampTime);

// General case
#else
  static unsigned long vtkTimeStampTime = 0;
  static vtkSimpleCriticalSection TimeStampCritSec;

  TimeStampCritSec.Lock();
  this->ModifiedTime = ++vtkTimeStampTime;
  TimeStampCritSec.Unlock();
#endif
}
<commit_msg>COMP: fixed compiler error in vtkTimeStamp with pre-10.4 OS X headers, ie midworld.kitware dashboard<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkTimeStamp.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
//
// Initialize static member
//
#include "vtkTimeStamp.h"

#include "vtkCriticalSection.h"
#include "vtkObjectFactory.h"
#include "vtkWindows.h"
#if defined(__APPLE__) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1040)
  #include <libkern/OSAtomic.h>
#endif

//-------------------------------------------------------------------------
vtkTimeStamp* vtkTimeStamp::New()
{
  // If the factory was unable to create the object, then create it here.
  return new vtkTimeStamp;
}

//-------------------------------------------------------------------------
void vtkTimeStamp::Modified()
{
// Windows optimization
#if defined(WIN32) || defined(_WIN32)
  static LONG vtkTimeStampTime = 0;
  this->ModifiedTime = (unsigned long)InterlockedIncrement(&vtkTimeStampTime);

// Mac optimization (64 bit)
#elif defined(__APPLE__) && __LP64__
  // "ModifiedTime" is "unsigned long", a type that changess sizes
  // depending on architecture.  The atomic increment is safe, since it
  // operates on a variable of the exact type needed.  The cast does not
  // change the size, but does change signedness, which is not ideal.
  static volatile int64_t vtkTimeStampTime = 0;
  this->ModifiedTime = (unsigned long)OSAtomicIncrement64Barrier(&vtkTimeStampTime);

// Mac optimization (32 bit, 10.4 or later)
#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1040)
  static volatile int32_t vtkTimeStampTime = 0;
  this->ModifiedTime = (unsigned long)OSAtomicIncrement32Barrier(&vtkTimeStampTime);

// General case
#else
  static unsigned long vtkTimeStampTime = 0;
  static vtkSimpleCriticalSection TimeStampCritSec;

  TimeStampCritSec.Lock();
  this->ModifiedTime = ++vtkTimeStampTime;
  TimeStampCritSec.Unlock();
#endif
}
<|endoftext|>


<commit_before>/*
 * Autoconnect.cpp
 *
 *  Created on: Apr 6, 2016
 *      Author: James Hong
 */

#include <scan/AutoConnect.h>

#include <bluetooth/bluetooth.h>
#include <boost/thread/lock_types.hpp>
#include <boost/thread/pthread/shared_mutex.hpp>
#include <cstring>
#include <iostream>
#include <fstream>
#include <memory>
#include <unistd.h>
#include <utility>

#include "Beetle.h"
#include "ble/helper.h"
#include "device/socket/LEPeripheral.h"
#include "Debug.h"
#include "Device.h"
#include "sync/ThreadPool.h"
#include "util/file.h"
#include "util/trim.h"

AutoConnect::AutoConnect(Beetle &beetle, bool connectAll_, double minBackoff_, std::string autoConnectWhitelist) :
		beetle { beetle } {
	connectAll = connectAll_;
	minBackoff = minBackoff_;

	if (autoConnectWhitelist != "") {
		if (!file_exists(autoConnectWhitelist)) {
			throw std::invalid_argument("whitelist file does not exist - " + autoConnectWhitelist);
		}

		std::cout << "whitelist file: " << autoConnectWhitelist << std::endl;

		std::ifstream ifs(autoConnectWhitelist);
		std::string line;
		while (std::getline(ifs, line)) {
			std::string addr = trimmed(line);
			if (addr.find('#') != addr.npos) {
				addr = addr.substr(0, addr.find('#'));
			}

			trim(addr);
			if (addr == "") {
				continue;
			}

			if (is_bd_addr(addr)) {
				bdaddr_t bdaddr;
				str2ba(addr.c_str(), &bdaddr);
				whitelist.insert(ba2str_cpp(bdaddr));
				std::cout << "  " << ba2str_cpp(bdaddr) << std::endl;
			} else {
				throw ParseExecption("invalid address in whitelist file - " + line);
			}
		}
	}
}

AutoConnect::~AutoConnect() {

}

std::function<void()> AutoConnect::getDaemon() {
	return [this] {
		time_t now = time(NULL);

		std::lock_guard<std::mutex> lg(lastAttemptMutex);
		for (auto it = lastAttempt.cbegin(); it != lastAttempt.cend();) {
			if (difftime(now, it->second) > minBackoff) {
				if (debug_scan) {
					pdebug("can try connecting to '" + it->first + "' again");
				}
				lastAttempt.erase(it++);
			} else {
				++it;
			}
		}
	};
}

DiscoveryHandler AutoConnect::getDiscoveryHandler() {
	return [this](peripheral_info_t info) {
		std::string addr = ba2str_cpp(info.bdaddr);

		std::unique_lock<std::mutex> connectLk(connectMutex, std::try_to_lock);
		if (connectLk.owns_lock()) {
			/*
			 * Consult whitelist
			 */
			if (!connectAll && whitelist.find(addr) == whitelist.end()) {
				return;
			}

			/*
			 * Have we tried to connect recently?
			 */
			std::unique_lock<std::mutex> lastAttemptLk(lastAttemptMutex);
			if (lastAttempt.find(addr) != lastAttempt.end()) {
				return;
			} else {
				time_t now = time(NULL);
				lastAttempt[addr] = now;
				lastAttemptLk.unlock();
			}

			/*
			 * Are we already connected? This is needed to support some peripherals
			 * which keep advertising even after connecting.
			 */
			boost::shared_lock<boost::shared_mutex> devicesLk(beetle.devicesMutex);
			for (auto &kv : beetle.devices) {
				std::shared_ptr<LEPeripheral> le = NULL;
				if (kv.second->getType() == Device::LE_PERIPHERAL &&
						(le = std::dynamic_pointer_cast<LEPeripheral>(kv.second))) {
					if (le->getAddrType() == info.bdaddrType &&
							memcmp(le->getBdaddr().b, info.bdaddr.b, sizeof(bdaddr_t))) {
						return;
					}
				}
			}
			devicesLk.unlock();

			if (debug_scan) {
				pdebug("trying to auto-connect to " + addr);
			}

			beetle.workers.schedule([this, info]{
				std::lock_guard<std::mutex> connectLg(connectMutex, std::adopt_lock);
				connect(info, true);
			});

			// do not unlock
			connectLk.release();
		} else {
			if (debug_scan) {
				pdebug("auto-connect in progress, skipping");
			}
		}
	};
}

void AutoConnect::connect(peripheral_info_t info, bool discover) {
	std::shared_ptr<VirtualDevice> device = NULL;
	try {
		device = std::make_shared<LEPeripheral>(beetle, info.bdaddr, info.bdaddrType);

		boost::shared_lock<boost::shared_mutex> devicesLk;
		beetle.addDevice(device, devicesLk);

		device->start(discover);

		if (debug_scan) {
			pdebug("auto-connected to " + device->getName());
			pdebug(device->getName() + " has handle range [0," + std::to_string(device->getHighestHandle()) + "]");
		}
	} catch (DeviceException& e) {
		if (debug) {
			pexcept(e);
			pdebug("failed to connect to " + ba2str_cpp(info.bdaddr));
		}
		if (device) {
			beetle.removeDevice(device->getId());
		}
	}
}
<commit_msg>Fix bug in address comparison<commit_after>/*
 * Autoconnect.cpp
 *
 *  Created on: Apr 6, 2016
 *      Author: James Hong
 */

#include <scan/AutoConnect.h>

#include <bluetooth/bluetooth.h>
#include <boost/thread/lock_types.hpp>
#include <boost/thread/pthread/shared_mutex.hpp>
#include <cstring>
#include <iostream>
#include <fstream>
#include <memory>
#include <unistd.h>
#include <utility>

#include "Beetle.h"
#include "ble/helper.h"
#include "device/socket/LEPeripheral.h"
#include "Debug.h"
#include "Device.h"
#include "sync/ThreadPool.h"
#include "util/file.h"
#include "util/trim.h"

AutoConnect::AutoConnect(Beetle &beetle, bool connectAll_, double minBackoff_, std::string autoConnectWhitelist) :
		beetle { beetle } {
	connectAll = connectAll_;
	minBackoff = minBackoff_;

	if (autoConnectWhitelist != "") {
		if (!file_exists(autoConnectWhitelist)) {
			throw std::invalid_argument("whitelist file does not exist - " + autoConnectWhitelist);
		}

		std::cout << "whitelist file: " << autoConnectWhitelist << std::endl;

		std::ifstream ifs(autoConnectWhitelist);
		std::string line;
		while (std::getline(ifs, line)) {
			std::string addr = trimmed(line);
			if (addr.find('#') != addr.npos) {
				addr = addr.substr(0, addr.find('#'));
			}

			trim(addr);
			if (addr == "") {
				continue;
			}

			if (is_bd_addr(addr)) {
				bdaddr_t bdaddr;
				str2ba(addr.c_str(), &bdaddr);
				whitelist.insert(ba2str_cpp(bdaddr));
			} else {
				throw ParseExecption("invalid address in whitelist file - " + line);
			}
		}

		for (auto &addr : whitelist) {
			std::cout << "  " << addr << std::endl;
		}
	}
}

AutoConnect::~AutoConnect() {

}

std::function<void()> AutoConnect::getDaemon() {
	return [this] {
		time_t now = time(NULL);

		std::lock_guard<std::mutex> lg(lastAttemptMutex);
		for (auto it = lastAttempt.cbegin(); it != lastAttempt.cend();) {
			if (difftime(now, it->second) > minBackoff) {
				if (debug_scan) {
					pdebug("can try connecting to '" + it->first + "' again");
				}
				lastAttempt.erase(it++);
			} else {
				++it;
			}
		}
	};
}

DiscoveryHandler AutoConnect::getDiscoveryHandler() {
	return [this](peripheral_info_t info) {
		std::string addr = ba2str_cpp(info.bdaddr);

		std::unique_lock<std::mutex> connectLk(connectMutex, std::try_to_lock);
		if (connectLk.owns_lock()) {
			/*
			 * Consult whitelist
			 */
			if (!connectAll && whitelist.find(addr) == whitelist.end()) {
				if (debug_scan) {
					std::stringstream ss;
					ss << "whitelist does not contain " << addr;
					pdebug(ss.str());
				}
				return;
			}

			/*
			 * Have we tried to connect recently?
			 */
			std::unique_lock<std::mutex> lastAttemptLk(lastAttemptMutex);
			if (lastAttempt.find(addr) != lastAttempt.end()) {
				if (debug_scan) {
					std::stringstream ss;
					ss << "recently tried connecting to " << addr;
					pdebug(ss.str());
				}
				return;
			} else {
				time_t now = time(NULL);
				lastAttempt[addr] = now;
				lastAttemptLk.unlock();
			}

			/*
			 * Are we already connected? This is needed to support some peripherals
			 * which keep advertising even after connecting.
			 */
			boost::shared_lock<boost::shared_mutex> devicesLk(beetle.devicesMutex);
			for (auto &kv : beetle.devices) {
				std::shared_ptr<LEPeripheral> le = NULL;
				if (kv.second->getType() == Device::LE_PERIPHERAL &&
						(le = std::dynamic_pointer_cast<LEPeripheral>(kv.second))) {
					if (le->getAddrType() == info.bdaddrType &&
							memcmp(le->getBdaddr().b, info.bdaddr.b, sizeof(bdaddr_t)) == 0) {
						return;
					}
				}
			}
			devicesLk.unlock();

			if (debug_scan) {
				pdebug("trying to auto-connect to " + addr);
			}

			beetle.workers.schedule([this, info]{
				std::lock_guard<std::mutex> connectLg(connectMutex, std::adopt_lock);
				connect(info, true);
			});

			// do not unlock
			connectLk.release();
		} else {
			if (debug_scan) {
				pdebug("auto-connect in progress, skipping");
			}
		}
	};
}

void AutoConnect::connect(peripheral_info_t info, bool discover) {
	std::shared_ptr<VirtualDevice> device = NULL;
	try {
		device = std::make_shared<LEPeripheral>(beetle, info.bdaddr, info.bdaddrType);

		boost::shared_lock<boost::shared_mutex> devicesLk;
		beetle.addDevice(device, devicesLk);

		device->start(discover);

		if (debug_scan) {
			pdebug("auto-connected to " + device->getName());
			pdebug(device->getName() + " has handle range [0," + std::to_string(device->getHighestHandle()) + "]");
		}
	} catch (DeviceException& e) {
		if (debug) {
			pexcept(e);
			pdebug("failed to connect to " + ba2str_cpp(info.bdaddr));
		}
		if (device) {
			beetle.removeDevice(device->getId());
		}
	}
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <string.h>
#include <utility>
using namespace std;

// Assume all inputs are valid.
// Assume n is the number of elements to be sorted.

// TC: Best = O(n^2), Average = O(n^2), Worst = O(n^2)
// SC: O(1)
void SelectionSort(int *data, int first, int last)
{
	// [first, first_unsorted) is sorted, [first_unsorted, last) is unsorted.
	for(int first_unsorted = first; first_unsorted < last - 1; ++first_unsorted)
	{
		int min_index = first_unsorted;
		for(int compare_index = first_unsorted + 1; compare_index < last; ++compare_index)
		{
			if(data[min_index] > data[compare_index])
			{
				min_index = compare_index;
			}
		}
		if(min_index != first_unsorted)
		{
			swap(data[min_index], data[first_unsorted]);
		}
		// One more element is sorted:
		// [first, first_unsorted + 1) is sorted, [first_unsorted + 1, last) is unsorted.
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TC: Best = O(n), Average = O(n^2), Worst = O(n^2)
// SC: O(1)
void BubbleSort(int *data, int first, int last) // [first, last)
{
	// [first, first_sorted) is unsorted, [first_sorted, last) is sorted.
	for(int first_sorted = last; first_sorted != first;)
	{
		int last_swap_latter_index = first;
		// Traverse [first, first_sorted)
		for(int latter_index = first + 1; latter_index < first_sorted; ++latter_index)
		{
			if(data[latter_index - 1] > data[latter_index])
			{
				swap(data[latter_index - 1], data[latter_index]);
				last_swap_latter_index = latter_index;
			}
		}
		// [first, last_swap_latter_index) is unsorted, [last_swap_latter_index, last) is sorted.
		first_sorted = last_swap_latter_index;
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TC: Best = O(n), Average = O(n^2), Worst = O(n^2)
// SC: O(1)
void InsertionSort(int *data, int first, int last)
{
	// [first, first_unsorted) is sorted, [first_unsorted, last) is unsorted.
	for(int first_unsorted = first + 1; first_unsorted < last; ++first_unsorted)
	{
		for(int compare_index = first_unsorted;
			compare_index - 1 >= first && data[compare_index - 1] > data[compare_index];
			--compare_index)
		{
			swap(data[compare_index - 1], data[compare_index]);
		}
		// One more element is sorted.
		// [first, first_unsorted + 1) is sorted; [first_unsorted + 1, last) is unsorted.
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int Partition(int *data, int first, int last) // O(n)
{
	int pivot = data[last - 1];
	int not_greater_count = 0;
	for(int index = first; index < last - 1; ++index)
	{
		if(data[index] <= pivot)
		{
			++not_greater_count;
			if(index != first + not_greater_count - 1)
			{
				swap(data[index], data[first + not_greater_count - 1]);
			}
		}
	}
	if(first + not_greater_count != last - 1)
	{
		swap(data[first + not_greater_count], data[last - 1]);
	}
	return first + not_greater_count;
}
// TC: Best = O(nlogn), Average = O(nlogn), Worst = O(n^2)
// SC: Best = O(logn), Worst = O(n)
void QuickSort(int *data, int first, int last) // [first, last)
{
	if(last - first <= 1) // Only one element is auto sorted.
	{
		return;
	}
	// Divide: [first, divide) <= [divide, divide + 1) < [divide + 1, last)
	int divide = Partition(data, first, last);
	// Conquer: sort [first, divide) and [divide + 1, last) by recursive calls.
	QuickSort(data, first, divide);
	QuickSort(data, divide + 1, last);
	// Combine: sub arrays are sorted, no work is needed to combine them.
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Merge(int *data, int first, int middle, int last, int *helper) // O(n)
{
	int left = first; // index in left-subrange [first, middle).
	int right = middle; // index in right-subrange [middle, last).
	int helper_index = first; // index in helper.
	while(left < middle || right < last)  // Either subrange is not empty
	{
		// Copy left element into helper when:
		// 1.	Left subrange is not empty and right subrange is empty:
		//		`left < middle && right >= last`
		// 2.	Both are not empty and left element is lesser than or equal to right element:
		//		`left < middle && right < last && data[left] <= data[right]`
		// NOTE:
		// 1. `||` is short-circuit.
		// 2. `<=` keep the relative order of equal elements, thus guarantee sorting stability.
		if(right >= last || (left < middle && data[left] <= data[right]))
		{
			helper[helper_index++] = data[left++];
		}
		else
		{
			helper[helper_index++] = data[right++];
		}
	}
	// Copy sorted elements into data.
	for(int index = first; index < last; ++index)
	{
		data[index] = helper[index];
	}
}
void MergeSortMain(int *data, int first, int last, int *helper)
{
	if(last - first <= 1) // Only 1 element is auto sorted.
	{
		return;
	}
	// Divide: divide n-element array into two n/2-element subarrays.
	int middle = first + (last - first) / 2;
	// Conquer: sort two subarrays [first, middle) and [middle, last) recursively.
	MergeSortMain(data, first, middle, helper);
	MergeSortMain(data, middle, last, helper);
	// Combine: merge two sorted subarrays.
	Merge(data, first, middle, last, helper);
}
// TC: Best = O(nlogn), Average = O(nlogn), Worst = O(nlogn)
// SC: O(n)
void MergeSort(int *data, int first, int last) // [first, last)
{
	int helper[last]; // helper temporary stores the sorted subarrays in Merge.
	MergeSortMain(data, first, last, helper);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void FixDown(int *data, int parent_index, int length)
{
	int max_child_index = parent_index * 2 + 1;
	while(max_child_index < length)
	{
		if(max_child_index < length - 1 && data[max_child_index] < data[max_child_index + 1])
		{
			++max_child_index;
		}
		if(data[parent_index] >= data[max_child_index]) // `=` guarantee stable.
		{
			return;
		}
		swap(data[parent_index], data[max_child_index]);
		parent_index = max_child_index;
		max_child_index = parent_index * 2 + 1;
	}
}
// TC: Best = O(nlogn), Average = O(nlogn), Worst = O(nlogn)
// SC: O(1)
void HeapSort(int *data, int first, int last)
{
	// 1. Convert to max heap. O(nlogn). (Tight is O(n), see ITA $6.3).
	int length = last - first;
	data = data + first; // [first, last) -> [0, length)
	for(int parent_index = (length - 2) / 2; parent_index >= 0; --parent_index)
	{
		FixDown(data, parent_index, length);
	}
	// 2. Extract maximum. O(nlogn)
	for(int now_length = length - 1; now_length > 0; --now_length)
	{
		if(data[0] != data[now_length]) // Guarantee stable.
		{
			swap(data[0], data[now_length]);
			FixDown(data, 0, now_length);
		}
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// n is the number of inputs, m is the max value.
// TC: Best = Average = Worst = O(n + m)
// SC: O(n + m)
void CountingSort(int *data, int first, int last) // [first, last)
{
	int length = last - first;
	data += first;
	// Get the maximum value.
	int max = data[0];
	for(int index = 1; index < length; ++index)
	{
		if(max < data[index])
		{
			max = data[index];
		}
	}
	int count[max + 1]; // count[value] is the count of elements that are <= value.
	memset(count, 0, sizeof count);
	// Count the frequency of every value in data.
	for(int index = 0; index < length; ++index)
	{
		++count[data[index]]; // WRONG: count[data[index]] = 1
	}
	// Compute how many elements are <= value.
	for(int value = 1; value <= max; ++value)
	{
		count[value] += count[value - 1];
	}
	// 1. x elements <= value: place value in [x - 1].
	// 2. Place from back to front: keep stability.
	int temp[length]; // Temporary store the sorted elements.
	for(int index = length - 1; index >= 0; --index)
	{
		temp[--count[data[index]]] = data[index];
	}
	// Copy the sorted elements into data.
	for(int index = 0; index < length; ++index)
	{
		data[index] = temp[index];
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// n is the number of inputs, d is the number of digits, m is the max value in each digit.
// TC: Best = Average = Worst = O(d(n + m))
// SC: O(n + m)
void RadixSort(int *data, int first, int last)
{
	const int kMaxDigitValue = 9;
	const int kDigitValueNumber = kMaxDigitValue + 1;
	const int kMaxDigitNumber = 10; // 10^10 < 2^31 < 10^11, thus has at most 10 digits.
	data = data + first;
	int length = last - first;
	int divisor = 1;
	for(int digit = 1; digit <= kMaxDigitNumber; ++digit)
	{
		int digit_number[length], count[kDigitValueNumber];
		memset(count, 0, sizeof count);
		// Get each digit number from least to most significant digit.
		for(int index = 0; index < length; ++index)
		{
			digit_number[index] = (data[index] / divisor) % kDigitValueNumber;
			++count[digit_number[index]];
		}
		for(int value = 1; value <= kMaxDigitValue; ++value)
		{
			count[value] += count[value - 1];
		}
		int temp[length];
		for(int index = length - 1; index >= 0; --index)
		{
			// Sort according to digit_number, but store data.
			temp[--count[digit_number[index]]] = data[index];
		}
		for(int index = 0; index < length; ++index)
		{
			data[index] = temp[index];
		}
		// Update divisor to get the next digit_number.
		divisor *= kDigitValueNumber;
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void PrintData(int *data, int first, int last)
{
	printf("%d", data[first]);
	for(int index = first + 1; index < last; ++index)
	{
		printf(" %d", data[index]);
	}
	printf("\n");
}
using SortFunction = void(*)(int*, int, int);
void Test(const char *name, SortFunction Sort)
{
	printf("----------%s----------\n", name);
	const int data_length = 10;
	int data[][data_length] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
		{ 0, 2, 4, 6, 8, 9, 7, 5, 3, 1 } };
	int data_number = static_cast<int>(sizeof(data) / sizeof(data[0]));
	for(int data_index = 0; data_index < data_number; ++data_index)
	{
		Sort(data[data_index], 0, data_length);
		PrintData(data[data_index], 0, data_length);
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
	Test("SelectionSort", SelectionSort);
	Test("BubbleSort", BubbleSort);
	Test("InsertionSort", InsertionSort);
	Test("QuickSort", QuickSort);
	Test("MergeSort", MergeSort);
	Test("HeapSort", HeapSort);
	Test("CountingSort", CountingSort);
	Test("RadixSort", RadixSort);
}
<commit_msg>feat: add ShellSort<commit_after>#include <stdio.h>
#include <string.h>
#include <utility>
using namespace std;

// Assume all inputs are valid.
// Assume n is the number of elements to be sorted.

// TC: Best = O(n^2), Average = O(n^2), Worst = O(n^2)
// SC: O(1)
void SelectionSort(int *data, int first, int last)
{
	// [first, first_unsorted) is sorted, [first_unsorted, last) is unsorted.
	for(int first_unsorted = first; first_unsorted < last - 1; ++first_unsorted)
	{
		int min_index = first_unsorted;
		for(int compare_index = first_unsorted + 1; compare_index < last; ++compare_index)
		{
			if(data[min_index] > data[compare_index])
			{
				min_index = compare_index;
			}
		}
		if(min_index != first_unsorted)
		{
			swap(data[min_index], data[first_unsorted]);
		}
		// One more element is sorted:
		// [first, first_unsorted + 1) is sorted, [first_unsorted + 1, last) is unsorted.
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TC: Best = O(n), Average = O(n^2), Worst = O(n^2)
// SC: O(1)
void BubbleSort(int *data, int first, int last) // [first, last)
{
	// [first, first_sorted) is unsorted, [first_sorted, last) is sorted.
	for(int first_sorted = last; first_sorted != first;)
	{
		int last_swap_latter_index = first;
		// Traverse [first, first_sorted)
		for(int latter_index = first + 1; latter_index < first_sorted; ++latter_index)
		{
			if(data[latter_index - 1] > data[latter_index])
			{
				swap(data[latter_index - 1], data[latter_index]);
				last_swap_latter_index = latter_index;
			}
		}
		// [first, last_swap_latter_index) is unsorted, [last_swap_latter_index, last) is sorted.
		first_sorted = last_swap_latter_index;
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TC: Best = O(n), Average = O(n^2), Worst = O(n^2)
// SC: O(1)
void InsertionSort(int *data, int first, int last)
{
	// [first, first_unsorted) is sorted, [first_unsorted, last) is unsorted.
	for(int first_unsorted = first + 1; first_unsorted < last; ++first_unsorted)
	{
		for(int compare_index = first_unsorted;
			compare_index - 1 >= first && data[compare_index - 1] > data[compare_index];
			--compare_index)
		{
			swap(data[compare_index - 1], data[compare_index]);
		}
		// One more element is sorted.
		// [first, first_unsorted + 1) is sorted; [first_unsorted + 1, last) is unsorted.
	}
}
void ShellSort(int *data, int first, int last)
{
	for(int gap = (last - first) / 2; gap > 0; gap /= 2)
	{
		for(int first_sorted = first; first_sorted < first + gap; ++first_sorted)
		{
			for(int first_unsorted = first_sorted + gap; first_unsorted < last; first_unsorted +=
				gap)
			{
				for(int compare_index = first_unsorted;
					compare_index - gap >= first && data[compare_index - gap] > data[compare_index];
					compare_index -= gap)
				{
					swap(data[compare_index - gap], data[compare_index]);
				}
			}
		}
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int Partition(int *data, int first, int last) // O(n)
{
	int pivot = data[last - 1];
	int not_greater_count = 0;
	for(int index = first; index < last - 1; ++index)
	{
		if(data[index] <= pivot)
		{
			++not_greater_count;
			if(index != first + not_greater_count - 1)
			{
				swap(data[index], data[first + not_greater_count - 1]);
			}
		}
	}
	if(first + not_greater_count != last - 1)
	{
		swap(data[first + not_greater_count], data[last - 1]);
	}
	return first + not_greater_count;
}
// TC: Best = O(nlogn), Average = O(nlogn), Worst = O(n^2)
// SC: Best = O(logn), Worst = O(n)
void QuickSort(int *data, int first, int last) // [first, last)
{
	if(last - first <= 1) // Only one element is auto sorted.
	{
		return;
	}
	// Divide: [first, divide) <= [divide, divide + 1) < [divide + 1, last)
	int divide = Partition(data, first, last);
	// Conquer: sort [first, divide) and [divide + 1, last) by recursive calls.
	QuickSort(data, first, divide);
	QuickSort(data, divide + 1, last);
	// Combine: sub arrays are sorted, no work is needed to combine them.
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Merge(int *data, int first, int middle, int last, int *helper) // O(n)
{
	int left = first; // index in left-subrange [first, middle).
	int right = middle; // index in right-subrange [middle, last).
	int helper_index = first; // index in helper.
	while(left < middle || right < last)  // Either subrange is not empty
	{
		// Copy left element into helper when:
		// 1.	Left subrange is not empty and right subrange is empty:
		//		`left < middle && right >= last`
		// 2.	Both are not empty and left element is lesser than or equal to right element:
		//		`left < middle && right < last && data[left] <= data[right]`
		// NOTE:
		// 1. `||` is short-circuit.
		// 2. `<=` keep the relative order of equal elements, thus guarantee sorting stability.
		if(right >= last || (left < middle && data[left] <= data[right]))
		{
			helper[helper_index++] = data[left++];
		}
		else
		{
			helper[helper_index++] = data[right++];
		}
	}
	// Copy sorted elements into data.
	for(int index = first; index < last; ++index)
	{
		data[index] = helper[index];
	}
}
void MergeSortMain(int *data, int first, int last, int *helper)
{
	if(last - first <= 1) // Only 1 element is auto sorted.
	{
		return;
	}
	// Divide: divide n-element array into two n/2-element subarrays.
	int middle = first + (last - first) / 2;
	// Conquer: sort two subarrays [first, middle) and [middle, last) recursively.
	MergeSortMain(data, first, middle, helper);
	MergeSortMain(data, middle, last, helper);
	// Combine: merge two sorted subarrays.
	Merge(data, first, middle, last, helper);
}
// TC: Best = O(nlogn), Average = O(nlogn), Worst = O(nlogn)
// SC: O(n)
void MergeSort(int *data, int first, int last) // [first, last)
{
	int helper[last]; // helper temporary stores the sorted subarrays in Merge.
	MergeSortMain(data, first, last, helper);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void FixDown(int *data, int parent_index, int length)
{
	int max_child_index = parent_index * 2 + 1;
	while(max_child_index < length)
	{
		if(max_child_index < length - 1 && data[max_child_index] < data[max_child_index + 1])
		{
			++max_child_index;
		}
		if(data[parent_index] >= data[max_child_index]) // `=` guarantee stable.
		{
			return;
		}
		swap(data[parent_index], data[max_child_index]);
		parent_index = max_child_index;
		max_child_index = parent_index * 2 + 1;
	}
}
// TC: Best = O(nlogn), Average = O(nlogn), Worst = O(nlogn)
// SC: O(1)
void HeapSort(int *data, int first, int last)
{
	// 1. Convert to max heap. O(nlogn). (Tight is O(n), see ITA $6.3).
	int length = last - first;
	data = data + first; // [first, last) -> [0, length)
	for(int parent_index = (length - 2) / 2; parent_index >= 0; --parent_index)
	{
		FixDown(data, parent_index, length);
	}
	// 2. Extract maximum. O(nlogn)
	for(int now_length = length - 1; now_length > 0; --now_length)
	{
		if(data[0] != data[now_length]) // Guarantee stable.
		{
			swap(data[0], data[now_length]);
			FixDown(data, 0, now_length);
		}
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// n is the number of inputs, m is the max value.
// TC: Best = Average = Worst = O(n + m)
// SC: O(n + m)
void CountingSort(int *data, int first, int last) // [first, last)
{
	int length = last - first;
	data += first;
	// Get the maximum value.
	int max = data[0];
	for(int index = 1; index < length; ++index)
	{
		if(max < data[index])
		{
			max = data[index];
		}
	}
	int count[max + 1]; // count[value] is the count of elements that are <= value.
	memset(count, 0, sizeof count);
	// Count the frequency of every value in data.
	for(int index = 0; index < length; ++index)
	{
		++count[data[index]]; // WRONG: count[data[index]] = 1
	}
	// Compute how many elements are <= value.
	for(int value = 1; value <= max; ++value)
	{
		count[value] += count[value - 1];
	}
	// 1. x elements <= value: place value in [x - 1].
	// 2. Place from back to front: keep stability.
	int temp[length]; // Temporary store the sorted elements.
	for(int index = length - 1; index >= 0; --index)
	{
		temp[--count[data[index]]] = data[index];
	}
	// Copy the sorted elements into data.
	for(int index = 0; index < length; ++index)
	{
		data[index] = temp[index];
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// n is the number of inputs, d is the number of digits, m is the max value in each digit.
// TC: Best = Average = Worst = O(d(n + m))
// SC: O(n + m)
void RadixSort(int *data, int first, int last)
{
	const int kMaxDigitValue = 9;
	const int kDigitValueNumber = kMaxDigitValue + 1;
	const int kMaxDigitNumber = 10; // 10^10 < 2^31 < 10^11, thus has at most 10 digits.
	data = data + first;
	int length = last - first;
	int divisor = 1;
	for(int digit = 1; digit <= kMaxDigitNumber; ++digit)
	{
		int digit_number[length], count[kDigitValueNumber];
		memset(count, 0, sizeof count);
		// Get each digit number from least to most significant digit.
		for(int index = 0; index < length; ++index)
		{
			digit_number[index] = (data[index] / divisor) % kDigitValueNumber;
			++count[digit_number[index]];
		}
		for(int value = 1; value <= kMaxDigitValue; ++value)
		{
			count[value] += count[value - 1];
		}
		int temp[length];
		for(int index = length - 1; index >= 0; --index)
		{
			// Sort according to digit_number, but store data.
			temp[--count[digit_number[index]]] = data[index];
		}
		for(int index = 0; index < length; ++index)
		{
			data[index] = temp[index];
		}
		// Update divisor to get the next digit_number.
		divisor *= kDigitValueNumber;
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void PrintData(int *data, int first, int last)
{
	printf("%d", data[first]);
	for(int index = first + 1; index < last; ++index)
	{
		printf(" %d", data[index]);
	}
	printf("\n");
}
using SortFunction = void(*)(int*, int, int);
void Test(const char *name, SortFunction Sort)
{
	printf("----------%s----------\n", name);
	const int data_length = 10;
	int data[][data_length] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
		{ 0, 2, 4, 6, 8, 9, 7, 5, 3, 1 } };
	int data_number = static_cast<int>(sizeof(data) / sizeof(data[0]));
	for(int data_index = 0; data_index < data_number; ++data_index)
	{
		Sort(data[data_index], 3, data_length);
		PrintData(data[data_index], 0, data_length);
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
	Test("SelectionSort", SelectionSort);
	Test("BubbleSort", BubbleSort);
	Test("InsertionSort", InsertionSort);
	Test("ShellSort", ShellSort);
	Test("QuickSort", QuickSort);
	Test("MergeSort", MergeSort);
	Test("HeapSort", HeapSort);
	Test("CountingSort", CountingSort);
	Test("RadixSort", RadixSort);
}
<|endoftext|>


<commit_before>#include "sequencer.hpp"

#include "services/audio_manager.hpp"

namespace otto::engines {

  using namespace services;

  static std::unique_ptr<ui::Screen> make_screen(Sequencer* seq);

  Sequencer::Sequencer() : MiscEngine<Sequencer>(make_screen(this)) {}

  template<std::size_t N>
  void Sequencer::SamplerGroup<N>::process(audio::AudioBufferHandle audio, int step_n) noexcept
  {
    auto& step = seq.steps[step_n];
    bool trig = step.triggered() and !mutes[step.note];

    if (trig and &samplers.current() != &samplers[step.note]) {
      samplers.current().finish();
      samplers.select(step.note);
    }

    samplers.current().process(audio, trig);
  }

  audio::ProcessData<1> Sequencer::process(audio::ProcessData<0> data) noexcept
  {
    auto buf = AudioManager::current().buffer_pool().allocate_clear();

    props.group0.process(buf, props.cur_step);
    props.group1.process(buf, props.cur_step);
    props.group2.process(buf, props.cur_step);
    props.group3.process(buf, props.cur_step);

    static const int smpl_pr_step = (AudioManager::current().samplerate() * 60) / (4 * 120 * substeps);

    smpl_counter += data.nframes;

    if (smpl_counter > smpl_pr_step) {
      props.cur_step = (props.cur_step + (smpl_counter / smpl_pr_step)) % (substeps * 16);
      smpl_counter %= smpl_pr_step;
    }

    return data.redirect(buf);
  }

  template<typename F>
  auto Sequencer::for_cur_chan(F&& f) {
    for_chan(UIManager::current().state.active_channel.get(), FWD(f));
  }

  template<typename F>
  auto Sequencer::for_chan(ChannelEnum chan, F&& f)
  {
    switch (chan) {
      case ChannelEnum::sampler0: return f(props.group0, 0);
      case ChannelEnum::sampler1: return f(props.group0, 1);
      case ChannelEnum::sampler2: return f(props.group1, 0);
      case ChannelEnum::sampler3: return f(props.group1, 1);
      case ChannelEnum::sampler4: return f(props.group1, 2);
      case ChannelEnum::sampler5: return f(props.group2, 0);
      case ChannelEnum::sampler6: return f(props.group2, 1);
      case ChannelEnum::sampler7: return f(props.group3, 0);
      case ChannelEnum::sampler8: return f(props.group3, 1);
      case ChannelEnum::sampler9: return f(props.group3, 2);
      default: return f(props.group0, 0);
    }
  }

  template<typename F>
  void Sequencer::for_all_chans(F&& f)
  {
    f(ChannelEnum::sampler0, props.group0, 0);
    f(ChannelEnum::sampler1, props.group0, 1);
    f(ChannelEnum::sampler2, props.group1, 0);
    f(ChannelEnum::sampler3, props.group1, 1);
    f(ChannelEnum::sampler4, props.group1, 2);
    f(ChannelEnum::sampler5, props.group2, 0);
    f(ChannelEnum::sampler6, props.group2, 1);
    f(ChannelEnum::sampler7, props.group3, 0);
    f(ChannelEnum::sampler8, props.group3, 1);
    f(ChannelEnum::sampler9, props.group3, 2);
  }

  ui::Screen& Sequencer::sampler_screen() noexcept
  {
    switch (UIManager::current().state.active_channel.get()) {
      case ChannelEnum::sampler0: return props.group0.samplers[0].screen();
      case ChannelEnum::sampler1: return props.group0.samplers[1].screen();
      case ChannelEnum::sampler2: return props.group1.samplers[0].screen();
      case ChannelEnum::sampler3: return props.group1.samplers[1].screen();
      case ChannelEnum::sampler4: return props.group1.samplers[2].screen();
      case ChannelEnum::sampler5: return props.group2.samplers[0].screen();
      case ChannelEnum::sampler6: return props.group2.samplers[1].screen();
      case ChannelEnum::sampler7: return props.group3.samplers[0].screen();
      case ChannelEnum::sampler8: return props.group3.samplers[1].screen();
      case ChannelEnum::sampler9: return props.group3.samplers[2].screen();
      case ChannelEnum::internal: return screen();
      case ChannelEnum::external: return screen();
    }
  }

  ui::Screen& Sequencer::envelope_screen() noexcept
  {
    switch (UIManager::current().state.active_channel.get()) {
      case ChannelEnum::sampler0: return props.group0.samplers[0].envelope_screen();
      case ChannelEnum::sampler1: return props.group0.samplers[1].envelope_screen();
      case ChannelEnum::sampler2: return props.group1.samplers[0].envelope_screen();
      case ChannelEnum::sampler3: return props.group1.samplers[1].envelope_screen();
      case ChannelEnum::sampler4: return props.group1.samplers[2].envelope_screen();
      case ChannelEnum::sampler5: return props.group2.samplers[0].envelope_screen();
      case ChannelEnum::sampler6: return props.group2.samplers[1].envelope_screen();
      case ChannelEnum::sampler7: return props.group3.samplers[0].envelope_screen();
      case ChannelEnum::sampler8: return props.group3.samplers[1].envelope_screen();
      case ChannelEnum::sampler9: return props.group3.samplers[2].envelope_screen();
      case ChannelEnum::internal: return screen();
      case ChannelEnum::external: return screen();
    }
  }

  // Screen //

  using namespace core::ui;
  using namespace core::ui::vg;

  LED seq_led(int idx)
  {
    switch (idx) {
      case 0: return LED{Key::S0};
      case 1: return LED{Key::S1};
      case 2: return LED{Key::S2};
      case 3: return LED{Key::S3};
      case 4: return LED{Key::S4};
      case 5: return LED{Key::S5};
      case 6: return LED{Key::S6};
      case 7: return LED{Key::S7};
      case 8: return LED{Key::S8};
      case 9: return LED{Key::S9};
      case 10: return LED{Key::S10};
      case 11: return LED{Key::S11};
      case 12: return LED{Key::S12};
      case 13: return LED{Key::S13};
      case 14: return LED{Key::S14};
      case 15: return LED{Key::S15};
    }
    OTTO_UNREACHABLE;
  }

  LED chan_led(ChannelEnum chan)
  {
    switch (chan) {
      case ChannelEnum::sampler0: return LED{Key::C0};
      case ChannelEnum::sampler1: return LED{Key::C1};
      case ChannelEnum::sampler2: return LED{Key::C2};
      case ChannelEnum::sampler3: return LED{Key::C3};
      case ChannelEnum::sampler4: return LED{Key::C4};
      case ChannelEnum::sampler5: return LED{Key::C5};
      case ChannelEnum::sampler6: return LED{Key::C6};
      case ChannelEnum::sampler7: return LED{Key::C7};
      case ChannelEnum::sampler8: return LED{Key::C8};
      case ChannelEnum::sampler9: return LED{Key::C9};
      default: OTTO_UNREACHABLE;
    }
  }

  struct SeqScreen : EngineScreen<Sequencer> {
    SeqScreen(Sequencer* seq);
    void on_show() override {}

    void on_hide() override {}

    void draw(Canvas& ctx) override;

    void update_leds();

    bool keypress(Key k) override;

    void input_handler(const services::Controller::Event& event);

  private:
    util::Slot key_mode_change;
    util::Slot on_draw;
    util::Slot on_input;
  };

  static std::unique_ptr<ui::Screen> make_screen(Sequencer* seq)
  {
    return std::make_unique<SeqScreen>(seq);
  }

  SeqScreen::SeqScreen(Sequencer* seq) : EngineScreen<Sequencer>(seq)
  {
    // Set up LED and input handlers when the keymode is KeyMode::seq
    key_mode_change =
      UIManager::current().state.key_mode.on_change().connect([this](auto&& new_val, auto&& old_val) mutable {
        if (new_val == old_val) return;
        if (new_val == +KeyMode::seq) {
          on_draw = UIManager::current().signals.on_draw.connect([this](ui::vg::Canvas&) { update_leds(); });
          on_input = Controller::current().signals.on_input.connect([this](auto&& event) { input_handler(event); });
        } else {
          on_draw.disconnect();
          on_input.disconnect();
          // Clear LEDs
          engine.for_all_chans([] (ChannelEnum i, auto&&, auto&&) {
            Controller::current().set_color(chan_led(i), LEDColor::Black);
          });
          for (int i : {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}) {
            Controller::current().set_color(seq_led(i), LEDColor::Black);
          }
        }
      });
  }
  void SeqScreen::update_leds()
  {
    constexpr auto substeps = Sequencer::substeps;

    engine.for_all_chans([](auto chan, auto& group, auto idx) {
      bool is_current = chan == UIManager::current().state.active_channel;
      bool is_muted = group.mutes[idx];
      LEDColor color = is_current ? LEDColor::White : is_muted ? LEDColor::Red : LEDColor::Blue;
      Sampler& sampler = group.samplers[idx];
      float progress = sampler.progress();
      if (is_current || is_muted) progress *= 0.5;
      color = color.mix(is_muted ? LEDColor::Red : LEDColor::Black, progress);
      Controller::current().set_color(chan_led(chan), color);
    });

    engine.for_cur_chan([&](auto& group, auto idx) {
      auto& c = Controller::current();
      for (int i = 0; i < 16; i++) {
        // 0: no trig, 1: trig; 2: trig on substep
        int trig = group.seq.steps[i * substeps].note == idx ? 1 : 0;
        if (trig == 0)
          for (int j = 1; j < substeps; j++) {
            if (group.seq.steps[i * substeps + j].note == idx) {
              trig = 2;
            }
          }
        auto col = [&] {
          switch (trig) {
            case 0: return LEDColor::Black;
            case 1: return LEDColor::Red;
            case 2: return LEDColor::Red.mix(LEDColor::Blue);
          }
          OTTO_UNREACHABLE;
        }();
        if (i == (props.cur_step / substeps)) col = col.mix(LEDColor::White);
        c.set_color(seq_led(i), col);
      }
    });
  }

  bool SeqScreen::keypress(Key k)
  {
    return false;
  }

  void SeqScreen::input_handler(const services::Controller::Event& event)
  {
    util::match(
      event,
      [this](const services::KeyPressEvent& evt) {
        auto k = evt.key;
        auto toggle_step = [&](int i) {
          engine.for_cur_chan([&](auto& group, auto note) {
            DLOGI("Toggle step");
            if constexpr (std::is_same_v<std::decay_t<decltype(group.seq)>, Sequencer::MonoSequence>) {
              auto& step = group.seq.steps[i * Sequencer::substeps];
              if (step.triggered() && step.note == note) {
                step.clear();
              } else {
                step = {note};
              }
            }
          });
        };

        auto channel_action = [&] (ChannelEnum ch) {
          engine.for_chan(ch, [&] (auto& group, auto idx) {
            if (Controller::current().is_pressed(Key::shift)) {
              group.mutes[idx] = !group.mutes[idx];
            } else {
              UIManager::current().state.active_channel = ch;
            }
          });
        };

        switch (k) {
          case Key::S0: toggle_step(0); return;
          case Key::S1: toggle_step(1); return;
          case Key::S2: toggle_step(2); return;
          case Key::S3: toggle_step(3); return;
          case Key::S4: toggle_step(4); return;
          case Key::S5: toggle_step(5); return;
          case Key::S6: toggle_step(6); return;
          case Key::S7: toggle_step(7); return;
          case Key::S8: toggle_step(8); return;
          case Key::S9: toggle_step(9); return;
          case Key::S10: toggle_step(10); return;
          case Key::S11: toggle_step(11); return;
          case Key::S12: toggle_step(12); return;
          case Key::S13: toggle_step(13); return;
          case Key::S14: toggle_step(14); return;
          case Key::S15: toggle_step(15); return;

          case Key::C0: channel_action(ChannelEnum::sampler0); return;
          case Key::C1: channel_action(ChannelEnum::sampler1); return;
          case Key::C2: channel_action(ChannelEnum::sampler2); return;
          case Key::C3: channel_action(ChannelEnum::sampler3); return;
          case Key::C4: channel_action(ChannelEnum::sampler4); return;
          case Key::C5: channel_action(ChannelEnum::sampler5); return;
          case Key::C6: channel_action(ChannelEnum::sampler6); return;
          case Key::C7: channel_action(ChannelEnum::sampler7); return;
          case Key::C8: channel_action(ChannelEnum::sampler8); return;
          case Key::C9: channel_action(ChannelEnum::sampler9); return;

          default: return;
        }
      },
      [](auto&&) {});
  }
  // Draw

  void SeqScreen::draw(Canvas& ctx) {}

} // namespace otto::engines
<commit_msg>Fix GCC errors<commit_after>#include "sequencer.hpp"

#include "services/audio_manager.hpp"

namespace otto::engines {

  using namespace services;

  static std::unique_ptr<ui::Screen> make_screen(Sequencer* seq);

  Sequencer::Sequencer() : MiscEngine<Sequencer>(make_screen(this)) {}

  template<std::size_t N>
  void Sequencer::SamplerGroup<N>::process(audio::AudioBufferHandle audio, int step_n) noexcept
  {
    auto& step = seq.steps[step_n];
    bool trig = step.triggered() and !mutes[step.note];

    if (trig and &samplers.current() != &samplers[step.note]) {
      samplers.current().finish();
      samplers.select(step.note);
    }

    samplers.current().process(audio, trig);
  }

  audio::ProcessData<1> Sequencer::process(audio::ProcessData<0> data) noexcept
  {
    auto buf = AudioManager::current().buffer_pool().allocate_clear();

    props.group0.process(buf, props.cur_step);
    props.group1.process(buf, props.cur_step);
    props.group2.process(buf, props.cur_step);
    props.group3.process(buf, props.cur_step);

    static const int smpl_pr_step = (AudioManager::current().samplerate() * 60) / (4 * 120 * substeps);

    smpl_counter += data.nframes;

    if (smpl_counter > smpl_pr_step) {
      props.cur_step = (props.cur_step + (smpl_counter / smpl_pr_step)) % (substeps * 16);
      smpl_counter %= smpl_pr_step;
    }

    return data.redirect(buf);
  }

  template<typename F>
  auto Sequencer::for_cur_chan(F&& f)
  {
    for_chan(UIManager::current().state.active_channel.get(), FWD(f));
  }

  template<typename F>
  auto Sequencer::for_chan(ChannelEnum chan, F&& f)
  {
    switch (chan) {
      case ChannelEnum::sampler0: return f(props.group0, 0);
      case ChannelEnum::sampler1: return f(props.group0, 1);
      case ChannelEnum::sampler2: return f(props.group1, 0);
      case ChannelEnum::sampler3: return f(props.group1, 1);
      case ChannelEnum::sampler4: return f(props.group1, 2);
      case ChannelEnum::sampler5: return f(props.group2, 0);
      case ChannelEnum::sampler6: return f(props.group2, 1);
      case ChannelEnum::sampler7: return f(props.group3, 0);
      case ChannelEnum::sampler8: return f(props.group3, 1);
      case ChannelEnum::sampler9: return f(props.group3, 2);
      default: return f(props.group0, 0);
    }
    OTTO_UNREACHABLE;
  }

  template<typename F>
  void Sequencer::for_all_chans(F&& f)
  {
    f(ChannelEnum::sampler0, props.group0, 0);
    f(ChannelEnum::sampler1, props.group0, 1);
    f(ChannelEnum::sampler2, props.group1, 0);
    f(ChannelEnum::sampler3, props.group1, 1);
    f(ChannelEnum::sampler4, props.group1, 2);
    f(ChannelEnum::sampler5, props.group2, 0);
    f(ChannelEnum::sampler6, props.group2, 1);
    f(ChannelEnum::sampler7, props.group3, 0);
    f(ChannelEnum::sampler8, props.group3, 1);
    f(ChannelEnum::sampler9, props.group3, 2);
  }

  ui::Screen& Sequencer::sampler_screen() noexcept
  {
    switch (UIManager::current().state.active_channel.get()) {
      case ChannelEnum::sampler0: return props.group0.samplers[0].screen();
      case ChannelEnum::sampler1: return props.group0.samplers[1].screen();
      case ChannelEnum::sampler2: return props.group1.samplers[0].screen();
      case ChannelEnum::sampler3: return props.group1.samplers[1].screen();
      case ChannelEnum::sampler4: return props.group1.samplers[2].screen();
      case ChannelEnum::sampler5: return props.group2.samplers[0].screen();
      case ChannelEnum::sampler6: return props.group2.samplers[1].screen();
      case ChannelEnum::sampler7: return props.group3.samplers[0].screen();
      case ChannelEnum::sampler8: return props.group3.samplers[1].screen();
      case ChannelEnum::sampler9: return props.group3.samplers[2].screen();
      case ChannelEnum::internal: return screen();
      case ChannelEnum::external: return screen();
    }
    OTTO_UNREACHABLE;
  }

  ui::Screen& Sequencer::envelope_screen() noexcept
  {
    switch (UIManager::current().state.active_channel.get()) {
      case ChannelEnum::sampler0: return props.group0.samplers[0].envelope_screen();
      case ChannelEnum::sampler1: return props.group0.samplers[1].envelope_screen();
      case ChannelEnum::sampler2: return props.group1.samplers[0].envelope_screen();
      case ChannelEnum::sampler3: return props.group1.samplers[1].envelope_screen();
      case ChannelEnum::sampler4: return props.group1.samplers[2].envelope_screen();
      case ChannelEnum::sampler5: return props.group2.samplers[0].envelope_screen();
      case ChannelEnum::sampler6: return props.group2.samplers[1].envelope_screen();
      case ChannelEnum::sampler7: return props.group3.samplers[0].envelope_screen();
      case ChannelEnum::sampler8: return props.group3.samplers[1].envelope_screen();
      case ChannelEnum::sampler9: return props.group3.samplers[2].envelope_screen();
      case ChannelEnum::internal: return screen();
      case ChannelEnum::external: return screen();
    }
    OTTO_UNREACHABLE;
  }

  // Screen //

  using namespace core::ui;
  using namespace core::ui::vg;

  LED seq_led(int idx)
  {
    switch (idx) {
      case 0: return LED{Key::S0};
      case 1: return LED{Key::S1};
      case 2: return LED{Key::S2};
      case 3: return LED{Key::S3};
      case 4: return LED{Key::S4};
      case 5: return LED{Key::S5};
      case 6: return LED{Key::S6};
      case 7: return LED{Key::S7};
      case 8: return LED{Key::S8};
      case 9: return LED{Key::S9};
      case 10: return LED{Key::S10};
      case 11: return LED{Key::S11};
      case 12: return LED{Key::S12};
      case 13: return LED{Key::S13};
      case 14: return LED{Key::S14};
      case 15: return LED{Key::S15};
    }
    OTTO_UNREACHABLE;
  }

  LED chan_led(ChannelEnum chan)
  {
    switch (chan) {
      case ChannelEnum::sampler0: return LED{Key::C0};
      case ChannelEnum::sampler1: return LED{Key::C1};
      case ChannelEnum::sampler2: return LED{Key::C2};
      case ChannelEnum::sampler3: return LED{Key::C3};
      case ChannelEnum::sampler4: return LED{Key::C4};
      case ChannelEnum::sampler5: return LED{Key::C5};
      case ChannelEnum::sampler6: return LED{Key::C6};
      case ChannelEnum::sampler7: return LED{Key::C7};
      case ChannelEnum::sampler8: return LED{Key::C8};
      case ChannelEnum::sampler9: return LED{Key::C9};
    }
    OTTO_UNREACHABLE;
  }

  struct SeqScreen : EngineScreen<Sequencer> {
    SeqScreen(Sequencer* seq);
    void on_show() override {}

    void on_hide() override {}

    void draw(Canvas& ctx) override;

    void update_leds();

    bool keypress(Key k) override;

    void input_handler(const services::Controller::Event& event);

  private:
    util::Slot key_mode_change;
    util::Slot on_draw;
    util::Slot on_input;
  };

  static std::unique_ptr<ui::Screen> make_screen(Sequencer* seq)
  {
    return std::make_unique<SeqScreen>(seq);
  }

  SeqScreen::SeqScreen(Sequencer* seq) : EngineScreen<Sequencer>(seq)
  {
    // Set up LED and input handlers when the keymode is KeyMode::seq
    key_mode_change =
      UIManager::current().state.key_mode.on_change().connect([this](auto&& new_val, auto&& old_val) mutable {
        if (new_val == old_val) return;
        if (new_val == +KeyMode::seq) {
          on_draw = UIManager::current().signals.on_draw.connect([this](ui::vg::Canvas&) { update_leds(); });
          on_input = Controller::current().signals.on_input.connect([this](auto&& event) { input_handler(event); });
        } else {
          on_draw.disconnect();
          on_input.disconnect();
          // Clear LEDs
          engine.for_all_chans(
            [](ChannelEnum i, auto&&, auto&&) { Controller::current().set_color(chan_led(i), LEDColor::Black); });
          for (int i : {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}) {
            Controller::current().set_color(seq_led(i), LEDColor::Black);
          }
        }
      });
  }
  void SeqScreen::update_leds()
  {
    constexpr auto substeps = Sequencer::substeps;

    engine.for_all_chans([](auto chan, auto& group, auto idx) {
      bool is_current = chan == UIManager::current().state.active_channel;
      bool is_muted = group.mutes[idx];
      LEDColor color = is_current ? LEDColor::White : is_muted ? LEDColor::Red : LEDColor::Blue;
      Sampler& sampler = group.samplers[idx];
      float progress = sampler.progress();
      if (is_current || is_muted) progress *= 0.5;
      color = color.mix(is_muted ? LEDColor::Red : LEDColor::Black, progress);
      Controller::current().set_color(chan_led(chan), color);
    });

    engine.for_cur_chan([&](auto& group, auto idx) {
      auto& c = Controller::current();
      for (int i = 0; i < 16; i++) {
        // 0: no trig, 1: trig; 2: trig on substep
        int trig = group.seq.steps[i * substeps].note == idx ? 1 : 0;
        if (trig == 0)
          for (int j = 1; j < substeps; j++) {
            if (group.seq.steps[i * substeps + j].note == idx) {
              trig = 2;
            }
          }
        auto col = [&] {
          switch (trig) {
            case 0: return LEDColor::Black;
            case 1: return LEDColor::Red;
            case 2: return LEDColor::Red.mix(LEDColor::Blue);
          }
          OTTO_UNREACHABLE;
        }();
        if (i == (props.cur_step / substeps)) col = col.mix(LEDColor::White);
        c.set_color(seq_led(i), col);
      }
    });
  }

  bool SeqScreen::keypress(Key k)
  {
    return false;
  }

  void SeqScreen::input_handler(const services::Controller::Event& event)
  {
    util::match(
      event,
      [this](const services::KeyPressEvent& evt) {
        auto k = evt.key;
        auto toggle_step = [&](int i) {
          engine.for_cur_chan([&](auto& group, auto note) {
            DLOGI("Toggle step");
            if constexpr (std::is_same_v<std::decay_t<decltype(group.seq)>, Sequencer::MonoSequence>) {
              auto& step = group.seq.steps[i * Sequencer::substeps];
              if (step.triggered() && step.note == note) {
                step.clear();
              } else {
                step = {note};
              }
            }
          });
        };

        auto channel_action = [&](ChannelEnum ch) {
          engine.for_chan(ch, [&](auto& group, auto idx) {
            if (Controller::current().is_pressed(Key::shift)) {
              group.mutes[idx] = !group.mutes[idx];
            } else {
              UIManager::current().state.active_channel = ch;
            }
          });
        };

        switch (k) {
          case Key::S0: toggle_step(0); return;
          case Key::S1: toggle_step(1); return;
          case Key::S2: toggle_step(2); return;
          case Key::S3: toggle_step(3); return;
          case Key::S4: toggle_step(4); return;
          case Key::S5: toggle_step(5); return;
          case Key::S6: toggle_step(6); return;
          case Key::S7: toggle_step(7); return;
          case Key::S8: toggle_step(8); return;
          case Key::S9: toggle_step(9); return;
          case Key::S10: toggle_step(10); return;
          case Key::S11: toggle_step(11); return;
          case Key::S12: toggle_step(12); return;
          case Key::S13: toggle_step(13); return;
          case Key::S14: toggle_step(14); return;
          case Key::S15: toggle_step(15); return;

          case Key::C0: channel_action(ChannelEnum::sampler0); return;
          case Key::C1: channel_action(ChannelEnum::sampler1); return;
          case Key::C2: channel_action(ChannelEnum::sampler2); return;
          case Key::C3: channel_action(ChannelEnum::sampler3); return;
          case Key::C4: channel_action(ChannelEnum::sampler4); return;
          case Key::C5: channel_action(ChannelEnum::sampler5); return;
          case Key::C6: channel_action(ChannelEnum::sampler6); return;
          case Key::C7: channel_action(ChannelEnum::sampler7); return;
          case Key::C8: channel_action(ChannelEnum::sampler8); return;
          case Key::C9: channel_action(ChannelEnum::sampler9); return;

          default: return;
        }
      },
      [](auto&&) {});
  }
  // Draw

  void SeqScreen::draw(Canvas& ctx) {}

} // namespace otto::engines
<|endoftext|>