<commit_before>/*******************************************************************
 KNotes -- Notes for the KDE project

 Copyright (c) 2002-2004, Michael Brade <brade@kde.org>

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program 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 General Public License for more details.

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

#include "knoteslegacy.h"
#include "knoteconfig.h"
#include "version.h"

#include <QFile>
#include <QFont>
#include <QPoint>
#include <QColor>
#include <QStringList>
#include <QTextStream>

#include <kdebug.h>
#include <kapplication.h>
#include <kglobal.h>
#include <kurl.h>
#include <kstandarddirs.h>
#include <kconfig.h>
#include <kio/netaccess.h>
#include <kcal/calendarlocal.h>
#include <kcal/journal.h>

#include <unistd.h>
#include <netwm.h>

using namespace KCal;

void KNotesLegacy::cleanUp()
{
  // remove old (KDE 1.x) local config file if it still exists
  const QString configfile = KGlobal::dirs()->saveLocation( "config" ) + "knotesrc";
  if ( QFile::exists( configfile ) ) {
    KConfigGroup test(
      KSharedConfig::openConfig( configfile, KConfig::SimpleConfig ),
      "General" );
    double version = test.readEntry( "version", 1.0 );

    if ( version == 1.0 ) {
      if ( !( KStandardDirs::checkAccess( configfile, W_OK ) &&
        QFile::remove( configfile ) ) ) {
          kError( 5500 ) <<"Could not delete old config file" << configfile;
      }
    }
  }
}

bool KNotesLegacy::convert( CalendarLocal *calendar )
{
  bool converted = false;

  QDir noteDir( KGlobal::dirs()->saveLocation( "appdata", "notes/" ) );
  const QStringList notes = noteDir.entryList( QDir::Files, QDir::Name );
  for ( QStringList::ConstIterator note = notes.constBegin(); note != notes.constEnd();
        ++note ) {
    QString file = noteDir.absoluteFilePath( *note );
    KConfig *test = new KConfig( file, KConfig::SimpleConfig );
    KConfigGroup grp( test, "General" );
    double version = grp.readEntry( "version", 1.0 );

    if ( version < 3.0 ) {

      // create the new note
      Journal *journal = new Journal();
      bool success;

      if ( version < 2.0 ) {
        success = convertKNotes1Config( journal, noteDir, *note );
      } else {
        success = convertKNotes2Config( journal, noteDir, *note );
      }

      // could not convert file => do not add a new note
      if ( !success ) {
        delete journal;
      } else {
        calendar->addJournal( journal );
        converted = true;
      }
    } else if ( version < 3.2 ) { // window state changed for version 3.2
#ifdef Q_WS_X11
      uint state = grp.readEntry( "state", uint( NET::SkipTaskbar ) );

      grp.writeEntry( "ShowInTaskbar",
                        ( state & NET::SkipTaskbar ) ? false : true );
      grp.writeEntry( "KeepAbove",
                        ( state & NET::KeepAbove ) ? true : false );
#endif
      grp.deleteEntry( "state" );
    }
    delete test;
  }

  return converted;
}

bool KNotesLegacy::convertKNotes1Config( Journal *journal, QDir &noteDir,
                                         const QString &file )
{
    QFile infile( noteDir.absoluteFilePath( file ) );
    if ( !infile.open( QIODevice::ReadOnly ) ) {
        kError( 5500 ) << "Could not open input file: \""
                       << infile.fileName() << "\"";
        return false;
    }

    QTextStream input( &infile );

    // get the name
    journal->setSummary( input.readLine() );

    const QStringList props = input.readLine().split( '+', QString::SkipEmptyParts );

    // robustness
    if ( props.count() != 13 ) {
      kWarning( 5500 ) <<"The file \"" << infile.fileName()
                       << "\" lacks version information but is not a valid"
                       << "KNotes 1 config file either!";
      return false;
    }

    // the new configfile's name
    const QString configFile = noteDir.absoluteFilePath( journal->uid() );

    // set the defaults
    KIO::NetAccess::file_copy(
        KUrl( KGlobal::dirs()->saveLocation( "config" ) + "knotesrc" ),
        KUrl( configFile ),
        0
    );

    KNoteConfig config( KSharedConfig::openConfig( configFile,
                                                   KConfig::NoGlobals ) );
    config.readConfig();
    config.setVersion( KNOTES_VERSION );

    // get the geometry
    config.setWidth( props[3].toUInt() );
    config.setHeight( props[4].toUInt() );

    // get the background color
    uint red = input.readLine().toUInt();
    uint green = input.readLine().toUInt();
    uint blue = input.readLine().toUInt();
    config.setBgColor( QColor( Qt::red, Qt::green, Qt::blue ) );

    // get the foreground color
    red = input.readLine().toUInt();
    green = input.readLine().toUInt();
    blue = input.readLine().toUInt();
    config.setFgColor( QColor( Qt::red, Qt::green, Qt::blue ) );

    // get the font
    QString fontfamily = input.readLine();
    if ( fontfamily.isEmpty() )
        fontfamily = QString( "Sans Serif" );
    uint size = input.readLine().toUInt();
    size = qMax( size, ( uint ) 4 );
    uint weight = input.readLine().toUInt();
    bool italic = ( input.readLine().toUInt() == 1 );
    QFont font( fontfamily, size, weight, italic );

    config.setTitleFont( font );
    config.setFont( font );

    // 3d frame? Not supported yet!
    input.readLine();

    // autoindent
    config.setAutoIndent( input.readLine().toUInt() == 1 );

    // KNotes 1 never had rich text
    config.setRichText( false );

    int note_desktop = props[0].toUInt();

    // hidden or on all desktops?
    if ( input.readLine().toUInt() == 1 )
        note_desktop = 0;
#ifdef Q_WS_X11
    else if ( props[11].toUInt() == 1 )
        note_desktop = NETWinInfo::OnAllDesktops;
#endif

    config.setDesktop( note_desktop );
    config.setPosition( QPoint( props[1].toUInt(), props[2].toUInt() ) );
    config.setKeepAbove( props[12].toUInt() & 2048 );

    config.writeConfig();

    // get the text
    QString text;
    while ( !input.atEnd() ) {
      text.append( input.readLine() );
      if ( !input.atEnd() ) {
        text.append( '\n' );
      }
    }

    journal->setDescription( text );

    if ( !infile.remove() )
    {
      kWarning( 5500 ) << "Could not delete input file: \"" << infile.fileName()
                       << "\"";
    }

    return true;
}

bool KNotesLegacy::convertKNotes2Config( Journal *journal, QDir &noteDir,
                                         const QString &file )
{
  const QString configFile = noteDir.absoluteFilePath( journal->uid() );

  // new name for config file
  if ( !noteDir.rename( file, journal->uid() ) ) {
    kError( 5500 ) << "Could not rename input file: \""
                   << noteDir.absoluteFilePath( file ) << "\" to \""
                   << configFile << "\"!";
    return false;
  }

  // update the config
  KConfig config( configFile );
  KConfigGroup grp( &config, "Data" );
  journal->setSummary( grp.readEntry( "name" ) );
  config.deleteGroup( "Data", KConfig::Localized );
  KConfigGroup grp2(&config, "General" ); // XXX right?
  grp2.writeEntry( "version", KNOTES_VERSION );
  KConfigGroup grp3(&config, "WindowDisplay" ); // XXX right?
#ifdef Q_WS_X11
  uint state = grp3.readEntry( "state", uint( NET::SkipTaskbar ) );
  grp3.writeEntry( "ShowInTaskbar",
                     ( state & NET::SkipTaskbar ) ? false : true );
  grp3.writeEntry( "KeepAbove",
                      ( state & NET::KeepAbove ) ? true : false );
#endif
  grp3.deleteEntry( "state" );

  // load the saved text and put it in the journal
  QFile infile( noteDir.absoluteFilePath( '.' + file + "_data" ) );
  if ( infile.open( QIODevice::ReadOnly ) ) {
    QTextStream input( &infile );
    input.setCodec( "UTF-8" );
    journal->setDescription( input.readAll() );
    if ( !infile.remove() ) {
      kWarning( 5500 ) << "Could not delete data file: \"" << infile.fileName()
                       << "\"";
    }
  }
  else
    kWarning( 5500 ) << "Could not open data file: \"" << infile.fileName()
                   << "\"";

    return true;
}
<commit_msg>grp* are already defined on windows, so let's use another name<commit_after>/*******************************************************************
 KNotes -- Notes for the KDE project

 Copyright (c) 2002-2004, Michael Brade <brade@kde.org>

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program 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 General Public License for more details.

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

#include "knoteslegacy.h"
#include "knoteconfig.h"
#include "version.h"

#include <QFile>
#include <QFont>
#include <QPoint>
#include <QColor>
#include <QStringList>
#include <QTextStream>

#include <kdebug.h>
#include <kapplication.h>
#include <kglobal.h>
#include <kurl.h>
#include <kstandarddirs.h>
#include <kconfig.h>
#include <kio/netaccess.h>
#include <kcal/calendarlocal.h>
#include <kcal/journal.h>

#include <unistd.h>
#include <netwm.h>

using namespace KCal;

void KNotesLegacy::cleanUp()
{
  // remove old (KDE 1.x) local config file if it still exists
  const QString configfile = KGlobal::dirs()->saveLocation( "config" ) + "knotesrc";
  if ( QFile::exists( configfile ) ) {
    KConfigGroup test(
      KSharedConfig::openConfig( configfile, KConfig::SimpleConfig ),
      "General" );
    double version = test.readEntry( "version", 1.0 );

    if ( version == 1.0 ) {
      if ( !( KStandardDirs::checkAccess( configfile, W_OK ) &&
        QFile::remove( configfile ) ) ) {
          kError( 5500 ) <<"Could not delete old config file" << configfile;
      }
    }
  }
}

bool KNotesLegacy::convert( CalendarLocal *calendar )
{
  bool converted = false;

  QDir noteDir( KGlobal::dirs()->saveLocation( "appdata", "notes/" ) );
  const QStringList notes = noteDir.entryList( QDir::Files, QDir::Name );
  for ( QStringList::ConstIterator note = notes.constBegin(); note != notes.constEnd();
        ++note ) {
    QString file = noteDir.absoluteFilePath( *note );
    KConfig *test = new KConfig( file, KConfig::SimpleConfig );
    KConfigGroup grp( test, "General" );
    double version = grp.readEntry( "version", 1.0 );

    if ( version < 3.0 ) {

      // create the new note
      Journal *journal = new Journal();
      bool success;

      if ( version < 2.0 ) {
        success = convertKNotes1Config( journal, noteDir, *note );
      } else {
        success = convertKNotes2Config( journal, noteDir, *note );
      }

      // could not convert file => do not add a new note
      if ( !success ) {
        delete journal;
      } else {
        calendar->addJournal( journal );
        converted = true;
      }
    } else if ( version < 3.2 ) { // window state changed for version 3.2
#ifdef Q_WS_X11
      uint state = grp.readEntry( "state", uint( NET::SkipTaskbar ) );

      grp.writeEntry( "ShowInTaskbar",
                        ( state & NET::SkipTaskbar ) ? false : true );
      grp.writeEntry( "KeepAbove",
                        ( state & NET::KeepAbove ) ? true : false );
#endif
      grp.deleteEntry( "state" );
    }
    delete test;
  }

  return converted;
}

bool KNotesLegacy::convertKNotes1Config( Journal *journal, QDir &noteDir,
                                         const QString &file )
{
    QFile infile( noteDir.absoluteFilePath( file ) );
    if ( !infile.open( QIODevice::ReadOnly ) ) {
        kError( 5500 ) << "Could not open input file: \""
                       << infile.fileName() << "\"";
        return false;
    }

    QTextStream input( &infile );

    // get the name
    journal->setSummary( input.readLine() );

    const QStringList props = input.readLine().split( '+', QString::SkipEmptyParts );

    // robustness
    if ( props.count() != 13 ) {
      kWarning( 5500 ) <<"The file \"" << infile.fileName()
                       << "\" lacks version information but is not a valid"
                       << "KNotes 1 config file either!";
      return false;
    }

    // the new configfile's name
    const QString configFile = noteDir.absoluteFilePath( journal->uid() );

    // set the defaults
    KIO::NetAccess::file_copy(
        KUrl( KGlobal::dirs()->saveLocation( "config" ) + "knotesrc" ),
        KUrl( configFile ),
        0
    );

    KNoteConfig config( KSharedConfig::openConfig( configFile,
                                                   KConfig::NoGlobals ) );
    config.readConfig();
    config.setVersion( KNOTES_VERSION );

    // get the geometry
    config.setWidth( props[3].toUInt() );
    config.setHeight( props[4].toUInt() );

    // get the background color
    uint red = input.readLine().toUInt();
    uint green = input.readLine().toUInt();
    uint blue = input.readLine().toUInt();
    config.setBgColor( QColor( Qt::red, Qt::green, Qt::blue ) );

    // get the foreground color
    red = input.readLine().toUInt();
    green = input.readLine().toUInt();
    blue = input.readLine().toUInt();
    config.setFgColor( QColor( Qt::red, Qt::green, Qt::blue ) );

    // get the font
    QString fontfamily = input.readLine();
    if ( fontfamily.isEmpty() )
        fontfamily = QString( "Sans Serif" );
    uint size = input.readLine().toUInt();
    size = qMax( size, ( uint ) 4 );
    uint weight = input.readLine().toUInt();
    bool italic = ( input.readLine().toUInt() == 1 );
    QFont font( fontfamily, size, weight, italic );

    config.setTitleFont( font );
    config.setFont( font );

    // 3d frame? Not supported yet!
    input.readLine();

    // autoindent
    config.setAutoIndent( input.readLine().toUInt() == 1 );

    // KNotes 1 never had rich text
    config.setRichText( false );

    int note_desktop = props[0].toUInt();

    // hidden or on all desktops?
    if ( input.readLine().toUInt() == 1 )
        note_desktop = 0;
#ifdef Q_WS_X11
    else if ( props[11].toUInt() == 1 )
        note_desktop = NETWinInfo::OnAllDesktops;
#endif

    config.setDesktop( note_desktop );
    config.setPosition( QPoint( props[1].toUInt(), props[2].toUInt() ) );
    config.setKeepAbove( props[12].toUInt() & 2048 );

    config.writeConfig();

    // get the text
    QString text;
    while ( !input.atEnd() ) {
      text.append( input.readLine() );
      if ( !input.atEnd() ) {
        text.append( '\n' );
      }
    }

    journal->setDescription( text );

    if ( !infile.remove() )
    {
      kWarning( 5500 ) << "Could not delete input file: \"" << infile.fileName()
                       << "\"";
    }

    return true;
}

bool KNotesLegacy::convertKNotes2Config( Journal *journal, QDir &noteDir,
                                         const QString &file )
{
  const QString configFile = noteDir.absoluteFilePath( journal->uid() );

  // new name for config file
  if ( !noteDir.rename( file, journal->uid() ) ) {
    kError( 5500 ) << "Could not rename input file: \""
                   << noteDir.absoluteFilePath( file ) << "\" to \""
                   << configFile << "\"!";
    return false;
  }

  // update the config
  KConfig config( configFile );
  KConfigGroup grp( &config, "Data" );
  journal->setSummary( grp.readEntry( "name" ) );
  config.deleteGroup( "Data", KConfig::Localized );
  KConfigGroup _grp2(&config, "General" ); // XXX right?
  _grp2.writeEntry( "version", KNOTES_VERSION );
  KConfigGroup _grp3(&config, "WindowDisplay" ); // XXX right?
#ifdef Q_WS_X11
  uint state = _grp3.readEntry( "state", uint( NET::SkipTaskbar ) );
  _grp3.writeEntry( "ShowInTaskbar",
                     ( state & NET::SkipTaskbar ) ? false : true );
  _grp3.writeEntry( "KeepAbove",
                      ( state & NET::KeepAbove ) ? true : false );
#endif
  _grp3.deleteEntry( "state" );

  // load the saved text and put it in the journal
  QFile infile( noteDir.absoluteFilePath( '.' + file + "_data" ) );
  if ( infile.open( QIODevice::ReadOnly ) ) {
    QTextStream input( &infile );
    input.setCodec( "UTF-8" );
    journal->setDescription( input.readAll() );
    if ( !infile.remove() ) {
      kWarning( 5500 ) << "Could not delete data file: \"" << infile.fileName()
                       << "\"";
    }
  }
  else
    kWarning( 5500 ) << "Could not open data file: \"" << infile.fileName()
                   << "\"";

    return true;
}
<|endoftext|>


<commit_before>/**
 * Basis Universal single file library. Generated using:
 * \code
 *	./combine.sh -r ../../transcoder -o basisutranslib.cpp basisutranslib-in.cpp
 * \endcode
 *
 * \note BASISD_SUPPORT_DXT5A needs enabling for BC3
 *
 * \todo remove the need for -Wno-pragma-once-outside-header when compiling standalone
 */

/*
 * Build options for known platforms.
 */
#ifdef __APPLE__
#include <TargetConditionals.h>
#endif
#if TARGET_OS_IPHONE
#define BASISD_SUPPORT_DXT1 0
#define BASISD_SUPPORT_DXT5A 0
#endif
#if TARGET_OS_IPHONE || defined(__EMSCRIPTEN__)
#define BASISD_SUPPORT_BC7 0
#define BASISD_SUPPORT_ATC 0
#endif

#include "basisu_transcoder.cpp"

/**
 * Collection of unused functions and const variables to work around \c
 * -Wunused-function and \c -Wunused-const-variable warnings.
 *
 * \todo LTO does its thing so any unused are removed but is there a better way?
 */
void _basisu_translib_dummy() {
	// These first ones are not used at all
	BASISU_NOTE_UNUSED(basisu::byteswap16);
	BASISU_NOTE_UNUSED(basisu::byteswap32);
	BASISU_NOTE_UNUSED(basisu::BASISU_PATH_SEPERATOR_CHAR);
	BASISU_NOTE_UNUSED(basisu::cHuffmanTotalSortedCodelengthCodes);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL0_DELTA_LO);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL0_DELTA_HI);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL1_DELTA_LO);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL1_DELTA_HI);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL2_DELTA_LO);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL2_DELTA_HI);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL2_PREV_HI);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL_MIN_DELTA_B_RUNLEN);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL_DELTA_5_RUNLEN_VLC_BITS);
	BASISU_NOTE_UNUSED(basist::NO_ENDPOINT_PRED_INDEX);
	BASISU_NOTE_UNUSED(basist::MAX_SELECTOR_HISTORY_BUF_SIZE);
#if BASISD_SUPPORT_ETC2_EAC_A8
	// Unused but only when building with EAC
	BASISU_NOTE_UNUSED(basist::g_eac_a8_modifier_table);
#endif
#if BASISD_SUPPORT_PVRTC1
	// Unused but only when building with PVRTC
	BASISU_NOTE_UNUSED(basist::g_pvrtc_bilinear_weights);
#else
	// Unused only when not building with PVRTC
	BASISU_NOTE_UNUSED(basist::g_etc1_inten_tables16);
	BASISU_NOTE_UNUSED(basist::g_etc1_inten_tables48);
	BASISU_NOTE_UNUSED(basist::g_etc_5_to_8);
	BASISU_NOTE_UNUSED(basist::g_etc1_x_selector_unpack);
#endif
}
<commit_msg>Minor: moved note<commit_after>/**
 * Basis Universal single file library. Generated using:
 * \code
 *	./combine.sh -r ../../transcoder -o basisutranslib.cpp basisutranslib-in.cpp
 * \endcode
 *
 * \todo remove the need for -Wno-pragma-once-outside-header when compiling standalone
 */

/*
 * Build options for known platforms.
 *
 * Note: BASISD_SUPPORT_DXT5A needs enabling for BC3
 */
#ifdef __APPLE__
#include <TargetConditionals.h>
#endif
#if TARGET_OS_IPHONE
#define BASISD_SUPPORT_DXT1 0
#define BASISD_SUPPORT_DXT5A 0
#endif
#if TARGET_OS_IPHONE || defined(__EMSCRIPTEN__)
#define BASISD_SUPPORT_BC7 0
#define BASISD_SUPPORT_ATC 0
#endif

#include "basisu_transcoder.cpp"

/**
 * Collection of unused functions and const variables to work around \c
 * -Wunused-function and \c -Wunused-const-variable warnings.
 *
 * \todo LTO does its thing so any unused are removed but is there a better way?
 */
void _basisu_translib_dummy() {
	// These first ones are not used at all
	BASISU_NOTE_UNUSED(basisu::byteswap16);
	BASISU_NOTE_UNUSED(basisu::byteswap32);
	BASISU_NOTE_UNUSED(basisu::BASISU_PATH_SEPERATOR_CHAR);
	BASISU_NOTE_UNUSED(basisu::cHuffmanTotalSortedCodelengthCodes);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL0_DELTA_LO);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL0_DELTA_HI);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL1_DELTA_LO);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL1_DELTA_HI);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL2_DELTA_LO);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL2_DELTA_HI);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL2_PREV_HI);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL_MIN_DELTA_B_RUNLEN);
	BASISU_NOTE_UNUSED(basist::COLOR5_PAL_DELTA_5_RUNLEN_VLC_BITS);
	BASISU_NOTE_UNUSED(basist::NO_ENDPOINT_PRED_INDEX);
	BASISU_NOTE_UNUSED(basist::MAX_SELECTOR_HISTORY_BUF_SIZE);
#if BASISD_SUPPORT_ETC2_EAC_A8
	// Unused but only when building with EAC
	BASISU_NOTE_UNUSED(basist::g_eac_a8_modifier_table);
#endif
#if BASISD_SUPPORT_PVRTC1
	// Unused but only when building with PVRTC
	BASISU_NOTE_UNUSED(basist::g_pvrtc_bilinear_weights);
#else
	// Unused only when not building with PVRTC
	BASISU_NOTE_UNUSED(basist::g_etc1_inten_tables16);
	BASISU_NOTE_UNUSED(basist::g_etc1_inten_tables48);
	BASISU_NOTE_UNUSED(basist::g_etc_5_to_8);
	BASISU_NOTE_UNUSED(basist::g_etc1_x_selector_unpack);
#endif
}
<|endoftext|>


<commit_before>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/core/Mesh.hpp
 *
 * Copyright 2014, 2015 Patrik Huber
 *
 * 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.
 */
#pragma once

#ifndef EOS_MESH_HPP_
#define EOS_MESH_HPP_

#include "Eigen/Core"

#include <array>
#include <cassert>
#include <fstream>
#include <string>
#include <vector>

namespace eos {
namespace core {

/**
 * @brief This class represents a 3D mesh consisting of vertices, vertex colour
 * information and texture coordinates.
 *
 * Additionally it stores the indices that specify which vertices
 * to use to generate the triangle mesh out of the vertices.
 */
struct Mesh
{
    std::vector<Eigen::Vector3f> vertices;  ///< 3D vertex positions.
    std::vector<Eigen::Vector3f> colors;    ///< Colour information for each vertex. Expected to be in RGB order.
    std::vector<Eigen::Vector2f> texcoords; ///< Texture coordinates for each vertex.

    std::vector<std::array<int, 3>> tvi;    ///< Triangle vertex indices
    std::vector<std::array<int, 3>> tci;    ///< Triangle color indices
    std::vector<std::array<int, 3>> tti;    ///< Triangle texture indices
};

/**
 * @brief Writes the given Mesh to an obj file that for example can be read by MeshLab.
 *
 * If the mesh contains vertex colour information, it will be written to the obj as well.
 *
 * @param[in] mesh The mesh to save as obj.
 * @param[in] filename Output filename (including ".obj").
 */
inline void write_obj(Mesh mesh, std::string filename)
{
    assert(mesh.vertices.size() == mesh.colors.size() || mesh.colors.empty());

    std::ofstream obj_file(filename);

    if (mesh.colors.empty())
    {
        for (std::size_t i = 0; i < mesh.vertices.size(); ++i)
        {
            obj_file << "v " << mesh.vertices[i][0] << " " << mesh.vertices[i][1] << " "
                     << mesh.vertices[i][2] << std::endl;
        }
    } else
    {
        for (std::size_t i = 0; i < mesh.vertices.size(); ++i)
        {
            obj_file << "v " << mesh.vertices[i][0] << " " << mesh.vertices[i][1] << " "
                     << mesh.vertices[i][2] << " " << mesh.colors[i][0] << " " << mesh.colors[i][1] << " "
                     << mesh.colors[i][2] << std::endl;
        }
    }

    if (!mesh.texcoords.empty())
    {
        for (auto&& tc : mesh.texcoords)
        {
            obj_file << "vt " << tc[0] << " " << tc[1] << std::endl;
        }
    }

    for (auto&& v : mesh.tvi)
    {
        // Add one because obj starts counting triangle indices at 1
        obj_file << "f " << v[0] + 1 << " " << v[1] + 1 << " " << v[2] + 1 << std::endl;
    }

    return;
}

/**
 * @brief Writes an obj file of the given Mesh, including texture coordinates,
 * and an mtl file containing a reference to the isomap.
 *
 * The obj will contain texture coordinates for the mesh, and the
 * mtl file will link to a file named <filename>.isomap.png.
 * Note that the texture (isomap) has to be saved separately.
 *
 * @param[in] mesh The mesh to save as obj.
 * @param[in] filename Output filename, including .obj.
 */
inline void write_textured_obj(Mesh mesh, std::string filename)
{
    assert((mesh.vertices.size() == mesh.colors.size() || mesh.colors.empty()) && !mesh.texcoords.empty());

    if (filename.at(filename.size() - 4) != '.')
    {
        throw std::runtime_error(
            "Error in given filename: Expected a dot and a 3-letter extension at the end (i.e. '.obj'). " +
            filename);
    }

    // Takes a full path to a file and returns only the filename:
    const auto get_filename = [](const std::string& path) {
        auto last_slash = path.find_last_of("/\\");
        if (last_slash == std::string::npos)
        {
            return path;
        }
        return path.substr(last_slash + 1, path.size());
    };

    std::ofstream obj_file(filename);

    std::string mtl_filename(filename);
    // replace '.obj' at the end with '.mtl':
    mtl_filename.replace(std::end(mtl_filename) - 4, std::end(mtl_filename), ".mtl");

    obj_file << "mtllib " << get_filename(mtl_filename) << std::endl; // first line of the obj file

    // same as in write_obj():
    if (mesh.colors.empty())
    {
        for (std::size_t i = 0; i < mesh.vertices.size(); ++i)
        {
            obj_file << "v " << mesh.vertices[i][0] << " " << mesh.vertices[i][1] << " "
                     << mesh.vertices[i][2] << " " << std::endl;
        }
    } else
    {
        for (std::size_t i = 0; i < mesh.vertices.size(); ++i)
        {
            obj_file << "v " << mesh.vertices[i][0] << " " << mesh.vertices[i][1] << " "
                     << mesh.vertices[i][2] << " " << mesh.colors[i][0] << " " << mesh.colors[i][1] << " "
                     << mesh.colors[i][2] << " " << std::endl;
        }
    }
    // end

    for (std::size_t i = 0; i < mesh.texcoords.size(); ++i)
    {
        obj_file << "vt " << mesh.texcoords[i][0] << " " << 1.0f - mesh.texcoords[i][1] << std::endl;
        // We invert y because Meshlab's uv origin (0, 0) is on the bottom-left
    }

    obj_file << "usemtl FaceTexture" << std::endl; // the name of our texture (material) will be 'FaceTexture'

    for (auto&& v : mesh.tvi)
    {
        // This assumes mesh.texcoords.size() == mesh.vertices.size(). The texture indices could theoretically be different (for example in the cube-mapped 3D scan).
        // Add one because obj starts counting triangle indices at 1
        obj_file << "f " << v[0] + 1 << "/" << v[0] + 1 << " " << v[1] + 1 << "/" << v[1] + 1 << " "
                 << v[2] + 1 << "/" << v[2] + 1 << std::endl;
    }

    std::ofstream mtl_file(mtl_filename);
    std::string texture_filename(filename);
    // replace '.obj' at the end with '.isomap.png':
    texture_filename.replace(std::end(texture_filename) - 4, std::end(texture_filename), ".isomap.png");

    mtl_file << "newmtl FaceTexture" << std::endl;
    mtl_file << "map_Kd " << get_filename(texture_filename) << std::endl;

    return;
};

} /* namespace core */
} /* namespace eos */

#endif /* EOS_MESH_HPP_ */
<commit_msg>Added note about tti to Mesh<commit_after>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/core/Mesh.hpp
 *
 * Copyright 2014, 2015 Patrik Huber
 *
 * 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.
 */
#pragma once

#ifndef EOS_MESH_HPP_
#define EOS_MESH_HPP_

#include "Eigen/Core"

#include <array>
#include <cassert>
#include <fstream>
#include <string>
#include <vector>

namespace eos {
namespace core {

/**
 * @brief This class represents a 3D mesh consisting of vertices, vertex colour
 * information and texture coordinates.
 *
 * Additionally it stores the indices that specify which vertices
 * to use to generate the triangle mesh out of the vertices.
 *
 * \c texcoords should either be the same size as \c vertices (i.e. one set of texture coordinates per
 * vertex), or alternatively \c tti can be set, then a separate triangulation for the texture coordinates can
 * be used (e.g. for texture maps that contain seams).
 */
struct Mesh
{
    std::vector<Eigen::Vector3f> vertices;  ///< 3D vertex positions.
    std::vector<Eigen::Vector3f> colors;    ///< Colour information for each vertex. Expected to be in RGB order.
    std::vector<Eigen::Vector2f> texcoords; ///< Texture coordinates.

    std::vector<std::array<int, 3>> tvi;    ///< Triangle vertex indices
    std::vector<std::array<int, 3>> tci;    ///< Triangle color indices (usually the same as tvi)
    std::vector<std::array<int, 3>> tti;    ///< Triangle texture indices
};

/**
 * @brief Writes the given Mesh to an obj file that for example can be read by MeshLab.
 *
 * If the mesh contains vertex colour information, it will be written to the obj as well.
 *
 * @param[in] mesh The mesh to save as obj.
 * @param[in] filename Output filename (including ".obj").
 */
inline void write_obj(Mesh mesh, std::string filename)
{
    assert(mesh.vertices.size() == mesh.colors.size() || mesh.colors.empty());

    std::ofstream obj_file(filename);

    if (mesh.colors.empty())
    {
        for (std::size_t i = 0; i < mesh.vertices.size(); ++i)
        {
            obj_file << "v " << mesh.vertices[i][0] << " " << mesh.vertices[i][1] << " "
                     << mesh.vertices[i][2] << std::endl;
        }
    } else
    {
        for (std::size_t i = 0; i < mesh.vertices.size(); ++i)
        {
            obj_file << "v " << mesh.vertices[i][0] << " " << mesh.vertices[i][1] << " "
                     << mesh.vertices[i][2] << " " << mesh.colors[i][0] << " " << mesh.colors[i][1] << " "
                     << mesh.colors[i][2] << std::endl;
        }
    }

    if (!mesh.texcoords.empty())
    {
        for (auto&& tc : mesh.texcoords)
        {
            obj_file << "vt " << tc[0] << " " << tc[1] << std::endl;
        }
    }

    for (auto&& v : mesh.tvi)
    {
        // Add one because obj starts counting triangle indices at 1
        obj_file << "f " << v[0] + 1 << " " << v[1] + 1 << " " << v[2] + 1 << std::endl;
    }

    return;
}

/**
 * @brief Writes an obj file of the given Mesh, including texture coordinates,
 * and an mtl file containing a reference to the isomap.
 *
 * The obj will contain texture coordinates for the mesh, and the
 * mtl file will link to a file named <filename>.isomap.png.
 * Note that the texture (isomap) has to be saved separately.
 *
 * @param[in] mesh The mesh to save as obj.
 * @param[in] filename Output filename, including .obj.
 */
inline void write_textured_obj(Mesh mesh, std::string filename)
{
    assert((mesh.vertices.size() == mesh.colors.size() || mesh.colors.empty()) && !mesh.texcoords.empty());

    if (filename.at(filename.size() - 4) != '.')
    {
        throw std::runtime_error(
            "Error in given filename: Expected a dot and a 3-letter extension at the end (i.e. '.obj'). " +
            filename);
    }

    // Takes a full path to a file and returns only the filename:
    const auto get_filename = [](const std::string& path) {
        auto last_slash = path.find_last_of("/\\");
        if (last_slash == std::string::npos)
        {
            return path;
        }
        return path.substr(last_slash + 1, path.size());
    };

    std::ofstream obj_file(filename);

    std::string mtl_filename(filename);
    // replace '.obj' at the end with '.mtl':
    mtl_filename.replace(std::end(mtl_filename) - 4, std::end(mtl_filename), ".mtl");

    obj_file << "mtllib " << get_filename(mtl_filename) << std::endl; // first line of the obj file

    // same as in write_obj():
    if (mesh.colors.empty())
    {
        for (std::size_t i = 0; i < mesh.vertices.size(); ++i)
        {
            obj_file << "v " << mesh.vertices[i][0] << " " << mesh.vertices[i][1] << " "
                     << mesh.vertices[i][2] << " " << std::endl;
        }
    } else
    {
        for (std::size_t i = 0; i < mesh.vertices.size(); ++i)
        {
            obj_file << "v " << mesh.vertices[i][0] << " " << mesh.vertices[i][1] << " "
                     << mesh.vertices[i][2] << " " << mesh.colors[i][0] << " " << mesh.colors[i][1] << " "
                     << mesh.colors[i][2] << " " << std::endl;
        }
    }
    // end

    for (std::size_t i = 0; i < mesh.texcoords.size(); ++i)
    {
        obj_file << "vt " << mesh.texcoords[i][0] << " " << 1.0f - mesh.texcoords[i][1] << std::endl;
        // We invert y because Meshlab's uv origin (0, 0) is on the bottom-left
    }

    obj_file << "usemtl FaceTexture" << std::endl; // the name of our texture (material) will be 'FaceTexture'

    for (auto&& v : mesh.tvi)
    {
        // This assumes mesh.texcoords.size() == mesh.vertices.size(). The texture indices could theoretically be different (for example in the cube-mapped 3D scan).
        // Add one because obj starts counting triangle indices at 1
        obj_file << "f " << v[0] + 1 << "/" << v[0] + 1 << " " << v[1] + 1 << "/" << v[1] + 1 << " "
                 << v[2] + 1 << "/" << v[2] + 1 << std::endl;
    }

    std::ofstream mtl_file(mtl_filename);
    std::string texture_filename(filename);
    // replace '.obj' at the end with '.isomap.png':
    texture_filename.replace(std::end(texture_filename) - 4, std::end(texture_filename), ".isomap.png");

    mtl_file << "newmtl FaceTexture" << std::endl;
    mtl_file << "map_Kd " << get_filename(texture_filename) << std::endl;

    return;
};

} /* namespace core */
} /* namespace eos */

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


<commit_before>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file
 * \brief Contains allocation utilities
 */

#pragma once

#include <memory>

namespace etl {

/*!
 * \brief Allocated for aligned memory
 * \tparam Expr The expression typoe
 * \tparam A The alignment
 */
template <typename Expr, std::size_t A>
struct aligned_allocator {
    /*!
     * \brief Allocate a block of memory of *size* elements
     * \param size The number of elements
     * \return A pointer to the allocated memory
     */
    template <typename T>
    static T* allocate(std::size_t size) {
        auto required_bytes = sizeof(T) * size;
        auto offset         = (A - 1) + sizeof(uintptr_t);
        auto orig           = malloc(required_bytes + offset);

        if (!orig) {
            return nullptr;
        }

        auto aligned = reinterpret_cast<void**>((reinterpret_cast<size_t>(orig) + offset) & ~(A - 1));
        aligned[-1] = orig;
        return reinterpret_cast<T*>(aligned);
    }

    /*!
     * \brief Release the memory
     * \param ptr The pointer to the memory to be released
     */
    template <typename T>
    static void release(T* ptr) {
        //Note the const_cast is only to allow compilation
        free((reinterpret_cast<void**>(const_cast<std::remove_const_t<T>*>(ptr)))[-1]);
    }
};

/*!
 * \brief Allocate an array of the given size for the given type
 * \param size The number of elements
 * \return An unique pointer to the memory
 */
template <typename T>
auto allocate(std::size_t size) {
    return std::make_unique<T[]>(size);
}

/*!
 * \brief Allocate an aligned rray of the given size for the given type
 * \param size The number of elements
 * \return A pointer to the aligned memory
 */
template <typename T>
T* aligned_allocate(std::size_t size) {
    return aligned_allocator<void, 32>::allocate<T>(size);
}

/*!
 * \brief Release some aligned memory
 * \param ptr The ptr to the aligned memory
 */
template <typename T>
void aligned_release(T* ptr) {
    return aligned_allocator<void, 32>::release<T>(ptr);
}

} //end of namespace etl
<commit_msg>Add RAII support to aligned allocations<commit_after>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file
 * \brief Contains allocation utilities
 */

#pragma once

#include <memory>

namespace etl {

/*!
 * \brief Allocated for aligned memory
 * \tparam Expr The expression typoe
 * \tparam A The alignment
 */
template <typename Expr, std::size_t A>
struct aligned_allocator {
    /*!
     * \brief Allocate a block of memory of *size* elements
     * \param size The number of elements
     * \return A pointer to the allocated memory
     */
    template <typename T>
    static T* allocate(std::size_t size) {
        auto required_bytes = sizeof(T) * size;
        auto offset         = (A - 1) + sizeof(uintptr_t);
        auto orig           = malloc(required_bytes + offset);

        if (!orig) {
            return nullptr;
        }

        auto aligned = reinterpret_cast<void**>((reinterpret_cast<size_t>(orig) + offset) & ~(A - 1));
        aligned[-1] = orig;
        return reinterpret_cast<T*>(aligned);
    }

    /*!
     * \brief Release the memory
     * \param ptr The pointer to the memory to be released
     */
    template <typename T>
    static void release(T* ptr) {
        //Note the const_cast is only to allow compilation
        free((reinterpret_cast<void**>(const_cast<std::remove_const_t<T>*>(ptr)))[-1]);
    }
};

/*!
 * \brief Allocate an array of the given size for the given type
 * \param size The number of elements
 * \return An unique pointer to the memory
 */
template <typename T>
auto allocate(std::size_t size) {
    return std::make_unique<T[]>(size);
}

/*!
 * \brief Allocate an aligned rray of the given size for the given type
 * \param size The number of elements
 * \return A pointer to the aligned memory
 */
template <typename T>
T* aligned_allocate(std::size_t size) {
    return aligned_allocator<void, 32>::allocate<T>(size);
}

/*!
 * \brief Release some aligned memory
 * \param ptr The ptr to the aligned memory
 */
template <typename T>
void aligned_release(T* ptr) {
    return aligned_allocator<void, 32>::release<T>(ptr);
}

template <typename T>
struct aligned_ptr {
    T* ptr;

    aligned_ptr(T* ptr) : ptr(ptr) {}

    aligned_ptr(const aligned_ptr& rhs) = delete;
    aligned_ptr& operator=(const aligned_ptr& rhs) = delete;

    aligned_ptr(aligned_ptr&& rhs) : ptr(rhs.ptr) {
        rhs.ptr = nullptr;
    }

    aligned_ptr& operator=(aligned_ptr&& rhs){
        if(this != &rhs){
            ptr = rhs.ptr;
            rhs.ptr = nullptr;
        }

        return *this;
    }

    inline T& operator[](std::size_t i){
        return ptr[i];
    }

    inline const T& operator[](std::size_t i) const {
        return ptr[i];
    }

    ~aligned_ptr(){
        if(ptr){
            aligned_release(ptr);
        }
    }

    T* get(){
        return ptr;
    }
};

/*!
 * \brief Allocate an aligned rray of the given size for the given type
 * \param size The number of elements
 * \return A pointer to the aligned memory
 */
template <typename T>
aligned_ptr<T> aligned_allocate_auto(std::size_t size) {
    return {aligned_allocate(size)};
}

} //end of namespace etl
<|endoftext|>


<commit_before>#pragma once
#include <cstdint>
#include <array>
#include <vector>
#include <utility>
#include <algorithm.hpp>
#include <case.hpp>
#include <cube.hpp>

namespace InsertionFinder {
    class Finder {
    protected:
        struct CycleStatus {
            bool parity;
            int corner_cycles;
            int edge_cycles;
            int placement;
        };
    public:
        struct Insertion {
            Algorithm skeleton;
            std::size_t insert_place;
            const Algorithm* insertion;
        };
        struct Solution {
            std::vector<Insertion> insertions;
            std::size_t cancellation;
        };
        enum class Status {
            SUCCESS,
            SUCCESS_SOLVED,
            FAILURE_PARITY_ALGORITHMS_NEEDED,
            FAILURE_CORNER_CYCLE_ALGORITHMS_NEEDED,
            FAILURE_EDGE_CYCLE_ALGORITHMS_NEEDED,
            FAILURE_CENTER_ALGORITHMS_NEEDED
        };
        struct Result {
            Status status;
            std::int64_t duration;
        };
    protected:
        const Algorithm scramble;
        const Algorithm skeleton;
        const std::vector<Case>& cases;
        std::size_t fewest_moves;
        std::vector<Solution> solutions;
        Result result;
        bool verbose;
    protected:
        std::array<int, 7 * 24 * 11 * 24> parity_index;
        std::array<int, 6 * 24 * 24> corner_cycle_index;
        std::array<int, 10 * 24 * 24> edge_cycle_index;
        std::array<int, 24> center_index;
        bool change_parity;
        bool change_corner;
        bool change_edge;
        bool change_center;
        Cube scramble_cube;
        Cube inverse_scramble_cube;
    public:
        Finder(
            const Algorithm& scramble, const Algorithm& skeleton,
            const std::vector<Case>& cases
        );
    public:
        void search(std::size_t max_threads);
        virtual Status search_core(std::size_t max_threads) = 0;
    public:
        std::size_t get_fewest_moves() const noexcept {
            return this->fewest_moves;
        }
        std::vector<Solution> get_solutions() const noexcept {
            return this->solutions;
        }
        Result get_result() const noexcept {
            return this->result;
        }
    public:
        void set_verbose(bool verbose = true) noexcept {
            this->verbose = verbose;
        }
    };
};
<commit_msg>make Finder::fewest_moves atomic<commit_after>#pragma once
#include <cstdint>
#include <array>
#include <atomic>
#include <vector>
#include <utility>
#include <algorithm.hpp>
#include <case.hpp>
#include <cube.hpp>

namespace InsertionFinder {
    class Finder {
    protected:
        struct CycleStatus {
            bool parity;
            int corner_cycles;
            int edge_cycles;
            int placement;
        };
    public:
        struct Insertion {
            Algorithm skeleton;
            std::size_t insert_place;
            const Algorithm* insertion;
        };
        struct Solution {
            std::vector<Insertion> insertions;
            std::size_t cancellation;
        };
        enum class Status {
            SUCCESS,
            SUCCESS_SOLVED,
            FAILURE_PARITY_ALGORITHMS_NEEDED,
            FAILURE_CORNER_CYCLE_ALGORITHMS_NEEDED,
            FAILURE_EDGE_CYCLE_ALGORITHMS_NEEDED,
            FAILURE_CENTER_ALGORITHMS_NEEDED
        };
        struct Result {
            Status status;
            std::int64_t duration;
        };
    protected:
        const Algorithm scramble;
        const Algorithm skeleton;
        const std::vector<Case>& cases;
        std::atomic<std::size_t> fewest_moves;
        std::vector<Solution> solutions;
        Result result;
        bool verbose;
    protected:
        std::array<int, 7 * 24 * 11 * 24> parity_index;
        std::array<int, 6 * 24 * 24> corner_cycle_index;
        std::array<int, 10 * 24 * 24> edge_cycle_index;
        std::array<int, 24> center_index;
        bool change_parity;
        bool change_corner;
        bool change_edge;
        bool change_center;
        Cube scramble_cube;
        Cube inverse_scramble_cube;
    public:
        Finder(
            const Algorithm& scramble, const Algorithm& skeleton,
            const std::vector<Case>& cases
        );
    public:
        void search(std::size_t max_threads);
        virtual Status search_core(std::size_t max_threads) = 0;
    public:
        std::size_t get_fewest_moves() const noexcept {
            return this->fewest_moves;
        }
        std::vector<Solution> get_solutions() const noexcept {
            return this->solutions;
        }
        Result get_result() const noexcept {
            return this->result;
        }
    public:
        void set_verbose(bool verbose = true) noexcept {
            this->verbose = verbose;
        }
    };
};
<|endoftext|>


<commit_before>// Copyright 2017 Global Phasing Ltd.
//
// to_str(float|double), handling -D USE_STD_SNPRINTF

#ifndef GEMMI_SPRINTF_HPP_
#define GEMMI_SPRINTF_HPP_

#ifdef USE_STD_SNPRINTF  // for benchmarking and testing only
# include <cstdio>
# define gstb_snprintf std::snprintf
# define gstb_sprintf std::sprintf
#else
# ifdef GEMMI_WRITE_IMPLEMENTATION
#  define STB_SPRINTF_IMPLEMENTATION
# endif
# define STB_SPRINTF_DECORATE(name) gstb_##name
# include "third_party/stb_sprintf.h"
#endif
#include <string>

namespace gemmi {

inline std::string to_str(double d) {
  char buf[24];
  int len = gstb_sprintf(buf, "%.9g", d);
  return std::string(buf, len > 0 ? len : 0);
}

inline std::string to_str(float d) {
  char buf[16];
  int len = gstb_sprintf(buf, "%.6g", d);
  return std::string(buf, len > 0 ? len : 0);
}

template<int Prec>
std::string to_str_prec(double d) {
  static_assert(Prec >= 0 && Prec < 7, "unsupported precision");
  char buf[16];
  int len = d > -1e8 && d < 1e8 ? gstb_sprintf(buf, "%.*f", Prec, d)
                                : gstb_sprintf(buf, "%g", d);
  return std::string(buf, len > 0 ? len : 0);
}

// this is equivalent of stbsp_snprintf, but with __attribute__(format)
#if defined(__GNUC__) || defined(__clang)
__attribute__((format(printf, 3, 4)))
#endif
inline int gf_snprintf(char *buf, int count, char const *fmt, ...) {
   int result;
   va_list va;
   va_start(va, fmt);
   result = gstb_vsnprintf(buf, count, fmt, va);
   va_end(va);
   return result;
}

} // namespace gemmi
#endif
<commit_msg>MinGW may not support %zu when it uses old msvcrt<commit_after>// Copyright 2017 Global Phasing Ltd.
//
// to_str(float|double), handling -D USE_STD_SNPRINTF

#ifndef GEMMI_SPRINTF_HPP_
#define GEMMI_SPRINTF_HPP_

#ifdef USE_STD_SNPRINTF  // for benchmarking and testing only
# include <cstdio>
# define gstb_snprintf std::snprintf
# define gstb_sprintf std::sprintf
#else
# ifdef GEMMI_WRITE_IMPLEMENTATION
#  define STB_SPRINTF_IMPLEMENTATION
# endif
# define STB_SPRINTF_DECORATE(name) gstb_##name
# include "third_party/stb_sprintf.h"
#endif
#include <string>

namespace gemmi {

inline std::string to_str(double d) {
  char buf[24];
  int len = gstb_sprintf(buf, "%.9g", d);
  return std::string(buf, len > 0 ? len : 0);
}

inline std::string to_str(float d) {
  char buf[16];
  int len = gstb_sprintf(buf, "%.6g", d);
  return std::string(buf, len > 0 ? len : 0);
}

template<int Prec>
std::string to_str_prec(double d) {
  static_assert(Prec >= 0 && Prec < 7, "unsupported precision");
  char buf[16];
  int len = d > -1e8 && d < 1e8 ? gstb_sprintf(buf, "%.*f", Prec, d)
                                : gstb_sprintf(buf, "%g", d);
  return std::string(buf, len > 0 ? len : 0);
}

// this is equivalent of stbsp_snprintf, but with __attribute__(format)
#if (defined(__GNUC__) && !defined(__MINGW32__)) || defined(__clang)
__attribute__((format(printf, 3, 4)))
#endif
inline int gf_snprintf(char *buf, int count, char const *fmt, ...) {
   int result;
   va_list va;
   va_start(va, fmt);
   result = gstb_vsnprintf(buf, count, fmt, va);
   va_end(va);
   return result;
}

} // namespace gemmi
#endif
<|endoftext|>


<commit_before>#pragma once

#include <random>
using std::random_device;
using std::mt19937_64;

namespace hop {
  class Random {
    public:
      static mt19937_64 RNG;

    protected:
      static random_device RANDOM_DEVIDE;
  };
}
<commit_msg>devel: Removed "using ..." notation and added namespaces directly<commit_after>#pragma once

#include <random>

namespace hop {
  class Random {
    public:
      static std::mt19937_64 RNG;

    protected:
      static std::random_device RANDOM_DEVIDE;
  };
}
<|endoftext|>


<commit_before>#include "Config.hpp"
#include "EventOutputQueue.hpp"
#include "ListHookedConsumer.hpp"
#include "ListHookedKeyboard.hpp"
#include "ListHookedPointing.hpp"
#include "PressDownKeys.hpp"
#include "RemapClass.hpp"
#include "VirtualKey.hpp"
#include "VK_IOHIDPOSTEVENT.hpp"

namespace org_pqrs_Karabiner {
List EventOutputQueue::queue_;
TimerWrapper EventOutputQueue::fire_timer_;
Buttons EventOutputQueue::previousButtons_;
uint64_t EventOutputQueue::lastProcessedEventInputQueueSerialNumber_;

void EventOutputQueue::initialize(IOWorkLoop& workloop) {
  fire_timer_.initialize(&workloop, nullptr, EventOutputQueue::fire_timer_callback);
  lastProcessedEventInputQueueSerialNumber_ = 0;
}

void EventOutputQueue::terminate(void) {
  fire_timer_.terminate();

  queue_.clear();
}

// ----------------------------------------------------------------------
#define PUSH_TO_OUTPUTQUEUE                              \
  {                                                      \
    queue_.push_back(new Item(p, AutogenId(autogenId))); \
    fire_timer_.setTimeoutMS(0, false);                  \
  }
void EventOutputQueue::push(const Params_KeyboardEventCallBack& p, AutogenId autogenId) {
  PUSH_TO_OUTPUTQUEUE;
  if (p.eventType == EventType::DOWN) {
    FlagStatus::globalFlagStatus().sticky_clear();
  }
}
void EventOutputQueue::push(const Params_KeyboardSpecialEventCallback& p, AutogenId autogenId) {
  PUSH_TO_OUTPUTQUEUE;
  if (p.ex_iskeydown) {
    FlagStatus::globalFlagStatus().sticky_clear();
  }
}
void EventOutputQueue::push(const Params_RelativePointerEventCallback& p, AutogenId autogenId) {
  PUSH_TO_OUTPUTQUEUE;
  if (p.buttons != Buttons(0)) {
    FlagStatus::globalFlagStatus().sticky_clear();
  }
}
void EventOutputQueue::push(const Params_ScrollWheelEventCallback& p, AutogenId autogenId) {
  PUSH_TO_OUTPUTQUEUE;
  FlagStatus::globalFlagStatus().sticky_clear();
}
void EventOutputQueue::push(const Params_Wait& p, AutogenId autogenId) {
  PUSH_TO_OUTPUTQUEUE;
}
#undef PUSH_TO_OUTPUTQUEUE

// ----------------------------------------------------------------------
unsigned int
EventOutputQueue::calcDelay(const Params_Base& paramsBase) {
  // ----------------------------------------
  {
    // Delay before and after modifier
    //
    // We need to wait before and after a modifier event because
    // events will be dropped by window server if
    // we send a mouse click event and a modifier event at the same time.
    //
    // For example, change middle click to command-left click by this autogen.
    // We need to put a wait on this setting in Mail.app.
    //    <autogen>
    //      __KeyToKey__
    //      PointingButton::MIDDLE, ModifierFlag::NONE,
    //      PointingButton::LEFT, ModifierFlag::COMMAND_L,
    //    </autogen>
    //
    if (paramsBase.isModifier()) {
      return Config::get_wait_before_and_after_a_modifier_key_event();
    }
  }

  // ----------------------------------------
  {
    // Delay before and after modifier
    //
    // We need to wait before and after a pointing device click event because
    // events will be dropped by processes (eg. NetBeans) if
    // we send press button event and release button event at the same time.
    //

    auto params = paramsBase.get_Params_RelativePointerEventCallback();
    if (params) {
      if (params->buttons != previousButtons_) {
        previousButtons_ = params->buttons;
        return Config::get_wait_before_and_after_a_click_event();
      }
    }
  }

  // ----------------------------------------
  return 0;
}

namespace {
unsigned int maxDelay(unsigned int v1, unsigned int v2) {
  if (v1 > v2) {
    return v1;
  } else {
    return v2;
  }
}
}

void EventOutputQueue::fire_timer_callback(OSObject* /* owner */, IOTimerEventSource* /* sender */) {
  // We need to cancelEventOutputQueueItems in fire_timer_callback
  // in order to cancel __HoldingKeyToKey__ events.
  RemapClassManager::cancelEventOutputQueueItems();

  // Delete canceled items.
  Item* p = nullptr;

  p = static_cast<Item*>(queue_.safe_front());
  while (p) {
    if (p->isCanceled()) {
      p = static_cast<Item*>(queue_.erase_and_delete(p));
    } else {
      p = static_cast<Item*>(p->getnext());
    }
  }

  // ------------------------------------------------------------
  // Send key event.
  p = static_cast<Item*>(queue_.safe_front());
  if (!p) return;

  // Delay after modifier or click.
  unsigned int delay = calcDelay(p->getParamsBase());

  // ----------------------------------------
  {
    auto params = (p->getParamsBase()).get_Params_KeyboardEventCallBack();
    if (params) {
      bool handled = VirtualKey::handleAfterEnqueued(*params);
      if (!handled) {
        ListHookedKeyboard::instance().apply(*params);
      }

      // We need to wait at least 1ms in order to avoid changing key sequence order randomly.
      // (If VMware Fusion's driver is installed, the wrong order issue will be happen.)
      delay = maxDelay(delay, 1);
    }
  }
  {
    auto params = (p->getParamsBase()).get_Params_UpdateEventFlagsCallback();
    if (params) {
      // We need to wait at least 1ms in order to avoid changing key sequence order randomly.
      // (If VMware Fusion's driver is installed, the wrong order issue will be happen.)
      delay = maxDelay(delay, 1);
    }
  }
  {
    auto params = (p->getParamsBase()).get_Params_KeyboardSpecialEventCallback();
    if (params) {
      if (!ListHookedConsumer::instance().apply(*params)) {
        // If there is no consumer device, we send an event as a software key.
        VirtualKey::VK_IOHIDPOSTEVENT::post(*params);
      }

      // We need to wait at least 1ms in order to avoid changing key sequence order randomly.
      // (If VMware Fusion's driver is installed, the wrong order issue will be happen.)
      delay = maxDelay(delay, 1);
    }
  }
  {
    auto params = (p->getParamsBase()).get_Params_RelativePointerEventCallback();
    if (params) {
      ListHookedPointing::instance().apply(*params);
    }
  }
  {
    auto params = (p->getParamsBase()).get_Params_ScrollWheelEventCallback();
    if (params) {
      ListHookedPointing::instance().apply(*params);
    }
  }
  {
    auto params = (p->getParamsBase()).get_Params_Wait();
    if (params) {
      delay = maxDelay(delay, static_cast<unsigned int>(params->milliseconds));
    }
  }

  queue_.pop_front();

  // ----------------------------------------
  // Set timeout for next event.

  // Delay before modifier and click.
  Item* next = static_cast<Item*>(queue_.safe_front());
  if (!next) return;
  delay = maxDelay(delay, calcDelay(next->getParamsBase()));

  fire_timer_.setTimeoutMS(delay);
}

void EventOutputQueue::collapseModifierKeyUpDownEvent(void) {
  // Find EventType::UP
  for (Item* p = static_cast<Item*>(queue_.safe_front()); p; p = static_cast<Item*>(p->getnext())) {
    auto params = (p->getParamsBase()).get_Params_KeyboardEventCallBack();
    if (params &&
        params->isModifier() &&
        !params->ex_iskeydown) {
      // `p` is modifier up event.
      // Check next event is EventType::DOWN
      auto next = static_cast<Item*>(p->getnext());
      if (next &&
          p->getEventInputQueueSerialNumber() == next->getEventInputQueueSerialNumber()) {
#if 0
        auto nextParams = (next->getParamsBase()).get_Params_KeyboardEventCallBack();
        if (nextParams &&
            params->key == nextParams->key &&
            nextParams->ex_iskeydown) {
          // `next` is modifier down event.
          p->cancel();
          next->cancel();
        }
#endif
      }
    }
  }
}

// ======================================================================
Flags EventOutputQueue::FireModifiers::lastFlags_(0);

void EventOutputQueue::FireModifiers::fire(AutogenId autogenId, Flags toFlags, KeyboardType keyboardType) {
  if (lastFlags_ == toFlags) return;

  // ------------------------------------------------------------
  // At first we handle KeyUp events and handle KeyDown events next.
  // We need to end KeyDown at Command+Space to Option_L+Shift_L.
  //
  // When Option_L+Shift_L has a meaning (switch input language at Windows),
  // it does not works well when the last is KeyUp of Command.

  // ------------------------------------------------------------
  // KeyUp
  for (size_t i = 0; i < FlagStatus::globalFlagStatus().itemSize(); ++i) {
    ModifierFlag flag = FlagStatus::globalFlagStatus().getFlag(i);

    // Skipping ModifierFlag::NUMPAD
    if (flag.getKeyCode() == KeyCode::VK_NONE) continue;
    // Skipping virtual modifiers.
    if (flag.getRawBits() == 0) continue;

    // ----------------------------------------
    if (!lastFlags_.isOn(flag)) continue;
    if (toFlags.isOn(flag)) continue;

    lastFlags_.remove(flag);

    Params_KeyboardEventCallBack params(EventType::MODIFY, lastFlags_, flag.getKeyCode(), keyboardType, false);
    EventOutputQueue::push(params, autogenId);
  }

  // KeyDown
  for (size_t i = 0; i < FlagStatus::globalFlagStatus().itemSize(); ++i) {
    ModifierFlag flag = FlagStatus::globalFlagStatus().getFlag(i);

    // Skipping ModifierFlag::NUMPAD
    if (flag.getKeyCode() == KeyCode::VK_NONE) continue;
    // Skipping virtual modifiers.
    if (flag.getRawBits() == 0) continue;

    // ----------------------------------------
    if (!toFlags.isOn(flag)) continue;
    if (lastFlags_.isOn(flag)) continue;

    lastFlags_.add(flag);

    Params_KeyboardEventCallBack params(EventType::MODIFY, lastFlags_, flag.getKeyCode(), keyboardType, false);
    EventOutputQueue::push(params, autogenId);
  }
}

// ======================================================================
void EventOutputQueue::FireKey::fire(const Params_KeyboardEventCallBack& params, AutogenId autogenId) {
  if (VirtualKey::handle(params, autogenId)) return;

  // ------------------------------------------------------------
  KeyCode newkeycode = params.key;
  Flags newflags = params.flags;

  KeyCode::reverseNormalizeKey(newkeycode, newflags, params.eventType, params.keyboardType);

  // skip no-outputable keycodes.
  // Note: check before FireModifiers to avoid meaningless modifier event.
  if (newkeycode == KeyCode::VK_NONE ||
      newkeycode == KeyCode::VK_PSEUDO_KEY) {
    return;
  }
  if (newkeycode.isModifier() && newkeycode.getModifierFlag().getRawBits() == 0) {
    // virtual modifiers.
    return;
  }

  FireModifiers::fire(autogenId, newflags, params.keyboardType);

  if (params.eventType == EventType::DOWN || params.eventType == EventType::UP) {
    Params_KeyboardEventCallBack p(params.eventType, newflags, newkeycode,
                                   params.charCode, params.charSet, params.origCharCode, params.origCharSet,
                                   params.keyboardType, params.repeat);
    EventOutputQueue::push(p, autogenId);

    if (!params.repeat) {
      if (params.eventType == EventType::DOWN) {
        PressDownKeys::add(newkeycode, params.keyboardType);
      } else {
        PressDownKeys::remove(newkeycode, params.keyboardType);
      }
    }
  }
}

// ======================================================================
void EventOutputQueue::FireConsumer::fire(const Params_KeyboardSpecialEventCallback& params, AutogenId autogenId) {
  // skip no-outputable keycodes.
  // Note: check before FireModifiers to avoid meaningless modifier event.
  if (params.key == ConsumerKeyCode::VK_NONE ||
      params.key == ConsumerKeyCode::VK_PSEUDO_KEY) {
    return;
  }

  FireModifiers::fire(autogenId);

  EventOutputQueue::push(params, autogenId);
}

// ======================================================================
Buttons EventOutputQueue::FireRelativePointer::lastButtons_(0);

void EventOutputQueue::FireRelativePointer::fire(AutogenId autogenId, Buttons toButtons, int dx, int dy) {
  // When changing space to command+left click,
  //   __KeyToKey__ KeyCode::SPACE, PointingButton::LEFT, ModifierFlag::COMMAND_L
  //
  // We need to release command key after left click was released as follows.
  //   (1) KeyDown   Command_L
  //   (2) MouseDown Left
  //   (3) MouseUp   Left
  //   (4) KeyUp     Command_L
  //
  // For mouse drag support, command modifier is increased as normal (not temporary_increase).
  // Therefore, command modifier is decreased when space key is released.
  // If we call FireModifiers::fire() at the begining of this function,
  // input events are fired as follows order.
  //   (1) KeyDown   Command_L
  //   (2) MouseDown Left
  //   (3) KeyUp     Command_L
  //   (4) MouseUp   Left
  //
  // It's not desired order.
  // So, we call FireModifiers::fire() at the end of this function when button is released.

  Buttons releasedButtons = lastButtons_;
  releasedButtons.remove(toButtons);
  bool isButtonReleased = !releasedButtons.isNONE();

  if (!isButtonReleased) {
    FireModifiers::fire(autogenId);
  }

  // Sending button event
  if (lastButtons_ != toButtons) {
    lastButtons_ = toButtons;

    Params_RelativePointerEventCallback params(toButtons, 0, 0, PointingButton::NONE, false);
    EventOutputQueue::push(params, autogenId);
  }

  // Sending cursor
  if (dx != 0 || dy != 0) {
    Params_RelativePointerEventCallback params(toButtons, dx, dy, PointingButton::NONE, false);
    EventOutputQueue::push(params, autogenId);
  }

  if (isButtonReleased) {
    FireModifiers::fire(autogenId);
  }
}

// ======================================================================
void EventOutputQueue::FireScrollWheel::fire(const Params_ScrollWheelEventCallback& params, AutogenId autogenId) {
  FireModifiers::fire(autogenId);
  EventOutputQueue::push(params, autogenId);
}

void EventOutputQueue::FireScrollWheel::fire(int delta1, int delta2, AutogenId autogenId) {
  short deltaAxis1;
  short deltaAxis2;
  IOFixed fixedDelta1;
  IOFixed fixedDelta2;
  SInt32 pointDelta1;
  SInt32 pointDelta2;

  int relative2scroll_rate = Config::get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_pointing_relative2scroll_rate);

  deltaAxis1 = (delta1 * relative2scroll_rate) / 1024 / DELTA_SCALE;
  deltaAxis2 = (delta2 * relative2scroll_rate) / 1024 / DELTA_SCALE;

  fixedDelta1 = (delta1 * relative2scroll_rate) * (POINTING_FIXED_SCALE / 1024) / DELTA_SCALE;
  fixedDelta2 = (delta2 * relative2scroll_rate) * (POINTING_FIXED_SCALE / 1024) / DELTA_SCALE;

  pointDelta1 = (delta1 * POINTING_POINT_SCALE * relative2scroll_rate) / 1024 / DELTA_SCALE;
  pointDelta2 = (delta2 * POINTING_POINT_SCALE * relative2scroll_rate) / 1024 / DELTA_SCALE;

  // see IOHIDSystem/IOHIDevicePrivateKeys.h about options.
  const int kScrollTypeContinuous_ = 0x0001;
  int options = kScrollTypeContinuous_;

  Params_ScrollWheelEventCallback params(deltaAxis1, deltaAxis2, 0,
                                         fixedDelta1, fixedDelta2, 0,
                                         pointDelta1, pointDelta2, 0,
                                         options);
  EventOutputQueue::FireScrollWheel::fire(params, autogenId);
}

// ======================================================================
void EventOutputQueue::FireWait::fire(const Params_Wait& params, AutogenId autogenId) {
  EventOutputQueue::push(params, autogenId);
}
}
<commit_msg>update comment<commit_after>#include "Config.hpp"
#include "EventOutputQueue.hpp"
#include "ListHookedConsumer.hpp"
#include "ListHookedKeyboard.hpp"
#include "ListHookedPointing.hpp"
#include "PressDownKeys.hpp"
#include "RemapClass.hpp"
#include "VirtualKey.hpp"
#include "VK_IOHIDPOSTEVENT.hpp"

namespace org_pqrs_Karabiner {
List EventOutputQueue::queue_;
TimerWrapper EventOutputQueue::fire_timer_;
Buttons EventOutputQueue::previousButtons_;
uint64_t EventOutputQueue::lastProcessedEventInputQueueSerialNumber_;

void EventOutputQueue::initialize(IOWorkLoop& workloop) {
  fire_timer_.initialize(&workloop, nullptr, EventOutputQueue::fire_timer_callback);
  lastProcessedEventInputQueueSerialNumber_ = 0;
}

void EventOutputQueue::terminate(void) {
  fire_timer_.terminate();

  queue_.clear();
}

// ----------------------------------------------------------------------
#define PUSH_TO_OUTPUTQUEUE                              \
  {                                                      \
    queue_.push_back(new Item(p, AutogenId(autogenId))); \
    fire_timer_.setTimeoutMS(0, false);                  \
  }
void EventOutputQueue::push(const Params_KeyboardEventCallBack& p, AutogenId autogenId) {
  PUSH_TO_OUTPUTQUEUE;
  if (p.eventType == EventType::DOWN) {
    FlagStatus::globalFlagStatus().sticky_clear();
  }
}
void EventOutputQueue::push(const Params_KeyboardSpecialEventCallback& p, AutogenId autogenId) {
  PUSH_TO_OUTPUTQUEUE;
  if (p.ex_iskeydown) {
    FlagStatus::globalFlagStatus().sticky_clear();
  }
}
void EventOutputQueue::push(const Params_RelativePointerEventCallback& p, AutogenId autogenId) {
  PUSH_TO_OUTPUTQUEUE;
  if (p.buttons != Buttons(0)) {
    FlagStatus::globalFlagStatus().sticky_clear();
  }
}
void EventOutputQueue::push(const Params_ScrollWheelEventCallback& p, AutogenId autogenId) {
  PUSH_TO_OUTPUTQUEUE;
  FlagStatus::globalFlagStatus().sticky_clear();
}
void EventOutputQueue::push(const Params_Wait& p, AutogenId autogenId) {
  PUSH_TO_OUTPUTQUEUE;
}
#undef PUSH_TO_OUTPUTQUEUE

// ----------------------------------------------------------------------
unsigned int
EventOutputQueue::calcDelay(const Params_Base& paramsBase) {
  // ----------------------------------------
  {
    // Delay before and after modifier
    //
    // We need to wait before and after a modifier event because
    // events will be dropped by window server if
    // we send a mouse click event and a modifier event at the same time.
    //
    // For example, change middle click to command-left click by this autogen.
    // We need to put a wait on this setting in Mail.app.
    //    <autogen>
    //      __KeyToKey__
    //      PointingButton::MIDDLE, ModifierFlag::NONE,
    //      PointingButton::LEFT, ModifierFlag::COMMAND_L,
    //    </autogen>
    //
    if (paramsBase.isModifier()) {
      return Config::get_wait_before_and_after_a_modifier_key_event();
    }
  }

  // ----------------------------------------
  {
    // Delay before and after modifier
    //
    // We need to wait before and after a pointing device click event because
    // events will be dropped by processes (eg. NetBeans) if
    // we send press button event and release button event at the same time.
    //

    auto params = paramsBase.get_Params_RelativePointerEventCallback();
    if (params) {
      if (params->buttons != previousButtons_) {
        previousButtons_ = params->buttons;
        return Config::get_wait_before_and_after_a_click_event();
      }
    }
  }

  // ----------------------------------------
  return 0;
}

namespace {
unsigned int maxDelay(unsigned int v1, unsigned int v2) {
  if (v1 > v2) {
    return v1;
  } else {
    return v2;
  }
}
}

void EventOutputQueue::fire_timer_callback(OSObject* /* owner */, IOTimerEventSource* /* sender */) {
  // We need to cancelEventOutputQueueItems in fire_timer_callback
  // in order to cancel key repeat and __HoldingKeyToKey__ events.
  RemapClassManager::cancelEventOutputQueueItems();

  // Delete canceled items.
  Item* p = nullptr;

  p = static_cast<Item*>(queue_.safe_front());
  while (p) {
    if (p->isCanceled()) {
      p = static_cast<Item*>(queue_.erase_and_delete(p));
    } else {
      p = static_cast<Item*>(p->getnext());
    }
  }

  // ------------------------------------------------------------
  // Send key event.
  p = static_cast<Item*>(queue_.safe_front());
  if (!p) return;

  // Delay after modifier or click.
  unsigned int delay = calcDelay(p->getParamsBase());

  // ----------------------------------------
  {
    auto params = (p->getParamsBase()).get_Params_KeyboardEventCallBack();
    if (params) {
      bool handled = VirtualKey::handleAfterEnqueued(*params);
      if (!handled) {
        ListHookedKeyboard::instance().apply(*params);
      }

      // We need to wait at least 1ms in order to avoid changing key sequence order randomly.
      // (If VMware Fusion's driver is installed, the wrong order issue will be happen.)
      delay = maxDelay(delay, 1);
    }
  }
  {
    auto params = (p->getParamsBase()).get_Params_UpdateEventFlagsCallback();
    if (params) {
      // We need to wait at least 1ms in order to avoid changing key sequence order randomly.
      // (If VMware Fusion's driver is installed, the wrong order issue will be happen.)
      delay = maxDelay(delay, 1);
    }
  }
  {
    auto params = (p->getParamsBase()).get_Params_KeyboardSpecialEventCallback();
    if (params) {
      if (!ListHookedConsumer::instance().apply(*params)) {
        // If there is no consumer device, we send an event as a software key.
        VirtualKey::VK_IOHIDPOSTEVENT::post(*params);
      }

      // We need to wait at least 1ms in order to avoid changing key sequence order randomly.
      // (If VMware Fusion's driver is installed, the wrong order issue will be happen.)
      delay = maxDelay(delay, 1);
    }
  }
  {
    auto params = (p->getParamsBase()).get_Params_RelativePointerEventCallback();
    if (params) {
      ListHookedPointing::instance().apply(*params);
    }
  }
  {
    auto params = (p->getParamsBase()).get_Params_ScrollWheelEventCallback();
    if (params) {
      ListHookedPointing::instance().apply(*params);
    }
  }
  {
    auto params = (p->getParamsBase()).get_Params_Wait();
    if (params) {
      delay = maxDelay(delay, static_cast<unsigned int>(params->milliseconds));
    }
  }

  queue_.pop_front();

  // ----------------------------------------
  // Set timeout for next event.

  // Delay before modifier and click.
  Item* next = static_cast<Item*>(queue_.safe_front());
  if (!next) return;
  delay = maxDelay(delay, calcDelay(next->getParamsBase()));

  fire_timer_.setTimeoutMS(delay);
}

void EventOutputQueue::collapseModifierKeyUpDownEvent(void) {
  // Find EventType::UP
  for (Item* p = static_cast<Item*>(queue_.safe_front()); p; p = static_cast<Item*>(p->getnext())) {
    auto params = (p->getParamsBase()).get_Params_KeyboardEventCallBack();
    if (params &&
        params->isModifier() &&
        !params->ex_iskeydown) {
      // `p` is modifier up event.
      // Check next event is EventType::DOWN
      auto next = static_cast<Item*>(p->getnext());
      if (next &&
          p->getEventInputQueueSerialNumber() == next->getEventInputQueueSerialNumber()) {
#if 0
        auto nextParams = (next->getParamsBase()).get_Params_KeyboardEventCallBack();
        if (nextParams &&
            params->key == nextParams->key &&
            nextParams->ex_iskeydown) {
          // `next` is modifier down event.
          p->cancel();
          next->cancel();
        }
#endif
      }
    }
  }
}

// ======================================================================
Flags EventOutputQueue::FireModifiers::lastFlags_(0);

void EventOutputQueue::FireModifiers::fire(AutogenId autogenId, Flags toFlags, KeyboardType keyboardType) {
  if (lastFlags_ == toFlags) return;

  // ------------------------------------------------------------
  // At first we handle KeyUp events and handle KeyDown events next.
  // We need to end KeyDown at Command+Space to Option_L+Shift_L.
  //
  // When Option_L+Shift_L has a meaning (switch input language at Windows),
  // it does not works well when the last is KeyUp of Command.

  // ------------------------------------------------------------
  // KeyUp
  for (size_t i = 0; i < FlagStatus::globalFlagStatus().itemSize(); ++i) {
    ModifierFlag flag = FlagStatus::globalFlagStatus().getFlag(i);

    // Skipping ModifierFlag::NUMPAD
    if (flag.getKeyCode() == KeyCode::VK_NONE) continue;
    // Skipping virtual modifiers.
    if (flag.getRawBits() == 0) continue;

    // ----------------------------------------
    if (!lastFlags_.isOn(flag)) continue;
    if (toFlags.isOn(flag)) continue;

    lastFlags_.remove(flag);

    Params_KeyboardEventCallBack params(EventType::MODIFY, lastFlags_, flag.getKeyCode(), keyboardType, false);
    EventOutputQueue::push(params, autogenId);
  }

  // KeyDown
  for (size_t i = 0; i < FlagStatus::globalFlagStatus().itemSize(); ++i) {
    ModifierFlag flag = FlagStatus::globalFlagStatus().getFlag(i);

    // Skipping ModifierFlag::NUMPAD
    if (flag.getKeyCode() == KeyCode::VK_NONE) continue;
    // Skipping virtual modifiers.
    if (flag.getRawBits() == 0) continue;

    // ----------------------------------------
    if (!toFlags.isOn(flag)) continue;
    if (lastFlags_.isOn(flag)) continue;

    lastFlags_.add(flag);

    Params_KeyboardEventCallBack params(EventType::MODIFY, lastFlags_, flag.getKeyCode(), keyboardType, false);
    EventOutputQueue::push(params, autogenId);
  }
}

// ======================================================================
void EventOutputQueue::FireKey::fire(const Params_KeyboardEventCallBack& params, AutogenId autogenId) {
  if (VirtualKey::handle(params, autogenId)) return;

  // ------------------------------------------------------------
  KeyCode newkeycode = params.key;
  Flags newflags = params.flags;

  KeyCode::reverseNormalizeKey(newkeycode, newflags, params.eventType, params.keyboardType);

  // skip no-outputable keycodes.
  // Note: check before FireModifiers to avoid meaningless modifier event.
  if (newkeycode == KeyCode::VK_NONE ||
      newkeycode == KeyCode::VK_PSEUDO_KEY) {
    return;
  }
  if (newkeycode.isModifier() && newkeycode.getModifierFlag().getRawBits() == 0) {
    // virtual modifiers.
    return;
  }

  FireModifiers::fire(autogenId, newflags, params.keyboardType);

  if (params.eventType == EventType::DOWN || params.eventType == EventType::UP) {
    Params_KeyboardEventCallBack p(params.eventType, newflags, newkeycode,
                                   params.charCode, params.charSet, params.origCharCode, params.origCharSet,
                                   params.keyboardType, params.repeat);
    EventOutputQueue::push(p, autogenId);

    if (!params.repeat) {
      if (params.eventType == EventType::DOWN) {
        PressDownKeys::add(newkeycode, params.keyboardType);
      } else {
        PressDownKeys::remove(newkeycode, params.keyboardType);
      }
    }
  }
}

// ======================================================================
void EventOutputQueue::FireConsumer::fire(const Params_KeyboardSpecialEventCallback& params, AutogenId autogenId) {
  // skip no-outputable keycodes.
  // Note: check before FireModifiers to avoid meaningless modifier event.
  if (params.key == ConsumerKeyCode::VK_NONE ||
      params.key == ConsumerKeyCode::VK_PSEUDO_KEY) {
    return;
  }

  FireModifiers::fire(autogenId);

  EventOutputQueue::push(params, autogenId);
}

// ======================================================================
Buttons EventOutputQueue::FireRelativePointer::lastButtons_(0);

void EventOutputQueue::FireRelativePointer::fire(AutogenId autogenId, Buttons toButtons, int dx, int dy) {
  // When changing space to command+left click,
  //   __KeyToKey__ KeyCode::SPACE, PointingButton::LEFT, ModifierFlag::COMMAND_L
  //
  // We need to release command key after left click was released as follows.
  //   (1) KeyDown   Command_L
  //   (2) MouseDown Left
  //   (3) MouseUp   Left
  //   (4) KeyUp     Command_L
  //
  // For mouse drag support, command modifier is increased as normal (not temporary_increase).
  // Therefore, command modifier is decreased when space key is released.
  // If we call FireModifiers::fire() at the begining of this function,
  // input events are fired as follows order.
  //   (1) KeyDown   Command_L
  //   (2) MouseDown Left
  //   (3) KeyUp     Command_L
  //   (4) MouseUp   Left
  //
  // It's not desired order.
  // So, we call FireModifiers::fire() at the end of this function when button is released.

  Buttons releasedButtons = lastButtons_;
  releasedButtons.remove(toButtons);
  bool isButtonReleased = !releasedButtons.isNONE();

  if (!isButtonReleased) {
    FireModifiers::fire(autogenId);
  }

  // Sending button event
  if (lastButtons_ != toButtons) {
    lastButtons_ = toButtons;

    Params_RelativePointerEventCallback params(toButtons, 0, 0, PointingButton::NONE, false);
    EventOutputQueue::push(params, autogenId);
  }

  // Sending cursor
  if (dx != 0 || dy != 0) {
    Params_RelativePointerEventCallback params(toButtons, dx, dy, PointingButton::NONE, false);
    EventOutputQueue::push(params, autogenId);
  }

  if (isButtonReleased) {
    FireModifiers::fire(autogenId);
  }
}

// ======================================================================
void EventOutputQueue::FireScrollWheel::fire(const Params_ScrollWheelEventCallback& params, AutogenId autogenId) {
  FireModifiers::fire(autogenId);
  EventOutputQueue::push(params, autogenId);
}

void EventOutputQueue::FireScrollWheel::fire(int delta1, int delta2, AutogenId autogenId) {
  short deltaAxis1;
  short deltaAxis2;
  IOFixed fixedDelta1;
  IOFixed fixedDelta2;
  SInt32 pointDelta1;
  SInt32 pointDelta2;

  int relative2scroll_rate = Config::get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_pointing_relative2scroll_rate);

  deltaAxis1 = (delta1 * relative2scroll_rate) / 1024 / DELTA_SCALE;
  deltaAxis2 = (delta2 * relative2scroll_rate) / 1024 / DELTA_SCALE;

  fixedDelta1 = (delta1 * relative2scroll_rate) * (POINTING_FIXED_SCALE / 1024) / DELTA_SCALE;
  fixedDelta2 = (delta2 * relative2scroll_rate) * (POINTING_FIXED_SCALE / 1024) / DELTA_SCALE;

  pointDelta1 = (delta1 * POINTING_POINT_SCALE * relative2scroll_rate) / 1024 / DELTA_SCALE;
  pointDelta2 = (delta2 * POINTING_POINT_SCALE * relative2scroll_rate) / 1024 / DELTA_SCALE;

  // see IOHIDSystem/IOHIDevicePrivateKeys.h about options.
  const int kScrollTypeContinuous_ = 0x0001;
  int options = kScrollTypeContinuous_;

  Params_ScrollWheelEventCallback params(deltaAxis1, deltaAxis2, 0,
                                         fixedDelta1, fixedDelta2, 0,
                                         pointDelta1, pointDelta2, 0,
                                         options);
  EventOutputQueue::FireScrollWheel::fire(params, autogenId);
}

// ======================================================================
void EventOutputQueue::FireWait::fire(const Params_Wait& params, AutogenId autogenId) {
  EventOutputQueue::push(params, autogenId);
}
}
<|endoftext|>


<commit_before>#ifndef LIBICS3_ICS3_EEPPARAM_H_
#define LIBICS3_ICS3_EEPPARAM_H_

#include"ics3/check_invalid.hpp"
#include"ics3/baudrate.hpp"

#include<array>
#include<stdexcept>

namespace ics {
  class EepParam {
  public:
    enum Flag : uint16_t {
      REVERSE =   0x1,
      FREE =      0x2,
      PWMINH =    0x8,
      ROLL_MODE = 0x10,
      SLAVE =     0x80
    };

    static constexpr EepParam strech(uint16_t = 60);
    static constexpr EepParam speed(uint16_t = 127);
    static constexpr EepParam punch(uint16_t = 1);
    static constexpr EepParam deadBand(uint16_t = 2);
    static constexpr EepParam dumping(uint16_t = 40);
    static constexpr EepParam selfTimer(uint16_t = 250);
    static constexpr EepParam flag(uint16_t = 0x8C);
    static constexpr EepParam pulseMax(uint16_t = 11500);
    static constexpr EepParam pulseMin(uint16_t = 3500);
    static constexpr EepParam baudrate(uint16_t = 10);
    static constexpr EepParam temperature(uint16_t = 80);
    static constexpr EepParam current(uint16_t = 63);
    static constexpr EepParam response(uint16_t = 0);
    static constexpr EepParam userOffset(uint16_t = 0);
    static constexpr EepParam id(uint16_t = 0);
    static constexpr EepParam strech1(uint16_t = 60);
    static constexpr EepParam strech2(uint16_t = 60);
    static constexpr EepParam strech3(uint16_t = 60);

    constexpr uint16_t get() const noexcept;
    void set(uint16_t);
    void write(std::array<unsigned char, 64>&) const noexcept;
    void read(const std::array<unsigned char, 64>&);
  private:
    constexpr explicit EepParam(
        size_t,
        size_t,
        uint16_t,
        uint16_t,
        uint16_t (*)(uint16_t, uint16_t, uint16_t),
        uint16_t
    );
    static constexpr uint16_t checkInvalidRange(uint16_t, uint16_t, uint16_t);
    static constexpr uint16_t checkInvalidEvenRange(uint16_t, uint16_t, uint16_t);
    static constexpr uint16_t checkInvalidFlag(uint16_t, uint16_t, uint16_t);
    static constexpr uint16_t checkInvalidBaudrate(uint16_t, uint16_t, uint16_t);
    static constexpr uint16_t checkInvalidOffset(uint16_t, uint16_t, uint16_t);

    const size_t offset;
    const size_t length;
    const uint16_t min;
    const uint16_t max;
    uint16_t (*const setFunc)(uint16_t, uint16_t, uint16_t);
    uint16_t data;
  };

  constexpr EepParam EepParam::strech(uint16_t data) {
    return EepParam {2, 2, 2, 254, &EepParam::checkInvalidEvenRange, data};
  }

  constexpr EepParam EepParam::speed(uint16_t data) {
    return EepParam {4, 2, 1, 127, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::punch(uint16_t data) {
    return EepParam {6, 2, 0, 10, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::deadBand(uint16_t data) {
    return EepParam {8, 2, 0, 5, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::dumping(uint16_t data) {
    return EepParam {10, 2, 1, 255, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::selfTimer(uint16_t data) {
    return EepParam {12, 2, 10, 255, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::flag(uint16_t data) {
    return EepParam {14, 2, 0, 255, &EepParam::checkInvalidFlag, data};
  }

  constexpr EepParam EepParam::pulseMax(uint16_t data) {
    return EepParam {16, 4, 3500, 11500, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::pulseMin(uint16_t data) {
    return EepParam {20, 4, 3500, 11500, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::baudrate(uint16_t data) {
    return EepParam {26, 2, 0, 10, &EepParam::checkInvalidBaudrate, data};
  }

  constexpr EepParam EepParam::temperature(uint16_t data) {
    return EepParam {28, 2, 1, 127, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::current(uint16_t data) {
    return EepParam {30, 2, 1, 63, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::response(uint16_t data) {
    return EepParam {50, 2, 1, 5, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::userOffset(uint16_t data) {
    return EepParam {52, 2, static_cast<uint16_t>(-127), 127, &EepParam::checkInvalidOffset, data};
  }

  constexpr EepParam EepParam::id(uint16_t data) {
    return EepParam {56, 2, 0, 31, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::strech1(uint16_t data) {
    return EepParam {58, 2, 2, 254, &EepParam::checkInvalidEvenRange, data};
  }

  constexpr EepParam EepParam::strech2(uint16_t data) {
    return EepParam {60, 2, 2, 254, &EepParam::checkInvalidEvenRange, data};
  }

  constexpr EepParam EepParam::strech3(uint16_t data) {
    return EepParam {62, 2, 2, 254, &EepParam::checkInvalidEvenRange, data};
  }

  constexpr uint16_t EepParam::get() const noexcept {
    return data;
  }

  inline void EepParam::set(uint16_t input) {
    data = (*setFunc)(input, min, max); // throw std::invalid_argument
  }

  constexpr EepParam::EepParam(
      size_t offset,
      size_t length,
      uint16_t min,
      uint16_t max,
      uint16_t (*setFunc)(uint16_t, uint16_t, uint16_t),
      uint16_t data
  )
  : offset(offset),
    length(length),
    min(min),
    max(max),
    setFunc(setFunc),
    data(setFunc(data, min, max)) // throw std::invalid_argument
  {}

  constexpr uint16_t EepParam::checkInvalidRange(uint16_t input, uint16_t min, uint16_t max) {
    return ics::checkInvalidRange(input, min, max);
  }

  constexpr uint16_t EepParam::checkInvalidEvenRange(uint16_t input, uint16_t min, uint16_t max) {
    return input % 2 ?
           throw std::invalid_argument {"Must even value"} :
           checkInvalidRange(input, min, max); // throw std::invalid_argument
  }

  constexpr uint16_t EepParam::checkInvalidFlag(uint16_t input, uint16_t, uint16_t) {
    return !(input & 0x04) ? throw std::invalid_argument {"Eepparam(flag): Must up bits 0x04"} :
           ~(input | ~0x60) ? throw std::invalid_argument {"Eepparam(flag): Must down bits 0x60"} :
           input;
  }

  constexpr uint16_t EepParam::checkInvalidBaudrate(uint16_t input, uint16_t, uint16_t) {
    return input == Baudrate::RATE115200().getRomData() ? input :
           //input == Baudrate::RATE625000().getRomData() ? input :
           //input == Baudrate::RATE1250000().getRomData() ? input :
           throw std::invalid_argument {"baudrate not exist"};
  }

  constexpr uint16_t EepParam::checkInvalidOffset(uint16_t input, uint16_t min, uint16_t max) {
    return input < max ? input : // this min < 0; min of uint16_t is 0
           min < input ? input : // this min < 0; input must bigger than min.
           throw std::invalid_argument {"Eeprom(offset): range over"}; // min < input < max is failed
  }
}

#endif // LIBICS3_ICS3_EEPPARAM_H_
<commit_msg>Fix typo strech to stretch<commit_after>#ifndef LIBICS3_ICS3_EEPPARAM_H_
#define LIBICS3_ICS3_EEPPARAM_H_

#include"ics3/check_invalid.hpp"
#include"ics3/baudrate.hpp"

#include<array>
#include<stdexcept>

namespace ics {
  class EepParam {
  public:
    enum Flag : uint16_t {
      REVERSE =   0x1,
      FREE =      0x2,
      PWMINH =    0x8,
      ROLL_MODE = 0x10,
      SLAVE =     0x80
    };

    static constexpr EepParam stretch(uint16_t = 60);
    static constexpr EepParam speed(uint16_t = 127);
    static constexpr EepParam punch(uint16_t = 1);
    static constexpr EepParam deadBand(uint16_t = 2);
    static constexpr EepParam dumping(uint16_t = 40);
    static constexpr EepParam selfTimer(uint16_t = 250);
    static constexpr EepParam flag(uint16_t = 0x8C);
    static constexpr EepParam pulseMax(uint16_t = 11500);
    static constexpr EepParam pulseMin(uint16_t = 3500);
    static constexpr EepParam baudrate(uint16_t = 10);
    static constexpr EepParam temperature(uint16_t = 80);
    static constexpr EepParam current(uint16_t = 63);
    static constexpr EepParam response(uint16_t = 0);
    static constexpr EepParam userOffset(uint16_t = 0);
    static constexpr EepParam id(uint16_t = 0);
    static constexpr EepParam strech1(uint16_t = 60);
    static constexpr EepParam strech2(uint16_t = 60);
    static constexpr EepParam strech3(uint16_t = 60);

    constexpr uint16_t get() const noexcept;
    void set(uint16_t);
    void write(std::array<unsigned char, 64>&) const noexcept;
    void read(const std::array<unsigned char, 64>&);
  private:
    constexpr explicit EepParam(
        size_t,
        size_t,
        uint16_t,
        uint16_t,
        uint16_t (*)(uint16_t, uint16_t, uint16_t),
        uint16_t
    );
    static constexpr uint16_t checkInvalidRange(uint16_t, uint16_t, uint16_t);
    static constexpr uint16_t checkInvalidEvenRange(uint16_t, uint16_t, uint16_t);
    static constexpr uint16_t checkInvalidFlag(uint16_t, uint16_t, uint16_t);
    static constexpr uint16_t checkInvalidBaudrate(uint16_t, uint16_t, uint16_t);
    static constexpr uint16_t checkInvalidOffset(uint16_t, uint16_t, uint16_t);

    const size_t offset;
    const size_t length;
    const uint16_t min;
    const uint16_t max;
    uint16_t (*const setFunc)(uint16_t, uint16_t, uint16_t);
    uint16_t data;
  };

  constexpr EepParam EepParam::stretch(uint16_t data) {
    return EepParam {2, 2, 2, 254, &EepParam::checkInvalidEvenRange, data};
  }

  constexpr EepParam EepParam::speed(uint16_t data) {
    return EepParam {4, 2, 1, 127, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::punch(uint16_t data) {
    return EepParam {6, 2, 0, 10, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::deadBand(uint16_t data) {
    return EepParam {8, 2, 0, 5, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::dumping(uint16_t data) {
    return EepParam {10, 2, 1, 255, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::selfTimer(uint16_t data) {
    return EepParam {12, 2, 10, 255, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::flag(uint16_t data) {
    return EepParam {14, 2, 0, 255, &EepParam::checkInvalidFlag, data};
  }

  constexpr EepParam EepParam::pulseMax(uint16_t data) {
    return EepParam {16, 4, 3500, 11500, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::pulseMin(uint16_t data) {
    return EepParam {20, 4, 3500, 11500, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::baudrate(uint16_t data) {
    return EepParam {26, 2, 0, 10, &EepParam::checkInvalidBaudrate, data};
  }

  constexpr EepParam EepParam::temperature(uint16_t data) {
    return EepParam {28, 2, 1, 127, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::current(uint16_t data) {
    return EepParam {30, 2, 1, 63, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::response(uint16_t data) {
    return EepParam {50, 2, 1, 5, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::userOffset(uint16_t data) {
    return EepParam {52, 2, static_cast<uint16_t>(-127), 127, &EepParam::checkInvalidOffset, data};
  }

  constexpr EepParam EepParam::id(uint16_t data) {
    return EepParam {56, 2, 0, 31, &EepParam::checkInvalidRange, data};
  }

  constexpr EepParam EepParam::strech1(uint16_t data) {
    return EepParam {58, 2, 2, 254, &EepParam::checkInvalidEvenRange, data};
  }

  constexpr EepParam EepParam::strech2(uint16_t data) {
    return EepParam {60, 2, 2, 254, &EepParam::checkInvalidEvenRange, data};
  }

  constexpr EepParam EepParam::strech3(uint16_t data) {
    return EepParam {62, 2, 2, 254, &EepParam::checkInvalidEvenRange, data};
  }

  constexpr uint16_t EepParam::get() const noexcept {
    return data;
  }

  inline void EepParam::set(uint16_t input) {
    data = (*setFunc)(input, min, max); // throw std::invalid_argument
  }

  constexpr EepParam::EepParam(
      size_t offset,
      size_t length,
      uint16_t min,
      uint16_t max,
      uint16_t (*setFunc)(uint16_t, uint16_t, uint16_t),
      uint16_t data
  )
  : offset(offset),
    length(length),
    min(min),
    max(max),
    setFunc(setFunc),
    data(setFunc(data, min, max)) // throw std::invalid_argument
  {}

  constexpr uint16_t EepParam::checkInvalidRange(uint16_t input, uint16_t min, uint16_t max) {
    return ics::checkInvalidRange(input, min, max);
  }

  constexpr uint16_t EepParam::checkInvalidEvenRange(uint16_t input, uint16_t min, uint16_t max) {
    return input % 2 ?
           throw std::invalid_argument {"Must even value"} :
           checkInvalidRange(input, min, max); // throw std::invalid_argument
  }

  constexpr uint16_t EepParam::checkInvalidFlag(uint16_t input, uint16_t, uint16_t) {
    return !(input & 0x04) ? throw std::invalid_argument {"Eepparam(flag): Must up bits 0x04"} :
           ~(input | ~0x60) ? throw std::invalid_argument {"Eepparam(flag): Must down bits 0x60"} :
           input;
  }

  constexpr uint16_t EepParam::checkInvalidBaudrate(uint16_t input, uint16_t, uint16_t) {
    return input == Baudrate::RATE115200().getRomData() ? input :
           //input == Baudrate::RATE625000().getRomData() ? input :
           //input == Baudrate::RATE1250000().getRomData() ? input :
           throw std::invalid_argument {"baudrate not exist"};
  }

  constexpr uint16_t EepParam::checkInvalidOffset(uint16_t input, uint16_t min, uint16_t max) {
    return input < max ? input : // this min < 0; min of uint16_t is 0
           min < input ? input : // this min < 0; input must bigger than min.
           throw std::invalid_argument {"Eeprom(offset): range over"}; // min < input < max is failed
  }
}

#endif // LIBICS3_ICS3_EEPPARAM_H_
<|endoftext|>