<commit_before>/*
  This file is part of Kontact.

  Copyright (c) 2004 Tobias Koenig <tokoe@kde.org>
  adapted for karm 2005 by Thorsten Staerk <kde@staerk.de>
  karm renamed to ktimetracker 2007-2008

  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.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "ktimetracker_plugin.h"
#include "ktimetrackerinterface.h"

#include <ktimetrackerpart.h>

#include <kontactinterfaces/core.h>
#include <kontactinterfaces/plugin.h>

#include <kactioncollection.h>
#include <kcmdlineargs.h>
#include <kgenericfactory.h>
#include <kicon.h>
#include <kparts/componentfactory.h>

EXPORT_KONTACT_PLUGIN( ktimetrackerplugin, ktimetracker )

ktimetrackerplugin::ktimetrackerplugin( Kontact::Core *core, const QVariantList & )
  : Kontact::Plugin( core, core, "ktimetracker" ), mInterface( 0 )
{
  setComponentData( KontactPluginFactory::componentData() );

  KAction *action  = new KAction( KIcon( "ktimetracker" ), i18n( "New Task" ), this );
  actionCollection()->addAction( "new_task", action );
  action->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_W ) );
  connect( action, SIGNAL(triggered(bool)), SLOT(newTask()) );
  insertNewAction( action );

  mUniqueAppWatcher = new Kontact::UniqueAppWatcher(
    new Kontact::UniqueAppHandlerFactory<KtimetrackerUniqueAppHandler>(), this );
}

ktimetrackerplugin::~ktimetrackerplugin()
{
}

bool ktimetrackerplugin::isRunningStandalone()
{
  return mUniqueAppWatcher->isRunningStandalone();
}

QStringList ktimetrackerplugin::invisibleToolbarActions() const
{
  return QStringList() << "new_task" << "new_sub_task" ;
}

KParts::ReadOnlyPart *ktimetrackerplugin::createPart()
{
  KParts::ReadOnlyPart *part = loadPart();
  if ( !part ) return 0;

  mInterface = new OrgKdeKtimetrackerKtimetrackerInterface(
    "org.kde.ktimetracker", "/KTimeTracker", QDBusConnection::sessionBus() );

  return part;
}

OrgKdeKtimetrackerKtimetrackerInterface *ktimetrackerplugin::interface()
{
  if ( !mInterface ) part();
  Q_ASSERT( mInterface );
  return mInterface;
}

QStringList ktimetrackerplugin::configModules() const
{
  QStringList modules;
  modules << "PIM/ktimetrackerconfig.desktop";
  return modules;
}

void ktimetrackerplugin::newTask()
{
  core()->selectPlugin( this );
  interface()->newTask();
}

void KtimetrackerUniqueAppHandler::loadCommandLineOptions()
{
  // TODO: handle command line options
  KCmdLineArgs::addCmdLineOptions( KCmdLineOptions() );
}

int KtimetrackerUniqueAppHandler::newInstance()
{
  kDebug();
  // Ensure part is loaded
  (void)plugin()->part();
  return Kontact::UniqueAppHandler::newInstance();
}

#include "ktimetracker_plugin.moc"

<commit_msg>Fix mem leak<commit_after>/*
  This file is part of Kontact.

  Copyright (c) 2004 Tobias Koenig <tokoe@kde.org>
  adapted for karm 2005 by Thorsten Staerk <kde@staerk.de>
  karm renamed to ktimetracker 2007-2008

  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.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "ktimetracker_plugin.h"
#include "ktimetrackerinterface.h"

#include <ktimetrackerpart.h>

#include <kontactinterfaces/core.h>
#include <kontactinterfaces/plugin.h>

#include <kactioncollection.h>
#include <kcmdlineargs.h>
#include <kgenericfactory.h>
#include <kicon.h>
#include <kparts/componentfactory.h>

EXPORT_KONTACT_PLUGIN( ktimetrackerplugin, ktimetracker )

ktimetrackerplugin::ktimetrackerplugin( Kontact::Core *core, const QVariantList & )
  : Kontact::Plugin( core, core, "ktimetracker" ), mInterface( 0 )
{
  setComponentData( KontactPluginFactory::componentData() );

  KAction *action  = new KAction( KIcon( "ktimetracker" ), i18n( "New Task" ), this );
  actionCollection()->addAction( "new_task", action );
  action->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_W ) );
  connect( action, SIGNAL(triggered(bool)), SLOT(newTask()) );
  insertNewAction( action );

  mUniqueAppWatcher = new Kontact::UniqueAppWatcher(
    new Kontact::UniqueAppHandlerFactory<KtimetrackerUniqueAppHandler>(), this );
}

ktimetrackerplugin::~ktimetrackerplugin()
{
  delete mInterface;
}

bool ktimetrackerplugin::isRunningStandalone()
{
  return mUniqueAppWatcher->isRunningStandalone();
}

QStringList ktimetrackerplugin::invisibleToolbarActions() const
{
  return QStringList() << "new_task" << "new_sub_task" ;
}

KParts::ReadOnlyPart *ktimetrackerplugin::createPart()
{
  KParts::ReadOnlyPart *part = loadPart();
  if ( !part ) return 0;

  mInterface = new OrgKdeKtimetrackerKtimetrackerInterface(
    "org.kde.ktimetracker", "/KTimeTracker", QDBusConnection::sessionBus() );

  return part;
}

OrgKdeKtimetrackerKtimetrackerInterface *ktimetrackerplugin::interface()
{
  if ( !mInterface ) part();
  Q_ASSERT( mInterface );
  return mInterface;
}

QStringList ktimetrackerplugin::configModules() const
{
  QStringList modules;
  modules << "PIM/ktimetrackerconfig.desktop";
  return modules;
}

void ktimetrackerplugin::newTask()
{
  core()->selectPlugin( this );
  interface()->newTask();
}

void KtimetrackerUniqueAppHandler::loadCommandLineOptions()
{
  // TODO: handle command line options
  KCmdLineArgs::addCmdLineOptions( KCmdLineOptions() );
}

int KtimetrackerUniqueAppHandler::newInstance()
{
  kDebug();
  // Ensure part is loaded
  (void)plugin()->part();
  return Kontact::UniqueAppHandler::newInstance();
}

#include "ktimetracker_plugin.moc"

<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "rpcserver.h"
#include "rpcclient.h"
#include "init.h"
#include "main.h"
#include "noui.h"
#include "ui_interface.h"
#include "util.h"

#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>

/* Introduction text for doxygen: */

/*! \mainpage Developer documentation
 *
 * \section intro_sec Introduction
 *
 * This is the developer documentation of the reference client for an experimental new digital currency called Bitcoin (http://www.bitcoin.org/),
 * which enables instant payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer technology to operate
 * with no central authority: managing transactions and issuing money are carried out collectively by the network.
 *
 * The software is a community-driven open source project, released under the MIT license.
 *
 * \section Navigation
 * Use the buttons Namespaces, Classes or Files at the top of the page to start navigating the code.
 */

static bool fDaemon;

void DetectShutdownThread(boost::thread_group* threadGroup)
{
    bool fShutdown = ShutdownRequested();
    // Tell the main threads to shutdown.
    while (!fShutdown)
    {
        MilliSleep(200);
        fShutdown = ShutdownRequested();
    }
    if (threadGroup)
    {
        threadGroup->interrupt_all();
        threadGroup->join_all();
    }
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//
bool AppInit(int argc, char* argv[])
{
    boost::thread_group threadGroup;
    boost::thread* detectShutdownThread = NULL;

    bool fRet = false;
    try
    {
        //
        // Parameters
        //
        // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
        ParseParameters(argc, argv);
        if (!boost::filesystem::is_directory(GetDataDir(false)))
        {
            fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
            return false;
        }
        try
        {
            ReadConfigFile(mapArgs, mapMultiArgs);
        } catch(std::exception &e) {
            fprintf(stderr,"Error reading configuration file: %s\n", e.what());
            return false;
        }
        // Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause)
        if (!SelectParamsFromCommandLine()) {
            fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
            return false;
        }

        if (mapArgs.count("-?") || mapArgs.count("--help"))
        {
            // First part of help message is specific to bitcoind / RPC client
            std::string strUsage = _("Reddcoin Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n\n" +
                _("Usage:") + "\n" +
                  "  reddcoind [options]                     " + _("Start Reddcoin Core Daemon") + "\n" +
                _("Usage (deprecated, use reddcoin-cli):") + "\n" +
                  "  reddcoind [options] <command> [params]  " + _("Send command to Reddcoin Core") + "\n" +
                  "  reddcoind [options] help                " + _("List commands") + "\n" +
                  "  reddcoind [options] help <command>      " + _("Get help for a command") + "\n";

            strUsage += "\n" + HelpMessage(HMM_BITCOIND);
            strUsage += "\n" + HelpMessageCli(false);

            fprintf(stdout, "%s", strUsage.c_str());
            return false;
        }

        // Command-line RPC
        bool fCommandLine = false;
        for (int i = 1; i < argc; i++)
            if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "bitcoin:"))
                fCommandLine = true;

        if (fCommandLine)
        {
            int ret = CommandLineRPC(argc, argv);
            exit(ret);
        }
#ifndef WIN32
        fDaemon = GetBoolArg("-daemon", false);
        if (fDaemon)
        {
            fprintf(stdout, "Bitcoin server starting\n");

            // Daemonize
            pid_t pid = fork();
            if (pid < 0)
            {
                fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
                return false;
            }
            if (pid > 0) // Parent process, pid is child process id
            {
                CreatePidFile(GetPidFile(), pid);
                return true;
            }
            // Child process falls through to rest of initialization

            pid_t sid = setsid();
            if (sid < 0)
                fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
        }
#endif
        SoftSetBoolArg("-server", true);

        detectShutdownThread = new boost::thread(boost::bind(&DetectShutdownThread, &threadGroup));
        fRet = AppInit2(threadGroup);
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "AppInit()");
    } catch (...) {
        PrintExceptionContinue(NULL, "AppInit()");
    }

    if (!fRet)
    {
        if (detectShutdownThread)
            detectShutdownThread->interrupt();

        threadGroup.interrupt_all();
        // threadGroup.join_all(); was left out intentionally here, because we didn't re-test all of
        // the startup-failure cases to make sure they don't result in a hang due to some
        // thread-blocking-waiting-for-another-thread-during-startup case
    }

    if (detectShutdownThread)
    {
        detectShutdownThread->join();
        delete detectShutdownThread;
        detectShutdownThread = NULL;
    }
    Shutdown();

    return fRet;
}

int main(int argc, char* argv[])
{
    SetupEnvironment();

    bool fRet = false;

    // Connect bitcoind signal handlers
    noui_connect();

    fRet = AppInit(argc, argv);

    if (fRet && fDaemon)
        return 0;

    return (fRet ? 0 : 1);
}
<commit_msg>Update bitcoind.cpp<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "rpcserver.h"
#include "rpcclient.h"
#include "init.h"
#include "main.h"
#include "noui.h"
#include "ui_interface.h"
#include "util.h"

#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>

/* Introduction text for doxygen: */

/*! \mainpage Developer documentation
 *
 * \section intro_sec Introduction
 *
 * This is the developer documentation of the reference client for an experimental new digital currency called Bitcoin (http://www.bitcoin.org/),
 * which enables instant payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer technology to operate
 * with no central authority: managing transactions and issuing money are carried out collectively by the network.
 *
 * The software is a community-driven open source project, released under the MIT license.
 *
 * \section Navigation
 * Use the buttons Namespaces, Classes or Files at the top of the page to start navigating the code.
 */

static bool fDaemon;

void DetectShutdownThread(boost::thread_group* threadGroup)
{
    bool fShutdown = ShutdownRequested();
    // Tell the main threads to shutdown.
    while (!fShutdown)
    {
        MilliSleep(200);
        fShutdown = ShutdownRequested();
    }
    if (threadGroup)
    {
        threadGroup->interrupt_all();
        threadGroup->join_all();
    }
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//
bool AppInit(int argc, char* argv[])
{
    boost::thread_group threadGroup;
    boost::thread* detectShutdownThread = NULL;

    bool fRet = false;
    try
    {
        //
        // Parameters
        //
        // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
        ParseParameters(argc, argv);
        if (!boost::filesystem::is_directory(GetDataDir(false)))
        {
            fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
            return false;
        }
        try
        {
            ReadConfigFile(mapArgs, mapMultiArgs);
        } catch(std::exception &e) {
            fprintf(stderr,"Error reading configuration file: %s\n", e.what());
            return false;
        }
        // Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause)
        if (!SelectParamsFromCommandLine()) {
            fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
            return false;
        }

        if (mapArgs.count("-?") || mapArgs.count("--help"))
        {
            // First part of help message is specific to bitcoind / RPC client
            std::string strUsage = _("Reddcoin Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n\n" +
                _("Usage:") + "\n" +
                  "  reddcoind [options]                     " + _("Start Reddcoin Core Daemon") + "\n" +
                _("Usage (deprecated, use reddcoin-cli):") + "\n" +
                  "  reddcoind [options] <command> [params]  " + _("Send command to Reddcoin Core") + "\n" +
                  "  reddcoind [options] help                " + _("List commands") + "\n" +
                  "  reddcoind [options] help <command>      " + _("Get help for a command") + "\n";

            strUsage += "\n" + HelpMessage(HMM_BITCOIND);
            strUsage += "\n" + HelpMessageCli(false);

            fprintf(stdout, "%s", strUsage.c_str());
            return false;
        }

        // Command-line RPC
        bool fCommandLine = false;
        for (int i = 1; i < argc; i++)
            if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "bitcoin:"))
                fCommandLine = true;

        if (fCommandLine)
        {
            int ret = CommandLineRPC(argc, argv);
            exit(ret);
        }
#ifndef WIN32
        fDaemon = GetBoolArg("-daemon", false);
        if (fDaemon)
        {
            fprintf(stdout, "Reddcoin server starting\n");

            // Daemonize
            pid_t pid = fork();
            if (pid < 0)
            {
                fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
                return false;
            }
            if (pid > 0) // Parent process, pid is child process id
            {
                CreatePidFile(GetPidFile(), pid);
                return true;
            }
            // Child process falls through to rest of initialization

            pid_t sid = setsid();
            if (sid < 0)
                fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
        }
#endif
        SoftSetBoolArg("-server", true);

        detectShutdownThread = new boost::thread(boost::bind(&DetectShutdownThread, &threadGroup));
        fRet = AppInit2(threadGroup);
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "AppInit()");
    } catch (...) {
        PrintExceptionContinue(NULL, "AppInit()");
    }

    if (!fRet)
    {
        if (detectShutdownThread)
            detectShutdownThread->interrupt();

        threadGroup.interrupt_all();
        // threadGroup.join_all(); was left out intentionally here, because we didn't re-test all of
        // the startup-failure cases to make sure they don't result in a hang due to some
        // thread-blocking-waiting-for-another-thread-during-startup case
    }

    if (detectShutdownThread)
    {
        detectShutdownThread->join();
        delete detectShutdownThread;
        detectShutdownThread = NULL;
    }
    Shutdown();

    return fRet;
}

int main(int argc, char* argv[])
{
    SetupEnvironment();

    bool fRet = false;

    // Connect bitcoind signal handlers
    noui_connect();

    fRet = AppInit(argc, argv);

    if (fRet && fDaemon)
        return 0;

    return (fRet ? 0 : 1);
}
<|endoftext|>


<commit_before>#include "bitstream.h"

#include <complex>

#include "wdsp/wdsp.h"

#include "filters.h"

#define FS        250000.0
#define FC_0      57000.0
#define IBUFLEN   4096
#define OBUFLEN   128
#define BITBUFLEN 1024

namespace redsea {

int sign(double a) {
  return (a >= 0 ? 1 : 0);
}

BitStream::BitStream() : tot_errs_(2), reading_frame_(0), counter_(0), fsc_(FC_0), bit_buffer_(BITBUFLEN), mixer_phi_(0), clock_offset_(0), is_eof_(false), subcarr_lopass_fir_(wdsp::FIR(4000.0 / FS, 127)), subcarr_baseband_(IBUFLEN) {

}

void BitStream::deltaBit(int b) {
  bit_buffer_.append(b ^ dbit_);
  dbit_ = b;
}

void BitStream::biphase(double acc) {

  if (sign(acc) != sign(prev_acc_)) {
    tot_errs_[counter_ % 2] ++;
  }

  if (counter_ % 2 == reading_frame_) {
    deltaBit(sign(acc + prev_acc_));
  }
  if (counter_ == 0) {
    if (tot_errs_[1 - reading_frame_] < tot_errs_[reading_frame_]) {
      reading_frame_ = 1 - reading_frame_;
    }
    tot_errs_[0] = 0;
    tot_errs_[1] = 0;
  }

  prev_acc_ = acc;
  counter_ = (counter_ + 1) % 800;
}

void BitStream::demodulateMoreBits() {

  int16_t sample[IBUFLEN];
  int bytesread = fread(sample, sizeof(int16_t), IBUFLEN, stdin);
  if (bytesread < IBUFLEN) {
    is_eof_ = true;
    return;
  }

  for (int i = 0; i < bytesread; i++) {

    /* Subcarrier downmix & phase recovery */

    mixer_phi_ += 2 * M_PI * fsc_ * (1.0/FS);
    subcarr_baseband_.appendOverlapFiltered(wdsp::mix(sample[i] / 32768.0, mixer_phi_),
        subcarr_lopass_fir_);

    double pll_beta = 2e-3;

    std::complex<double> sc_sample = subcarr_baseband_.getNext();

    double phi1 = arg(sc_sample);
    if (phi1 >= M_PI_2) {
      phi1 -= M_PI;
    } else if (phi1 <= -M_PI_2) {
      phi1 += M_PI;
    }

    mixer_phi_ -= pll_beta * phi1;
    fsc_            -= .5 * pll_beta * phi1;

    /* 1187.5 Hz clock */

    double clock_phi = mixer_phi_ / 48.0 + clock_offset_;
    double lo_clock  = (fmod(clock_phi, 2*M_PI) < M_PI ? 1 : -1);

    /* Clock phase recovery */

    if (sign(prev_bb_) != sign(real(sc_sample))) {
      double d_cphi = fmod(clock_phi, M_PI);
      if (d_cphi >= M_PI_2) d_cphi -= M_PI;
      clock_offset_ -= 0.005 * d_cphi;
    }

    /* Decimate band-limited signal */
    if (numsamples_ % 8 == 0) {

      /* biphase symbol integrate & dump */
      acc_ += real(sc_sample) * lo_clock;

      if (sign(lo_clock) != sign(prevclock_)) {
        biphase(acc_);
        acc_ = 0;
      }

      prevclock_ = lo_clock;
    }

    numsamples_ ++;

    prev_bb_ = real(sc_sample);

  }

}

int BitStream::getNextBit() {
  while (bit_buffer_.getFillCount() < 1 && !isEOF())
    demodulateMoreBits();

  int result = bit_buffer_.getNext();
  //printf("read %d, write %d, fill count %d\n",bit_buffer_read_ptr_, bit_buffer_write_ptr_, bit_buffer_fill_count_);
  return result;
}

bool BitStream::isEOF() const {
  return is_eof_;
}

} // namespace redsea
<commit_msg>move some code to low-throughput side<commit_after>#include "bitstream.h"

#include <complex>

#include "wdsp/wdsp.h"

#include "filters.h"

#define FS        250000.0
#define FC_0      57000.0
#define IBUFLEN   4096
#define OBUFLEN   128
#define BITBUFLEN 1024

namespace redsea {

int sign(double a) {
  return (a >= 0 ? 1 : 0);
}

BitStream::BitStream() : tot_errs_(2), reading_frame_(0), counter_(0), fsc_(FC_0), bit_buffer_(BITBUFLEN), mixer_phi_(0), clock_offset_(0), is_eof_(false), subcarr_lopass_fir_(wdsp::FIR(4000.0 / FS, 127)), subcarr_baseband_(IBUFLEN) {

}

void BitStream::deltaBit(int b) {
  bit_buffer_.append(b ^ dbit_);
  dbit_ = b;
}

void BitStream::biphase(double acc) {

  if (sign(acc) != sign(prev_acc_)) {
    tot_errs_[counter_ % 2] ++;
  }

  if (counter_ % 2 == reading_frame_) {
    deltaBit(sign(acc + prev_acc_));
  }
  if (counter_ == 0) {
    if (tot_errs_[1 - reading_frame_] < tot_errs_[reading_frame_]) {
      reading_frame_ = 1 - reading_frame_;
    }
    tot_errs_[0] = 0;
    tot_errs_[1] = 0;
  }

  prev_acc_ = acc;
  counter_ = (counter_ + 1) % 800;
}

void BitStream::demodulateMoreBits() {

  int16_t sample[IBUFLEN];
  int bytesread = fread(sample, sizeof(int16_t), IBUFLEN, stdin);
  if (bytesread < IBUFLEN) {
    is_eof_ = true;
    return;
  }

  for (int i = 0; i < bytesread; i++) {

    /* Subcarrier downmix & phase recovery */

    mixer_phi_ += 2 * M_PI * fsc_ * (1.0/FS);
    subcarr_baseband_.appendOverlapFiltered(wdsp::mix(sample[i] / 32768.0,
        mixer_phi_), subcarr_lopass_fir_);

    double pll_beta = 16e-3;

    /* Decimate band-limited signal */
    if (numsamples_ % 8 == 0) {

      std::complex<double> sc_sample = subcarr_baseband_.at(0);
      subcarr_baseband_.forward(8);

      double phi1 = arg(sc_sample);
      if (phi1 >= M_PI_2) {
        phi1 -= M_PI;
      } else if (phi1 <= -M_PI_2) {
        phi1 += M_PI;
      }

      mixer_phi_ -= pll_beta * phi1;
      fsc_       -= .5 * pll_beta * phi1;

      /* 1187.5 Hz clock */

      double clock_phi = mixer_phi_ / 48.0 + clock_offset_;
      double lo_clock  = (fmod(clock_phi, 2*M_PI) < M_PI ? 1 : -1);

      /* Clock phase recovery */

      if (sign(prev_bb_) != sign(real(sc_sample))) {
        double d_cphi = fmod(clock_phi, M_PI);
        if (d_cphi >= M_PI_2) d_cphi -= M_PI;
        clock_offset_ -= 0.005 * d_cphi;
      }

      /* biphase symbol integrate & dump */
      acc_ += real(sc_sample) * lo_clock;

      if (sign(lo_clock) != sign(prevclock_)) {
        biphase(acc_);
        acc_ = 0;
      }

      prevclock_ = lo_clock;
      prev_bb_ = real(sc_sample);
    }

    numsamples_ ++;

  }

}

int BitStream::getNextBit() {
  while (bit_buffer_.getFillCount() < 1 && !isEOF())
    demodulateMoreBits();

  int result = bit_buffer_.getNext();
  //printf("read %d, write %d, fill count %d\n",bit_buffer_read_ptr_, bit_buffer_write_ptr_, bit_buffer_fill_count_);
  return result;
}

bool BitStream::isEOF() const {
  return is_eof_;
}

} // namespace redsea
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QDebug>
#include "qmediaplaylist.h"

class tst_QMediaPlaylist : public QObject
{
    Q_OBJECT
public slots:
    void init();
    void cleanup();

private slots:
    void construction();
    void append();
    void currentItem();
};

void tst_QMediaPlaylist::init()
{
}

void tst_QMediaPlaylist::cleanup()
{
}

void tst_QMediaPlaylist::construction()
{
    QMediaPlaylist playlist;
    QCOMPARE(playlist.size(), 0);
    QVERIFY(playlist.isEmpty());
}

void tst_QMediaPlaylist::append()
{
    QMediaPlaylist playlist;
    QVERIFY(!playlist.isReadOnly());

    QMediaSource source1(QUrl(QLatin1String("file:///1")));
    playlist.appendItem(source1);
    QCOMPARE(playlist.size(), 1);
    QCOMPARE(playlist.media(0), source1);

    QMediaSource source2(QUrl(QLatin1String("file:///2")));
    playlist.appendItem(source2);
    QCOMPARE(playlist.size(), 2);
    QCOMPARE(playlist.media(1), source2);
}

void tst_QMediaPlaylist::currentItem()
{
    QMediaPlaylist playlist;

    QMediaSource source1(QUrl(QLatin1String("file:///1")));
    playlist.appendItem(source1);

    QMediaSource source2(QUrl(QLatin1String("file:///2")));
    playlist.appendItem(source2);

    QCOMPARE(playlist.currentPosition(), -1);
    QCOMPARE(playlist.currentMedia(), QMediaSource());

    QCOMPARE(playlist.nextPosition(), 0);
    QCOMPARE(playlist.nextPosition(2), 1);
    QCOMPARE(playlist.previousPosition(), -1);
    QCOMPARE(playlist.previousPosition(2), -1);

    playlist.setCurrentPosition(0);
    QCOMPARE(playlist.currentPosition(), 0);
    QCOMPARE(playlist.currentMedia(), source1);

    QCOMPARE(playlist.nextPosition(), 1);
    QCOMPARE(playlist.nextPosition(2), -1);
    QCOMPARE(playlist.previousPosition(), -1);
    QCOMPARE(playlist.previousPosition(2), -1);

    playlist.setCurrentPosition(1);
    QCOMPARE(playlist.currentPosition(), 1);
    QCOMPARE(playlist.currentMedia(), source2);

    playlist.setCurrentPosition(2); //warning is expected
    QCOMPARE(playlist.currentPosition(), 1);
    QCOMPARE(playlist.currentMedia(), source2);

    QCOMPARE(playlist.nextPosition(), -1);
    QCOMPARE(playlist.nextPosition(2), -1);
    QCOMPARE(playlist.previousPosition(), 0);
    QCOMPARE(playlist.previousPosition(2), -1);
}

QTEST_MAIN(tst_QMediaPlaylist)
#include "tst_qmediaplaylist.moc"

<commit_msg>added more qmediaplaylist related tests<commit_after>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QDebug>
#include "qmediaplaylist.h"

class tst_QMediaPlaylist : public QObject
{
    Q_OBJECT
public slots:
    void init();
    void cleanup();
    void initTestCase();

private slots:
    void construction();
    void append();
    void insert();
    void clear();
    void removeItems();
    void currentItem();
    void saveAndLoad();

private:
    QMediaSource source1;
    QMediaSource source2;
    QMediaSource source3;
};

void tst_QMediaPlaylist::init()
{
}

void tst_QMediaPlaylist::initTestCase()
{
    source1 = QMediaSource(QUrl(QLatin1String("file:///1")));
    source2 = QMediaSource(QUrl(QLatin1String("file:///2")));
    source3 = QMediaSource(QUrl(QLatin1String("file:///3")));
}

void tst_QMediaPlaylist::cleanup()
{
}

void tst_QMediaPlaylist::construction()
{
    QMediaPlaylist playlist;
    QCOMPARE(playlist.size(), 0);
    QVERIFY(playlist.isEmpty());
}

void tst_QMediaPlaylist::append()
{
    QMediaPlaylist playlist;
    QVERIFY(!playlist.isReadOnly());

    playlist.appendItem(source1);
    QCOMPARE(playlist.size(), 1);
    QCOMPARE(playlist.media(0), source1);

    playlist.appendItem(source2);
    QCOMPARE(playlist.size(), 2);
    QCOMPARE(playlist.media(1), source2);
}

void tst_QMediaPlaylist::insert()
{
    QMediaPlaylist playlist;
    QVERIFY(!playlist.isReadOnly());

    playlist.appendItem(source1);
    QCOMPARE(playlist.size(), 1);
    QCOMPARE(playlist.media(0), source1);

    playlist.appendItem(source2);
    QCOMPARE(playlist.size(), 2);
    QCOMPARE(playlist.media(1), source2);

    QSignalSpy aboutToBeInsertedSignalSpy(&playlist, SIGNAL(itemsAboutToBeInserted(int,int)));
    QSignalSpy insertedSignalSpy(&playlist, SIGNAL(itemsInserted(int,int)));

    playlist.insertItem(1, source3);
    QCOMPARE(playlist.size(), 3);
    QCOMPARE(playlist.media(0), source1);
    QCOMPARE(playlist.media(1), source3);
    QCOMPARE(playlist.media(2), source2);

    QCOMPARE(aboutToBeInsertedSignalSpy.count(), 1);
    QCOMPARE(aboutToBeInsertedSignalSpy.first()[0].toInt(), 1);
    QCOMPARE(aboutToBeInsertedSignalSpy.first()[1].toInt(), 1);

    QCOMPARE(insertedSignalSpy.count(), 1);
    QCOMPARE(insertedSignalSpy.first()[0].toInt(), 1);
    QCOMPARE(insertedSignalSpy.first()[1].toInt(), 1);
}

void tst_QMediaPlaylist::currentItem()
{
    QMediaPlaylist playlist;
    playlist.appendItem(source1);
    playlist.appendItem(source2);

    QCOMPARE(playlist.currentPosition(), -1);
    QCOMPARE(playlist.currentMedia(), QMediaSource());

    QCOMPARE(playlist.nextPosition(), 0);
    QCOMPARE(playlist.nextPosition(2), 1);
    QCOMPARE(playlist.previousPosition(), -1);
    QCOMPARE(playlist.previousPosition(2), -1);

    playlist.setCurrentPosition(0);
    QCOMPARE(playlist.currentPosition(), 0);
    QCOMPARE(playlist.currentMedia(), source1);

    QCOMPARE(playlist.nextPosition(), 1);
    QCOMPARE(playlist.nextPosition(2), -1);
    QCOMPARE(playlist.previousPosition(), -1);
    QCOMPARE(playlist.previousPosition(2), -1);

    playlist.setCurrentPosition(1);
    QCOMPARE(playlist.currentPosition(), 1);
    QCOMPARE(playlist.currentMedia(), source2);

    playlist.setCurrentPosition(2); //warning is expected
    QCOMPARE(playlist.currentPosition(), 1);
    QCOMPARE(playlist.currentMedia(), source2);

    QCOMPARE(playlist.nextPosition(), -1);
    QCOMPARE(playlist.nextPosition(2), -1);
    QCOMPARE(playlist.previousPosition(), 0);
    QCOMPARE(playlist.previousPosition(2), -1);
}

void tst_QMediaPlaylist::clear()
{
    QMediaPlaylist playlist;
    playlist.appendItem(source1);
    playlist.appendItem(source2);

    playlist.clear();
    QVERIFY(playlist.isEmpty());
    QCOMPARE(playlist.size(), 0);
}

void tst_QMediaPlaylist::removeItems()
{
    QMediaPlaylist playlist;
    playlist.appendItem(source1);
    playlist.appendItem(source2);
    playlist.appendItem(source3);

    QSignalSpy aboutToBeRemovedSignalSpy(&playlist, SIGNAL(itemsAboutToBeRemoved(int,int)));
    QSignalSpy removedSignalSpy(&playlist, SIGNAL(itemsRemoved(int,int)));
    playlist.removeItem(1);
    QCOMPARE(playlist.size(), 2);
    QCOMPARE(playlist.media(1), source3);

    QCOMPARE(aboutToBeRemovedSignalSpy.count(), 1);
    QCOMPARE(aboutToBeRemovedSignalSpy.first()[0].toInt(), 1);
    QCOMPARE(aboutToBeRemovedSignalSpy.first()[1].toInt(), 1);

    QCOMPARE(removedSignalSpy.count(), 1);
    QCOMPARE(removedSignalSpy.first()[0].toInt(), 1);
    QCOMPARE(removedSignalSpy.first()[1].toInt(), 1);

    aboutToBeRemovedSignalSpy.clear();
    removedSignalSpy.clear();

    playlist.removeItems(0,1);
    QVERIFY(playlist.isEmpty());

    QCOMPARE(aboutToBeRemovedSignalSpy.count(), 1);
    QCOMPARE(aboutToBeRemovedSignalSpy.first()[0].toInt(), 0);
    QCOMPARE(aboutToBeRemovedSignalSpy.first()[1].toInt(), 1);

    QCOMPARE(removedSignalSpy.count(), 1);
    QCOMPARE(removedSignalSpy.first()[0].toInt(), 0);
    QCOMPARE(removedSignalSpy.first()[1].toInt(), 1);

    playlist.appendItem(source1);
    playlist.appendItem(source2);
    playlist.appendItem(source3);

    playlist.removeItems(0,1);
    QCOMPARE(playlist.size(), 1);
    QCOMPARE(playlist.media(0), source3);
}

void tst_QMediaPlaylist::saveAndLoad()
{
    /*
    QMediaPlaylist playlist;
    playlist.appendItem(source1);
    playlist.appendItem(source2);
    playlist.appendItem(source3);

    QBuffer buffer;
    buffer.open(QBuffer::ReadWrite);

    bool res = playlist.save(&buffer, "m3u");

    QVERIFY(res);
    QVERIFY(buffer.pos() > 0);
    buffer.seek(0);

    QMediaPlaylist playlist2;
    res = playlist2.load(&buffer, "m3u");
    QVERIFY(res);
    QCOMPARE(playlist.size(), playlist2.size());
    QCOMPARE(playlist.media(0), playlist2.media(0));
    */
}

QTEST_MAIN(tst_QMediaPlaylist)
#include "tst_qmediaplaylist.moc"

<|endoftext|>


<commit_before>//  Copyright (c) 2014, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.
//
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#ifndef ROCKSDB_LITE
#include "table/cuckoo_table_reader.h"

#include <algorithm>
#include <limits>
#include <string>
#include <utility>
#include <vector>
#include "rocksdb/iterator.h"
#include "rocksdb/table.h"
#include "table/meta_blocks.h"
#include "table/cuckoo_table_factory.h"
#include "table/get_context.h"
#include "util/arena.h"
#include "util/coding.h"

namespace rocksdb {
namespace {
const uint64_t CACHE_LINE_MASK = ~((uint64_t)CACHE_LINE_SIZE - 1);
const uint32_t kInvalidIndex = std::numeric_limits<uint32_t>::max();
}

extern const uint64_t kCuckooTableMagicNumber;

CuckooTableReader::CuckooTableReader(
    const ImmutableCFOptions& ioptions,
    std::unique_ptr<RandomAccessFile>&& file,
    uint64_t file_size,
    const Comparator* comparator,
    uint64_t (*get_slice_hash)(const Slice&, uint32_t, uint64_t))
    : file_(std::move(file)),
      ucomp_(comparator),
      get_slice_hash_(get_slice_hash) {
  if (!ioptions.allow_mmap_reads) {
    status_ = Status::InvalidArgument("File is not mmaped");
  }
  TableProperties* props = nullptr;
  status_ = ReadTableProperties(file_.get(), file_size, kCuckooTableMagicNumber,
      ioptions.env, ioptions.info_log, &props);
  if (!status_.ok()) {
    return;
  }
  table_props_.reset(props);
  auto& user_props = props->user_collected_properties;
  auto hash_funs = user_props.find(CuckooTablePropertyNames::kNumHashFunc);
  if (hash_funs == user_props.end()) {
    status_ = Status::Corruption("Number of hash functions not found");
    return;
  }
  num_hash_func_ = *reinterpret_cast<const uint32_t*>(hash_funs->second.data());
  auto unused_key = user_props.find(CuckooTablePropertyNames::kEmptyKey);
  if (unused_key == user_props.end()) {
    status_ = Status::Corruption("Empty bucket value not found");
    return;
  }
  unused_key_ = unused_key->second;

  key_length_ = props->fixed_key_len;
  auto user_key_len = user_props.find(CuckooTablePropertyNames::kUserKeyLength);
  if (user_key_len == user_props.end()) {
    status_ = Status::Corruption("User key length not found");
    return;
  }
  user_key_length_ = *reinterpret_cast<const uint32_t*>(
      user_key_len->second.data());

  auto value_length = user_props.find(CuckooTablePropertyNames::kValueLength);
  if (value_length == user_props.end()) {
    status_ = Status::Corruption("Value length not found");
    return;
  }
  value_length_ = *reinterpret_cast<const uint32_t*>(
      value_length->second.data());
  bucket_length_ = key_length_ + value_length_;

  auto hash_table_size = user_props.find(
      CuckooTablePropertyNames::kHashTableSize);
  if (hash_table_size == user_props.end()) {
    status_ = Status::Corruption("Hash table size not found");
    return;
  }
  table_size_ = *reinterpret_cast<const uint64_t*>(
      hash_table_size->second.data());

  auto is_last_level = user_props.find(CuckooTablePropertyNames::kIsLastLevel);
  if (is_last_level == user_props.end()) {
    status_ = Status::Corruption("Is last level not found");
    return;
  }
  is_last_level_ = *reinterpret_cast<const bool*>(is_last_level->second.data());

  auto identity_as_first_hash = user_props.find(
      CuckooTablePropertyNames::kIdentityAsFirstHash);
  if (identity_as_first_hash == user_props.end()) {
    status_ = Status::Corruption("identity as first hash not found");
    return;
  }
  identity_as_first_hash_ = *reinterpret_cast<const bool*>(
      identity_as_first_hash->second.data());

  auto use_module_hash = user_props.find(
      CuckooTablePropertyNames::kUseModuleHash);
  if (use_module_hash == user_props.end()) {
    status_ = Status::Corruption("hash type is not found");
    return;
  }
  use_module_hash_ = *reinterpret_cast<const bool*>(
      use_module_hash->second.data());
  auto cuckoo_block_size = user_props.find(
      CuckooTablePropertyNames::kCuckooBlockSize);
  if (cuckoo_block_size == user_props.end()) {
    status_ = Status::Corruption("Cuckoo block size not found");
    return;
  }
  cuckoo_block_size_ = *reinterpret_cast<const uint32_t*>(
      cuckoo_block_size->second.data());
  cuckoo_block_bytes_minus_one_ = cuckoo_block_size_ * bucket_length_ - 1;
  status_ = file_->Read(0, file_size, &file_data_, nullptr);
}

Status CuckooTableReader::Get(const ReadOptions& readOptions, const Slice& key,
                              GetContext* get_context) {
  assert(key.size() == key_length_ + (is_last_level_ ? 8 : 0));
  Slice user_key = ExtractUserKey(key);
  for (uint32_t hash_cnt = 0; hash_cnt < num_hash_func_; ++hash_cnt) {
    uint64_t offset = bucket_length_ * CuckooHash(
        user_key, hash_cnt, use_module_hash_, table_size_,
        identity_as_first_hash_, get_slice_hash_);
    const char* bucket = &file_data_.data()[offset];
    for (uint32_t block_idx = 0; block_idx < cuckoo_block_size_;
         ++block_idx, bucket += bucket_length_) {
      if (ucomp_->Compare(Slice(unused_key_.data(), user_key.size()),
                          Slice(bucket, user_key.size())) == 0) {
        return Status::OK();
      }
      // Here, we compare only the user key part as we support only one entry
      // per user key and we don't support sanpshot.
      if (ucomp_->Compare(user_key, Slice(bucket, user_key.size())) == 0) {
        Slice value(bucket + key_length_, value_length_);
        if (is_last_level_) {
          get_context->SaveValue(value);
        } else {
          Slice full_key(bucket, key_length_);
          ParsedInternalKey found_ikey;
          ParseInternalKey(full_key, &found_ikey);
          get_context->SaveValue(found_ikey, value);
        }
        // We don't support merge operations. So, we return here.
        return Status::OK();
      }
    }
  }
  return Status::OK();
}

void CuckooTableReader::Prepare(const Slice& key) {
  // Prefetch the first Cuckoo Block.
  Slice user_key = ExtractUserKey(key);
  uint64_t addr = reinterpret_cast<uint64_t>(file_data_.data()) +
    bucket_length_ * CuckooHash(user_key, 0, use_module_hash_, table_size_,
                                identity_as_first_hash_, nullptr);
  uint64_t end_addr = addr + cuckoo_block_bytes_minus_one_;
  for (addr &= CACHE_LINE_MASK; addr < end_addr; addr += CACHE_LINE_SIZE) {
    PREFETCH(reinterpret_cast<const char*>(addr), 0, 3);
  }
}

class CuckooTableIterator : public Iterator {
 public:
  explicit CuckooTableIterator(CuckooTableReader* reader);
  ~CuckooTableIterator() {}
  bool Valid() const override;
  void SeekToFirst() override;
  void SeekToLast() override;
  void Seek(const Slice& target) override;
  void Next() override;
  void Prev() override;
  Slice key() const override;
  Slice value() const override;
  Status status() const override { return status_; }
  void InitIfNeeded();

 private:
  struct BucketComparator {
    BucketComparator(const Slice& file_data, const Comparator* ucomp,
                     uint32_t bucket_len, uint32_t user_key_len,
                     const Slice target = Slice())
      : file_data_(file_data),
        ucomp_(ucomp),
        bucket_len_(bucket_len),
        user_key_len_(user_key_len),
        target_(target) {}
    bool operator()(const uint32_t first, const uint32_t second) const {
      const char* first_bucket =
        (first == kInvalidIndex) ? target_.data() :
                                   &file_data_.data()[first * bucket_len_];
      const char* second_bucket =
        (second == kInvalidIndex) ? target_.data() :
                                    &file_data_.data()[second * bucket_len_];
      return ucomp_->Compare(Slice(first_bucket, user_key_len_),
                             Slice(second_bucket, user_key_len_)) < 0;
    }
   private:
    const Slice file_data_;
    const Comparator* ucomp_;
    const uint32_t bucket_len_;
    const uint32_t user_key_len_;
    const Slice target_;
  };

  const BucketComparator bucket_comparator_;
  void PrepareKVAtCurrIdx();
  CuckooTableReader* reader_;
  bool initialized_;
  Status status_;
  // Contains a map of keys to bucket_id sorted in key order.
  std::vector<uint32_t> sorted_bucket_ids_;
  // We assume that the number of items can be stored in uint32 (4 Billion).
  uint32_t curr_key_idx_;
  Slice curr_value_;
  IterKey curr_key_;
  // No copying allowed
  CuckooTableIterator(const CuckooTableIterator&) = delete;
  void operator=(const Iterator&) = delete;
};

CuckooTableIterator::CuckooTableIterator(CuckooTableReader* reader)
  : bucket_comparator_(reader->file_data_, reader->ucomp_,
                       reader->bucket_length_, reader->user_key_length_),
    reader_(reader),
    initialized_(false),
    curr_key_idx_(kInvalidIndex) {
  sorted_bucket_ids_.clear();
  curr_value_.clear();
  curr_key_.Clear();
}

void CuckooTableIterator::InitIfNeeded() {
  if (initialized_) {
    return;
  }
  sorted_bucket_ids_.reserve(reader_->GetTableProperties()->num_entries);
  uint64_t num_buckets = reader_->table_size_ + reader_->cuckoo_block_size_ - 1;
  assert(num_buckets < kInvalidIndex);
  const char* bucket = reader_->file_data_.data();
  for (uint32_t bucket_id = 0; bucket_id < num_buckets; ++bucket_id) {
    if (Slice(bucket, reader_->key_length_) != Slice(reader_->unused_key_)) {
      sorted_bucket_ids_.push_back(bucket_id);
    }
    bucket += reader_->bucket_length_;
  }
  assert(sorted_bucket_ids_.size() ==
      reader_->GetTableProperties()->num_entries);
  std::sort(sorted_bucket_ids_.begin(), sorted_bucket_ids_.end(),
            bucket_comparator_);
  curr_key_idx_ = kInvalidIndex;
  initialized_ = true;
}

void CuckooTableIterator::SeekToFirst() {
  InitIfNeeded();
  curr_key_idx_ = 0;
  PrepareKVAtCurrIdx();
}

void CuckooTableIterator::SeekToLast() {
  InitIfNeeded();
  curr_key_idx_ = sorted_bucket_ids_.size() - 1;
  PrepareKVAtCurrIdx();
}

void CuckooTableIterator::Seek(const Slice& target) {
  InitIfNeeded();
  const BucketComparator seek_comparator(
      reader_->file_data_, reader_->ucomp_,
      reader_->bucket_length_, reader_->user_key_length_,
      ExtractUserKey(target));
  auto seek_it = std::lower_bound(sorted_bucket_ids_.begin(),
      sorted_bucket_ids_.end(),
      kInvalidIndex,
      seek_comparator);
  curr_key_idx_ = std::distance(sorted_bucket_ids_.begin(), seek_it);
  PrepareKVAtCurrIdx();
}

bool CuckooTableIterator::Valid() const {
  return curr_key_idx_ < sorted_bucket_ids_.size();
}

void CuckooTableIterator::PrepareKVAtCurrIdx() {
  if (!Valid()) {
    curr_value_.clear();
    curr_key_.Clear();
    return;
  }
  uint32_t id = sorted_bucket_ids_[curr_key_idx_];
  const char* offset = reader_->file_data_.data() +
                       id * reader_->bucket_length_;
  if (reader_->is_last_level_) {
    // Always return internal key.
    curr_key_.SetInternalKey(Slice(offset, reader_->user_key_length_),
                             0, kTypeValue);
  } else {
    curr_key_.SetKey(Slice(offset, reader_->key_length_));
  }
  curr_value_ = Slice(offset + reader_->key_length_, reader_->value_length_);
}

void CuckooTableIterator::Next() {
  if (!Valid()) {
    curr_value_.clear();
    curr_key_.Clear();
    return;
  }
  ++curr_key_idx_;
  PrepareKVAtCurrIdx();
}

void CuckooTableIterator::Prev() {
  if (curr_key_idx_ == 0) {
    curr_key_idx_ = sorted_bucket_ids_.size();
  }
  if (!Valid()) {
    curr_value_.clear();
    curr_key_.Clear();
    return;
  }
  --curr_key_idx_;
  PrepareKVAtCurrIdx();
}

Slice CuckooTableIterator::key() const {
  assert(Valid());
  return curr_key_.GetKey();
}

Slice CuckooTableIterator::value() const {
  assert(Valid());
  return curr_value_;
}

extern Iterator* NewErrorIterator(const Status& status, Arena* arena);

Iterator* CuckooTableReader::NewIterator(
    const ReadOptions& read_options, Arena* arena) {
  if (!status().ok()) {
    return NewErrorIterator(
        Status::Corruption("CuckooTableReader status is not okay."), arena);
  }
  if (read_options.total_order_seek) {
    return NewErrorIterator(
        Status::InvalidArgument("total_order_seek is not supported."), arena);
  }
  CuckooTableIterator* iter;
  if (arena == nullptr) {
    iter = new CuckooTableIterator(this);
  } else {
    auto iter_mem = arena->AllocateAligned(sizeof(CuckooTableIterator));
    iter = new (iter_mem) CuckooTableIterator(this);
  }
  return iter;
}

size_t CuckooTableReader::ApproximateMemoryUsage() const { return 0; }

}  // namespace rocksdb
#endif
<commit_msg>table/cuckoo_table_reader.cc: pass func parameter by reference<commit_after>//  Copyright (c) 2014, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.
//
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#ifndef ROCKSDB_LITE
#include "table/cuckoo_table_reader.h"

#include <algorithm>
#include <limits>
#include <string>
#include <utility>
#include <vector>
#include "rocksdb/iterator.h"
#include "rocksdb/table.h"
#include "table/meta_blocks.h"
#include "table/cuckoo_table_factory.h"
#include "table/get_context.h"
#include "util/arena.h"
#include "util/coding.h"

namespace rocksdb {
namespace {
const uint64_t CACHE_LINE_MASK = ~((uint64_t)CACHE_LINE_SIZE - 1);
const uint32_t kInvalidIndex = std::numeric_limits<uint32_t>::max();
}

extern const uint64_t kCuckooTableMagicNumber;

CuckooTableReader::CuckooTableReader(
    const ImmutableCFOptions& ioptions,
    std::unique_ptr<RandomAccessFile>&& file,
    uint64_t file_size,
    const Comparator* comparator,
    uint64_t (*get_slice_hash)(const Slice&, uint32_t, uint64_t))
    : file_(std::move(file)),
      ucomp_(comparator),
      get_slice_hash_(get_slice_hash) {
  if (!ioptions.allow_mmap_reads) {
    status_ = Status::InvalidArgument("File is not mmaped");
  }
  TableProperties* props = nullptr;
  status_ = ReadTableProperties(file_.get(), file_size, kCuckooTableMagicNumber,
      ioptions.env, ioptions.info_log, &props);
  if (!status_.ok()) {
    return;
  }
  table_props_.reset(props);
  auto& user_props = props->user_collected_properties;
  auto hash_funs = user_props.find(CuckooTablePropertyNames::kNumHashFunc);
  if (hash_funs == user_props.end()) {
    status_ = Status::Corruption("Number of hash functions not found");
    return;
  }
  num_hash_func_ = *reinterpret_cast<const uint32_t*>(hash_funs->second.data());
  auto unused_key = user_props.find(CuckooTablePropertyNames::kEmptyKey);
  if (unused_key == user_props.end()) {
    status_ = Status::Corruption("Empty bucket value not found");
    return;
  }
  unused_key_ = unused_key->second;

  key_length_ = props->fixed_key_len;
  auto user_key_len = user_props.find(CuckooTablePropertyNames::kUserKeyLength);
  if (user_key_len == user_props.end()) {
    status_ = Status::Corruption("User key length not found");
    return;
  }
  user_key_length_ = *reinterpret_cast<const uint32_t*>(
      user_key_len->second.data());

  auto value_length = user_props.find(CuckooTablePropertyNames::kValueLength);
  if (value_length == user_props.end()) {
    status_ = Status::Corruption("Value length not found");
    return;
  }
  value_length_ = *reinterpret_cast<const uint32_t*>(
      value_length->second.data());
  bucket_length_ = key_length_ + value_length_;

  auto hash_table_size = user_props.find(
      CuckooTablePropertyNames::kHashTableSize);
  if (hash_table_size == user_props.end()) {
    status_ = Status::Corruption("Hash table size not found");
    return;
  }
  table_size_ = *reinterpret_cast<const uint64_t*>(
      hash_table_size->second.data());

  auto is_last_level = user_props.find(CuckooTablePropertyNames::kIsLastLevel);
  if (is_last_level == user_props.end()) {
    status_ = Status::Corruption("Is last level not found");
    return;
  }
  is_last_level_ = *reinterpret_cast<const bool*>(is_last_level->second.data());

  auto identity_as_first_hash = user_props.find(
      CuckooTablePropertyNames::kIdentityAsFirstHash);
  if (identity_as_first_hash == user_props.end()) {
    status_ = Status::Corruption("identity as first hash not found");
    return;
  }
  identity_as_first_hash_ = *reinterpret_cast<const bool*>(
      identity_as_first_hash->second.data());

  auto use_module_hash = user_props.find(
      CuckooTablePropertyNames::kUseModuleHash);
  if (use_module_hash == user_props.end()) {
    status_ = Status::Corruption("hash type is not found");
    return;
  }
  use_module_hash_ = *reinterpret_cast<const bool*>(
      use_module_hash->second.data());
  auto cuckoo_block_size = user_props.find(
      CuckooTablePropertyNames::kCuckooBlockSize);
  if (cuckoo_block_size == user_props.end()) {
    status_ = Status::Corruption("Cuckoo block size not found");
    return;
  }
  cuckoo_block_size_ = *reinterpret_cast<const uint32_t*>(
      cuckoo_block_size->second.data());
  cuckoo_block_bytes_minus_one_ = cuckoo_block_size_ * bucket_length_ - 1;
  status_ = file_->Read(0, file_size, &file_data_, nullptr);
}

Status CuckooTableReader::Get(const ReadOptions& readOptions, const Slice& key,
                              GetContext* get_context) {
  assert(key.size() == key_length_ + (is_last_level_ ? 8 : 0));
  Slice user_key = ExtractUserKey(key);
  for (uint32_t hash_cnt = 0; hash_cnt < num_hash_func_; ++hash_cnt) {
    uint64_t offset = bucket_length_ * CuckooHash(
        user_key, hash_cnt, use_module_hash_, table_size_,
        identity_as_first_hash_, get_slice_hash_);
    const char* bucket = &file_data_.data()[offset];
    for (uint32_t block_idx = 0; block_idx < cuckoo_block_size_;
         ++block_idx, bucket += bucket_length_) {
      if (ucomp_->Compare(Slice(unused_key_.data(), user_key.size()),
                          Slice(bucket, user_key.size())) == 0) {
        return Status::OK();
      }
      // Here, we compare only the user key part as we support only one entry
      // per user key and we don't support sanpshot.
      if (ucomp_->Compare(user_key, Slice(bucket, user_key.size())) == 0) {
        Slice value(bucket + key_length_, value_length_);
        if (is_last_level_) {
          get_context->SaveValue(value);
        } else {
          Slice full_key(bucket, key_length_);
          ParsedInternalKey found_ikey;
          ParseInternalKey(full_key, &found_ikey);
          get_context->SaveValue(found_ikey, value);
        }
        // We don't support merge operations. So, we return here.
        return Status::OK();
      }
    }
  }
  return Status::OK();
}

void CuckooTableReader::Prepare(const Slice& key) {
  // Prefetch the first Cuckoo Block.
  Slice user_key = ExtractUserKey(key);
  uint64_t addr = reinterpret_cast<uint64_t>(file_data_.data()) +
    bucket_length_ * CuckooHash(user_key, 0, use_module_hash_, table_size_,
                                identity_as_first_hash_, nullptr);
  uint64_t end_addr = addr + cuckoo_block_bytes_minus_one_;
  for (addr &= CACHE_LINE_MASK; addr < end_addr; addr += CACHE_LINE_SIZE) {
    PREFETCH(reinterpret_cast<const char*>(addr), 0, 3);
  }
}

class CuckooTableIterator : public Iterator {
 public:
  explicit CuckooTableIterator(CuckooTableReader* reader);
  ~CuckooTableIterator() {}
  bool Valid() const override;
  void SeekToFirst() override;
  void SeekToLast() override;
  void Seek(const Slice& target) override;
  void Next() override;
  void Prev() override;
  Slice key() const override;
  Slice value() const override;
  Status status() const override { return status_; }
  void InitIfNeeded();

 private:
  struct BucketComparator {
    BucketComparator(const Slice& file_data, const Comparator* ucomp,
                     uint32_t bucket_len, uint32_t user_key_len,
                     const Slice& target = Slice())
      : file_data_(file_data),
        ucomp_(ucomp),
        bucket_len_(bucket_len),
        user_key_len_(user_key_len),
        target_(target) {}
    bool operator()(const uint32_t first, const uint32_t second) const {
      const char* first_bucket =
        (first == kInvalidIndex) ? target_.data() :
                                   &file_data_.data()[first * bucket_len_];
      const char* second_bucket =
        (second == kInvalidIndex) ? target_.data() :
                                    &file_data_.data()[second * bucket_len_];
      return ucomp_->Compare(Slice(first_bucket, user_key_len_),
                             Slice(second_bucket, user_key_len_)) < 0;
    }
   private:
    const Slice file_data_;
    const Comparator* ucomp_;
    const uint32_t bucket_len_;
    const uint32_t user_key_len_;
    const Slice target_;
  };

  const BucketComparator bucket_comparator_;
  void PrepareKVAtCurrIdx();
  CuckooTableReader* reader_;
  bool initialized_;
  Status status_;
  // Contains a map of keys to bucket_id sorted in key order.
  std::vector<uint32_t> sorted_bucket_ids_;
  // We assume that the number of items can be stored in uint32 (4 Billion).
  uint32_t curr_key_idx_;
  Slice curr_value_;
  IterKey curr_key_;
  // No copying allowed
  CuckooTableIterator(const CuckooTableIterator&) = delete;
  void operator=(const Iterator&) = delete;
};

CuckooTableIterator::CuckooTableIterator(CuckooTableReader* reader)
  : bucket_comparator_(reader->file_data_, reader->ucomp_,
                       reader->bucket_length_, reader->user_key_length_),
    reader_(reader),
    initialized_(false),
    curr_key_idx_(kInvalidIndex) {
  sorted_bucket_ids_.clear();
  curr_value_.clear();
  curr_key_.Clear();
}

void CuckooTableIterator::InitIfNeeded() {
  if (initialized_) {
    return;
  }
  sorted_bucket_ids_.reserve(reader_->GetTableProperties()->num_entries);
  uint64_t num_buckets = reader_->table_size_ + reader_->cuckoo_block_size_ - 1;
  assert(num_buckets < kInvalidIndex);
  const char* bucket = reader_->file_data_.data();
  for (uint32_t bucket_id = 0; bucket_id < num_buckets; ++bucket_id) {
    if (Slice(bucket, reader_->key_length_) != Slice(reader_->unused_key_)) {
      sorted_bucket_ids_.push_back(bucket_id);
    }
    bucket += reader_->bucket_length_;
  }
  assert(sorted_bucket_ids_.size() ==
      reader_->GetTableProperties()->num_entries);
  std::sort(sorted_bucket_ids_.begin(), sorted_bucket_ids_.end(),
            bucket_comparator_);
  curr_key_idx_ = kInvalidIndex;
  initialized_ = true;
}

void CuckooTableIterator::SeekToFirst() {
  InitIfNeeded();
  curr_key_idx_ = 0;
  PrepareKVAtCurrIdx();
}

void CuckooTableIterator::SeekToLast() {
  InitIfNeeded();
  curr_key_idx_ = sorted_bucket_ids_.size() - 1;
  PrepareKVAtCurrIdx();
}

void CuckooTableIterator::Seek(const Slice& target) {
  InitIfNeeded();
  const BucketComparator seek_comparator(
      reader_->file_data_, reader_->ucomp_,
      reader_->bucket_length_, reader_->user_key_length_,
      ExtractUserKey(target));
  auto seek_it = std::lower_bound(sorted_bucket_ids_.begin(),
      sorted_bucket_ids_.end(),
      kInvalidIndex,
      seek_comparator);
  curr_key_idx_ = std::distance(sorted_bucket_ids_.begin(), seek_it);
  PrepareKVAtCurrIdx();
}

bool CuckooTableIterator::Valid() const {
  return curr_key_idx_ < sorted_bucket_ids_.size();
}

void CuckooTableIterator::PrepareKVAtCurrIdx() {
  if (!Valid()) {
    curr_value_.clear();
    curr_key_.Clear();
    return;
  }
  uint32_t id = sorted_bucket_ids_[curr_key_idx_];
  const char* offset = reader_->file_data_.data() +
                       id * reader_->bucket_length_;
  if (reader_->is_last_level_) {
    // Always return internal key.
    curr_key_.SetInternalKey(Slice(offset, reader_->user_key_length_),
                             0, kTypeValue);
  } else {
    curr_key_.SetKey(Slice(offset, reader_->key_length_));
  }
  curr_value_ = Slice(offset + reader_->key_length_, reader_->value_length_);
}

void CuckooTableIterator::Next() {
  if (!Valid()) {
    curr_value_.clear();
    curr_key_.Clear();
    return;
  }
  ++curr_key_idx_;
  PrepareKVAtCurrIdx();
}

void CuckooTableIterator::Prev() {
  if (curr_key_idx_ == 0) {
    curr_key_idx_ = sorted_bucket_ids_.size();
  }
  if (!Valid()) {
    curr_value_.clear();
    curr_key_.Clear();
    return;
  }
  --curr_key_idx_;
  PrepareKVAtCurrIdx();
}

Slice CuckooTableIterator::key() const {
  assert(Valid());
  return curr_key_.GetKey();
}

Slice CuckooTableIterator::value() const {
  assert(Valid());
  return curr_value_;
}

extern Iterator* NewErrorIterator(const Status& status, Arena* arena);

Iterator* CuckooTableReader::NewIterator(
    const ReadOptions& read_options, Arena* arena) {
  if (!status().ok()) {
    return NewErrorIterator(
        Status::Corruption("CuckooTableReader status is not okay."), arena);
  }
  if (read_options.total_order_seek) {
    return NewErrorIterator(
        Status::InvalidArgument("total_order_seek is not supported."), arena);
  }
  CuckooTableIterator* iter;
  if (arena == nullptr) {
    iter = new CuckooTableIterator(this);
  } else {
    auto iter_mem = arena->AllocateAligned(sizeof(CuckooTableIterator));
    iter = new (iter_mem) CuckooTableIterator(this);
  }
  return iter;
}

size_t CuckooTableReader::ApproximateMemoryUsage() const { return 0; }

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


<commit_before>#include "mikemap.h"
#include <stdio.h>
//#include <string.h>
//#include <stdlib.h>

//#define TEST_MIKEMAP

#ifdef TEST_MIKEMAP
#include <assert.h>

#define DEFAULT_TEST_VALUE 99
using namespace mikemap;

int main(int argc, char *argv[])
{
  MikeMap mm;
  char input[] = "[100,1,101,0,10,0,9,0,14,0,11,0,15,0]";
  MAP_KEY_TYPE key = DEFAULT_TEST_VALUE;
  MAP_VALUE_TYPE value = DEFAULT_TEST_VALUE;
  int converted = 0;

  assert(mm.get_len() == 0);
  for (int i = 0; i < MAX_MAP_LEN - 4; i++)
    mm.set(i, i);
  assert(mm.get_len() == MAX_MAP_LEN - 4);
  mm.del(1);
  assert(mm.get_len() == MAX_MAP_LEN - 5);
  assert(mm.get(4) == 4);
  assert(mm.has(1) == false);
  assert(mm.has(2) == true);
  mm.get_at(MAX_MAP_LEN + 4, &key, &value);
  assert(key == DEFAULT_TEST_VALUE);
  assert(value == DEFAULT_TEST_VALUE);
  mm.get_at(3, &key, &value);
  assert(key == 4);
  assert(value == 4);
  mm.clear();
  key = DEFAULT_TEST_VALUE;
  value = DEFAULT_TEST_VALUE;
  assert(mm.get_len() == 0);
  for (int i = 0; i < MAX_MAP_LEN - 4; i++)
    mm.set(i, i);
  assert(mm.get_len() == MAX_MAP_LEN - 4);
  mm.del(1);
  assert(mm.get_len() == MAX_MAP_LEN - 5);
  assert(mm.get(4) == 4);
  assert(mm.get(10) == 10);
  assert(mm.has(1) == false);
  assert(mm.has(2) == true);
  mm.get_at(MAX_MAP_LEN + 4, &key, &value);
  assert(key == DEFAULT_TEST_VALUE);
  assert(value == DEFAULT_TEST_VALUE);
  mm.get_at(3, &key, &value);
  assert(key == 4);
  assert(value == 4);
  mm.del(2);
  mm.del(5);
  mm.set(2, 20);
  assert(mm.has(2) == true);
  assert(mm.get_len() == MAX_MAP_LEN - 6);
  mm.get_at(MAX_MAP_LEN - 7, &key, &value);
  assert(key == 2);
  assert(value == 20);
  assert(mm.has(5) == false);
  mm.clear();
  assert(mm.from_string(input, &converted) == 0);
  assert(converted == 14);
  mm.get_at(0, &key, &value);
  printf("k0: %d  v0: %d\n", key, value);
  assert(key == 100);
  assert(value == 1);
  mm.get_at(4, &key, &value);
  assert(key == 14);
  assert(value == 0);
}
#endif

namespace mikemap
{

  MikeMap::MikeMap()
  {
    this->mikemap_len = 0;
  }

  void MikeMap::set(MAP_KEY_TYPE key, MAP_VALUE_TYPE value)
  {
    for (unsigned int i = 0; i < mikemap_len; i++)
    {
      if (mikemap_keys[i] == key)
      {
        mikemap_values[i] = value;
        return;
      }
    }
    if (mikemap_len == MAX_MAP_LEN)
      return;
    mikemap_keys[mikemap_len] = key;
    mikemap_values[mikemap_len] = value;
    mikemap_len++;
  }

  bool MikeMap::has(MAP_KEY_TYPE key) const
  {
    for (unsigned int i = 0; i < mikemap_len; i++)
    {
      if (mikemap_keys[i] == key)
      {
        return true;
      }
    }
    return false;
  }

  MAP_VALUE_TYPE MikeMap::get(MAP_KEY_TYPE key) const
  {
    for (unsigned int i = 0; i < mikemap_len; i++)
    {
      if (mikemap_keys[i] == key)
      {
        return mikemap_values[i];
      }
    }
    return 0;
  }

  void MikeMap::to_string(char *ptr)
  {
    int offset = 0;
    for (unsigned int i = 0; i < mikemap_len; i++)
    {
      if (i > 0)
      {
        ptr[offset] = ',';
        offset++;
      }
      offset += sprintf(&ptr[offset], "%d", mikemap_keys[i]);
      ptr[offset] = ',';
      offset++;
      offset += sprintf(&ptr[offset], "%d", mikemap_values[i]);
    }
  }

  int MikeMap::to_int(const char *data, int len)
  {
    int val = 0;
    while (len)
    {
      int new_val = ((int)*data - (int)'0');
      val = val * 10 + new_val;
      len--;
      data++;
    }
#ifdef TEST_MIKEMAP
    printf("val: %d\n", val);
#endif
    return val;
  }

  int MikeMap::from_string(const char *data_start, int *converted)
  {
    const char *data_ptr = data_start;

    this->clear();
    // the map is supposed to start with "["
    if (*data_ptr != '[')
      return MM_ERR_WRONG_START;
    data_ptr++;

    while (1)
    {
      int len_key = 0;
      const char *key_start = data_ptr;
      {
        while (len_key < MAX_SINGLE_DATA_LEN && *data_ptr != ',' && *data_ptr != ']')
        {
          if (*data_ptr < '0' || *data_ptr > '9')
            return MM_ERR_NO_DIGIT;
          len_key++;
          data_ptr++;
        }
        if (len_key == 0 || len_key == MAX_SINGLE_DATA_LEN)
          return MM_ERR_ZERO_MAX_LEN_KEY;
        if (*data_ptr == ']')
          return MM_ERR_MISSING_VAL;
      }
      int k = this->to_int(key_start, len_key);
      (*converted)++;
      data_ptr++;
      int len_val = 0;
      const char *val_start = data_ptr;
      {
        while (len_val < MAX_SINGLE_DATA_LEN && *data_ptr != ',' && *data_ptr != ']')
        {
          if (*data_ptr < '0' || *data_ptr > '9')
            return MM_ERR_NO_DIGIT;
          len_val++;
          data_ptr++;
        }
        if (len_val == 0 || len_val == MAX_SINGLE_DATA_LEN)
          return MM_ERR_ZERO_MAX_LEN_VAL;
      }
      int v = this->to_int(val_start, len_val);
      (*converted)++;
      this->set(k, v);
      if (*data_ptr == ']')
        break;
      else
        data_ptr++;
    }

    return MM_OK;
  }

  void MikeMap::del(MAP_KEY_TYPE key)
  {
    for (unsigned int i = 0; i < mikemap_len; i++)
    {
      if (mikemap_keys[i] == key)
      {
        for (unsigned int si = i; si < (mikemap_len - 1); si++)
        {
          mikemap_keys[si] = mikemap_keys[si + 1];
          mikemap_values[si] = mikemap_values[si + 1];
        }
        mikemap_keys[mikemap_len] = 0;
        mikemap_values[mikemap_len] = 0;
        mikemap_len--;
        return;
      }
    }
  }

  unsigned int MikeMap::get_len() const
  {
    return mikemap_len;
  }

  void MikeMap::clear()
  {
    mikemap_len = 0;
  }

  void MikeMap::get_at(unsigned int at, MAP_KEY_TYPE *key, MAP_VALUE_TYPE *value) const
  {
    if (at < mikemap_len)
    {
      *key = mikemap_keys[at];
      *value = mikemap_values[at];
    }
  }
}<commit_msg>tried to fix what looks like unsigned 32 bit thing, did not work<commit_after>#include "mikemap.h"
#include <stdio.h>
//#include <string.h>
//#include <stdlib.h>

//#define TEST_MIKEMAP

#ifdef TEST_MIKEMAP
#include <assert.h>

#define DEFAULT_TEST_VALUE 99
using namespace mikemap;

int main(int argc, char *argv[])
{
  MikeMap mm;
  char input[] = "[100,1,101,0,10,0,9,0,14,0,11,0,15,0]";
  MAP_KEY_TYPE key = DEFAULT_TEST_VALUE;
  MAP_VALUE_TYPE value = DEFAULT_TEST_VALUE;
  int converted = 0;

  assert(mm.get_len() == 0);
  for (int i = 0; i < MAX_MAP_LEN - 4; i++)
    mm.set(i, i);
  assert(mm.get_len() == MAX_MAP_LEN - 4);
  mm.del(1);
  assert(mm.get_len() == MAX_MAP_LEN - 5);
  assert(mm.get(4) == 4);
  assert(mm.has(1) == false);
  assert(mm.has(2) == true);
  mm.get_at(MAX_MAP_LEN + 4, &key, &value);
  assert(key == DEFAULT_TEST_VALUE);
  assert(value == DEFAULT_TEST_VALUE);
  mm.get_at(3, &key, &value);
  assert(key == 4);
  assert(value == 4);
  mm.clear();
  key = DEFAULT_TEST_VALUE;
  value = DEFAULT_TEST_VALUE;
  assert(mm.get_len() == 0);
  for (int i = 0; i < MAX_MAP_LEN - 4; i++)
    mm.set(i, i);
  assert(mm.get_len() == MAX_MAP_LEN - 4);
  mm.del(1);
  assert(mm.get_len() == MAX_MAP_LEN - 5);
  assert(mm.get(4) == 4);
  assert(mm.get(10) == 10);
  assert(mm.has(1) == false);
  assert(mm.has(2) == true);
  mm.get_at(MAX_MAP_LEN + 4, &key, &value);
  assert(key == DEFAULT_TEST_VALUE);
  assert(value == DEFAULT_TEST_VALUE);
  mm.get_at(3, &key, &value);
  assert(key == 4);
  assert(value == 4);
  mm.del(2);
  mm.del(5);
  mm.set(2, 20);
  assert(mm.has(2) == true);
  assert(mm.get_len() == MAX_MAP_LEN - 6);
  mm.get_at(MAX_MAP_LEN - 7, &key, &value);
  assert(key == 2);
  assert(value == 20);
  assert(mm.has(5) == false);
  mm.clear();
  assert(mm.from_string(input, &converted) == 0);
  assert(converted == 14);
  mm.get_at(0, &key, &value);
  printf("k0: %d  v0: %d\n", key, value);
  assert(key == 100);
  assert(value == 1);
  mm.get_at(4, &key, &value);
  assert(key == 14);
  assert(value == 0);
}
#endif

namespace mikemap
{

  MikeMap::MikeMap()
  {
    this->mikemap_len = 0;
  }

  void MikeMap::set(MAP_KEY_TYPE key, MAP_VALUE_TYPE value)
  {
    for (unsigned int i = 0; i < mikemap_len; i++)
    {
      if (mikemap_keys[i] == key)
      {
        mikemap_values[i] = value;
        return;
      }
    }
    if (mikemap_len == MAX_MAP_LEN)
      return;
    mikemap_keys[mikemap_len] = key;
    mikemap_values[mikemap_len] = value;
    mikemap_len++;
  }

  bool MikeMap::has(MAP_KEY_TYPE key) const
  {
    for (unsigned int i = 0; i < mikemap_len; i++)
    {
      if (mikemap_keys[i] == key)
      {
        return true;
      }
    }
    return false;
  }

  MAP_VALUE_TYPE MikeMap::get(MAP_KEY_TYPE key) const
  {
    for (unsigned int i = 0; i < mikemap_len; i++)
    {
      if (mikemap_keys[i] == key)
      {
        return mikemap_values[i];
      }
    }
    return 0;
  }

  void MikeMap::to_string(char *ptr)
  {
    int offset = 0;
    for (unsigned int i = 0; i < mikemap_len; i++)
    {
      if (i > 0)
      {
        ptr[offset] = ',';
        offset++;
      }
      offset += sprintf(&ptr[offset], "%d", mikemap_keys[i]);
      ptr[offset] = ',';
      offset++;
      offset += sprintf(&ptr[offset], "%d", mikemap_values[i]);
    }
  }

  int MikeMap::to_int(const char *data, int len)
  {
    long int val = 0;
    while (len)
    {
      long int new_val = ((int)*data - (int)'0');
      val = val * 10 + new_val;
      len--;
      data++;
    }
#ifdef TEST_MIKEMAP
    printf("val: %d\n", val);
#endif
    return val;
  }

  int MikeMap::from_string(const char *data_start, int *converted)
  {
    const char *data_ptr = data_start;

    this->clear();
    // the map is supposed to start with "["
    if (*data_ptr != '[')
      return MM_ERR_WRONG_START;
    data_ptr++;

    while (1)
    {
      int len_key = 0;
      const char *key_start = data_ptr;
      {
        while (len_key < MAX_SINGLE_DATA_LEN && *data_ptr != ',' && *data_ptr != ']')
        {
          if (*data_ptr < '0' || *data_ptr > '9')
            return MM_ERR_NO_DIGIT;
          len_key++;
          data_ptr++;
        }
        if (len_key == 0 || len_key == MAX_SINGLE_DATA_LEN)
          return MM_ERR_ZERO_MAX_LEN_KEY;
        if (*data_ptr == ']')
          return MM_ERR_MISSING_VAL;
      }
      int k = this->to_int(key_start, len_key);
      (*converted)++;
      data_ptr++;
      int len_val = 0;
      const char *val_start = data_ptr;
      {
        while (len_val < MAX_SINGLE_DATA_LEN && *data_ptr != ',' && *data_ptr != ']')
        {
          if (*data_ptr < '0' || *data_ptr > '9')
            return MM_ERR_NO_DIGIT;
          len_val++;
          data_ptr++;
        }
        if (len_val == 0 || len_val == MAX_SINGLE_DATA_LEN)
          return MM_ERR_ZERO_MAX_LEN_VAL;
      }
      int v = this->to_int(val_start, len_val);
      (*converted)++;
      this->set(k, v);
      if (*data_ptr == ']')
        break;
      else
        data_ptr++;
    }

    return MM_OK;
  }

  void MikeMap::del(MAP_KEY_TYPE key)
  {
    for (unsigned int i = 0; i < mikemap_len; i++)
    {
      if (mikemap_keys[i] == key)
      {
        for (unsigned int si = i; si < (mikemap_len - 1); si++)
        {
          mikemap_keys[si] = mikemap_keys[si + 1];
          mikemap_values[si] = mikemap_values[si + 1];
        }
        mikemap_keys[mikemap_len] = 0;
        mikemap_values[mikemap_len] = 0;
        mikemap_len--;
        return;
      }
    }
  }

  unsigned int MikeMap::get_len() const
  {
    return mikemap_len;
  }

  void MikeMap::clear()
  {
    mikemap_len = 0;
  }

  void MikeMap::get_at(unsigned int at, MAP_KEY_TYPE *key, MAP_VALUE_TYPE *value) const
  {
    if (at < mikemap_len)
    {
      *key = mikemap_keys[at];
      *value = mikemap_values[at];
    }
  }
}<|endoftext|>


<commit_before>#include "miomain.h"
#include "config/configuration.h"
#include "devicedetection.h"
#include "sysex/midi.h"
#include "sysex/retcommandlist.h"
#include "ui_miomain.h"
#include "widgets/centralwidget.h"
#include "widgets/deviceinfowidget.h"
#include "widgets/multiinfowidget.h"
#include "widgets/portswidget.h"

#include <QCloseEvent>
#include <QDesktopWidget>
#include <QMessageBox>
#include <QPixmap>
#include <QSignalMapper>
#include <QStyle>
#include <QTimer>
#include <QToolButton>
#include <QtDebug>

MioMain::MioMain(QWidget *parent) : QMainWindow(parent), ui(new Ui::MioMain) {
  ui->setupUi(this);
	setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::ForceTabbedDocks |
                 QMainWindow::VerticalTabs);
	/*QPixmap *pm = new QPixmap("/develop/mioconfig/graphik/restore.svg");
	pm->save("/develop/mioconfig/graphik/restore.xpm", "xpm");
	pm->load("/develop/mioconfig/graphik/SaveToDevice.svg");
	pm->save("/develop/mioconfig/graphik/SaveToDevice.xpm", "xpm");*/
  readSettings();
  if (readDevicesFromSettings())
    openDefaultDevice();
  else
    QTimer::singleShot(100, this, SLOT(openDetectionWindow()));
}

MioMain::~MioMain() {
  if (deviceDetectionWindow)
    delete deviceDetectionWindow;
  delete ui;
}

void MioMain::openDefaultDevice() {
  writeDevicesToSettings();
  long defaultDeviceSN = Configuration::getInstance().getDefaultDevice();
  Device *d = Configuration::getInstance().getDevices()->at(defaultDeviceSN);
  addDevicesToSelectionMenu(defaultDeviceSN);
  openDeviceGUI(d);
}

void MioMain::addDevicesToSelectionMenu(long defaultDeviceSN) {
  QSignalMapper *signalMapper = new QSignalMapper();
  Devices *devices = Configuration::getInstance().getDevices();
  QActionGroup *devicesGroup = new QActionGroup(this);
  devicesGroup->setExclusive(true);
  for (Devices::iterator it = devices->begin(); it != devices->end(); ++it) {
    Device *d = it->second;
    QAction *a =
        ui->menuSelect->addAction(QString::fromStdString(d->getDeviceName()));
    a->setCheckable(true);
    devicesGroup->addAction(a);
    connect(a, SIGNAL(triggered()), signalMapper, SLOT(map()));
    signalMapper->setMapping(a, new DeviceMenuMapper(d));
    if (it->first == defaultDeviceSN)
      a->setChecked(true);
  }
  connect(signalMapper, SIGNAL(mapped(QObject *)), this,
          SLOT(openDeviceGUI(QObject *)));
}

void MioMain::openDeviceGUI(QObject *o) {
  DeviceMenuMapper *m = (DeviceMenuMapper *)o;
#ifdef __MIO_DEBUG__
  std::cout << "open device GUI: " << m->device->getDeviceName() << std::endl;
#endif //__MIO_DEBUG__
  openDeviceGUI(m->device);
}

void MioMain::addDock(QDockWidget *dockWidget, Qt::DockWidgetArea area) {
  if (MultiInfoWidget *miw = dynamic_cast<MultiInfoWidget *>(dockWidget)) {
    miw->createInfoSections();
  }
  switch (area) {
  case Qt::NoDockWidgetArea:
    setCentralWidget(dockWidget);
    break;
  case Qt::LeftDockWidgetArea:
    this->addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
    break;
  default:
    break;
  }
  std::vector<QDockWidget *> v = dockWidgetAreas[area];
  if (v.size() > 0) {
    tabifyDockWidget(v[v.size() - 1], dockWidget);
  }
  dockWidgetAreas[area].push_back(dockWidget);
}

void MioMain::clearDocWidgets() {
	removeToolBar(toolBar);
	delete toolBar;
	toolBar = 0;
  for (std::map<Qt::DockWidgetArea, std::vector<QDockWidget *>>::iterator it =
           dockWidgetAreas.begin();
       it != dockWidgetAreas.end(); ++it) {
    std::vector<QDockWidget *> v = it->second;
    for (unsigned int j = 0; j < v.size(); j++) {
      QWidget *w = v.at(j);
      delete w;
    }
    v.clear();
  }
  dockWidgetAreas.clear();
}

void MioMain::replacePanel(QWidget *w) {
  CentralWidget *cw = (CentralWidget *)centralWidget();
  cw->replacePanel(w);
}

void MioMain::addDeviceToolButtons() {
	BYTE_VECTOR *saveRestoreList = this->currentDevice->saveRestoreList;
	for (unsigned int i = 0; i < saveRestoreList->size(); ++i) {
		switch ((SaveRestore::SaveResstoreId)(*saveRestoreList)[i]) {
		case SaveRestore::SAVE_TO_DEVICE: {
			QToolButton *btn = new QToolButton();
			btn->setToolButtonStyle(Qt::ToolButtonIconOnly);
			btn->setText("Save");
			btn->setToolTip(tr("Save current settings to device"));
			toolBar->addWidget(btn);
			btn->setIcon(QIcon(":/pixmaps/saveto"));
			connect(btn, SIGNAL(pressed()), this, SLOT(storeToDevice()));
		} break;
		case SaveRestore::RESTORE_FROM_DEVICE: {
			QToolButton *btn = new QToolButton();
			btn->setToolButtonStyle(Qt::ToolButtonIconOnly);
			btn->setText("Restore");
			btn->setToolTip(tr("Restore settings from device"));
			toolBar->addWidget(btn);
			btn->setIcon(QIcon(":/pixmaps/readfrom"));
			connect(btn, SIGNAL(pressed()), this, SLOT(restoreFromDevice()));
		} break;
		case SaveRestore::SET_TO_FACTORY_DEFAULT: {
			QToolButton *btn = new QToolButton();
			btn->setToolButtonStyle(Qt::ToolButtonIconOnly);
			btn->setText("Fact");
			btn->setToolTip(tr("Reset settings to factory default"));
			toolBar->addWidget(btn);
			btn->setIcon(QIcon(":/pixmaps/restore"));
			connect(btn, SIGNAL(pressed()), this, SLOT(resetToFactoryDefaults()));
		} break;
		default:
			break;
		}
	}
}

void MioMain::openDeviceGUI(Device *d) {
  clearDocWidgets();
	toolBar = new QToolBar(tr("Device Actions"), this);
	toolBar->setObjectName("DeviceActions");
	this->addToolBar(toolBar);

	this->currentDevice = d;
	d->connect();
  RetCommandList *c = d->getCommands();
  if (c == 0) {
    // TODO throw error
    exit(2);
  }
  setWindowTitle(this->title + QString(": ") +
                 QString::fromStdString(d->getDeviceName()));
  CentralWidget *centralWidget = new CentralWidget(this, d);
  this->addDock(centralWidget);

  DeviceInfoWidget *deviceInfoWidget =
      new DeviceInfoWidget(this, d, d->getDeviceInfo());
  this->addDock(deviceInfoWidget, Qt::LeftDockWidgetArea);

  PortsWidget *portsWidget = new PortsWidget(this, d);
  this->addDock(portsWidget, Qt::LeftDockWidgetArea);

	addDeviceToolButtons();

  QSettings *settings = Configuration::getInstance().getSettings();
  settings->beginGroup("MainWindow");
  restoreGeometry(settings->value("geometry").toByteArray());
  settings->endGroup();
  settings->beginGroup("Docks");
  // restoreState(settings->value("DockWindows").toByteArray());
  settings->endGroup();
  deviceInfoWidget->show();
	deviceInfoWidget->raise();
}

void MioMain::storeToDevice() {
	QMessageBox msgBox;
	msgBox.setText(tr("Store current setings to device?"));
	msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
	msgBox.setDefaultButton(QMessageBox::Save);
	int ret = msgBox.exec();
	if (ret == QMessageBox::Ok)
		saveRestore(SaveRestore::SAVE_TO_DEVICE);
}

void MioMain::restoreFromDevice() {
	QMessageBox msgBox;
	msgBox.setText(tr("Read all settings from device?"));
	msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
	msgBox.setDefaultButton(QMessageBox::Save);
	int ret = msgBox.exec();
	if (ret == QMessageBox::Ok) {
		saveRestore(SaveRestore::RESTORE_FROM_DEVICE);
		currentDevice->disconnect();
		openDeviceGUI(this->currentDevice);
	}
}

void MioMain::resetToFactoryDefaults() {
	QMessageBox msgBox;
	msgBox.setText(tr("Reset all settings to factory default?"));
	msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
	msgBox.setDefaultButton(QMessageBox::Save);
	int ret = msgBox.exec();
	if (ret == QMessageBox::Ok) {
		saveRestore(SaveRestore::SET_TO_FACTORY_DEFAULT);
		currentDevice->disconnect();
		openDeviceGUI(this->currentDevice);
	}
}

void MioMain::saveRestore(SaveRestore::SaveResstoreId saveRestoreId) {
	SaveRestore *saveRestore = new SaveRestore(currentDevice);
	saveRestore->setSaveRestoreId(saveRestoreId);
	saveRestore->execute();
}

void MioMain::closeEvent(QCloseEvent *event) {
  writeSettings();
  event->accept();
}

void MioMain::openDetectionWindow() {
  deviceDetectionWindow = new DeviceDetection(this);
  deviceDetectionWindow->exec();
}

void MioMain::writeSettings() {
  QSettings *settings = Configuration::getInstance().getSettings();
  settings->beginGroup("MainWindow");
  settings->setValue("geometry", saveGeometry());
  settings->setValue("size", size());
  settings->setValue("pos", pos());
  settings->endGroup();
  settings->beginGroup("Docks");
  settings->setValue("DockWindows", saveState());
  settings->endGroup();
}

void MioMain::writeDevicesToSettings() {
  QSettings *settings = Configuration::getInstance().getSettings();
  Devices *devices = Configuration::getInstance().getDevices();
  settings->remove("Devices");
  settings->beginWriteArray("Devices");
  int i = 0;
  for (Devices::iterator it = devices->begin(); it != devices->end(); ++it) {
    settings->setArrayIndex(i);
    Device *d = it->second;
    settings->setValue("Device Name",
                       QString::fromStdString(d->getDeviceName()));
    settings->setValue("Serial Number",
                       (qlonglong)(d->getSerialNumber()->getLongValue()));
    settings->setValue("Input Port", d->getInPortNumer());
    settings->setValue("Output Port", d->getOutPortNumer());
    settings->setValue("Product Id",
                       (qlonglong)d->getProductId()->getLongValue());
#ifdef __MIO_SIMULATE__
    if (d->getSimulate()) {
      settings->setValue("Simulate", true);
      settings->setValue("Model Name",
                         QString::fromStdString(d->getModelName()));
    }
#endif
    ++i;
  }
  settings->endArray();
}

void MioMain::connectSlots() {
  // connect(this->)
}

void MioMain::readSettings() {
  this->title = windowTitle();
  QSettings *settings = Configuration::getInstance().getSettings();
  settings->beginGroup("MainWindow");
  resize(settings->value("size", QSize(400, 400)).toSize());
  move(settings->value("pos", QPoint(200, 200)).toPoint());
  settings->endGroup();
}

bool MioMain::readDevicesFromSettings() {
  Devices *devices = Configuration::getInstance().getDevices();
  devices->clear();
  QSettings *settings = Configuration::getInstance().getSettings();
  int size = settings->beginReadArray("Devices");
  if (size == 0)
    return false;
  for (int i = 0; i < size; ++i) {
    Device *device = 0;
    settings->setArrayIndex(i);
    int productId = settings->value("Product Id").toInt();
    long serialNumber =
        (qlonglong)settings->value("Serial Number").toLongLong();
    int inputPort = (qlonglong)settings->value("Input Port").toInt();
    int outputPort = (qlonglong)settings->value("Output Port").toInt();
    bool simulate = settings->value("Simulate").toBool();
#ifdef __MIO_SIMULATE__
    if (simulate) {
      std::string modelName =
          settings->value("Model Name").toString().toStdString();
      std::string deviceName =
          settings->value("Device Name").toString().toStdString();
      device = new Device(inputPort, outputPort, serialNumber, productId,
                          modelName, deviceName);
    } else {
      device = new Device(inputPort, outputPort, serialNumber, productId);
    }
#else
    if (!simulate)
      device = new Device(inputPort, outputPort, serialNumber, productId);
#endif
    if (device && device->queryDeviceInfo())
      devices->insert(std::pair<long, Device *>(serialNumber, device));
  }
  settings->endArray();
  if (devices->size() == 0)
    return false;
  return true;
}
void MioMain::on_actionQuit_triggered() { close(); }
<commit_msg>unsuccessful try to get the device back, after restoring fro device memory<commit_after>#include "miomain.h"
#include "config/configuration.h"
#include "devicedetection.h"
#include "sysex/midi.h"
#include "sysex/retcommandlist.h"
#include "ui_miomain.h"
#include "widgets/centralwidget.h"
#include "widgets/deviceinfowidget.h"
#include "widgets/multiinfowidget.h"
#include "widgets/portswidget.h"

#include <QCloseEvent>
#include <QDesktopWidget>
#include <QMessageBox>
#include <QPixmap>
#include <QSignalMapper>
#include <QStyle>
#include <QTimer>
#include <QToolButton>
#include <QtDebug>

MioMain::MioMain(QWidget *parent) : QMainWindow(parent), ui(new Ui::MioMain) {
  ui->setupUi(this);
	setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::ForceTabbedDocks |
                 QMainWindow::VerticalTabs);
	/*QPixmap *pm = new QPixmap("/develop/mioconfig/graphik/restore.svg");
	pm->save("/develop/mioconfig/graphik/restore.xpm", "xpm");
	pm->load("/develop/mioconfig/graphik/SaveToDevice.svg");
	pm->save("/develop/mioconfig/graphik/SaveToDevice.xpm", "xpm");*/
  readSettings();
  if (readDevicesFromSettings())
    openDefaultDevice();
  else
    QTimer::singleShot(100, this, SLOT(openDetectionWindow()));
}

MioMain::~MioMain() {
  if (deviceDetectionWindow)
    delete deviceDetectionWindow;
  delete ui;
}

void MioMain::openDefaultDevice() {
  writeDevicesToSettings();
  long defaultDeviceSN = Configuration::getInstance().getDefaultDevice();
  Device *d = Configuration::getInstance().getDevices()->at(defaultDeviceSN);
  addDevicesToSelectionMenu(defaultDeviceSN);
  openDeviceGUI(d);
}

void MioMain::addDevicesToSelectionMenu(long defaultDeviceSN) {
  QSignalMapper *signalMapper = new QSignalMapper();
  Devices *devices = Configuration::getInstance().getDevices();
  QActionGroup *devicesGroup = new QActionGroup(this);
  devicesGroup->setExclusive(true);
  for (Devices::iterator it = devices->begin(); it != devices->end(); ++it) {
    Device *d = it->second;
    QAction *a =
        ui->menuSelect->addAction(QString::fromStdString(d->getDeviceName()));
    a->setCheckable(true);
    devicesGroup->addAction(a);
    connect(a, SIGNAL(triggered()), signalMapper, SLOT(map()));
    signalMapper->setMapping(a, new DeviceMenuMapper(d));
    if (it->first == defaultDeviceSN)
      a->setChecked(true);
  }
  connect(signalMapper, SIGNAL(mapped(QObject *)), this,
          SLOT(openDeviceGUI(QObject *)));
}

void MioMain::openDeviceGUI(QObject *o) {
  DeviceMenuMapper *m = (DeviceMenuMapper *)o;
#ifdef __MIO_DEBUG__
  std::cout << "open device GUI: " << m->device->getDeviceName() << std::endl;
#endif //__MIO_DEBUG__
  openDeviceGUI(m->device);
}

void MioMain::addDock(QDockWidget *dockWidget, Qt::DockWidgetArea area) {
  if (MultiInfoWidget *miw = dynamic_cast<MultiInfoWidget *>(dockWidget)) {
    miw->createInfoSections();
  }
  switch (area) {
  case Qt::NoDockWidgetArea:
    setCentralWidget(dockWidget);
    break;
  case Qt::LeftDockWidgetArea:
    this->addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
    break;
  default:
    break;
  }
  std::vector<QDockWidget *> v = dockWidgetAreas[area];
  if (v.size() > 0) {
    tabifyDockWidget(v[v.size() - 1], dockWidget);
  }
  dockWidgetAreas[area].push_back(dockWidget);
}

void MioMain::clearDocWidgets() {
	removeToolBar(toolBar);
	delete toolBar;
	toolBar = 0;
  for (std::map<Qt::DockWidgetArea, std::vector<QDockWidget *>>::iterator it =
           dockWidgetAreas.begin();
       it != dockWidgetAreas.end(); ++it) {
    std::vector<QDockWidget *> v = it->second;
    for (unsigned int j = 0; j < v.size(); j++) {
      QWidget *w = v.at(j);
      delete w;
    }
    v.clear();
  }
  dockWidgetAreas.clear();
}

void MioMain::replacePanel(QWidget *w) {
  CentralWidget *cw = (CentralWidget *)centralWidget();
  cw->replacePanel(w);
}

void MioMain::addDeviceToolButtons() {
	BYTE_VECTOR *saveRestoreList = this->currentDevice->saveRestoreList;
	for (unsigned int i = 0; i < saveRestoreList->size(); ++i) {
		switch ((SaveRestore::SaveResstoreId)(*saveRestoreList)[i]) {
		case SaveRestore::SAVE_TO_DEVICE: {
			QToolButton *btn = new QToolButton();
			btn->setToolButtonStyle(Qt::ToolButtonIconOnly);
			btn->setText("Save");
			btn->setToolTip(tr("Save current settings to device"));
			toolBar->addWidget(btn);
			btn->setIcon(QIcon(":/pixmaps/saveto"));
			connect(btn, SIGNAL(pressed()), this, SLOT(storeToDevice()));
		} break;
		case SaveRestore::RESTORE_FROM_DEVICE: {
			QToolButton *btn = new QToolButton();
			btn->setToolButtonStyle(Qt::ToolButtonIconOnly);
			btn->setText("Restore");
			btn->setToolTip(tr("Restore settings from device"));
			toolBar->addWidget(btn);
			btn->setIcon(QIcon(":/pixmaps/readfrom"));
			connect(btn, SIGNAL(pressed()), this, SLOT(restoreFromDevice()));
		} break;
		case SaveRestore::SET_TO_FACTORY_DEFAULT: {
			QToolButton *btn = new QToolButton();
			btn->setToolButtonStyle(Qt::ToolButtonIconOnly);
			btn->setText("Fact");
			btn->setToolTip(tr("Reset settings to factory default"));
			toolBar->addWidget(btn);
			btn->setIcon(QIcon(":/pixmaps/restore"));
			connect(btn, SIGNAL(pressed()), this, SLOT(resetToFactoryDefaults()));
		} break;
		default:
			break;
		}
	}
}

void MioMain::openDeviceGUI(Device *d) {
  clearDocWidgets();
	toolBar = new QToolBar(tr("Device Actions"), this);
	toolBar->setObjectName("DeviceActions");
	this->addToolBar(toolBar);

	this->currentDevice = d;
	d->connect();
  RetCommandList *c = d->getCommands();
  if (c == 0) {
    // TODO throw error
    exit(2);
  }
  setWindowTitle(this->title + QString(": ") +
                 QString::fromStdString(d->getDeviceName()));
  CentralWidget *centralWidget = new CentralWidget(this, d);
  this->addDock(centralWidget);

  DeviceInfoWidget *deviceInfoWidget =
      new DeviceInfoWidget(this, d, d->getDeviceInfo());
  this->addDock(deviceInfoWidget, Qt::LeftDockWidgetArea);

  PortsWidget *portsWidget = new PortsWidget(this, d);
  this->addDock(portsWidget, Qt::LeftDockWidgetArea);

	addDeviceToolButtons();

  QSettings *settings = Configuration::getInstance().getSettings();
  settings->beginGroup("MainWindow");
  restoreGeometry(settings->value("geometry").toByteArray());
  settings->endGroup();
  settings->beginGroup("Docks");
  // restoreState(settings->value("DockWindows").toByteArray());
  settings->endGroup();
  deviceInfoWidget->show();
	deviceInfoWidget->raise();
}

void MioMain::storeToDevice() {
	QMessageBox msgBox;
	msgBox.setText(tr("Store current setings to device?"));
	msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
	msgBox.setDefaultButton(QMessageBox::Save);
	int ret = msgBox.exec();
	if (ret == QMessageBox::Ok)
		saveRestore(SaveRestore::SAVE_TO_DEVICE);
}

void MioMain::restoreFromDevice() {
	QMessageBox msgBox;
	msgBox.setText(tr("Read all settings from device?"));
	msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
	msgBox.setDefaultButton(QMessageBox::Save);
	int ret = msgBox.exec();
	if (ret == QMessageBox::Ok) {
		saveRestore(SaveRestore::RESTORE_FROM_DEVICE);
		currentDevice->disconnect();
		SLEEP(5000);
		bool valid = false;
		for (int i = 0; i < 10; ++i) {
			currentDevice->connect();
			valid = currentDevice->isDeviceValid();
			if (valid) {
				currentDevice->getDeviceInfo();
				openDeviceGUI(currentDevice);
				break;
			}
		}
		if (!valid)
			exit(-1);
	}
}

void MioMain::resetToFactoryDefaults() {
	QMessageBox msgBox;
	msgBox.setText(tr("Reset all settings to factory default?"));
	msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
	msgBox.setDefaultButton(QMessageBox::Save);
	int ret = msgBox.exec();
	if (ret == QMessageBox::Ok) {
		saveRestore(SaveRestore::SET_TO_FACTORY_DEFAULT);
		currentDevice->disconnect();
		openDeviceGUI(this->currentDevice);
	}
}

void MioMain::saveRestore(SaveRestore::SaveResstoreId saveRestoreId) {
	SaveRestore *saveRestore = new SaveRestore(currentDevice);
	saveRestore->setSaveRestoreId(saveRestoreId);
	saveRestore->execute();
}

void MioMain::closeEvent(QCloseEvent *event) {
  writeSettings();
  event->accept();
}

void MioMain::openDetectionWindow() {
  deviceDetectionWindow = new DeviceDetection(this);
  deviceDetectionWindow->exec();
}

void MioMain::writeSettings() {
  QSettings *settings = Configuration::getInstance().getSettings();
  settings->beginGroup("MainWindow");
  settings->setValue("geometry", saveGeometry());
  settings->setValue("size", size());
  settings->setValue("pos", pos());
  settings->endGroup();
  settings->beginGroup("Docks");
  settings->setValue("DockWindows", saveState());
  settings->endGroup();
}

void MioMain::writeDevicesToSettings() {
  QSettings *settings = Configuration::getInstance().getSettings();
  Devices *devices = Configuration::getInstance().getDevices();
  settings->remove("Devices");
  settings->beginWriteArray("Devices");
  int i = 0;
  for (Devices::iterator it = devices->begin(); it != devices->end(); ++it) {
    settings->setArrayIndex(i);
    Device *d = it->second;
    settings->setValue("Device Name",
                       QString::fromStdString(d->getDeviceName()));
    settings->setValue("Serial Number",
                       (qlonglong)(d->getSerialNumber()->getLongValue()));
    settings->setValue("Input Port", d->getInPortNumer());
    settings->setValue("Output Port", d->getOutPortNumer());
    settings->setValue("Product Id",
                       (qlonglong)d->getProductId()->getLongValue());
#ifdef __MIO_SIMULATE__
    if (d->getSimulate()) {
      settings->setValue("Simulate", true);
      settings->setValue("Model Name",
                         QString::fromStdString(d->getModelName()));
    }
#endif
    ++i;
  }
  settings->endArray();
}

void MioMain::connectSlots() {
  // connect(this->)
}

void MioMain::readSettings() {
  this->title = windowTitle();
  QSettings *settings = Configuration::getInstance().getSettings();
  settings->beginGroup("MainWindow");
  resize(settings->value("size", QSize(400, 400)).toSize());
  move(settings->value("pos", QPoint(200, 200)).toPoint());
  settings->endGroup();
}

bool MioMain::readDevicesFromSettings() {
  Devices *devices = Configuration::getInstance().getDevices();
  devices->clear();
  QSettings *settings = Configuration::getInstance().getSettings();
  int size = settings->beginReadArray("Devices");
  if (size == 0)
    return false;
  for (int i = 0; i < size; ++i) {
    Device *device = 0;
    settings->setArrayIndex(i);
    int productId = settings->value("Product Id").toInt();
    long serialNumber =
        (qlonglong)settings->value("Serial Number").toLongLong();
    int inputPort = (qlonglong)settings->value("Input Port").toInt();
    int outputPort = (qlonglong)settings->value("Output Port").toInt();
    bool simulate = settings->value("Simulate").toBool();
#ifdef __MIO_SIMULATE__
    if (simulate) {
      std::string modelName =
          settings->value("Model Name").toString().toStdString();
      std::string deviceName =
          settings->value("Device Name").toString().toStdString();
      device = new Device(inputPort, outputPort, serialNumber, productId,
                          modelName, deviceName);
    } else {
      device = new Device(inputPort, outputPort, serialNumber, productId);
    }
#else
    if (!simulate)
      device = new Device(inputPort, outputPort, serialNumber, productId);
#endif
    if (device && device->queryDeviceInfo())
      devices->insert(std::pair<long, Device *>(serialNumber, device));
  }
  settings->endArray();
  if (devices->size() == 0)
    return false;
  return true;
}
void MioMain::on_actionQuit_triggered() { close(); }
<|endoftext|>