<commit_before>/*************************************************************************
 *
 *  $RCSfile: YTable.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: oj $ $Date: 2002-11-28 10:27:20 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef CONNECTIVITY_MYSQL_TABLE_HXX
#define CONNECTIVITY_MYSQL_TABLE_HXX

#ifndef CONNECTIVITY_TABLEHELPER_HXX
#include "connectivity/TTableHelper.hxx"
#endif
#ifndef _COM_SUN_STAR_SDBC_XDATABASEMETADATA_HPP_
#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
#endif
#ifndef COMPHELPER_IDPROPERTYARRAYUSAGEHELPER_HXX
#include <comphelper/IdPropArrayHelper.hxx>
#endif

namespace connectivity
{
    namespace mysql
    {

        ::rtl::OUString getTypeString(const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xColProp);

        class OMySQLTable;
        typedef ::comphelper::OIdPropertyArrayUsageHelper< OMySQLTable >    OMySQLTable_PROP;
        class OMySQLTable : public OTableHelper
                            ,public OMySQLTable_PROP
        {
            sal_Int32 m_nPrivileges; // we have to set our privileges by our own

            /** executes the statmenmt.
                @param  _rStatement
                    The statement to execute.
                */
            void executeStatement(const ::rtl::OUString& _rStatement );
        protected:

            /** creates the column collection for the table
                @param  _rNames
                    The column names.
            */
            virtual sdbcx::OCollection* createColumns(const TStringVector& _rNames);

            /** creates the key collection for the table
                @param  _rNames
                    The key names.
            */
            virtual sdbcx::OCollection* createKeys(const TStringVector& _rNames);

            /** creates the index collection for the table
                @param  _rNames
                    The index names.
            */
            virtual sdbcx::OCollection* createIndexes(const TStringVector& _rNames);

            /** used to implement the creation of the array helper which is shared amongst all instances of the class.
                This method needs to be implemented in derived classes.

                The method gets called with s_aMutex acquired.

                as long as IPropertyArrayHelper has no virtual destructor, the implementation of ~OPropertyArrayUsageHelper
                assumes that you created an ::cppu::OPropertyArrayHelper when deleting s_pProps.
                @return                         an pointer to the newly created array helper. Must not be NULL.
            */
            virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 nId) const;
            virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper();

        public:
            OMySQLTable(    sdbcx::OCollection* _pTables,
                            const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _xConnection);
            OMySQLTable(    sdbcx::OCollection* _pTables,
                            const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _xConnection,
                            const ::rtl::OUString& _Name,
                            const ::rtl::OUString& _Type,
                            const ::rtl::OUString& _Description = ::rtl::OUString(),
                            const ::rtl::OUString& _SchemaName = ::rtl::OUString(),
                            const ::rtl::OUString& _CatalogName = ::rtl::OUString(),
                            sal_Int32 _nPrivileges = 0
                );

            // ODescriptor
            virtual void construct();
            // com::sun::star::lang::XUnoTunnel
            virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException);
            static ::com::sun::star::uno::Sequence< sal_Int8 > getUnoTunnelImplementationId();

            // XAlterTable
            virtual void SAL_CALL alterColumnByName( const ::rtl::OUString& colName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& descriptor ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException);
            /**
                returns the ALTER TABLE XXX COLUMN statement
            */
            ::rtl::OUString getAlterTableColumnPart(const ::rtl::OUString& _rsColumnName );

            // some methods to alter table structures
            void alterColumnType(sal_Int32 nNewType,const ::rtl::OUString& _rColName,const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _xDescriptor);
            void alterDefaultValue(const ::rtl::OUString& _sNewDefault,const ::rtl::OUString& _rColName);
            void dropDefaultValue(const ::rtl::OUString& _sNewDefault);

        };
    }
}
#endif // CONNECTIVITY_MYSQL_TABLE_HXX

<commit_msg>INTEGRATION: CWS ooo19126 (1.2.320); FILE MERGED 2005/09/05 17:25:43 rt 1.2.320.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: YTable.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 07:33:09 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef CONNECTIVITY_MYSQL_TABLE_HXX
#define CONNECTIVITY_MYSQL_TABLE_HXX

#ifndef CONNECTIVITY_TABLEHELPER_HXX
#include "connectivity/TTableHelper.hxx"
#endif
#ifndef _COM_SUN_STAR_SDBC_XDATABASEMETADATA_HPP_
#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
#endif
#ifndef COMPHELPER_IDPROPERTYARRAYUSAGEHELPER_HXX
#include <comphelper/IdPropArrayHelper.hxx>
#endif

namespace connectivity
{
    namespace mysql
    {

        ::rtl::OUString getTypeString(const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xColProp);

        class OMySQLTable;
        typedef ::comphelper::OIdPropertyArrayUsageHelper< OMySQLTable >    OMySQLTable_PROP;
        class OMySQLTable : public OTableHelper
                            ,public OMySQLTable_PROP
        {
            sal_Int32 m_nPrivileges; // we have to set our privileges by our own

            /** executes the statmenmt.
                @param  _rStatement
                    The statement to execute.
                */
            void executeStatement(const ::rtl::OUString& _rStatement );
        protected:

            /** creates the column collection for the table
                @param  _rNames
                    The column names.
            */
            virtual sdbcx::OCollection* createColumns(const TStringVector& _rNames);

            /** creates the key collection for the table
                @param  _rNames
                    The key names.
            */
            virtual sdbcx::OCollection* createKeys(const TStringVector& _rNames);

            /** creates the index collection for the table
                @param  _rNames
                    The index names.
            */
            virtual sdbcx::OCollection* createIndexes(const TStringVector& _rNames);

            /** used to implement the creation of the array helper which is shared amongst all instances of the class.
                This method needs to be implemented in derived classes.

                The method gets called with s_aMutex acquired.

                as long as IPropertyArrayHelper has no virtual destructor, the implementation of ~OPropertyArrayUsageHelper
                assumes that you created an ::cppu::OPropertyArrayHelper when deleting s_pProps.
                @return                         an pointer to the newly created array helper. Must not be NULL.
            */
            virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 nId) const;
            virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper();

        public:
            OMySQLTable(    sdbcx::OCollection* _pTables,
                            const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _xConnection);
            OMySQLTable(    sdbcx::OCollection* _pTables,
                            const ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XConnection >& _xConnection,
                            const ::rtl::OUString& _Name,
                            const ::rtl::OUString& _Type,
                            const ::rtl::OUString& _Description = ::rtl::OUString(),
                            const ::rtl::OUString& _SchemaName = ::rtl::OUString(),
                            const ::rtl::OUString& _CatalogName = ::rtl::OUString(),
                            sal_Int32 _nPrivileges = 0
                );

            // ODescriptor
            virtual void construct();
            // com::sun::star::lang::XUnoTunnel
            virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException);
            static ::com::sun::star::uno::Sequence< sal_Int8 > getUnoTunnelImplementationId();

            // XAlterTable
            virtual void SAL_CALL alterColumnByName( const ::rtl::OUString& colName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& descriptor ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException);
            /**
                returns the ALTER TABLE XXX COLUMN statement
            */
            ::rtl::OUString getAlterTableColumnPart(const ::rtl::OUString& _rsColumnName );

            // some methods to alter table structures
            void alterColumnType(sal_Int32 nNewType,const ::rtl::OUString& _rColName,const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _xDescriptor);
            void alterDefaultValue(const ::rtl::OUString& _sNewDefault,const ::rtl::OUString& _rColName);
            void dropDefaultValue(const ::rtl::OUString& _sNewDefault);

        };
    }
}
#endif // CONNECTIVITY_MYSQL_TABLE_HXX

<|endoftext|>


<commit_before>#include "Generator.h"
#include "gtest/gtest.h"

#include <Tasks/TaskMeta.h>
#include <Tasks/TaskSerializer.h>

#include <Flatbuffers/generated/MetaData_generated.h>

using namespace Hearthstonepp;

TEST(TaskMeta, TraitConstructors)
{
    std::random_device rd;
    std::default_random_engine gen(rd());

    int sizeTaskID = static_cast<int>(TaskID::_size());
    int sizeMetaData = static_cast<int>(MetaData::GAME_END);

    TaskID randID = TaskID::_from_integral(gen() % sizeTaskID);
    MetaData randMeta = static_cast<MetaData>(gen() % sizeMetaData);
    BYTE randUser = gen() % 2;

    // Empty Trait Test
    TaskMetaTrait empty;
    EXPECT_EQ(empty.id, +TaskID::INVALID);
    EXPECT_EQ(empty.status, MetaData::INVALID);
    EXPECT_EQ(empty.userID, TaskMetaTrait::USER_INVALID);

    // TaskID Constructor
    TaskMetaTrait traitID(randID);
    EXPECT_EQ(traitID.id, randID);
    EXPECT_EQ(traitID.status, MetaData::INVALID);
    EXPECT_EQ(traitID.userID, TaskMetaTrait::USER_INVALID);

    // TaskID, Status Constructor
    TaskMetaTrait traitMeta(randID, randMeta);
    EXPECT_EQ(traitMeta.id, randID);
    EXPECT_EQ(traitMeta.status, randMeta);
    EXPECT_EQ(traitMeta.userID, TaskMetaTrait::USER_INVALID);

    // TaskID, Status, User Constructor
    TaskMetaTrait traitUser(randID, randMeta, randUser);
    EXPECT_EQ(traitUser.id, randID);
    EXPECT_EQ(traitUser.status, randMeta);
    EXPECT_EQ(traitUser.userID, randUser);

    // Copy Assignment
    TaskMetaTrait copied(traitUser);
    EXPECT_EQ(copied.id, traitUser.id);
    EXPECT_EQ(copied.status, traitUser.status);
    EXPECT_EQ(copied.userID, traitUser.userID);
}

TEST(TaskMeta, Constructors)
{
    constexpr size_t zero = 0;
    std::unique_ptr<BYTE[]> buffer;
    size_t size = TestUtils::GenerateRandomBuffer(buffer);
    TaskMetaTrait trait = TestUtils::GenerateRandomTrait();

    // Empty Constructor
    TaskMeta meta;
    EXPECT_EQ(meta.id, +TaskID::INVALID);
    EXPECT_EQ(meta.status, MetaData::INVALID);
    EXPECT_EQ(meta.userID, TaskMeta::USER_INVALID);
    EXPECT_EQ(meta.GetBufferSize(), zero);
    EXPECT_EQ(meta.GetConstBuffer().get(), nullptr);

    // Default Constructor
    TaskMeta task(trait, size, buffer.get());
    EXPECT_EQ(trait, task);
    EXPECT_EQ(task.GetBufferSize(), size);
    TestUtils::ExpectBufferEqual(task.GetConstBuffer(), buffer, size);

    // Move Constructor
    TaskMeta moved(trait, size, std::move(buffer));
    EXPECT_EQ(trait, moved);
    EXPECT_EQ(moved.GetBufferSize(), size);
    TestUtils::ExpectBufferEqual(moved.GetConstBuffer(), task.GetConstBuffer(),
                                 size);

    // Move Assignment
    meta = std::move(moved);
    EXPECT_EQ(trait, meta);
    EXPECT_EQ(meta.GetBufferSize(), size);
    TestUtils::ExpectBufferEqual(meta.GetConstBuffer(), task.GetConstBuffer(),
                                 size);
}

TEST(TaskMeta, UniquePtr)
{
    constexpr size_t zero = 0;
    std::unique_ptr<BYTE[]> buffer;
    size_t size = TestUtils::GenerateRandomBuffer(buffer);

    TaskMetaTrait trait = TestUtils::GenerateRandomTrait();
    TaskMeta meta(trait, size, buffer.get());

    // MoveBuffer
    std::unique_ptr<BYTE[]> moved = meta.MoveBuffer();
    EXPECT_EQ(meta.GetBufferSize(), zero);
    EXPECT_EQ(meta.GetConstBuffer().get(), nullptr);
    TestUtils::ExpectBufferEqual(buffer, moved, size);

    // reset
    meta = TaskMeta(trait, size, buffer.get());
    meta.reset();
    EXPECT_EQ(meta.GetBufferSize(), zero);
    EXPECT_EQ(meta.GetConstBuffer().get(), nullptr);
}

TEST(TaskMeta, CopyFrom)
{
    // CopyFrom
    TaskMeta meta = TestUtils::GenerateRandomTaskMeta();
    TaskMeta copied = TaskMeta::CopyFrom(meta);
    EXPECT_EQ(meta, copied);
}

TEST(TaskMeta, ConvertFrom)
{
    TaskMeta meta = TestUtils::GenerateRandomTaskMeta();
    const auto& buffer = meta.GetConstBuffer();
    size_t size = meta.GetBufferSize();

    flatbuffers::FlatBufferBuilder builder(512);
    auto trait = FlatData::TaskMetaTrait(static_cast<int>(meta.id),
                                         static_cast<status_t>(meta.status),
                                         meta.userID);

    auto data = builder.CreateVector(buffer.get(), size);
    auto serialized = FlatData::CreateTaskMeta(builder, &trait, data);
    builder.Finish(serialized);

    auto deserialized =
        flatbuffers::GetRoot<FlatData::TaskMeta>(builder.GetBufferPointer());

    // ConvertFrom
    TaskMeta converted = TaskMeta::ConvertFrom(deserialized);
    EXPECT_EQ(meta, converted);
}<commit_msg>[ci skip] Update TaskMetaTests - Fix header name TestUtils<commit_after>#include "TestUtils.h"
#include "gtest/gtest.h"

#include <Tasks/TaskMeta.h>
#include <Tasks/TaskSerializer.h>

#include <Flatbuffers/generated/MetaData_generated.h>

using namespace Hearthstonepp;

TEST(TaskMeta, TraitConstructors)
{
    std::random_device rd;
    std::default_random_engine gen(rd());

    int sizeTaskID = static_cast<int>(TaskID::_size());
    int sizeMetaData = static_cast<int>(MetaData::GAME_END);

    TaskID randID = TaskID::_from_integral(gen() % sizeTaskID);
    MetaData randMeta = static_cast<MetaData>(gen() % sizeMetaData);
    BYTE randUser = gen() % 2;

    // Empty Trait Test
    TaskMetaTrait empty;
    EXPECT_EQ(empty.id, +TaskID::INVALID);
    EXPECT_EQ(empty.status, MetaData::INVALID);
    EXPECT_EQ(empty.userID, TaskMetaTrait::USER_INVALID);

    // TaskID Constructor
    TaskMetaTrait traitID(randID);
    EXPECT_EQ(traitID.id, randID);
    EXPECT_EQ(traitID.status, MetaData::INVALID);
    EXPECT_EQ(traitID.userID, TaskMetaTrait::USER_INVALID);

    // TaskID, Status Constructor
    TaskMetaTrait traitMeta(randID, randMeta);
    EXPECT_EQ(traitMeta.id, randID);
    EXPECT_EQ(traitMeta.status, randMeta);
    EXPECT_EQ(traitMeta.userID, TaskMetaTrait::USER_INVALID);

    // TaskID, Status, User Constructor
    TaskMetaTrait traitUser(randID, randMeta, randUser);
    EXPECT_EQ(traitUser.id, randID);
    EXPECT_EQ(traitUser.status, randMeta);
    EXPECT_EQ(traitUser.userID, randUser);

    // Copy Assignment
    TaskMetaTrait copied(traitUser);
    EXPECT_EQ(copied.id, traitUser.id);
    EXPECT_EQ(copied.status, traitUser.status);
    EXPECT_EQ(copied.userID, traitUser.userID);
}

TEST(TaskMeta, Constructors)
{
    constexpr size_t zero = 0;
    std::unique_ptr<BYTE[]> buffer;
    size_t size = TestUtils::GenerateRandomBuffer(buffer);
    TaskMetaTrait trait = TestUtils::GenerateRandomTrait();

    // Empty Constructor
    TaskMeta meta;
    EXPECT_EQ(meta.id, +TaskID::INVALID);
    EXPECT_EQ(meta.status, MetaData::INVALID);
    EXPECT_EQ(meta.userID, TaskMeta::USER_INVALID);
    EXPECT_EQ(meta.GetBufferSize(), zero);
    EXPECT_EQ(meta.GetConstBuffer().get(), nullptr);

    // Default Constructor
    TaskMeta task(trait, size, buffer.get());
    EXPECT_EQ(trait, task);
    EXPECT_EQ(task.GetBufferSize(), size);
    TestUtils::ExpectBufferEqual(task.GetConstBuffer(), buffer, size);

    // Move Constructor
    TaskMeta moved(trait, size, std::move(buffer));
    EXPECT_EQ(trait, moved);
    EXPECT_EQ(moved.GetBufferSize(), size);
    TestUtils::ExpectBufferEqual(moved.GetConstBuffer(), task.GetConstBuffer(),
                                 size);

    // Move Assignment
    meta = std::move(moved);
    EXPECT_EQ(trait, meta);
    EXPECT_EQ(meta.GetBufferSize(), size);
    TestUtils::ExpectBufferEqual(meta.GetConstBuffer(), task.GetConstBuffer(),
                                 size);
}

TEST(TaskMeta, UniquePtr)
{
    constexpr size_t zero = 0;
    std::unique_ptr<BYTE[]> buffer;
    size_t size = TestUtils::GenerateRandomBuffer(buffer);

    TaskMetaTrait trait = TestUtils::GenerateRandomTrait();
    TaskMeta meta(trait, size, buffer.get());

    // MoveBuffer
    std::unique_ptr<BYTE[]> moved = meta.MoveBuffer();
    EXPECT_EQ(meta.GetBufferSize(), zero);
    EXPECT_EQ(meta.GetConstBuffer().get(), nullptr);
    TestUtils::ExpectBufferEqual(buffer, moved, size);

    // reset
    meta = TaskMeta(trait, size, buffer.get());
    meta.reset();
    EXPECT_EQ(meta.GetBufferSize(), zero);
    EXPECT_EQ(meta.GetConstBuffer().get(), nullptr);
}

TEST(TaskMeta, CopyFrom)
{
    // CopyFrom
    TaskMeta meta = TestUtils::GenerateRandomTaskMeta();
    TaskMeta copied = TaskMeta::CopyFrom(meta);
    EXPECT_EQ(meta, copied);
}

TEST(TaskMeta, ConvertFrom)
{
    TaskMeta meta = TestUtils::GenerateRandomTaskMeta();
    const auto& buffer = meta.GetConstBuffer();
    size_t size = meta.GetBufferSize();

    flatbuffers::FlatBufferBuilder builder(512);
    auto trait = FlatData::TaskMetaTrait(static_cast<int>(meta.id),
                                         static_cast<status_t>(meta.status),
                                         meta.userID);

    auto data = builder.CreateVector(buffer.get(), size);
    auto serialized = FlatData::CreateTaskMeta(builder, &trait, data);
    builder.Finish(serialized);

    auto deserialized =
        flatbuffers::GetRoot<FlatData::TaskMeta>(builder.GetBufferPointer());

    // ConvertFrom
    TaskMeta converted = TaskMeta::ConvertFrom(deserialized);
    EXPECT_EQ(meta, converted);
}<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////
// File:        thresholder.cpp
// Description: Base API for thresholding images in tesseract.
// Author:      Ray Smith
//
// (C) Copyright 2008, Google Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////

#include "allheaders.h"

#include <tesseract/thresholder.h>

#include <cstdint>      // for uint32_t
#include <cstring>

#include "otsuthr.h"
#include "tprintf.h"    // for tprintf

#if defined(USE_OPENCL)
#include "openclwrapper.h" // for OpenclDevice
#endif

namespace tesseract {

ImageThresholder::ImageThresholder()
  : pix_(nullptr),
    image_width_(0), image_height_(0),
    pix_channels_(0), pix_wpl_(0),
    scale_(1), yres_(300), estimated_res_(300) {
  SetRectangle(0, 0, 0, 0);
}

ImageThresholder::~ImageThresholder() {
  Clear();
}

// Destroy the Pix if there is one, freeing memory.
void ImageThresholder::Clear() {
  pixDestroy(&pix_);
}

// Return true if no image has been set.
bool ImageThresholder::IsEmpty() const {
  return pix_ == nullptr;
}

// SetImage makes a copy of all the image data, so it may be deleted
// immediately after this call.
// Greyscale of 8 and color of 24 or 32 bits per pixel may be given.
// Palette color images will not work properly and must be converted to
// 24 bit.
// Binary images of 1 bit per pixel may also be given but they must be
// byte packed with the MSB of the first byte being the first pixel, and a
// one pixel is WHITE. For binary images set bytes_per_pixel=0.
void ImageThresholder::SetImage(const unsigned char* imagedata,
                                int width, int height,
                                int bytes_per_pixel, int bytes_per_line) {
  int bpp = bytes_per_pixel * 8;
  if (bpp == 0) bpp = 1;
  Pix* pix = pixCreate(width, height, bpp == 24 ? 32 : bpp);
  l_uint32* data = pixGetData(pix);
  int wpl = pixGetWpl(pix);
  switch (bpp) {
  case 1:
    for (int y = 0; y < height; ++y, data += wpl, imagedata += bytes_per_line) {
      for (int x = 0; x < width; ++x) {
        if (imagedata[x / 8] & (0x80 >> (x % 8)))
          CLEAR_DATA_BIT(data, x);
        else
          SET_DATA_BIT(data, x);
      }
    }
    break;

  case 8:
    // Greyscale just copies the bytes in the right order.
    for (int y = 0; y < height; ++y, data += wpl, imagedata += bytes_per_line) {
      for (int x = 0; x < width; ++x)
        SET_DATA_BYTE(data, x, imagedata[x]);
    }
    break;

  case 24:
    // Put the colors in the correct places in the line buffer.
    for (int y = 0; y < height; ++y, imagedata += bytes_per_line) {
      for (int x = 0; x < width; ++x, ++data) {
        SET_DATA_BYTE(data, COLOR_RED, imagedata[3 * x]);
        SET_DATA_BYTE(data, COLOR_GREEN, imagedata[3 * x + 1]);
        SET_DATA_BYTE(data, COLOR_BLUE, imagedata[3 * x + 2]);
      }
    }
    break;

  case 32:
    // Maintain byte order consistency across different endianness.
    for (int y = 0; y < height; ++y, imagedata += bytes_per_line, data += wpl) {
      for (int x = 0; x < width; ++x) {
        data[x] = (imagedata[x * 4] << 24) | (imagedata[x * 4 + 1] << 16) |
                  (imagedata[x * 4 + 2] << 8) | imagedata[x * 4 + 3];
      }
    }
    break;

  default:
    tprintf("Cannot convert RAW image to Pix with bpp = %d\n", bpp);
  }
  SetImage(pix);
  pixDestroy(&pix);
}

// Store the coordinates of the rectangle to process for later use.
// Doesn't actually do any thresholding.
void ImageThresholder::SetRectangle(int left, int top, int width, int height) {
  rect_left_ = left;
  rect_top_ = top;
  rect_width_ = width;
  rect_height_ = height;
}

// Get enough parameters to be able to rebuild bounding boxes in the
// original image (not just within the rectangle).
// Left and top are enough with top-down coordinates, but
// the height of the rectangle and the image are needed for bottom-up.
void ImageThresholder::GetImageSizes(int* left, int* top,
                                     int* width, int* height,
                                     int* imagewidth, int* imageheight) {
  *left = rect_left_;
  *top = rect_top_;
  *width = rect_width_;
  *height = rect_height_;
  *imagewidth = image_width_;
  *imageheight = image_height_;
}

// Pix vs raw, which to use? Pix is the preferred input for efficiency,
// since raw buffers are copied.
// SetImage for Pix clones its input, so the source pix may be pixDestroyed
// immediately after, but may not go away until after the Thresholder has
// finished with it.
void ImageThresholder::SetImage(const Pix* pix) {
  if (pix_ != nullptr)
    pixDestroy(&pix_);
  Pix* src = const_cast<Pix*>(pix);
  int depth;
  pixGetDimensions(src, &image_width_, &image_height_, &depth);
  // Convert the image as necessary so it is one of binary, plain RGB, or
  // 8 bit with no colormap. Guarantee that we always end up with our own copy,
  // not just a clone of the input.
  if (pixGetColormap(src)) {
    Pix* tmp = pixRemoveColormap(src, REMOVE_CMAP_BASED_ON_SRC);
    depth = pixGetDepth(tmp);
    if (depth > 1 && depth < 8) {
      pix_ = pixConvertTo8(tmp, false);
      pixDestroy(&tmp);
    } else {
      pix_ = tmp;
    }
  } else if (depth > 1 && depth < 8) {
    pix_ = pixConvertTo8(src, false);
  } else {
    pix_ = pixCopy(nullptr, src);
  }
  depth = pixGetDepth(pix_);
  pix_channels_ = depth / 8;
  pix_wpl_ = pixGetWpl(pix_);
  scale_ = 1;
  estimated_res_ = yres_ = pixGetYRes(pix_);
  Init();
}

// Threshold the source image as efficiently as possible to the output Pix.
// Creates a Pix and sets pix to point to the resulting pointer.
// Caller must use pixDestroy to free the created Pix.
/// Returns false on error.
bool ImageThresholder::ThresholdToPix(PageSegMode pageseg_mode, Pix** pix) {
  if (image_width_ > INT16_MAX || image_height_ > INT16_MAX) {
    tprintf("Image too large: (%d, %d)\n", image_width_, image_height_);
    return false;
  }
  if (pix_channels_ == 0) {
    // We have a binary image, but it still has to be copied, as this API
    // allows the caller to modify the output.
    Pix* original = GetPixRect();
    *pix = pixCopy(nullptr, original);
    pixDestroy(&original);
  } else {
    OtsuThresholdRectToPix(pix_, pix);
  }
  return true;
}

// Gets a pix that contains an 8 bit threshold value at each pixel. The
// returned pix may be an integer reduction of the binary image such that
// the scale factor may be inferred from the ratio of the sizes, even down
// to the extreme of a 1x1 pixel thresholds image.
// Ideally the 8 bit threshold should be the exact threshold used to generate
// the binary image in ThresholdToPix, but this is not a hard constraint.
// Returns nullptr if the input is binary. PixDestroy after use.
Pix* ImageThresholder::GetPixRectThresholds() {
  if (IsBinary()) return nullptr;
  Pix* pix_grey = GetPixRectGrey();
  int width = pixGetWidth(pix_grey);
  int height = pixGetHeight(pix_grey);
  int* thresholds;
  int* hi_values;
  OtsuThreshold(pix_grey, 0, 0, width, height, &thresholds, &hi_values);
  pixDestroy(&pix_grey);
  Pix* pix_thresholds = pixCreate(width, height, 8);
  int threshold = thresholds[0] > 0 ? thresholds[0] : 128;
  pixSetAllArbitrary(pix_thresholds, threshold);
  delete [] thresholds;
  delete [] hi_values;
  return pix_thresholds;
}

// Common initialization shared between SetImage methods.
void ImageThresholder::Init() {
  SetRectangle(0, 0, image_width_, image_height_);
}

// Get a clone/copy of the source image rectangle.
// The returned Pix must be pixDestroyed.
// This function will be used in the future by the page layout analysis, and
// the layout analysis that uses it will only be available with Leptonica,
// so there is no raw equivalent.
Pix* ImageThresholder::GetPixRect() {
  if (IsFullImage()) {
    // Just clone the whole thing.
    return pixClone(pix_);
  } else {
    // Crop to the given rectangle.
    Box* box = boxCreate(rect_left_, rect_top_, rect_width_, rect_height_);
    Pix* cropped = pixClipRectangle(pix_, box, nullptr);
    boxDestroy(&box);
    return cropped;
  }
}

// Get a clone/copy of the source image rectangle, reduced to greyscale,
// and at the same resolution as the output binary.
// The returned Pix must be pixDestroyed.
// Provided to the classifier to extract features from the greyscale image.
Pix* ImageThresholder::GetPixRectGrey() {
  Pix* pix = GetPixRect();  // May have to be reduced to grey.
  int depth = pixGetDepth(pix);
  if (depth != 8) {
    Pix* result = depth < 8 ? pixConvertTo8(pix, false)
                            : pixConvertRGBToLuminance(pix);
    pixDestroy(&pix);
    return result;
  }
  return pix;
}

// Otsu thresholds the rectangle, taking the rectangle from *this.
void ImageThresholder::OtsuThresholdRectToPix(Pix* src_pix,
                                              Pix** out_pix) const {
  int* thresholds;
  int* hi_values;

  int num_channels = OtsuThreshold(src_pix, rect_left_, rect_top_, rect_width_,
                                   rect_height_, &thresholds, &hi_values);
  // only use opencl if compiled w/ OpenCL and selected device is opencl
#ifdef USE_OPENCL
  OpenclDevice od;
  if (num_channels == 4 &&
      od.selectedDeviceIsOpenCL() && rect_top_ == 0 && rect_left_ == 0) {
    od.ThresholdRectToPixOCL((unsigned char*)pixGetData(src_pix), num_channels,
                             pixGetWpl(src_pix) * 4, thresholds, hi_values,
                             out_pix /*pix_OCL*/, rect_height_, rect_width_,
                             rect_top_, rect_left_);
  } else {
#endif
    ThresholdRectToPix(src_pix, num_channels, thresholds, hi_values, out_pix);
#ifdef USE_OPENCL
  }
#endif
  delete [] thresholds;
  delete [] hi_values;
}

/// Threshold the rectangle, taking everything except the src_pix
/// from the class, using thresholds/hi_values to the output pix.
/// NOTE that num_channels is the size of the thresholds and hi_values
// arrays and also the bytes per pixel in src_pix.
void ImageThresholder::ThresholdRectToPix(Pix* src_pix,
                                          int num_channels,
                                          const int* thresholds,
                                          const int* hi_values,
                                          Pix** pix) const {
  *pix = pixCreate(rect_width_, rect_height_, 1);
  uint32_t* pixdata = pixGetData(*pix);
  int wpl = pixGetWpl(*pix);
  int src_wpl = pixGetWpl(src_pix);
  uint32_t* srcdata = pixGetData(src_pix);
  pixSetXRes(*pix, pixGetXRes(src_pix));
  pixSetYRes(*pix, pixGetYRes(src_pix));
  for (int y = 0; y < rect_height_; ++y) {
    const uint32_t* linedata = srcdata + (y + rect_top_) * src_wpl;
    uint32_t* pixline = pixdata + y * wpl;
    for (int x = 0; x < rect_width_; ++x) {
      bool white_result = true;
      for (int ch = 0; ch < num_channels; ++ch) {
        int pixel =
            GET_DATA_BYTE(linedata, (x + rect_left_) * num_channels + ch);
        if (hi_values[ch] >= 0 &&
            (pixel > thresholds[ch]) == (hi_values[ch] == 0)) {
          white_result = false;
          break;
        }
      }
      if (white_result)
        CLEAR_DATA_BIT(pixline, x);
      else
        SET_DATA_BIT(pixline, x);
    }
  }
}

}  // namespace tesseract.
<commit_msg>Fix conversion of images with 16 bpp or 24 bpp to grey<commit_after>///////////////////////////////////////////////////////////////////////
// File:        thresholder.cpp
// Description: Base API for thresholding images in tesseract.
// Author:      Ray Smith
//
// (C) Copyright 2008, Google Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////

#include "allheaders.h"

#include <tesseract/thresholder.h>

#include <cstdint>      // for uint32_t
#include <cstring>

#include "otsuthr.h"
#include "tprintf.h"    // for tprintf

#if defined(USE_OPENCL)
#include "openclwrapper.h" // for OpenclDevice
#endif

namespace tesseract {

ImageThresholder::ImageThresholder()
  : pix_(nullptr),
    image_width_(0), image_height_(0),
    pix_channels_(0), pix_wpl_(0),
    scale_(1), yres_(300), estimated_res_(300) {
  SetRectangle(0, 0, 0, 0);
}

ImageThresholder::~ImageThresholder() {
  Clear();
}

// Destroy the Pix if there is one, freeing memory.
void ImageThresholder::Clear() {
  pixDestroy(&pix_);
}

// Return true if no image has been set.
bool ImageThresholder::IsEmpty() const {
  return pix_ == nullptr;
}

// SetImage makes a copy of all the image data, so it may be deleted
// immediately after this call.
// Greyscale of 8 and color of 24 or 32 bits per pixel may be given.
// Palette color images will not work properly and must be converted to
// 24 bit.
// Binary images of 1 bit per pixel may also be given but they must be
// byte packed with the MSB of the first byte being the first pixel, and a
// one pixel is WHITE. For binary images set bytes_per_pixel=0.
void ImageThresholder::SetImage(const unsigned char* imagedata,
                                int width, int height,
                                int bytes_per_pixel, int bytes_per_line) {
  int bpp = bytes_per_pixel * 8;
  if (bpp == 0) bpp = 1;
  Pix* pix = pixCreate(width, height, bpp == 24 ? 32 : bpp);
  l_uint32* data = pixGetData(pix);
  int wpl = pixGetWpl(pix);
  switch (bpp) {
  case 1:
    for (int y = 0; y < height; ++y, data += wpl, imagedata += bytes_per_line) {
      for (int x = 0; x < width; ++x) {
        if (imagedata[x / 8] & (0x80 >> (x % 8)))
          CLEAR_DATA_BIT(data, x);
        else
          SET_DATA_BIT(data, x);
      }
    }
    break;

  case 8:
    // Greyscale just copies the bytes in the right order.
    for (int y = 0; y < height; ++y, data += wpl, imagedata += bytes_per_line) {
      for (int x = 0; x < width; ++x)
        SET_DATA_BYTE(data, x, imagedata[x]);
    }
    break;

  case 24:
    // Put the colors in the correct places in the line buffer.
    for (int y = 0; y < height; ++y, imagedata += bytes_per_line) {
      for (int x = 0; x < width; ++x, ++data) {
        SET_DATA_BYTE(data, COLOR_RED, imagedata[3 * x]);
        SET_DATA_BYTE(data, COLOR_GREEN, imagedata[3 * x + 1]);
        SET_DATA_BYTE(data, COLOR_BLUE, imagedata[3 * x + 2]);
      }
    }
    break;

  case 32:
    // Maintain byte order consistency across different endianness.
    for (int y = 0; y < height; ++y, imagedata += bytes_per_line, data += wpl) {
      for (int x = 0; x < width; ++x) {
        data[x] = (imagedata[x * 4] << 24) | (imagedata[x * 4 + 1] << 16) |
                  (imagedata[x * 4 + 2] << 8) | imagedata[x * 4 + 3];
      }
    }
    break;

  default:
    tprintf("Cannot convert RAW image to Pix with bpp = %d\n", bpp);
  }
  SetImage(pix);
  pixDestroy(&pix);
}

// Store the coordinates of the rectangle to process for later use.
// Doesn't actually do any thresholding.
void ImageThresholder::SetRectangle(int left, int top, int width, int height) {
  rect_left_ = left;
  rect_top_ = top;
  rect_width_ = width;
  rect_height_ = height;
}

// Get enough parameters to be able to rebuild bounding boxes in the
// original image (not just within the rectangle).
// Left and top are enough with top-down coordinates, but
// the height of the rectangle and the image are needed for bottom-up.
void ImageThresholder::GetImageSizes(int* left, int* top,
                                     int* width, int* height,
                                     int* imagewidth, int* imageheight) {
  *left = rect_left_;
  *top = rect_top_;
  *width = rect_width_;
  *height = rect_height_;
  *imagewidth = image_width_;
  *imageheight = image_height_;
}

// Pix vs raw, which to use? Pix is the preferred input for efficiency,
// since raw buffers are copied.
// SetImage for Pix clones its input, so the source pix may be pixDestroyed
// immediately after, but may not go away until after the Thresholder has
// finished with it.
void ImageThresholder::SetImage(const Pix* pix) {
  if (pix_ != nullptr)
    pixDestroy(&pix_);
  Pix* src = const_cast<Pix*>(pix);
  int depth;
  pixGetDimensions(src, &image_width_, &image_height_, &depth);
  // Convert the image as necessary so it is one of binary, plain RGB, or
  // 8 bit with no colormap. Guarantee that we always end up with our own copy,
  // not just a clone of the input.
  if (pixGetColormap(src)) {
    Pix* tmp = pixRemoveColormap(src, REMOVE_CMAP_BASED_ON_SRC);
    depth = pixGetDepth(tmp);
    if (depth > 1 && depth < 8) {
      pix_ = pixConvertTo8(tmp, false);
      pixDestroy(&tmp);
    } else {
      pix_ = tmp;
    }
  } else if (depth > 1 && depth < 8) {
    pix_ = pixConvertTo8(src, false);
  } else {
    pix_ = pixCopy(nullptr, src);
  }
  depth = pixGetDepth(pix_);
  pix_channels_ = depth / 8;
  pix_wpl_ = pixGetWpl(pix_);
  scale_ = 1;
  estimated_res_ = yres_ = pixGetYRes(pix_);
  Init();
}

// Threshold the source image as efficiently as possible to the output Pix.
// Creates a Pix and sets pix to point to the resulting pointer.
// Caller must use pixDestroy to free the created Pix.
/// Returns false on error.
bool ImageThresholder::ThresholdToPix(PageSegMode pageseg_mode, Pix** pix) {
  if (image_width_ > INT16_MAX || image_height_ > INT16_MAX) {
    tprintf("Image too large: (%d, %d)\n", image_width_, image_height_);
    return false;
  }
  if (pix_channels_ == 0) {
    // We have a binary image, but it still has to be copied, as this API
    // allows the caller to modify the output.
    Pix* original = GetPixRect();
    *pix = pixCopy(nullptr, original);
    pixDestroy(&original);
  } else {
    OtsuThresholdRectToPix(pix_, pix);
  }
  return true;
}

// Gets a pix that contains an 8 bit threshold value at each pixel. The
// returned pix may be an integer reduction of the binary image such that
// the scale factor may be inferred from the ratio of the sizes, even down
// to the extreme of a 1x1 pixel thresholds image.
// Ideally the 8 bit threshold should be the exact threshold used to generate
// the binary image in ThresholdToPix, but this is not a hard constraint.
// Returns nullptr if the input is binary. PixDestroy after use.
Pix* ImageThresholder::GetPixRectThresholds() {
  if (IsBinary()) return nullptr;
  Pix* pix_grey = GetPixRectGrey();
  int width = pixGetWidth(pix_grey);
  int height = pixGetHeight(pix_grey);
  int* thresholds;
  int* hi_values;
  OtsuThreshold(pix_grey, 0, 0, width, height, &thresholds, &hi_values);
  pixDestroy(&pix_grey);
  Pix* pix_thresholds = pixCreate(width, height, 8);
  int threshold = thresholds[0] > 0 ? thresholds[0] : 128;
  pixSetAllArbitrary(pix_thresholds, threshold);
  delete [] thresholds;
  delete [] hi_values;
  return pix_thresholds;
}

// Common initialization shared between SetImage methods.
void ImageThresholder::Init() {
  SetRectangle(0, 0, image_width_, image_height_);
}

// Get a clone/copy of the source image rectangle.
// The returned Pix must be pixDestroyed.
// This function will be used in the future by the page layout analysis, and
// the layout analysis that uses it will only be available with Leptonica,
// so there is no raw equivalent.
Pix* ImageThresholder::GetPixRect() {
  if (IsFullImage()) {
    // Just clone the whole thing.
    return pixClone(pix_);
  } else {
    // Crop to the given rectangle.
    Box* box = boxCreate(rect_left_, rect_top_, rect_width_, rect_height_);
    Pix* cropped = pixClipRectangle(pix_, box, nullptr);
    boxDestroy(&box);
    return cropped;
  }
}

// Get a clone/copy of the source image rectangle, reduced to greyscale,
// and at the same resolution as the output binary.
// The returned Pix must be pixDestroyed.
// Provided to the classifier to extract features from the greyscale image.
Pix* ImageThresholder::GetPixRectGrey() {
  auto pix = GetPixRect();  // May have to be reduced to grey.
  int depth = pixGetDepth(pix);
  if (depth != 8) {
    if (depth == 24) {
      auto tmp = pixConvert24To32(pix);
      pixDestroy(&pix);
      pix = tmp;
    }
    auto result = pixConvertTo8(pix, false);
    pixDestroy(&pix);
    return result;
  }
  return pix;
}

// Otsu thresholds the rectangle, taking the rectangle from *this.
void ImageThresholder::OtsuThresholdRectToPix(Pix* src_pix,
                                              Pix** out_pix) const {
  int* thresholds;
  int* hi_values;

  int num_channels = OtsuThreshold(src_pix, rect_left_, rect_top_, rect_width_,
                                   rect_height_, &thresholds, &hi_values);
  // only use opencl if compiled w/ OpenCL and selected device is opencl
#ifdef USE_OPENCL
  OpenclDevice od;
  if (num_channels == 4 &&
      od.selectedDeviceIsOpenCL() && rect_top_ == 0 && rect_left_ == 0) {
    od.ThresholdRectToPixOCL((unsigned char*)pixGetData(src_pix), num_channels,
                             pixGetWpl(src_pix) * 4, thresholds, hi_values,
                             out_pix /*pix_OCL*/, rect_height_, rect_width_,
                             rect_top_, rect_left_);
  } else {
#endif
    ThresholdRectToPix(src_pix, num_channels, thresholds, hi_values, out_pix);
#ifdef USE_OPENCL
  }
#endif
  delete [] thresholds;
  delete [] hi_values;
}

/// Threshold the rectangle, taking everything except the src_pix
/// from the class, using thresholds/hi_values to the output pix.
/// NOTE that num_channels is the size of the thresholds and hi_values
// arrays and also the bytes per pixel in src_pix.
void ImageThresholder::ThresholdRectToPix(Pix* src_pix,
                                          int num_channels,
                                          const int* thresholds,
                                          const int* hi_values,
                                          Pix** pix) const {
  *pix = pixCreate(rect_width_, rect_height_, 1);
  uint32_t* pixdata = pixGetData(*pix);
  int wpl = pixGetWpl(*pix);
  int src_wpl = pixGetWpl(src_pix);
  uint32_t* srcdata = pixGetData(src_pix);
  pixSetXRes(*pix, pixGetXRes(src_pix));
  pixSetYRes(*pix, pixGetYRes(src_pix));
  for (int y = 0; y < rect_height_; ++y) {
    const uint32_t* linedata = srcdata + (y + rect_top_) * src_wpl;
    uint32_t* pixline = pixdata + y * wpl;
    for (int x = 0; x < rect_width_; ++x) {
      bool white_result = true;
      for (int ch = 0; ch < num_channels; ++ch) {
        int pixel =
            GET_DATA_BYTE(linedata, (x + rect_left_) * num_channels + ch);
        if (hi_values[ch] >= 0 &&
            (pixel > thresholds[ch]) == (hi_values[ch] == 0)) {
          white_result = false;
          break;
        }
      }
      if (white_result)
        CLEAR_DATA_BIT(pixline, x);
      else
        SET_DATA_BIT(pixline, x);
    }
  }
}

}  // namespace tesseract.
<|endoftext|>


<commit_before>//#include <pch.h>
#include "Texture.h"

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image/stb_image.h>

const GLint pixelFormat[5] = { 0, GL_RED, GL_RG, GL_RGB, GL_RGBA };
const GLint internalFormat[][5] = {
	{ 0, GL_R8, GL_RG8, GL_RGB8, GL_RGBA8 },
	{ 0, GL_R16, GL_RG16, GL_RGB16, GL_RGBA16 },
	{ 0, GL_R16F, GL_RG16F, GL_RGB16F, GL_RGBA16F },
	{ 0, GL_R32F, GL_RG32F, GL_RGB32F, GL_RGBA32F }
};

Texture::Texture() {
	width = 0;
	height = 0;
	textureID = 0;
}

Texture::~Texture() {
}

GLuint Texture::GetTextureID()
{
	return textureID;
}

bool Texture::Load2D(const char* file_name, GLenum wrapping_mode)
{
	int width, height, chn;
	unsigned char *data = stbi_load(file_name, &width, &height, &chn, 0);

	#ifdef DEBUG_INFO
		cout << width << " * " << height << " channels: " << chn << endl;
	#endif

	if (data == NULL) {
		#ifdef DEBUG_INFO
		cout << "Error loading texture: " << file_name << endl;
		#endif
		return false;
	}

	#ifdef DEBUG_INFO
	cout << "Loaded " << file_name << endl;
	#endif

	Init2DTexture(width, height);

	SetParameters(GL_LINEAR, GL_LINEAR, wrapping_mode);
	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat[0][chn], width, height, 0, pixelFormat[chn], GL_UNSIGNED_BYTE, (void*)data);
	glGenerateMipmap(GL_TEXTURE_2D);

	glBindTexture(GL_TEXTURE_2D, 0);

	stbi_image_free(data);
	return true;
}

void Texture::Create2DTexture(const unsigned char* img, int width, int height, int chn) {
	Init2DTexture(width, height);

	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat[0][chn], width, height, 0, pixelFormat[chn], GL_UNSIGNED_BYTE, (void*)img);
	CheckOpenGLError();

	glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture::Create2DTexture(const unsigned short* img, int width, int height, int chn)
{
	Init2DTexture(width, height);

	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat[1][chn], width, height, 0, pixelFormat[chn], GL_UNSIGNED_SHORT, (void*)img);
	CheckOpenGLError();

	glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture::Create2DTextureFloat(const float* data, int width, int height, int chn, int precision /*= 16*/)
{
	int prec = precision == 32 ? 3 : 2;

	Init2DTexture(width, height);

	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat[prec][chn], width, height, 0, pixelFormat[chn], GL_FLOAT, (void*)data);

	CheckOpenGLError();
	glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture::CreateCubeTexture(const float* data, int width, int height, int chn)
{
	this->width = width;
	this->height = height;

	glDeleteTextures(1, &textureID);
	glGenTextures(1, &textureID);
	glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
	glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

	//	glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, internalFormat[3][chn], width, height);

	for (int i = 0; i < 6; i++) {
		glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalFormat[3][chn], width, height, 0, pixelFormat[chn], GL_FLOAT, NULL);
	}

	CheckOpenGLError();
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}

void Texture::CreateFrameBufferTexture(int width, int height, int targetID)
{
	Init2DTexture(width, height);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, 0);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + targetID, GL_TEXTURE_2D, textureID, 0);

	CheckOpenGLError();
	glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture::CreateDepthBufferTexture(int width, int height)
{
	Init2DTexture(width, height);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureID, 0);

	CheckOpenGLError();
	glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture::Bind(GLenum TextureUnit) const
{
	if (textureID) {
		glActiveTexture(TextureUnit);
		glBindTexture(GL_TEXTURE_2D, textureID);
	}
}

void Texture::BindForWriting(GLenum textureTarget) const
{
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureTarget, textureID, 0);
	glDrawBuffer(GL_COLOR_ATTACHMENT0);
}

void Texture::SetParameters(GLenum mag_filter, GLenum min_filter, GLenum wrapping_mode)
{
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapping_mode);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapping_mode);
}

void Texture::GetSize(unsigned int &width,unsigned int &height) const
{
	width = this->width;
	height = this->height;
}

void Texture::Init2DTexture(unsigned int width, unsigned int height)
{
	this->width = width;
	this->height = height;

	glDeleteTextures(1, &textureID);
	glGenTextures(1, &textureID);
	glBindTexture(GL_TEXTURE_2D, textureID);
	SetParameters(GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
}
<commit_msg>code re-factoring<commit_after>//#include <pch.h>
#include "Texture.h"

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image/stb_image.h>

const GLint pixelFormat[5] = { 0, GL_RED, GL_RG, GL_RGB, GL_RGBA };
const GLint internalFormat[][5] = {
	{ 0, GL_R8, GL_RG8, GL_RGB8, GL_RGBA8 },
	{ 0, GL_R16, GL_RG16, GL_RGB16, GL_RGBA16 },
	{ 0, GL_R16F, GL_RG16F, GL_RGB16F, GL_RGBA16F },
	{ 0, GL_R32F, GL_RG32F, GL_RGB32F, GL_RGBA32F }
};

Texture::Texture() {
	width = 0;
	height = 0;
	textureID = 0;
}

Texture::~Texture() {
}

GLuint Texture::GetTextureID()
{
	return textureID;
}

bool Texture::Load2D(const char* file_name, GLenum wrapping_mode)
{
	int width, height, chn;
	unsigned char *data = stbi_load(file_name, &width, &height, &chn, 0);

	if (data == NULL) {
		#ifdef DEBUG_INFO
		cout << "ERROR loading texture: " << file_name << endl << endl;
		#endif
		return false;
	}

	#ifdef DEBUG_INFO
	cout << "Loaded " << file_name << endl;
	cout << width << " * " << height << " channels: " << chn << endl << endl;
	#endif

	Init2DTexture(width, height);

	SetParameters(GL_LINEAR, GL_LINEAR, wrapping_mode);
	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat[0][chn], width, height, 0, pixelFormat[chn], GL_UNSIGNED_BYTE, (void*)data);
	glGenerateMipmap(GL_TEXTURE_2D);

	glBindTexture(GL_TEXTURE_2D, 0);

	stbi_image_free(data);
	return true;
}

void Texture::Create2DTexture(const unsigned char* img, int width, int height, int chn) {
	Init2DTexture(width, height);

	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat[0][chn], width, height, 0, pixelFormat[chn], GL_UNSIGNED_BYTE, (void*)img);
	CheckOpenGLError();

	glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture::Create2DTexture(const unsigned short* img, int width, int height, int chn)
{
	Init2DTexture(width, height);

	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat[1][chn], width, height, 0, pixelFormat[chn], GL_UNSIGNED_SHORT, (void*)img);
	CheckOpenGLError();

	glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture::Create2DTextureFloat(const float* data, int width, int height, int chn, int precision /*= 16*/)
{
	int prec = precision == 32 ? 3 : 2;

	Init2DTexture(width, height);

	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat[prec][chn], width, height, 0, pixelFormat[chn], GL_FLOAT, (void*)data);

	CheckOpenGLError();
	glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture::CreateCubeTexture(const float* data, int width, int height, int chn)
{
	this->width = width;
	this->height = height;

	glDeleteTextures(1, &textureID);
	glGenTextures(1, &textureID);
	glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
	glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

	//	glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, internalFormat[3][chn], width, height);

	for (int i = 0; i < 6; i++) {
		glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalFormat[3][chn], width, height, 0, pixelFormat[chn], GL_FLOAT, NULL);
	}

	CheckOpenGLError();
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}

void Texture::CreateFrameBufferTexture(int width, int height, int targetID)
{
	Init2DTexture(width, height);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, 0);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + targetID, GL_TEXTURE_2D, textureID, 0);

	CheckOpenGLError();
	glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture::CreateDepthBufferTexture(int width, int height)
{
	Init2DTexture(width, height);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureID, 0);

	CheckOpenGLError();
	glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture::Bind(GLenum TextureUnit) const
{
	if (textureID) {
		glActiveTexture(TextureUnit);
		glBindTexture(GL_TEXTURE_2D, textureID);
	}
}

void Texture::BindForWriting(GLenum textureTarget) const
{
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureTarget, textureID, 0);
	glDrawBuffer(GL_COLOR_ATTACHMENT0);
}

void Texture::SetParameters(GLenum mag_filter, GLenum min_filter, GLenum wrapping_mode)
{
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapping_mode);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapping_mode);
}

void Texture::GetSize(unsigned int &width,unsigned int &height) const
{
	width = this->width;
	height = this->height;
}

void Texture::Init2DTexture(unsigned int width, unsigned int height)
{
	this->width = width;
	this->height = height;

	glDeleteTextures(1, &textureID);
	glGenTextures(1, &textureID);
	glBindTexture(GL_TEXTURE_2D, textureID);
	SetParameters(GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
}
<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXQt - a lightweight, Qt based, desktop toolset
 * https://lxqt.org
 *
 * Copyright: 2015 LXQt team
 * Authors:
 *   Daniel Drzisga <sersmicro@gmail.com>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is diinstributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

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

#include <vector>

#include "directorymenu.h"
#include <QDebug>
#include <QDesktopServices>
#include <QProcess>
#include <QFileInfo>
#include <QUrl>
#include <QIcon>

#include <XdgIcon>

DirectoryMenu::DirectoryMenu(const ILXQtPanelPluginStartupInfo &startupInfo) :
    QObject(),
    ILXQtPanelPlugin(startupInfo),
    mMenu(0),
    mDefaultIcon(XdgIcon::fromTheme("folder"))
{
    mOpenDirectorySignalMapper = new QSignalMapper(this);
    mOpenTerminalSignalMapper = new QSignalMapper(this);
    mMenuSignalMapper = new QSignalMapper(this);

    mButton.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    mButton.setAutoRaise(true);
    mButton.setIcon(XdgIcon::fromTheme("folder"));

    connect(&mButton, SIGNAL(clicked()), this, SLOT(showMenu()));
    connect(mOpenDirectorySignalMapper, SIGNAL(mapped(QString)), this, SLOT(openDirectory(QString)));
    connect(mOpenTerminalSignalMapper, SIGNAL(mapped(QString)), this, SLOT(openInTerminal(QString)));
    connect(mMenuSignalMapper, SIGNAL(mapped(QString)), this, SLOT(addMenu(QString)));

    settingsChanged();
}

DirectoryMenu::~DirectoryMenu()
{
    if(mMenu)
    {
        delete mMenu;
        mMenu = 0;
    }
}

void DirectoryMenu::showMenu()
{
    if(mBaseDirectory.exists())
    {
        buildMenu(mBaseDirectory.absolutePath());
    }
    else
    {
        buildMenu(QDir::homePath());
    }

    willShowWindow(mMenu);
    // Just using Qt`s activateWindow() won't work on some WMs like Kwin.
    // Solution is to execute menu 1ms later using timer
    mMenu->popup(calculatePopupWindowPos(mMenu->sizeHint()).topLeft());
}

void DirectoryMenu::buildMenu(const QString& path)
{
    if(mMenu)
    {
        delete mMenu;
        mMenu = 0;
    }

    mPathStrings.clear();

    mMenu = new QMenu();

    addActions(mMenu, path);
}

void DirectoryMenu::openDirectory(const QString& path)
{
    QDesktopServices::openUrl(QUrl("file://" + QDir::toNativeSeparators(path)));
}

void DirectoryMenu::openInTerminal(const QString& path)
{
    QString action = mDefaultTerminal + " --workdir " + path;
    QProcess::startDetached(action);
}

void DirectoryMenu::addMenu(QString path)
{
    QSignalMapper* sender = (QSignalMapper* )QObject::sender();
    QMenu* parentMenu = (QMenu*) sender->mapping(path);

    if(parentMenu->isEmpty())
    {
        addActions(parentMenu, path);
    }
}

void DirectoryMenu::addActions(QMenu* menu, const QString& path)
{
    mPathStrings.push_back(path);

    QAction* openDirectoryAction = menu->addAction(XdgIcon::fromTheme("folder"), tr("Open"));
    connect(openDirectoryAction, SIGNAL(triggered()), mOpenDirectorySignalMapper, SLOT(map()));
    mOpenDirectorySignalMapper->setMapping(openDirectoryAction, mPathStrings.back());

    QAction* openTerminalAction = menu->addAction(XdgIcon::fromTheme("folder"), tr("Open in terminal"));
    connect(openTerminalAction, SIGNAL(triggered()), mOpenTerminalSignalMapper, SLOT(map()));
    mOpenTerminalSignalMapper->setMapping(openTerminalAction, mPathStrings.back());

    menu->addSeparator();

    QDir dir(path);
    const QFileInfoList list = dir.entryInfoList();

    for (const QFileInfo& entry : list)
    {
        if(entry.isDir() && !entry.isHidden())
        {
            mPathStrings.push_back(entry.fileName());

            QMenu* subMenu = menu->addMenu(XdgIcon::fromTheme("folder"), mPathStrings.back());

            connect(subMenu, SIGNAL(aboutToShow()), mMenuSignalMapper, SLOT(map()));
            mMenuSignalMapper->setMapping(subMenu, entry.absoluteFilePath());
        }
    }
}

QDialog* DirectoryMenu::configureDialog()
{
     return new DirectoryMenuConfiguration(settings());
}

void DirectoryMenu::settingsChanged()
{
    mBaseDirectory.setPath(settings()->value("baseDirectory", QDir::homePath()).toString());

    QString iconPath = settings()->value("icon", QString()).toString();
    QIcon icon = QIcon(iconPath);

    if(!icon.isNull())
    {
        QIcon buttonIcon = QIcon(icon);
        if(!buttonIcon.pixmap(QSize(24,24)).isNull())
        {
            mButton.setIcon(buttonIcon);
            return;
        }
    }

    mButton.setIcon(mDefaultIcon);

    // Set default terminal
    mDefaultTerminal = settings()->value("defaultTerminal", QString()).toString();
}
<commit_msg>Changed execution method<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXQt - a lightweight, Qt based, desktop toolset
 * https://lxqt.org
 *
 * Copyright: 2015 LXQt team
 * Authors:
 *   Daniel Drzisga <sersmicro@gmail.com>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is diinstributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

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

#include <vector>

#include "directorymenu.h"
#include <QDebug>
#include <QDesktopServices>
#include <QProcess>
#include <QStringList>
#include <QFileInfo>
#include <QUrl>
#include <QIcon>

#include <XdgIcon>

DirectoryMenu::DirectoryMenu(const ILXQtPanelPluginStartupInfo &startupInfo) :
    QObject(),
    ILXQtPanelPlugin(startupInfo),
    mMenu(0),
    mDefaultIcon(XdgIcon::fromTheme("folder"))
{
    mOpenDirectorySignalMapper = new QSignalMapper(this);
    mOpenTerminalSignalMapper = new QSignalMapper(this);
    mMenuSignalMapper = new QSignalMapper(this);

    mButton.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    mButton.setAutoRaise(true);
    mButton.setIcon(XdgIcon::fromTheme("folder"));

    connect(&mButton, SIGNAL(clicked()), this, SLOT(showMenu()));
    connect(mOpenDirectorySignalMapper, SIGNAL(mapped(QString)), this, SLOT(openDirectory(QString)));
    connect(mOpenTerminalSignalMapper, SIGNAL(mapped(QString)), this, SLOT(openInTerminal(QString)));
    connect(mMenuSignalMapper, SIGNAL(mapped(QString)), this, SLOT(addMenu(QString)));

    settingsChanged();
}

DirectoryMenu::~DirectoryMenu()
{
    if(mMenu)
    {
        delete mMenu;
        mMenu = 0;
    }
}

void DirectoryMenu::showMenu()
{
    if(mBaseDirectory.exists())
    {
        buildMenu(mBaseDirectory.absolutePath());
    }
    else
    {
        buildMenu(QDir::homePath());
    }

    willShowWindow(mMenu);
    // Just using Qt`s activateWindow() won't work on some WMs like Kwin.
    // Solution is to execute menu 1ms later using timer
    mMenu->popup(calculatePopupWindowPos(mMenu->sizeHint()).topLeft());
}

void DirectoryMenu::buildMenu(const QString& path)
{
    if(mMenu)
    {
        delete mMenu;
        mMenu = 0;
    }

    mPathStrings.clear();

    mMenu = new QMenu();

    addActions(mMenu, path);
}

void DirectoryMenu::openDirectory(const QString& path)
{
    QDesktopServices::openUrl(QUrl("file://" + QDir::toNativeSeparators(path)));
}

void DirectoryMenu::openInTerminal(const QString& path)
{
    // Create list of arguments
    QStringList args;
    args << "--workdir" << QDir::toNativeSeparators(path);
    // Execute the default terminal program with arguments
    QProcess::startDetached(mDefaultTerminal, args);
}

void DirectoryMenu::addMenu(QString path)
{
    QSignalMapper* sender = (QSignalMapper* )QObject::sender();
    QMenu* parentMenu = (QMenu*) sender->mapping(path);

    if(parentMenu->isEmpty())
    {
        addActions(parentMenu, path);
    }
}

void DirectoryMenu::addActions(QMenu* menu, const QString& path)
{
    mPathStrings.push_back(path);

    QAction* openDirectoryAction = menu->addAction(XdgIcon::fromTheme("folder"), tr("Open"));
    connect(openDirectoryAction, SIGNAL(triggered()), mOpenDirectorySignalMapper, SLOT(map()));
    mOpenDirectorySignalMapper->setMapping(openDirectoryAction, mPathStrings.back());

    QAction* openTerminalAction = menu->addAction(XdgIcon::fromTheme("folder"), tr("Open in terminal"));
    connect(openTerminalAction, SIGNAL(triggered()), mOpenTerminalSignalMapper, SLOT(map()));
    mOpenTerminalSignalMapper->setMapping(openTerminalAction, mPathStrings.back());

    menu->addSeparator();

    QDir dir(path);
    const QFileInfoList list = dir.entryInfoList();

    for (const QFileInfo& entry : list)
    {
        if(entry.isDir() && !entry.isHidden())
        {
            mPathStrings.push_back(entry.fileName());

            QMenu* subMenu = menu->addMenu(XdgIcon::fromTheme("folder"), mPathStrings.back());

            connect(subMenu, SIGNAL(aboutToShow()), mMenuSignalMapper, SLOT(map()));
            mMenuSignalMapper->setMapping(subMenu, entry.absoluteFilePath());
        }
    }
}

QDialog* DirectoryMenu::configureDialog()
{
     return new DirectoryMenuConfiguration(settings());
}

void DirectoryMenu::settingsChanged()
{
    mBaseDirectory.setPath(settings()->value("baseDirectory", QDir::homePath()).toString());

    QString iconPath = settings()->value("icon", QString()).toString();
    QIcon icon = QIcon(iconPath);

    if(!icon.isNull())
    {
        QIcon buttonIcon = QIcon(icon);
        if(!buttonIcon.pixmap(QSize(24,24)).isNull())
        {
            mButton.setIcon(buttonIcon);
            return;
        }
    }

    mButton.setIcon(mDefaultIcon);

    // Set default terminal
    mDefaultTerminal = settings()->value("defaultTerminal", QString()).toString();
}
<|endoftext|>


<commit_before>#ifndef AX_LINEAR_ALGEBRA_H
#define AX_LINEAR_ALGEBRA_H
#include "Vector3.hpp"
#include "Matrix.hpp"

namespace ax
{
    using Realvec = RealVector<3>;
    using Matrix3 = RealMatrix<3,3>;
    using Matrix4 = RealMatrix<4,4>;
}

#include "JacobiMethod.hpp"

#endif //AX_LINEAR_ALGEBRA_H
<commit_msg>add mat * vec into LinearAlgebra<commit_after>#ifndef AX_LINEAR_ALGEBRA_H
#define AX_LINEAR_ALGEBRA_H
#include "MatrixVectorMultiplication.hpp"

namespace ax
{
    using Realvec = RealVector<3>;
    using Matrix3 = RealMatrix<3,3>;
    using Matrix4 = RealMatrix<4,4>;
}

#include "JacobiMethod.hpp"

#endif //AX_LINEAR_ALGEBRA_H
<|endoftext|>


<commit_before>#ifndef __CONTROLLER_HH
#define __CONTROLLER_HH

#include "calibration.hh"
#include "path.hh"

const int BASE     = 0;
const int SHOULDER = 1;
const int ELBOW    = 2;
const int GRIPPER  = 3;
const int DRIVES   = 4;

class ControllerBase
{
public:
  ControllerBase(void): m_number(0), m_fraction(0), m_sign(0), m_teachFun(NULL), m_index(0) {
    memset(m_teach, 0, sizeof(m_teach));
    memset(m_configuration, 0, sizeof(m_configuration));
  }
  virtual ~ControllerBase() {}
  Path &curve(int drive) { return m_curve[drive]; }
  int drive(char c) {
    switch (tolower(c)) {
    case 'e':
      return ELBOW;
    case 's':
      return SHOULDER;
    case 'g':
      return GRIPPER;
    default:
      return BASE;
    };
  }
  float target(int drive) {
    return m_curve[drive].target();
  }
  float limit(float value, float lower, float upper) {
    return value < lower ? lower : value > upper ? upper : value;
  }
  float angleToPWM(int drive, float angle) {
    return offset(drive) + angle * resolution(drive);
  }
  float pwmToAngle(int drive, float pwm) {
    return (pwm - offset(drive)) / resolution(drive);
  }
  float clipPWM(int drive, float value) {
    return limit(value, lower(drive), upper(drive));
  }
  float clipAngle(int drive, float value) {
    return pwmToAngle(drive, clipPWM(drive, angleToPWM(drive, value)));
  }
  float limitJoint(float value, float other) {
    return limit(value, -45 - other, 45 - other);
  }
  float limitArmAngle(int drive, float value)
  {
    switch (drive) {
    case ELBOW:
      return limitJoint(value, target(SHOULDER));
    case SHOULDER:
      return limitJoint(value, target(ELBOW));
    default:
      return value;
    };
  }
  float limitElbowAngle(int drive, float value, float shoulder)
  {
    return drive == ELBOW ? limitJoint(value, shoulder) : value;
  }
  void saveTeachPoint(int index) {
    for (int i=0; i<DRIVES; i++)
      m_teach[index][i] = target(i);
  }
  void loadTeachPoint(int index) {
    targetPoint(m_teach[index]);
  }
  void displayTeachPoint(int index) {
    reportTeachPoint(m_teach[index][0], m_teach[index][1], m_teach[index][2], m_teach[index][3]);
  }
  void takeConfigurationValue(void) {
    if (m_index < 4) {
      float angle = limitElbowAngle(m_index, clipAngle(m_index, number()), m_configuration[SHOULDER]);
      m_configuration[m_index] = angle;
      m_index++;
    };
    resetNumber();
  }
  float timeRequired(int drive, float angle) {
    return Profile::timeRequired(fabs(angle - target(drive)), MAXJERK);
  }
  float timeRequired(float point[]) {
    float retval = 0;
    for (int i=0; i<DRIVES; i++) {
      float driveTime = timeRequired(i, point[i]);
      retval = retval < driveTime ? driveTime : retval;
    };
    return retval;
  }
  void targetAngleUnsafe(int drive, float angle, float time) {
    m_curve[drive].retarget(angle, time);
  }
  void targetPWM(int drive, float pwm) {
    float angle = limitArmAngle(drive, pwmToAngle(drive, clipPWM(drive, pwm)));
    targetAngleUnsafe(drive, angle, timeRequired(drive, angle));
  }
  void targetAngle(int drive, float value) {
    float angle = limitArmAngle(drive, clipAngle(drive, value));
    targetAngleUnsafe(drive, angle, timeRequired(drive, angle));
  }
  void targetPoint(float point[])
  {
    float time = timeRequired(point);
    for (int i=0; i<DRIVES; i++)
      targetAngleUnsafe(i, point[i], time);
  }
  void update(float dt) {
    for (int drive=0; drive<DRIVES; drive++)
      writePWM(drive, round(angleToPWM(drive, m_curve[drive].update(dt))));
  }
  void stopDrives(void) {
    resetParser();
    for (int drive=0; drive<DRIVES; drive++)
      m_curve[drive].stop(m_curve[drive].pos());
  }
  bool hasNumber(void) {
    return m_sign != 0;
  }
  float number(void) {
    float fraction = (m_fraction == 0) ? 1 : m_fraction;
    return m_number * fraction * m_sign;
  }
  void resetNumber(void) {
    m_number = 0;
    m_fraction = 0;
    m_sign = 0;
  }
  void resetParser(void) {
    resetNumber();
    memset(m_configuration, 0, sizeof(m_configuration));
    m_index = 0;
  }
  bool drivesReady(void) {
    bool retval = true;
    for (int i=0; i<DRIVES; i++)
      retval = retval && m_curve[i].ready();
    return retval;
  }
  void parseChar(char c) {
    if (m_teachFun) {
      if (c >= 'a' && c <= 'l')
        (this->*m_teachFun)(c - 'a');
      else
        stopDrives();
      resetParser();
      m_teachFun = NULL;
    } else {
      switch (c) {
      case 'r':
        reportReady(drivesReady());
        resetParser();
        break;
      case 't':
        if (hasNumber()) {
          takeConfigurationValue();
          reportRequired(timeRequired(m_configuration));
        } else
          reportTime();
        resetParser();
        break;
      case '.':
        if (m_fraction > 0)
          resetParser();
        else
          m_fraction = 1;
        break;
      case '-':
        m_sign = m_sign == 0 ? -1 : -m_sign;
        m_number = 0;
        m_fraction = 0;
        break;
      case 'b':
      case 'e':
      case 's':
      case 'g':
      case 'B':
      case 'E':
      case 'S':
      case 'G':
        if (hasNumber()) {
          if (isupper(c))
            targetPWM(drive(c), number());
          else
            targetAngle(drive(c), number());
        } else
          if (isupper(c))
            reportPWM(round(angleToPWM(drive(c), m_curve[drive(c)].pos())));
          else
            reportAngle(m_curve[drive(c)].pos());
        resetParser();
        break;
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        m_number = 10 * m_number + (c - '0');
        m_fraction *= 0.1;
        if (m_sign == 0) m_sign = 1;
        break;
      case '\'':
        m_teachFun = &ControllerBase::loadTeachPoint;
        break;
      case 'm':
        m_teachFun = &ControllerBase::saveTeachPoint;
        break;
      case 'p':
        m_teachFun = &ControllerBase::displayTeachPoint;
        break;
      case ' ':
        takeConfigurationValue();
        break;
      case 'c':
        if (hasNumber()) {
          takeConfigurationValue();
          targetPoint(m_configuration);
        } else
          reportConfiguration(m_curve[0].pos(), m_curve[1].pos(), m_curve[2].pos(), m_curve[3].pos());
        resetParser();
        break;
      case 'l':
        reportLower((lower(0) - offset(0)) / resolution(0),
                    (lower(1) - offset(1)) / resolution(1),
                    (lower(2) - offset(2)) / resolution(2),
                    (lower(3) - offset(3)) / resolution(3));
        resetParser();
        break;
      case 'u':
        reportUpper((upper(0) - offset(0)) / resolution(0),
                    (upper(1) - offset(1)) / resolution(1),
                    (upper(2) - offset(2)) / resolution(2),
                    (upper(3) - offset(3)) / resolution(3));
        resetParser();
        break;
      default:
        stopDrives();
      };
    };
  }
  virtual int offset(int drive) = 0;
  virtual float resolution(int drive) = 0;
  virtual int lower(int drive) = 0;
  virtual int upper(int drive) = 0;
  virtual void reportReady(bool ready) = 0;
  virtual void reportTime(void) = 0;
  virtual void reportRequired(float time) = 0;
  virtual void reportAngle(float) = 0;
  virtual void reportPWM(int) = 0;
  virtual void reportConfiguration(float, float, float, float) = 0;
  virtual void reportLower(float, float, float, float) = 0;
  virtual void reportUpper(float, float, float, float) = 0;
  virtual void reportTeachPoint(float, float, float, float) = 0;
  virtual void writePWM(int, int) = 0;
protected:
  float m_number;
  float m_fraction;
  char m_sign;
  void (ControllerBase::*m_teachFun)(int);
  float m_teach[12][DRIVES];
  int m_index;
  float m_configuration[4];
  Path m_curve[DRIVES];
};

#endif
<commit_msg>Replace '4' with 'DRIVES'<commit_after>#ifndef __CONTROLLER_HH
#define __CONTROLLER_HH

#include "calibration.hh"
#include "path.hh"

const int BASE     = 0;
const int SHOULDER = 1;
const int ELBOW    = 2;
const int GRIPPER  = 3;
const int DRIVES   = 4;

class ControllerBase
{
public:
  ControllerBase(void): m_number(0), m_fraction(0), m_sign(0), m_teachFun(NULL), m_index(0) {
    memset(m_teach, 0, sizeof(m_teach));
    memset(m_configuration, 0, sizeof(m_configuration));
  }
  virtual ~ControllerBase() {}
  Path &curve(int drive) { return m_curve[drive]; }
  int drive(char c) {
    switch (tolower(c)) {
    case 'e':
      return ELBOW;
    case 's':
      return SHOULDER;
    case 'g':
      return GRIPPER;
    default:
      return BASE;
    };
  }
  float target(int drive) {
    return m_curve[drive].target();
  }
  float limit(float value, float lower, float upper) {
    return value < lower ? lower : value > upper ? upper : value;
  }
  float angleToPWM(int drive, float angle) {
    return offset(drive) + angle * resolution(drive);
  }
  float pwmToAngle(int drive, float pwm) {
    return (pwm - offset(drive)) / resolution(drive);
  }
  float clipPWM(int drive, float value) {
    return limit(value, lower(drive), upper(drive));
  }
  float clipAngle(int drive, float value) {
    return pwmToAngle(drive, clipPWM(drive, angleToPWM(drive, value)));
  }
  float limitJoint(float value, float other) {
    return limit(value, -45 - other, 45 - other);
  }
  float limitArmAngle(int drive, float value)
  {
    switch (drive) {
    case ELBOW:
      return limitJoint(value, target(SHOULDER));
    case SHOULDER:
      return limitJoint(value, target(ELBOW));
    default:
      return value;
    };
  }
  float limitElbowAngle(int drive, float value, float shoulder)
  {
    return drive == ELBOW ? limitJoint(value, shoulder) : value;
  }
  void saveTeachPoint(int index) {
    for (int i=0; i<DRIVES; i++)
      m_teach[index][i] = target(i);
  }
  void loadTeachPoint(int index) {
    targetPoint(m_teach[index]);
  }
  void displayTeachPoint(int index) {
    reportTeachPoint(m_teach[index][0], m_teach[index][1], m_teach[index][2], m_teach[index][3]);
  }
  void takeConfigurationValue(void) {
    if (m_index < DRIVES) {
      float angle = limitElbowAngle(m_index, clipAngle(m_index, number()), m_configuration[SHOULDER]);
      m_configuration[m_index] = angle;
      m_index++;
    };
    resetNumber();
  }
  float timeRequired(int drive, float angle) {
    return Profile::timeRequired(fabs(angle - target(drive)), MAXJERK);
  }
  float timeRequired(float point[]) {
    float retval = 0;
    for (int i=0; i<DRIVES; i++) {
      float driveTime = timeRequired(i, point[i]);
      retval = retval < driveTime ? driveTime : retval;
    };
    return retval;
  }
  void targetAngleUnsafe(int drive, float angle, float time) {
    m_curve[drive].retarget(angle, time);
  }
  void targetPWM(int drive, float pwm) {
    float angle = limitArmAngle(drive, pwmToAngle(drive, clipPWM(drive, pwm)));
    targetAngleUnsafe(drive, angle, timeRequired(drive, angle));
  }
  void targetAngle(int drive, float value) {
    float angle = limitArmAngle(drive, clipAngle(drive, value));
    targetAngleUnsafe(drive, angle, timeRequired(drive, angle));
  }
  void targetPoint(float point[])
  {
    float time = timeRequired(point);
    for (int i=0; i<DRIVES; i++)
      targetAngleUnsafe(i, point[i], time);
  }
  void update(float dt) {
    for (int drive=0; drive<DRIVES; drive++)
      writePWM(drive, round(angleToPWM(drive, m_curve[drive].update(dt))));
  }
  void stopDrives(void) {
    resetParser();
    for (int drive=0; drive<DRIVES; drive++)
      m_curve[drive].stop(m_curve[drive].pos());
  }
  bool hasNumber(void) {
    return m_sign != 0;
  }
  float number(void) {
    float fraction = (m_fraction == 0) ? 1 : m_fraction;
    return m_number * fraction * m_sign;
  }
  void resetNumber(void) {
    m_number = 0;
    m_fraction = 0;
    m_sign = 0;
  }
  void resetParser(void) {
    resetNumber();
    memset(m_configuration, 0, sizeof(m_configuration));
    m_index = 0;
  }
  bool drivesReady(void) {
    bool retval = true;
    for (int i=0; i<DRIVES; i++)
      retval = retval && m_curve[i].ready();
    return retval;
  }
  void parseChar(char c) {
    if (m_teachFun) {
      if (c >= 'a' && c <= 'l')
        (this->*m_teachFun)(c - 'a');
      else
        stopDrives();
      resetParser();
      m_teachFun = NULL;
    } else {
      switch (c) {
      case 'r':
        reportReady(drivesReady());
        resetParser();
        break;
      case 't':
        if (hasNumber()) {
          takeConfigurationValue();
          reportRequired(timeRequired(m_configuration));
        } else
          reportTime();
        resetParser();
        break;
      case '.':
        if (m_fraction > 0)
          resetParser();
        else
          m_fraction = 1;
        break;
      case '-':
        m_sign = m_sign == 0 ? -1 : -m_sign;
        m_number = 0;
        m_fraction = 0;
        break;
      case 'b':
      case 'e':
      case 's':
      case 'g':
      case 'B':
      case 'E':
      case 'S':
      case 'G':
        if (hasNumber()) {
          if (isupper(c))
            targetPWM(drive(c), number());
          else
            targetAngle(drive(c), number());
        } else
          if (isupper(c))
            reportPWM(round(angleToPWM(drive(c), m_curve[drive(c)].pos())));
          else
            reportAngle(m_curve[drive(c)].pos());
        resetParser();
        break;
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        m_number = 10 * m_number + (c - '0');
        m_fraction *= 0.1;
        if (m_sign == 0) m_sign = 1;
        break;
      case '\'':
        m_teachFun = &ControllerBase::loadTeachPoint;
        break;
      case 'm':
        m_teachFun = &ControllerBase::saveTeachPoint;
        break;
      case 'p':
        m_teachFun = &ControllerBase::displayTeachPoint;
        break;
      case ' ':
        takeConfigurationValue();
        break;
      case 'c':
        if (hasNumber()) {
          takeConfigurationValue();
          targetPoint(m_configuration);
        } else
          reportConfiguration(m_curve[0].pos(), m_curve[1].pos(), m_curve[2].pos(), m_curve[3].pos());
        resetParser();
        break;
      case 'l':
        reportLower((lower(0) - offset(0)) / resolution(0),
                    (lower(1) - offset(1)) / resolution(1),
                    (lower(2) - offset(2)) / resolution(2),
                    (lower(3) - offset(3)) / resolution(3));
        resetParser();
        break;
      case 'u':
        reportUpper((upper(0) - offset(0)) / resolution(0),
                    (upper(1) - offset(1)) / resolution(1),
                    (upper(2) - offset(2)) / resolution(2),
                    (upper(3) - offset(3)) / resolution(3));
        resetParser();
        break;
      default:
        stopDrives();
      };
    };
  }
  virtual int offset(int drive) = 0;
  virtual float resolution(int drive) = 0;
  virtual int lower(int drive) = 0;
  virtual int upper(int drive) = 0;
  virtual void reportReady(bool ready) = 0;
  virtual void reportTime(void) = 0;
  virtual void reportRequired(float time) = 0;
  virtual void reportAngle(float) = 0;
  virtual void reportPWM(int) = 0;
  virtual void reportConfiguration(float, float, float, float) = 0;
  virtual void reportLower(float, float, float, float) = 0;
  virtual void reportUpper(float, float, float, float) = 0;
  virtual void reportTeachPoint(float, float, float, float) = 0;
  virtual void writePWM(int, int) = 0;
protected:
  float m_number;
  float m_fraction;
  char m_sign;
  void (ControllerBase::*m_teachFun)(int);
  float m_teach[12][DRIVES];
  int m_index;
  float m_configuration[DRIVES];
  Path m_curve[DRIVES];
};

#endif
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see doc/LICENSE.md or http://www.libelektra.org)
 */

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <sstream>
#include <string>
#include <sys/time.h>
#include <vector>

#ifdef __GNUC__
#define TIMER_NOINLINE __attribute__ ((noinline))
#endif

class Timer
{
public:
	// options what to do at cleanup
	enum option_t
	{
		raw_data_cerr, ///< print name,data\n (default!)
		median_cerr,   ///< print name,median\n
		quiet,	 ///< print nothing
	};

	// functions
	TIMER_NOINLINE void start ()
	{
		gettimeofday (&begin, nullptr);
	}
	TIMER_NOINLINE void stop ()
	{
		gettimeofday (&end, nullptr);
		// force calculation in long long:
		timer_t result = end.tv_sec - begin.tv_sec;
		result *= usec_factor;
		result += end.tv_usec - begin.tv_usec;
		results.push_back (result);
	}
	std::string getMedian () const;
	Timer (std::string name, option_t option = raw_data_cerr);
	~Timer (); // print csv table at end

	// data
	struct timeval begin;
	struct timeval end;
	typedef long long timer_t;
	typedef std::vector<timer_t> results_t;
	results_t results;
	std::string name;
	option_t option;
	static const timer_t usec_factor = 1000000LL;
};

inline Timer::Timer (std::string name_, option_t option_) : begin (), end (), results (), name (std::move (name_)), option (option_)
{
}

inline Timer::~Timer ()
{
	switch (option)
	{
	case raw_data_cerr:
		for (auto result : results)
		{
			// clang-format off
			std::cerr << name << ","
				 << result / Timer::usec_factor
				 << "."
				 << std::setw(6)
				 << std::setfill('0')
				 << result % Timer::usec_factor
				 << std::endl;
			// clang-format on
		}
		break;
	case median_cerr:
		std::cerr << name << "," << getMedian () << std::endl;
		break;
	case quiet:
		break;
	}
}

std::string Timer::getMedian () const
{
	Timer::results_t md = results;
	nth_element (md.begin (), md.begin () + md.size () / 2, md.end ());
	Timer::timer_t r = *(md.begin () + md.size () / 2);
	std::ostringstream os;
	os << r / Timer::usec_factor << "." << std::setw (6) << std::setfill ('0') << r % Timer::usec_factor;
	return os.str ();
}

inline std::ostream & operator<< (std::ostream & os, Timer const & t)
{
	// clang-format off
	Timer::timer_t r = t.results.back();
	os.width(30);
	os.fill(' ');
	os << t.name << "\t";
	os  << r / Timer::usec_factor
		<< "."
		<< std::setw(6)
		<< std::setfill('0')
		<< r % Timer::usec_factor
		<< " sec";
	r = std::accumulate(t.results.begin(), t.results.end(), 0LL);
	os  << "\t Sum: "
		<< r / Timer::usec_factor
		<< "."
		<< std::setw(6)
		<< std::setfill('0')
		<< r % Timer::usec_factor
		<< " sec";
	r = r / t.results.size();
	os  << "\tAvg: "
		<< r / Timer::usec_factor
		<< "."
		<< std::setw(6)
		<< std::setfill('0')
		<< r % Timer::usec_factor
		<< " sec";
	r = *std::min_element(t.results.begin(), t.results.end());
	os  << "\tMin: "
		<< r / Timer::usec_factor
		<< "."
		<< std::setw(6)
		<< std::setfill('0')
		<< r % Timer::usec_factor
		<< " sec";
	r = *std::max_element(t.results.begin(), t.results.end());
	os  << "\tMax: "
		<< r / Timer::usec_factor
		<< "."
		<< std::setw(6)
		<< std::setfill('0')
		<< r % Timer::usec_factor
		<< " sec";
	os  << "\tMedian: "
		<< t.getMedian()
		<< " sec"
		<< std::endl;
	// clang-format on
	return os;
}
<commit_msg>cpp: suggestion how to change timer<commit_after>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see doc/LICENSE.md or http://www.libelektra.org)
 */

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <sstream>
#include <string>
#include <sys/time.h>
#include <vector>

#ifdef __GNUC__
#define TIMER_NOINLINE __attribute__ ((noinline))
#endif

class Timer
{
public:
	// options what to do at cleanup
	enum option_t
	{
		raw_data_cerr, ///< print name,data\n (default!)
		median_cerr,   ///< print name,median\n
		quiet,	 ///< print nothing
	};

	// functions
	TIMER_NOINLINE void start ()
	{
		gettimeofday (&begin, nullptr);
		// clock_gettime(CLOCK_MONOTONIC, &begin);
	}
	TIMER_NOINLINE void stop ()
	{
		gettimeofday (&end, nullptr);
		// clock_gettime(CLOCK_MONOTONIC, &end);

		// force calculation in long long:
		// could use timersub here
		timer_t result = end.tv_sec - begin.tv_sec;
		result *= usec_factor;
		result += end.tv_usec - begin.tv_usec;
		results.push_back (result);
	}
	std::string getMedian () const;
	Timer (std::string name, option_t option = raw_data_cerr);
	~Timer (); // print csv table at end

	// data
	struct timeval begin;
	struct timeval end;
	typedef long long timer_t;
	typedef std::vector<timer_t> results_t;
	results_t results;
	std::string name;
	option_t option;
	static const timer_t usec_factor = 1000000LL;
};

inline Timer::Timer (std::string name_, option_t option_) : begin (), end (), results (), name (std::move (name_)), option (option_)
{
}

inline Timer::~Timer ()
{
	switch (option)
	{
	case raw_data_cerr:
		for (auto result : results)
		{
			// clang-format off
			std::cerr << name << ","
				 << result / Timer::usec_factor
				 << "."
				 << std::setw(6)
				 << std::setfill('0')
				 << result % Timer::usec_factor
				 << std::endl;
			// clang-format on
		}
		break;
	case median_cerr:
		std::cerr << name << "," << getMedian () << std::endl;
		break;
	case quiet:
		break;
	}
}

std::string Timer::getMedian () const
{
	Timer::results_t md = results;
	nth_element (md.begin (), md.begin () + md.size () / 2, md.end ());
	Timer::timer_t r = *(md.begin () + md.size () / 2);
	std::ostringstream os;
	os << r / Timer::usec_factor << "." << std::setw (6) << std::setfill ('0') << r % Timer::usec_factor;
	return os.str ();
}

inline std::ostream & operator<< (std::ostream & os, Timer const & t)
{
	// clang-format off
	Timer::timer_t r = t.results.back();
	os.width(30);
	os.fill(' ');
	os << t.name << "\t";
	os  << r / Timer::usec_factor
		<< "."
		<< std::setw(6)
		<< std::setfill('0')
		<< r % Timer::usec_factor
		<< " sec";
	r = std::accumulate(t.results.begin(), t.results.end(), 0LL);
	os  << "\t Sum: "
		<< r / Timer::usec_factor
		<< "."
		<< std::setw(6)
		<< std::setfill('0')
		<< r % Timer::usec_factor
		<< " sec";
	r = r / t.results.size();
	os  << "\tAvg: "
		<< r / Timer::usec_factor
		<< "."
		<< std::setw(6)
		<< std::setfill('0')
		<< r % Timer::usec_factor
		<< " sec";
	r = *std::min_element(t.results.begin(), t.results.end());
	os  << "\tMin: "
		<< r / Timer::usec_factor
		<< "."
		<< std::setw(6)
		<< std::setfill('0')
		<< r % Timer::usec_factor
		<< " sec";
	r = *std::max_element(t.results.begin(), t.results.end());
	os  << "\tMax: "
		<< r / Timer::usec_factor
		<< "."
		<< std::setw(6)
		<< std::setfill('0')
		<< r % Timer::usec_factor
		<< " sec";
	os  << "\tMedian: "
		<< t.getMedian()
		<< " sec"
		<< std::endl;
	// clang-format on
	return os;
}
<|endoftext|>