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

///
/// @file sim/main.cc
///
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <signal.h>

#include <string>
#include <vector>

#include "base/copyright.hh"
#include "base/inifile.hh"
#include "base/misc.hh"
#include "base/pollevent.hh"
#include "base/statistics.hh"
#include "base/time.hh"
#include "cpu/base_cpu.hh"
#include "cpu/full_cpu/smt.hh"
#include "sim/async.hh"
#include "sim/builder.hh"
#include "sim/configfile.hh"
#include "sim/host.hh"
#include "sim/sim_events.hh"
#include "sim/sim_exit.hh"
#include "sim/sim_init.hh"
#include "sim/sim_object.hh"
#include "sim/stat_control.hh"
#include "sim/stats.hh"
#include "sim/universe.hh"
#include "sim/pyconfig/pyconfig.hh"

using namespace std;

// See async.h.
volatile bool async_event = false;
volatile bool async_dump = false;
volatile bool async_dumpreset = false;
volatile bool async_exit = false;
volatile bool async_io = false;
volatile bool async_alarm = false;

/// Stats signal handler.
void
dumpStatsHandler(int sigtype)
{
    async_event = true;
    async_dump = true;
}

void
dumprstStatsHandler(int sigtype)
{
    async_event = true;
    async_dumpreset = true;
}

/// Exit signal handler.
void
exitNowHandler(int sigtype)
{
    async_event = true;
    async_exit = true;
}

/// Abort signal handler.
void
abortHandler(int sigtype)
{
    cerr << "Program aborted at cycle " << curTick << endl;

#if TRACING_ON
    // dump trace buffer, if there is one
    Trace::theLog.dump(cerr);
#endif
}

/// Simulator executable name
const char *myProgName = "";

/// Show brief help message.
static void
showBriefHelp(ostream &out)
{
    out << "Usage: " << myProgName
         << " [-hn] [-Dname[=def]] [-Uname] [-I[dir]] "
         << "[--<section>:<param>=<value>] [<config file> ...]" << endl
         << "   -h: print long help (including parameter listing)" << endl
         << "   -n: don't load default.ini" << endl
         << "   -u: don't quit on unreferenced parameters" << endl
         << "   -D,-U,-I: passed to cpp for preprocessing .ini files" << endl;
}

/// Show verbose help message.  Includes parameter listing from
/// showBriefHelp(), plus an exhaustive list of ini-file parameters
/// and SimObjects (with their parameters).
static void
showLongHelp(ostream &out)
{
    showBriefHelp(out);

    out << endl
        << endl
        << "-----------------" << endl
        << "Global Parameters" << endl
        << "-----------------" << endl
        << endl;

    ParamContext::describeAllContexts(out);

    out << endl
        << endl
        << "-----------------" << endl
        << "Simulator Objects" << endl
        << "-----------------" << endl
        << endl;

    SimObjectClass::describeAllClasses(out);
}

/// Print welcome message.
static void
sayHello(ostream &out)
{
    extern const char *compileDate;	// from date.cc

    ccprintf(out, "M5 Simulator System\n");
    // display copyright
    ccprintf(out, "%s\n", briefCopyright);
    ccprintf(out, "M5 compiled on %d\n", compileDate);

    char *host = getenv("HOSTNAME");
    if (!host)
        host = getenv("HOST");

    if (host)
        ccprintf(out, "M5 executing on %s\n", host);

    ccprintf(out, "M5 simulation started %s\n", Time::start);
}

///
/// Echo the command line for posterity in such a way that it can be
/// used to rerun the same simulation (given the same .ini files).
///
static void
echoCommandLine(int argc, char **argv, ostream &out)
{
    out << "command line: " << argv[0];
    for (int i = 1; i < argc; i++) {
        string arg(argv[i]);

        out << ' ';

        // If the arg contains spaces, we need to quote it.
        // The rest of this is overkill to make it look purty.

        // print dashes first outside quotes
        int non_dash_pos = arg.find_first_not_of("-");
        out << arg.substr(0, non_dash_pos);	// print dashes
        string body = arg.substr(non_dash_pos);	// the rest

        // if it's an assignment, handle the lhs & rhs separately
        int eq_pos = body.find("=");
        if (eq_pos == string::npos) {
            out << quote(body);
        }
        else {
            string lhs(body.substr(0, eq_pos));
            string rhs(body.substr(eq_pos + 1));

            out << quote(lhs) << "=" << quote(rhs);
        }
    }
    out << endl << endl;
}

///
/// The simulator configuration database.  This is the union of all
/// specified .ini files.  This shouldn't need to be visible outside
/// this file, as it is passed as a parameter to all the param-parsing
/// routines.
///
static IniFile simConfigDB;

/// Check for a default.ini file and load it if necessary.
static void
handleDefaultIni(bool &loadIt, vector<char *> &cppArgs)
{
    struct stat sb;

    if (loadIt) {
        if (stat("default.ini", &sb) == 0) {
            if (!simConfigDB.loadCPP("default.ini", cppArgs)) {
                cout << "Error processing file default.ini" << endl;
                exit(1);
            }
        }

        // set this whether it actually was found or not, so we don't
        // bother to check again next time
        loadIt = false;
    }
}

/// M5 entry point.
int
main(int argc, char **argv)
{
    // Save off program name
    myProgName = argv[0];

    signal(SIGFPE, SIG_IGN);		// may occur on misspeculated paths
    signal(SIGTRAP, SIG_IGN);
    signal(SIGUSR1, dumpStatsHandler);		// dump intermediate stats
    signal(SIGUSR2, dumprstStatsHandler);	// dump and reset stats
    signal(SIGINT, exitNowHandler);		// dump final stats and exit
    signal(SIGABRT, abortHandler);

    sayHello(cerr);

    // Initialize statistics database
    Stats::InitSimStats();

    vector<char *> cppArgs;

    // Should we use default.ini if it exists?  By default, yes.  (Use
    // -n to override.)
    bool loadDefaultIni = true;

    // Should we quit if there are unreferenced parameters?  By
    // default, yes... it's a good way of catching typos in
    // section/parameter names (which otherwise go by silently).  Use
    // -u to override.
    bool quitOnUnreferenced = true;

    // Parse command-line options.  The tricky part here is figuring
    // out whether to look for & load default.ini, and if needed,
    // doing so at the right time w.r.t. processing the other
    // parameters.
    //
    // Since most of the complex options are handled through the
    // config database, we don't mess with getopts, and just parse
    // manually.
    for (int i = 1; i < argc; ++i) {
        char *arg_str = argv[i];

        // if arg starts with '-', parse as option,
        // else treat it as a configuration file name and load it
        if (arg_str[0] == '-') {

            // switch on second char
            switch (arg_str[1]) {
              case 'h':
                // -h: show help
                showLongHelp(cerr);
                exit(1);

              case 'n':
                // -n: don't load default.ini
                if (!loadDefaultIni) {
                    cerr << "Warning: -n option needs to precede any "
                         << "explicit configuration file name " << endl
                         << "         or command-line configuration parameter."
                         << endl;
                }
                loadDefaultIni = false;
                break;

              case 'u':
                // -u: don't quit on unreferenced parameters
                quitOnUnreferenced = false;
                break;

              case 'D':
              case 'U':
              case 'I':
                // cpp options: record & pass to cpp.  Note that these
                // cannot have spaces, i.e., '-Dname=val' is OK, but
                // '-D name=val' is not.  I don't consider this a
                // problem, since even though gnu cpp accepts the
                // latter, other cpp implementations do not (Tru64,
                // for one).
                cppArgs.push_back(arg_str);
                break;

              case '-':
                // command-line configuration parameter:
                // '--<section>:<parameter>=<value>'

                // Load default.ini if necessary -- see comment in
                // else clause below.
                handleDefaultIni(loadDefaultIni, cppArgs);

                if (!simConfigDB.add(arg_str + 2)) {
                    // parse error
                    ccprintf(cerr,
                             "Could not parse configuration argument '%s'\n"
                             "Expecting --<section>:<parameter>=<value>\n",
                             arg_str);
                    exit(0);
                }
                break;

              default:
                showBriefHelp(cerr);
                ccprintf(cerr, "Fatal: invalid argument '%s'\n", arg_str);
                exit(0);
            }
        }
        else {
            // no '-', treat as config file name

            // make STL string out of file name
            string filename(arg_str);

            int ext_loc = filename.rfind(".");

            string ext =
                (ext_loc != string::npos) ? filename.substr(ext_loc) : "";

            if (ext == ".ini") {
                // If we haven't loaded default.ini yet, and we want to,
                // now is the time.  Can't do it sooner because we need to
                // look for '-n', can't do it later since we want
                // default.ini loaded first (so that any other settings
                // override it).
                handleDefaultIni(loadDefaultIni, cppArgs);

                if (!simConfigDB.loadCPP(filename, cppArgs)) {
                    cprintf("Error processing file %s\n", filename);
                    exit(1);
                }
            } else if (ext == ".py") {
                if (!loadPythonConfig(filename, &simConfigDB)) {
                    cprintf("Error processing file %s\n", filename);
                    exit(1);
                }
            }
            else {
                cprintf("Config file name '%s' must end in '.py' or '.ini'.\n",
                        filename);
                exit(1);
            }
        }
    }

    // Final check for default.ini, in case no config files or
    // command-line config parameters were given.
    handleDefaultIni(loadDefaultIni, cppArgs);

    // The configuration database is now complete; start processing it.

    // Parse and check all non-config-hierarchy parameters.
    ParamContext::parseAllContexts(simConfigDB);
    ParamContext::checkAllContexts();

    // Print header info into stats file.  Can't do this sooner since
    // the stat file name is set via a .ini param... thus it just got
    // opened above during ParamContext::checkAllContexts().

    // Print hello message to stats file if it's actually a file.  If
    // it's not (i.e. it's cout or cerr) then we already did it above.
    if (outputStream != &cout && outputStream != &cerr)
        sayHello(*outputStream);

    // Echo command line and all parameter settings to stats file as well.
    echoCommandLine(argc, argv, *outputStream);
    ParamContext::showAllContexts(*configStream);

    // Now process the configuration hierarchy and create the SimObjects.
    ConfigHierarchy configHierarchy(simConfigDB);
    configHierarchy.build();
    configHierarchy.createSimObjects();

    // Restore checkpointed state, if any.
    configHierarchy.unserializeSimObjects();

    // Done processing the configuration database.
    // Check for unreferenced entries.
    if (simConfigDB.printUnreferenced() && quitOnUnreferenced) {
        cerr << "Fatal: unreferenced .ini sections/entries." << endl
             << "If this is not an error, add 'unref_section_ok=y' or "
             << "'unref_entries_ok=y' to the appropriate sections "
             << "to suppress this message." << endl;
        exit(1);
    }

    SimObject::regAllStats();

    // uncomment the following to get PC-based execution-time profile
#ifdef DO_PROFILE
    init_profile((char *)&_init, (char *)&_fini);
#endif

    // Check to make sure that the stats package is properly initialized
    Stats::check();

    // Reset to put the stats in a consistent state.
    Stats::reset();

    // Nothing to simulate if we don't have at least one CPU somewhere.
    if (BaseCPU::numSimulatedCPUs() == 0) {
        cerr << "Fatal: no CPUs to simulate." << endl;
        exit(1);
    }

    SimInit();
    warn("Entering event queue.  Starting simulation...\n");

    while (!mainEventQueue.empty()) {
        assert(curTick <= mainEventQueue.nextTick() &&
               "event scheduled in the past");

        // forward current cycle to the time of the first event on the
        // queue
        curTick = mainEventQueue.nextTick();
        mainEventQueue.serviceOne();

        if (async_event) {
            async_event = false;
            if (async_dump) {
                async_dump = false;

                using namespace Stats;
                SetupEvent(Dump, curTick);
            }

            if (async_dumpreset) {
                async_dumpreset = false;

                using namespace Stats;
                SetupEvent(Dump | Reset, curTick);
            }

            if (async_exit) {
                async_exit = false;
                new SimExitEvent("User requested STOP");
            }

            if (async_io || async_alarm) {
                async_io = false;
                async_alarm = false;
                pollQueue.service();
            }
        }
    }

    // This should never happen... every conceivable way for the
    // simulation to terminate (hit max cycles/insts, signal,
    // simulated system halts/exits) generates an exit event, so we
    // should never run out of events on the queue.
    exitNow("no events on event loop!  All CPUs must be idle.", 1);

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

///
/// @file sim/main.cc
///
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <signal.h>

#include <string>
#include <vector>

#include "base/copyright.hh"
#include "base/inifile.hh"
#include "base/misc.hh"
#include "base/pollevent.hh"
#include "base/statistics.hh"
#include "base/time.hh"
#include "cpu/base_cpu.hh"
#include "cpu/full_cpu/smt.hh"
#include "sim/async.hh"
#include "sim/builder.hh"
#include "sim/configfile.hh"
#include "sim/host.hh"
#include "sim/sim_events.hh"
#include "sim/sim_exit.hh"
#include "sim/sim_init.hh"
#include "sim/sim_object.hh"
#include "sim/stat_control.hh"
#include "sim/stats.hh"
#include "sim/universe.hh"
#include "sim/pyconfig/pyconfig.hh"

using namespace std;

// See async.h.
volatile bool async_event = false;
volatile bool async_dump = false;
volatile bool async_dumpreset = false;
volatile bool async_exit = false;
volatile bool async_io = false;
volatile bool async_alarm = false;

/// Stats signal handler.
void
dumpStatsHandler(int sigtype)
{
    async_event = true;
    async_dump = true;
}

void
dumprstStatsHandler(int sigtype)
{
    async_event = true;
    async_dumpreset = true;
}

/// Exit signal handler.
void
exitNowHandler(int sigtype)
{
    async_event = true;
    async_exit = true;
}

/// Abort signal handler.
void
abortHandler(int sigtype)
{
    cerr << "Program aborted at cycle " << curTick << endl;

#if TRACING_ON
    // dump trace buffer, if there is one
    Trace::theLog.dump(cerr);
#endif
}

/// Simulator executable name
const char *myProgName = "";

/// Show brief help message.
static void
showBriefHelp(ostream &out)
{
    out << "Usage: " << myProgName
         << " [-hnu] [-Dname[=def]] [-Uname] [-I[dir]] "
         << "[--<section>:<param>=<value>] [<config file> ...]" << endl
         << "   -h: print long help (including parameter listing)" << endl
         << "   -n: don't load default.ini" << endl
         << "   -u: don't quit on unreferenced parameters" << endl
         << "   -D,-U,-I: passed to cpp for preprocessing .ini files" << endl;
}

/// Show verbose help message.  Includes parameter listing from
/// showBriefHelp(), plus an exhaustive list of ini-file parameters
/// and SimObjects (with their parameters).
static void
showLongHelp(ostream &out)
{
    showBriefHelp(out);

    out << endl
        << endl
        << "-----------------" << endl
        << "Global Parameters" << endl
        << "-----------------" << endl
        << endl;

    ParamContext::describeAllContexts(out);

    out << endl
        << endl
        << "-----------------" << endl
        << "Simulator Objects" << endl
        << "-----------------" << endl
        << endl;

    SimObjectClass::describeAllClasses(out);
}

/// Print welcome message.
static void
sayHello(ostream &out)
{
    extern const char *compileDate;	// from date.cc

    ccprintf(out, "M5 Simulator System\n");
    // display copyright
    ccprintf(out, "%s\n", briefCopyright);
    ccprintf(out, "M5 compiled on %d\n", compileDate);

    char *host = getenv("HOSTNAME");
    if (!host)
        host = getenv("HOST");

    if (host)
        ccprintf(out, "M5 executing on %s\n", host);

    ccprintf(out, "M5 simulation started %s\n", Time::start);
}

///
/// Echo the command line for posterity in such a way that it can be
/// used to rerun the same simulation (given the same .ini files).
///
static void
echoCommandLine(int argc, char **argv, ostream &out)
{
    out << "command line: " << argv[0];
    for (int i = 1; i < argc; i++) {
        string arg(argv[i]);

        out << ' ';

        // If the arg contains spaces, we need to quote it.
        // The rest of this is overkill to make it look purty.

        // print dashes first outside quotes
        int non_dash_pos = arg.find_first_not_of("-");
        out << arg.substr(0, non_dash_pos);	// print dashes
        string body = arg.substr(non_dash_pos);	// the rest

        // if it's an assignment, handle the lhs & rhs separately
        int eq_pos = body.find("=");
        if (eq_pos == string::npos) {
            out << quote(body);
        }
        else {
            string lhs(body.substr(0, eq_pos));
            string rhs(body.substr(eq_pos + 1));

            out << quote(lhs) << "=" << quote(rhs);
        }
    }
    out << endl << endl;
}

///
/// The simulator configuration database.  This is the union of all
/// specified .ini files.  This shouldn't need to be visible outside
/// this file, as it is passed as a parameter to all the param-parsing
/// routines.
///
static IniFile simConfigDB;

/// Check for a default.ini file and load it if necessary.
static void
handleDefaultIni(bool &loadIt, vector<char *> &cppArgs)
{
    struct stat sb;

    if (loadIt) {
        if (stat("default.ini", &sb) == 0) {
            if (!simConfigDB.loadCPP("default.ini", cppArgs)) {
                cout << "Error processing file default.ini" << endl;
                exit(1);
            }
        }

        // set this whether it actually was found or not, so we don't
        // bother to check again next time
        loadIt = false;
    }
}

/// M5 entry point.
int
main(int argc, char **argv)
{
    // Save off program name
    myProgName = argv[0];

    signal(SIGFPE, SIG_IGN);		// may occur on misspeculated paths
    signal(SIGTRAP, SIG_IGN);
    signal(SIGUSR1, dumpStatsHandler);		// dump intermediate stats
    signal(SIGUSR2, dumprstStatsHandler);	// dump and reset stats
    signal(SIGINT, exitNowHandler);		// dump final stats and exit
    signal(SIGABRT, abortHandler);

    sayHello(cerr);

    // Initialize statistics database
    Stats::InitSimStats();

    vector<char *> cppArgs;

    // Should we use default.ini if it exists?  By default, yes.  (Use
    // -n to override.)
    bool loadDefaultIni = true;

    // Should we quit if there are unreferenced parameters?  By
    // default, yes... it's a good way of catching typos in
    // section/parameter names (which otherwise go by silently).  Use
    // -u to override.
    bool quitOnUnreferenced = true;

    // Parse command-line options.  The tricky part here is figuring
    // out whether to look for & load default.ini, and if needed,
    // doing so at the right time w.r.t. processing the other
    // parameters.
    //
    // Since most of the complex options are handled through the
    // config database, we don't mess with getopts, and just parse
    // manually.
    for (int i = 1; i < argc; ++i) {
        char *arg_str = argv[i];

        // if arg starts with '-', parse as option,
        // else treat it as a configuration file name and load it
        if (arg_str[0] == '-') {

            // switch on second char
            switch (arg_str[1]) {
              case 'h':
                // -h: show help
                showLongHelp(cerr);
                exit(1);

              case 'n':
                // -n: don't load default.ini
                if (!loadDefaultIni) {
                    cerr << "Warning: -n option needs to precede any "
                         << "explicit configuration file name " << endl
                         << "         or command-line configuration parameter."
                         << endl;
                }
                loadDefaultIni = false;
                break;

              case 'u':
                // -u: don't quit on unreferenced parameters
                quitOnUnreferenced = false;
                break;

              case 'D':
              case 'U':
              case 'I':
                // cpp options: record & pass to cpp.  Note that these
                // cannot have spaces, i.e., '-Dname=val' is OK, but
                // '-D name=val' is not.  I don't consider this a
                // problem, since even though gnu cpp accepts the
                // latter, other cpp implementations do not (Tru64,
                // for one).
                cppArgs.push_back(arg_str);
                break;

              case '-':
                // command-line configuration parameter:
                // '--<section>:<parameter>=<value>'

                // Load default.ini if necessary -- see comment in
                // else clause below.
                handleDefaultIni(loadDefaultIni, cppArgs);

                if (!simConfigDB.add(arg_str + 2)) {
                    // parse error
                    ccprintf(cerr,
                             "Could not parse configuration argument '%s'\n"
                             "Expecting --<section>:<parameter>=<value>\n",
                             arg_str);
                    exit(0);
                }
                break;

              default:
                showBriefHelp(cerr);
                ccprintf(cerr, "Fatal: invalid argument '%s'\n", arg_str);
                exit(0);
            }
        }
        else {
            // no '-', treat as config file name

            // make STL string out of file name
            string filename(arg_str);

            int ext_loc = filename.rfind(".");

            string ext =
                (ext_loc != string::npos) ? filename.substr(ext_loc) : "";

            if (ext == ".ini") {
                // If we haven't loaded default.ini yet, and we want to,
                // now is the time.  Can't do it sooner because we need to
                // look for '-n', can't do it later since we want
                // default.ini loaded first (so that any other settings
                // override it).
                handleDefaultIni(loadDefaultIni, cppArgs);

                if (!simConfigDB.loadCPP(filename, cppArgs)) {
                    cprintf("Error processing file %s\n", filename);
                    exit(1);
                }
            } else if (ext == ".py") {
                if (!loadPythonConfig(filename, &simConfigDB)) {
                    cprintf("Error processing file %s\n", filename);
                    exit(1);
                }
            }
            else {
                cprintf("Config file name '%s' must end in '.py' or '.ini'.\n",
                        filename);
                exit(1);
            }
        }
    }

    // Final check for default.ini, in case no config files or
    // command-line config parameters were given.
    handleDefaultIni(loadDefaultIni, cppArgs);

    // The configuration database is now complete; start processing it.

    // Parse and check all non-config-hierarchy parameters.
    ParamContext::parseAllContexts(simConfigDB);
    ParamContext::checkAllContexts();

    // Print header info into stats file.  Can't do this sooner since
    // the stat file name is set via a .ini param... thus it just got
    // opened above during ParamContext::checkAllContexts().

    // Print hello message to stats file if it's actually a file.  If
    // it's not (i.e. it's cout or cerr) then we already did it above.
    if (outputStream != &cout && outputStream != &cerr)
        sayHello(*outputStream);

    // Echo command line and all parameter settings to stats file as well.
    echoCommandLine(argc, argv, *outputStream);
    ParamContext::showAllContexts(*configStream);

    // Now process the configuration hierarchy and create the SimObjects.
    ConfigHierarchy configHierarchy(simConfigDB);
    configHierarchy.build();
    configHierarchy.createSimObjects();

    // Restore checkpointed state, if any.
    configHierarchy.unserializeSimObjects();

    // Done processing the configuration database.
    // Check for unreferenced entries.
    if (simConfigDB.printUnreferenced() && quitOnUnreferenced) {
        cerr << "Fatal: unreferenced .ini sections/entries." << endl
             << "If this is not an error, add 'unref_section_ok=y' or "
             << "'unref_entries_ok=y' to the appropriate sections "
             << "to suppress this message." << endl;
        exit(1);
    }

    SimObject::regAllStats();

    // uncomment the following to get PC-based execution-time profile
#ifdef DO_PROFILE
    init_profile((char *)&_init, (char *)&_fini);
#endif

    // Check to make sure that the stats package is properly initialized
    Stats::check();

    // Reset to put the stats in a consistent state.
    Stats::reset();

    // Nothing to simulate if we don't have at least one CPU somewhere.
    if (BaseCPU::numSimulatedCPUs() == 0) {
        cerr << "Fatal: no CPUs to simulate." << endl;
        exit(1);
    }

    SimInit();
    warn("Entering event queue.  Starting simulation...\n");

    while (!mainEventQueue.empty()) {
        assert(curTick <= mainEventQueue.nextTick() &&
               "event scheduled in the past");

        // forward current cycle to the time of the first event on the
        // queue
        curTick = mainEventQueue.nextTick();
        mainEventQueue.serviceOne();

        if (async_event) {
            async_event = false;
            if (async_dump) {
                async_dump = false;

                using namespace Stats;
                SetupEvent(Dump, curTick);
            }

            if (async_dumpreset) {
                async_dumpreset = false;

                using namespace Stats;
                SetupEvent(Dump | Reset, curTick);
            }

            if (async_exit) {
                async_exit = false;
                new SimExitEvent("User requested STOP");
            }

            if (async_io || async_alarm) {
                async_io = false;
                async_alarm = false;
                pollQueue.service();
            }
        }
    }

    // This should never happen... every conceivable way for the
    // simulation to terminate (hit max cycles/insts, signal,
    // simulated system halts/exits) generates an exit event, so we
    // should never run out of events on the queue.
    exitNow("no events on event loop!  All CPUs must be idle.", 1);

    return 0;
}
<|endoftext|>


<commit_before>// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_AUDIO_EFFECT_HPP
#define OUZEL_AUDIO_EFFECT_HPP

#include <cstdint>
#include "audio/Node.hpp"

namespace ouzel
{
    namespace audio
    {
        class Audio;
        class Mix;
        class Source;

        class Effect: public Node
        {
            friend Mix;
        public:
            Effect(Audio& initAudio,
                   uintptr_t initProcessorId);
            virtual ~Effect();

            Effect(const Effect&) = delete;
            Effect& operator=(const Effect&) = delete;
            Effect(Effect&&) = delete;
            Effect& operator=(Effect&&) = delete;

            inline uintptr_t getProcessorId() const { return processorId; }

            inline bool isEnabled() const { return enabled; }
            inline void setEnabled(bool newEnabled);

        protected:
            Audio& audio;
            uintptr_t processorId = 0;
            Mix* mix = nullptr;
            Source* source = nullptr;
            bool enabled = true;
        };
    } // namespace audio
} // namespace ouzel

#endif // OUZEL_AUDIO_EFFECT_HPP
<commit_msg>Remove the forward declaration of Source<commit_after>// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_AUDIO_EFFECT_HPP
#define OUZEL_AUDIO_EFFECT_HPP

#include <cstdint>
#include "audio/Node.hpp"

namespace ouzel
{
    namespace audio
    {
        class Audio;
        class Mix;

        class Effect: public Node
        {
            friend Mix;
        public:
            Effect(Audio& initAudio,
                   uintptr_t initProcessorId);
            virtual ~Effect();

            Effect(const Effect&) = delete;
            Effect& operator=(const Effect&) = delete;
            Effect(Effect&&) = delete;
            Effect& operator=(Effect&&) = delete;

            inline uintptr_t getProcessorId() const { return processorId; }

            inline bool isEnabled() const { return enabled; }
            inline void setEnabled(bool newEnabled);

        protected:
            Audio& audio;
            uintptr_t processorId = 0;
            Mix* mix = nullptr;
            bool enabled = true;
        };
    } // namespace audio
} // namespace ouzel

#endif // OUZEL_AUDIO_EFFECT_HPP
<|endoftext|>


<commit_before>// Copyright (C) 2018 Elviss Strazdins
// This file is part of the Ouzel engine.

#pragma once

#include <list>
#include "scene/Component.hpp"
#include "math/Size2.hpp"
#include "math/Vector2.hpp"
#include "scene/SpriteData.hpp"
#include "core/UpdateCallback.hpp"
#include "graphics/Material.hpp"

namespace ouzel
{
    namespace scene
    {
        class Sprite: public Component
        {
        public:
            static const uint32_t TYPE = Component::SPRITE;

            Sprite();
            explicit Sprite(const SpriteData& spriteData);
            explicit Sprite(const std::string& filename, bool mipmaps = true,
                            uint32_t spritesX = 1, uint32_t spritesY = 1,
                            const Vector2& pivot = Vector2(0.5F, 0.5F));
            explicit Sprite(std::shared_ptr<graphics::Texture> texture,
                            uint32_t spritesX = 1, uint32_t spritesY = 1,
                            const Vector2& pivot = Vector2(0.5F, 0.5F));

            bool init(const SpriteData& spriteData);
            bool init(const std::string& filename, bool mipmaps = true,
                      uint32_t spritesX = 1, uint32_t spritesY = 1,
                      const Vector2& pivot = Vector2(0.5F, 0.5F));
            bool init(std::shared_ptr<graphics::Texture> newTexture,
                      uint32_t spritesX = 1, uint32_t spritesY = 1,
                      const Vector2& pivot = Vector2(0.5F, 0.5F));

            void update(float delta);

            virtual void draw(const Matrix4& transformMatrix,
                              float opacity,
                              const Matrix4& renderViewProjection,
                              const std::shared_ptr<graphics::Texture>& renderTarget,
                              const Rect& renderViewport,
                              bool depthWrite,
                              bool depthTest,
                              bool wireframe,
                              bool scissorTest,
                              const Rect& scissorRectangle) override;

            inline const std::shared_ptr<graphics::Material>& getMaterial() const { return material; }
            inline void setMaterial(const std::shared_ptr<graphics::Material>& newMaterial) { material = newMaterial; }

            inline const Vector2& getOffset() const { return offset; }
            void setOffset(const Vector2& newOffset);

            void play();
            void stop(bool resetAnimation = true);
            void reset();
            inline bool isPlaying() const { return playing; }

            inline const std::map<std::string, SpriteData::Animation>& getAnimations() const { return animations; }
            inline const SpriteData::Animation* getAnimation() const { return currentAnimation->animation; }
            inline std::string getAnimationName() const { return currentAnimation->animation->name; }
            bool hasAnimation(const std::string& animation) const;
            void setAnimation(const std::string& newAnimation, bool repeat = true);
            void addAnimation(const std::string& newAnimation, bool repeat = true);
            void setAnimationProgress(float progress);
            void setAnimationTime(float time);

        protected:
            void updateBoundingBox();

            std::shared_ptr<graphics::Material> material;
            std::map<std::string, SpriteData::Animation> animations;

            struct QueuedAnimation
            {
                const SpriteData::Animation* animation;
                bool repeat;
            };

            std::list<QueuedAnimation> animationQueue;
            std::list<QueuedAnimation>::iterator currentAnimation;

            std::shared_ptr<graphics::Texture> whitePixelTexture;

            Vector2 offset;
            Matrix4 offsetMatrix = Matrix4::IDENTITY;

            bool playing = false;
            bool running = false;
            float currentTime = 0.0F;

            UpdateCallback updateCallback;
        };
    } // namespace scene
} // namespace ouzel
<commit_msg>Fix Sprite.hpp<commit_after>// Copyright (C) 2018 Elviss Strazdins
// This file is part of the Ouzel engine.

#pragma once

#include <list>
#include "scene/Component.hpp"
#include "math/Size2.hpp"
#include "math/Vector2.hpp"
#include "scene/SpriteData.hpp"
#include "graphics/Material.hpp"
#include "scene/UpdateCallback.hpp"

namespace ouzel
{
    namespace scene
    {
        class Sprite: public Component
        {
        public:
            static const uint32_t TYPE = Component::SPRITE;

            Sprite();
            explicit Sprite(const SpriteData& spriteData);
            explicit Sprite(const std::string& filename, bool mipmaps = true,
                            uint32_t spritesX = 1, uint32_t spritesY = 1,
                            const Vector2& pivot = Vector2(0.5F, 0.5F));
            explicit Sprite(std::shared_ptr<graphics::Texture> texture,
                            uint32_t spritesX = 1, uint32_t spritesY = 1,
                            const Vector2& pivot = Vector2(0.5F, 0.5F));

            bool init(const SpriteData& spriteData);
            bool init(const std::string& filename, bool mipmaps = true,
                      uint32_t spritesX = 1, uint32_t spritesY = 1,
                      const Vector2& pivot = Vector2(0.5F, 0.5F));
            bool init(std::shared_ptr<graphics::Texture> newTexture,
                      uint32_t spritesX = 1, uint32_t spritesY = 1,
                      const Vector2& pivot = Vector2(0.5F, 0.5F));

            void update(float delta);

            virtual void draw(const Matrix4& transformMatrix,
                              float opacity,
                              const Matrix4& renderViewProjection,
                              const std::shared_ptr<graphics::Texture>& renderTarget,
                              const Rect& renderViewport,
                              bool depthWrite,
                              bool depthTest,
                              bool wireframe,
                              bool scissorTest,
                              const Rect& scissorRectangle) override;

            inline const std::shared_ptr<graphics::Material>& getMaterial() const { return material; }
            inline void setMaterial(const std::shared_ptr<graphics::Material>& newMaterial) { material = newMaterial; }

            inline const Vector2& getOffset() const { return offset; }
            void setOffset(const Vector2& newOffset);

            void play();
            void stop(bool resetAnimation = true);
            void reset();
            inline bool isPlaying() const { return playing; }

            inline const std::map<std::string, SpriteData::Animation>& getAnimations() const { return animations; }
            inline const SpriteData::Animation* getAnimation() const { return currentAnimation->animation; }
            inline std::string getAnimationName() const { return currentAnimation->animation->name; }
            bool hasAnimation(const std::string& animation) const;
            void setAnimation(const std::string& newAnimation, bool repeat = true);
            void addAnimation(const std::string& newAnimation, bool repeat = true);
            void setAnimationProgress(float progress);
            void setAnimationTime(float time);

        protected:
            void updateBoundingBox();

            std::shared_ptr<graphics::Material> material;
            std::map<std::string, SpriteData::Animation> animations;

            struct QueuedAnimation
            {
                const SpriteData::Animation* animation;
                bool repeat;
            };

            std::list<QueuedAnimation> animationQueue;
            std::list<QueuedAnimation>::iterator currentAnimation;

            std::shared_ptr<graphics::Texture> whitePixelTexture;

            Vector2 offset;
            Matrix4 offsetMatrix = Matrix4::IDENTITY;

            bool playing = false;
            bool running = false;
            float currentTime = 0.0F;

            UpdateCallback updateCallback;
        };
    } // namespace scene
} // namespace ouzel
<|endoftext|>


<commit_before>/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 2/9/2019, 10:35:35 PM
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <functional>
#include <random> // auto rd = bind(uniform_int_distribution<int>(0, 9), mt19937(19920725));
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const ll MOD = 998244353;
const int MAX_SIZE = 1000010;

long long inv[MAX_SIZE];
long long fact[MAX_SIZE];
long long factinv[MAX_SIZE];

void init()
{
  inv[1] = 1;
  for (int i = 2; i < MAX_SIZE; i++)
  {
    inv[i] = ((MOD - inv[MOD % i]) * (MOD / i)) % MOD;
  }
  fact[0] = factinv[0] = 1;
  for (int i = 1; i < MAX_SIZE; i++)
  {
    fact[i] = (i * fact[i - 1]) % MOD;
    factinv[i] = (inv[i] * factinv[i - 1]) % MOD;
  }
}

long long C(int n, int k)
{
  if (n >= 0 && k >= 0 && n - k >= 0)
  {
    return ((fact[n] * factinv[k]) % MOD * factinv[n - k]) % MOD;
  }
  return 0;
}

long long power(long long x, long long n)
{
  if (n == 0)
  {
    return 1;
  }
  else if (n % 2 == 1)
  {
    return (x * power(x, n - 1)) % MOD;
  }
  else
  {
    long long half = power(x, n / 2);
    return (half * half) % MOD;
  }
}

long long gcd(long long x, long long y)
{
  return y ? gcd(y, x % y) : x;
}

string S;
int N;
ll DP[2010][4010];
int R[2010];
int B[2010];

int main()
{
  init();
  cin >> S;
  N = S.size();
  for (auto i = 0; i < 4010; i++)
  {
    DP[0][i] = 0;
  }
  DP[0][0] = 1;
  R[0] = B[0] = 0;
  for (auto i = 1; i <= N; i++)
  {
    if (S[i - 1] == '0')
    {
      R[i] = R[i - 1] + 2;
      B[i] = B[i - 1];
    }
    else if (S[i - 1] == '1')
    {
      R[i] = R[i - 1] + 1;
      B[i] = B[i - 1] + 1;
    }
    else
    {
      R[i] = R[i - 1];
      B[i] = B[i - 1] + 2;
    }
  }
  for (auto i = 0; i < N; i++)
  {
    cerr << "R[" << i + 1 << "] = " << R[i + 1] << ", B[" << i + 1 << "] = " << B[i + 1] << endl;
    for (auto j = 0; j <= i; j++)
    {
      if (DP[i][j] == 0)
      {
        continue;
      }
      cerr << "DP[" << i << "][" << j << "] = " << DP[i][j] << endl;
      int r = j;
      int b = i - r;
      if (R[i + 1] - r > 0)
      {
        DP[i + 1][j + 1] += DP[i][j];
        DP[i + 1][j + 1] %= MOD;
      }
      if (B[i + 1] - b > 0)
      {
        DP[i + 1][j] += DP[i][j];
        DP[i + 1][j] %= MOD;
      }
    }
  }
  ll ans = 0;
  for (auto i = 0; i <= N; i++)
  {
    if (DP[N][i] == 0)
    {
      continue;
    }
    int r = i;
    int b = N = i;
    int res_r = R[N] - r;
    int res_b = B[N] - b;
    ans += (DP[N][i] * C(res_r + res_b, res_r)) % MOD;
    ans %= MOD;
  }
  cout << ans << endl;
}<commit_msg>submit F.cpp to 'F - Pass' (yahoo-procon2019-qual) [C++14 (GCC 5.4.1)]<commit_after>/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 2/9/2019, 10:35:35 PM
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <functional>
#include <random> // auto rd = bind(uniform_int_distribution<int>(0, 9), mt19937(19920725));
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const ll MOD = 998244353;
const int MAX_SIZE = 1000010;

long long inv[MAX_SIZE];
long long fact[MAX_SIZE];
long long factinv[MAX_SIZE];

void init()
{
  inv[1] = 1;
  for (int i = 2; i < MAX_SIZE; i++)
  {
    inv[i] = ((MOD - inv[MOD % i]) * (MOD / i)) % MOD;
  }
  fact[0] = factinv[0] = 1;
  for (int i = 1; i < MAX_SIZE; i++)
  {
    fact[i] = (i * fact[i - 1]) % MOD;
    factinv[i] = (inv[i] * factinv[i - 1]) % MOD;
  }
}

long long C(int n, int k)
{
  if (n >= 0 && k >= 0 && n - k >= 0)
  {
    return ((fact[n] * factinv[k]) % MOD * factinv[n - k]) % MOD;
  }
  return 0;
}

long long power(long long x, long long n)
{
  if (n == 0)
  {
    return 1;
  }
  else if (n % 2 == 1)
  {
    return (x * power(x, n - 1)) % MOD;
  }
  else
  {
    long long half = power(x, n / 2);
    return (half * half) % MOD;
  }
}

long long gcd(long long x, long long y)
{
  return y ? gcd(y, x % y) : x;
}

string S;
int N;
ll DP[2010][4010];
int R[2010];
int B[2010];

int main()
{
  init();
  cin >> S;
  N = S.size();
  for (auto i = 0; i < 4010; i++)
  {
    DP[0][i] = 0;
  }
  DP[0][0] = 1;
  R[0] = B[0] = 0;
  for (auto i = 1; i <= N; i++)
  {
    if (S[i - 1] == '0')
    {
      R[i] = R[i - 1] + 2;
      B[i] = B[i - 1];
    }
    else if (S[i - 1] == '1')
    {
      R[i] = R[i - 1] + 1;
      B[i] = B[i - 1] + 1;
    }
    else
    {
      R[i] = R[i - 1];
      B[i] = B[i - 1] + 2;
    }
  }
  for (auto i = 0; i < N; i++)
  {
    // cerr << "R[" << i + 1 << "] = " << R[i + 1] << ", B[" << i + 1 << "] = " << B[i + 1] << endl;
    for (auto j = 0; j <= i; j++)
    {
      if (DP[i][j] == 0)
      {
        continue;
      }
      cerr << "DP[" << i << "][" << j << "] = " << DP[i][j] << endl;
      int r = j;
      int b = i - r;
      if (R[i + 1] - r > 0)
      {
        DP[i + 1][j + 1] += DP[i][j];
        DP[i + 1][j + 1] %= MOD;
      }
      if (B[i + 1] - b > 0)
      {
        DP[i + 1][j] += DP[i][j];
        DP[i + 1][j] %= MOD;
      }
    }
  }
  ll ans = 0;
  for (auto i = 0; i <= N; i++)
  {
    if (DP[N][i] == 0)
    {
      continue;
    }
    int r = i;
    int b = N - i;
    int res_r = R[N] - r;
    int res_b = B[N] - b;
    ans += (DP[N][i] * C(res_r + res_b, res_r)) % MOD;
    ans %= MOD;
  }
  cout << ans << endl;
}<|endoftext|>


<commit_before>// Copyright (c) 2015, Matthew Malensek.
// Distributed under the BSD 2-Clause License (see LICENSE.txt for details)

#include "CoreAudio.h"

#include <math.h>
#include <stdlib.h>

#include "../../Logger.h"
#include "Functiondiscoverykeys_devpkey.h"
#include "VolumeTransformation.h"

// {EC9CB649-7E84-4B42-B367-7FC39BE17806}
static const GUID G3RVXCoreAudioEvent = { 0xec9cb649, 0x7e84, 0x4b42,
    { 0xb3, 0x67, 0x7f, 0xc3, 0x9b, 0xe1, 0x78, 0x6 } };

HRESULT CoreAudio::Init() {
    HRESULT hr;

    hr = CoCreateInstance(
        __uuidof(MMDeviceEnumerator),
        nullptr,
        CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&_devEnumerator));

    if (SUCCEEDED(hr)) {
        hr = _devEnumerator->RegisterEndpointNotificationCallback(this);

        if (SUCCEEDED(hr)) {
            hr = AttachDevice();
        }
    }

    return hr;
}

HRESULT CoreAudio::Init(std::wstring deviceId) {
    _devId = deviceId;
    return Init();
}

void CoreAudio::Dispose() {
    DetachDevice();
    _devEnumerator->UnregisterEndpointNotificationCallback(this);
}

HRESULT CoreAudio::AttachDevice() {
    HRESULT hr;

    if (_devId.empty()) {
        /* Use default device */
        hr = _devEnumerator->GetDefaultAudioEndpoint(eRender,
            eMultimedia, &_device);
        if (SUCCEEDED(hr)) {
            LPWSTR id = nullptr;
            hr = _device->GetId(&id);
            if (SUCCEEDED(hr) && id) {
                _devId = std::wstring(id);
                CoTaskMemFree(id);
            }
        }
    } else {
        hr = _devEnumerator->GetDevice(_devId.c_str(), &_device);
    }

    if (SUCCEEDED(hr)) {
        hr = _device->Activate(__uuidof(_volumeControl),
            CLSCTX_INPROC_SERVER, nullptr, (void **) &_volumeControl);

        CLOG(L"Attached to audio device: [%s]", DeviceName().c_str());

        if (SUCCEEDED(hr)) {
            hr = _volumeControl->RegisterControlChangeNotify(this);
            _registeredNotifications = SUCCEEDED(hr);
        }
    } else {
        CLOG(L"Failed to find audio device!");
    }

    return hr;
}

void CoreAudio::DetachDevice() {
    if (_volumeControl != nullptr) {

        if (_registeredNotifications) {
            _volumeControl->UnregisterControlChangeNotify(this);
            _registeredNotifications = false;
        }

        _volumeControl->Release();
    }

    if (_device != nullptr) {
        _device->Release();
    }
}

HRESULT CoreAudio::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) {
    if (pNotify->guidEventContext == G3RVXCoreAudioEvent) {
        PostMessage(_notifyHwnd, MSG_VOL_CHNG, (WPARAM) 1, 0);
    } else {
        PostMessage(_notifyHwnd, MSG_VOL_CHNG, 0, 0);
    }

    return S_OK;
}

HRESULT CoreAudio::OnDefaultDeviceChanged(
    EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId) {
    if (flow == eRender) {
        PostMessage(_notifyHwnd, MSG_VOL_DEVCHNG, 0, 0);
    }

    return S_OK;
}

HRESULT CoreAudio::SelectDevice(std::wstring deviceId) {
    HRESULT hr;
    _devId = deviceId;
    DetachDevice();
    hr = AttachDevice();
    return hr;
}

HRESULT CoreAudio::SelectDefaultDevice() {
    HRESULT hr;
    _devId = L"";
    DetachDevice();
    hr = AttachDevice();
    return hr;
}

std::list<VolumeController::DeviceInfo> CoreAudio::ListDevices() {
    std::list<VolumeController::DeviceInfo> devList;
    IMMDeviceCollection *devices = nullptr;

    HRESULT hr = _devEnumerator->EnumAudioEndpoints(
        eRender,
        DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED,
        &devices);

    if (FAILED(hr)) {
        return devList;
    }

    UINT numDevices = 0;
    hr = devices->GetCount(&numDevices);
    if (FAILED(hr)) {
        return devList;
    }
    LPWSTR devId;
    for (unsigned int i = 0; i < numDevices; ++i) {
        IMMDevice *device = nullptr;
        HRESULT hr = devices->Item(i, &device);
        if (FAILED(hr)) {
            continue;
        }

        hr = device->GetId(&devId);
        if (FAILED(hr)) {
            device->Release();
            continue;
        }

        std::wstring idStr;
        if (devId) {
            idStr = std::wstring(devId);
            CoTaskMemFree(devId);
        } else {
            continue;
        }

        VolumeController::DeviceInfo devInfo = {};
        devInfo.id = idStr;
        devInfo.name = DeviceName(idStr);
        devList.push_back(devInfo);
        device->Release();
    }

    devices->Release();
    return devList;
}

std::wstring CoreAudio::DeviceId() {
    return _devId;
}

std::wstring CoreAudio::DeviceName() {
    return DeviceName(_device);
}

std::wstring CoreAudio::DeviceDesc() {
    return DeviceDesc(_device);
}

std::wstring CoreAudio::DeviceName(std::wstring deviceId) {
    IMMDevice *device;
    HRESULT hr = _devEnumerator->GetDevice(deviceId.c_str(), &device);
    if (FAILED(hr)) {
        return L"";
    }
    std::wstring name = DeviceName(device);
    device->Release();
    return name;
}

std::wstring CoreAudio::DeviceDesc(std::wstring deviceId) {
    IMMDevice *device;
    HRESULT hr = _devEnumerator->GetDevice(deviceId.c_str(), &device);
    if (FAILED(hr)) {
        return L"";
    }
    std::wstring name = DeviceName(device);
    device->Release();
    return name;
}

std::wstring CoreAudio::DeviceName(IMMDevice *device) {
    if (device == nullptr) {
        return L"";
    }

    IPropertyStore *props = nullptr;
    HRESULT hr = device->OpenPropertyStore(STGM_READ, &props);
    if (FAILED(hr)) {
        return L"";
    }

    PROPVARIANT pvName;
    PropVariantInit(&pvName);
    hr = props->GetValue(PKEY_Device_FriendlyName, &pvName);
    if (FAILED(hr)) {
        props->Release();
        return L"";
    }

    std::wstring str(pvName.pwszVal);
    PropVariantClear(&pvName);
    props->Release();

    return str;
}

std::wstring CoreAudio::DeviceDesc(IMMDevice *device) {
    HRESULT hr;

    if (device == nullptr) {
        return L"";
    }

    IPropertyStore *props = nullptr;
    hr = device->OpenPropertyStore(STGM_READ, &props);
    if (FAILED(hr)) {
        return L"";
    }

    PROPVARIANT pvDesc;
    PropVariantInit(&pvDesc);
    hr = props->GetValue(PKEY_Device_DeviceDesc, &pvDesc);
    if (FAILED(hr)) {
        props->Release();
        return L"";
    }

    std::wstring str(pvDesc.pwszVal);
    PropVariantClear(&pvDesc);
    props->Release();
    return str;
}

float CoreAudio::Volume() {
    float vol = 0.0f;
    if (_volumeControl) {
        _volumeControl->GetMasterVolumeLevelScalar(&vol);
    }
    return vol;
}

void CoreAudio::Volume(float vol) {
    if (vol > 1.0f) {
        vol = 1.0f;
    }

    if (vol < 0.0f) {
        vol = 0.0f;
    }

    if (_volumeControl) {
        if (_transform) {
            vol = _transform->Transform(vol);
        }

        _volumeControl->SetMasterVolumeLevelScalar(vol, &G3RVXCoreAudioEvent);
    }
}

float CoreAudio::VolumeDB() {
    float vol = 0.0f;
    if (_volumeControl) {
        _volumeControl->GetMasterVolumeLevel(&vol);
    }
    return vol;
}

void CoreAudio::VolumeDB(float volDB) {
    if (_volumeControl) {
        _volumeControl->SetMasterVolumeLevel(volDB, &G3RVXCoreAudioEvent);
    }
}

bool CoreAudio::Muted() {
    if (_volumeControl == nullptr) {
        return true;
    }

    BOOL muted = FALSE;
    HRESULT hr = _volumeControl->GetMute(&muted);
    if (FAILED(hr)) {
        return false;
    }

    return (muted == TRUE) ? true : false;
}

void CoreAudio::Muted(bool muted) {
    if (_volumeControl) {
        _volumeControl->SetMute(muted, &G3RVXCoreAudioEvent);
    }
}

void CoreAudio::Transformation(VolumeTransformation* transform) {
    _transform = transform;
}

VolumeTransformation* CoreAudio::Transformation() {
    return _transform;
}

void CoreAudio::CurveInfo() {
    if (_volumeControl == nullptr) {
        return;
    }

    float min, max, inc;
    _volumeControl->GetVolumeRange(&min, &max, &inc);
    CLOG(L"Volume Range (min, max, increment): %f, %f, %f", min, max, inc);
    float range = abs(max - min);
    float steps = range / inc;
    CLOG(L"Full range: %f (%f steps)", range, steps);
    float orig = Volume();
    for (float f = 0; f < 100.1f; ++f) {
        Volume(f / 100.0f);
        QCLOG("%f    %f", Volume(), VolumeDB());
    }
    Volume(orig);
}

ULONG CoreAudio::AddRef() {
    return InterlockedIncrement(&_refCount);
}

ULONG CoreAudio::Release() {
    long lRef = InterlockedDecrement(&_refCount);
    if (lRef == 0) {
        delete this;
    }
    return lRef;
}

HRESULT CoreAudio::QueryInterface(REFIID iid, void **ppvObject) {
    if ((iid == __uuidof(IUnknown)) ||
        (iid == __uuidof(IMMNotificationClient))) {
        *ppvObject = static_cast<IMMNotificationClient*>(this);
    } else if (iid == __uuidof(IAudioEndpointVolumeCallback)) {
        *ppvObject = static_cast<IAudioEndpointVolumeCallback*>(this);
    } else {
        *ppvObject = nullptr;
        return E_NOINTERFACE;
    }

    AddRef();
    return S_OK;
}<commit_msg>Use the transformation when retrieving the volume<commit_after>// Copyright (c) 2015, Matthew Malensek.
// Distributed under the BSD 2-Clause License (see LICENSE.txt for details)

#include "CoreAudio.h"

#include <math.h>
#include <stdlib.h>

#include "../../Logger.h"
#include "Functiondiscoverykeys_devpkey.h"
#include "VolumeTransformation.h"

// {EC9CB649-7E84-4B42-B367-7FC39BE17806}
static const GUID G3RVXCoreAudioEvent = { 0xec9cb649, 0x7e84, 0x4b42,
    { 0xb3, 0x67, 0x7f, 0xc3, 0x9b, 0xe1, 0x78, 0x6 } };

HRESULT CoreAudio::Init() {
    HRESULT hr;

    hr = CoCreateInstance(
        __uuidof(MMDeviceEnumerator),
        nullptr,
        CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&_devEnumerator));

    if (SUCCEEDED(hr)) {
        hr = _devEnumerator->RegisterEndpointNotificationCallback(this);

        if (SUCCEEDED(hr)) {
            hr = AttachDevice();
        }
    }

    return hr;
}

HRESULT CoreAudio::Init(std::wstring deviceId) {
    _devId = deviceId;
    return Init();
}

void CoreAudio::Dispose() {
    DetachDevice();
    _devEnumerator->UnregisterEndpointNotificationCallback(this);
}

HRESULT CoreAudio::AttachDevice() {
    HRESULT hr;

    if (_devId.empty()) {
        /* Use default device */
        hr = _devEnumerator->GetDefaultAudioEndpoint(eRender,
            eMultimedia, &_device);
        if (SUCCEEDED(hr)) {
            LPWSTR id = nullptr;
            hr = _device->GetId(&id);
            if (SUCCEEDED(hr) && id) {
                _devId = std::wstring(id);
                CoTaskMemFree(id);
            }
        }
    } else {
        hr = _devEnumerator->GetDevice(_devId.c_str(), &_device);
    }

    if (SUCCEEDED(hr)) {
        hr = _device->Activate(__uuidof(_volumeControl),
            CLSCTX_INPROC_SERVER, nullptr, (void **) &_volumeControl);

        CLOG(L"Attached to audio device: [%s]", DeviceName().c_str());

        if (SUCCEEDED(hr)) {
            hr = _volumeControl->RegisterControlChangeNotify(this);
            _registeredNotifications = SUCCEEDED(hr);
        }
    } else {
        CLOG(L"Failed to find audio device!");
    }

    return hr;
}

void CoreAudio::DetachDevice() {
    if (_volumeControl != nullptr) {

        if (_registeredNotifications) {
            _volumeControl->UnregisterControlChangeNotify(this);
            _registeredNotifications = false;
        }

        _volumeControl->Release();
    }

    if (_device != nullptr) {
        _device->Release();
    }
}

HRESULT CoreAudio::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) {
    if (pNotify->guidEventContext == G3RVXCoreAudioEvent) {
        PostMessage(_notifyHwnd, MSG_VOL_CHNG, (WPARAM) 1, 0);
    } else {
        PostMessage(_notifyHwnd, MSG_VOL_CHNG, 0, 0);
    }

    return S_OK;
}

HRESULT CoreAudio::OnDefaultDeviceChanged(
    EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId) {
    if (flow == eRender) {
        PostMessage(_notifyHwnd, MSG_VOL_DEVCHNG, 0, 0);
    }

    return S_OK;
}

HRESULT CoreAudio::SelectDevice(std::wstring deviceId) {
    HRESULT hr;
    _devId = deviceId;
    DetachDevice();
    hr = AttachDevice();
    return hr;
}

HRESULT CoreAudio::SelectDefaultDevice() {
    HRESULT hr;
    _devId = L"";
    DetachDevice();
    hr = AttachDevice();
    return hr;
}

std::list<VolumeController::DeviceInfo> CoreAudio::ListDevices() {
    std::list<VolumeController::DeviceInfo> devList;
    IMMDeviceCollection *devices = nullptr;

    HRESULT hr = _devEnumerator->EnumAudioEndpoints(
        eRender,
        DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED,
        &devices);

    if (FAILED(hr)) {
        return devList;
    }

    UINT numDevices = 0;
    hr = devices->GetCount(&numDevices);
    if (FAILED(hr)) {
        return devList;
    }
    LPWSTR devId;
    for (unsigned int i = 0; i < numDevices; ++i) {
        IMMDevice *device = nullptr;
        HRESULT hr = devices->Item(i, &device);
        if (FAILED(hr)) {
            continue;
        }

        hr = device->GetId(&devId);
        if (FAILED(hr)) {
            device->Release();
            continue;
        }

        std::wstring idStr;
        if (devId) {
            idStr = std::wstring(devId);
            CoTaskMemFree(devId);
        } else {
            continue;
        }

        VolumeController::DeviceInfo devInfo = {};
        devInfo.id = idStr;
        devInfo.name = DeviceName(idStr);
        devList.push_back(devInfo);
        device->Release();
    }

    devices->Release();
    return devList;
}

std::wstring CoreAudio::DeviceId() {
    return _devId;
}

std::wstring CoreAudio::DeviceName() {
    return DeviceName(_device);
}

std::wstring CoreAudio::DeviceDesc() {
    return DeviceDesc(_device);
}

std::wstring CoreAudio::DeviceName(std::wstring deviceId) {
    IMMDevice *device;
    HRESULT hr = _devEnumerator->GetDevice(deviceId.c_str(), &device);
    if (FAILED(hr)) {
        return L"";
    }
    std::wstring name = DeviceName(device);
    device->Release();
    return name;
}

std::wstring CoreAudio::DeviceDesc(std::wstring deviceId) {
    IMMDevice *device;
    HRESULT hr = _devEnumerator->GetDevice(deviceId.c_str(), &device);
    if (FAILED(hr)) {
        return L"";
    }
    std::wstring name = DeviceName(device);
    device->Release();
    return name;
}

std::wstring CoreAudio::DeviceName(IMMDevice *device) {
    if (device == nullptr) {
        return L"";
    }

    IPropertyStore *props = nullptr;
    HRESULT hr = device->OpenPropertyStore(STGM_READ, &props);
    if (FAILED(hr)) {
        return L"";
    }

    PROPVARIANT pvName;
    PropVariantInit(&pvName);
    hr = props->GetValue(PKEY_Device_FriendlyName, &pvName);
    if (FAILED(hr)) {
        props->Release();
        return L"";
    }

    std::wstring str(pvName.pwszVal);
    PropVariantClear(&pvName);
    props->Release();

    return str;
}

std::wstring CoreAudio::DeviceDesc(IMMDevice *device) {
    HRESULT hr;

    if (device == nullptr) {
        return L"";
    }

    IPropertyStore *props = nullptr;
    hr = device->OpenPropertyStore(STGM_READ, &props);
    if (FAILED(hr)) {
        return L"";
    }

    PROPVARIANT pvDesc;
    PropVariantInit(&pvDesc);
    hr = props->GetValue(PKEY_Device_DeviceDesc, &pvDesc);
    if (FAILED(hr)) {
        props->Release();
        return L"";
    }

    std::wstring str(pvDesc.pwszVal);
    PropVariantClear(&pvDesc);
    props->Release();
    return str;
}

float CoreAudio::Volume() {
    float vol = 0.0f;
    if (_volumeControl) {
        _volumeControl->GetMasterVolumeLevelScalar(&vol);

        if (_transform) {
            vol = _transform->FromVirtual(vol);
        }
    }
    return vol;
}

void CoreAudio::Volume(float vol) {
    if (vol > 1.0f) {
        vol = 1.0f;
    }

    if (vol < 0.0f) {
        vol = 0.0f;
    }

    if (_volumeControl) {
        if (_transform) {
            vol = _transform->Transform(vol);
        }

        _volumeControl->SetMasterVolumeLevelScalar(vol, &G3RVXCoreAudioEvent);
    }
}

float CoreAudio::VolumeDB() {
    float vol = 0.0f;
    if (_volumeControl) {
        _volumeControl->GetMasterVolumeLevel(&vol);
    }
    return vol;
}

void CoreAudio::VolumeDB(float volDB) {
    if (_volumeControl) {
        _volumeControl->SetMasterVolumeLevel(volDB, &G3RVXCoreAudioEvent);
    }
}

bool CoreAudio::Muted() {
    if (_volumeControl == nullptr) {
        return true;
    }

    BOOL muted = FALSE;
    HRESULT hr = _volumeControl->GetMute(&muted);
    if (FAILED(hr)) {
        return false;
    }

    return (muted == TRUE) ? true : false;
}

void CoreAudio::Muted(bool muted) {
    if (_volumeControl) {
        _volumeControl->SetMute(muted, &G3RVXCoreAudioEvent);
    }
}

void CoreAudio::Transformation(VolumeTransformation* transform) {
    _transform = transform;
}

VolumeTransformation* CoreAudio::Transformation() {
    return _transform;
}

void CoreAudio::CurveInfo() {
    if (_volumeControl == nullptr) {
        return;
    }

    float min, max, inc;
    _volumeControl->GetVolumeRange(&min, &max, &inc);
    CLOG(L"Volume Range (min, max, increment): %f, %f, %f", min, max, inc);
    float range = abs(max - min);
    float steps = range / inc;
    CLOG(L"Full range: %f (%f steps)", range, steps);
    float orig = Volume();
    for (float f = 0; f < 100.1f; ++f) {
        Volume(f / 100.0f);
        QCLOG("%f    %f", Volume(), VolumeDB());
    }
    Volume(orig);
}

ULONG CoreAudio::AddRef() {
    return InterlockedIncrement(&_refCount);
}

ULONG CoreAudio::Release() {
    long lRef = InterlockedDecrement(&_refCount);
    if (lRef == 0) {
        delete this;
    }
    return lRef;
}

HRESULT CoreAudio::QueryInterface(REFIID iid, void **ppvObject) {
    if ((iid == __uuidof(IUnknown)) ||
        (iid == __uuidof(IMMNotificationClient))) {
        *ppvObject = static_cast<IMMNotificationClient*>(this);
    } else if (iid == __uuidof(IAudioEndpointVolumeCallback)) {
        *ppvObject = static_cast<IAudioEndpointVolumeCallback*>(this);
    } else {
        *ppvObject = nullptr;
        return E_NOINTERFACE;
    }

    AddRef();
    return S_OK;
}<|endoftext|>


<commit_before>//---------------------------------------------------------------------------
//
//             kPPP: A pppd front end for the KDE project
//
//---------------------------------------------------------------------------
//
// (c) 1997-1998 Bernd Johannes Wuebben <wuebben@kde.org>
// (c) 1997-1999 Mario Weilguni <mweilguni@kde.org>
// (c) 1998-1999 Harri Porten <porten@kde.org>
//
// derived from Jay Painters "ezppp"
//
//---------------------------------------------------------------------------
//
//  $Id$
//
//---------------------------------------------------------------------------
//
//  This program is free software; you can redistribute it and-or
//  modify it under the terms of the GNU Library 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
//  Library General Public License for more details.
//
//  You should have received a copy of the GNU Library General Public
//  License along with this program; if not, write to the Free
//  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//---------------------------------------------------------------------------

#include <qlabel.h>
#include <qlistbox.h>
#include <qstringlist.h>
#include <kbuttonbox.h>
#include <qlayout.h>
#include <kapp.h>
#include "modemdb.h"
#include "log.h"
#include <klocale.h>

ModemSelector::ModemSelector(QWidget *parent) : QDialog(parent, 0, true) {
  // set up widgets and such
  setCaption(i18n("Select modem type..."));
  QVBoxLayout *tl = new QVBoxLayout(this, 10, 10);
  QLabel *l1 = new QLabel(i18n("To setup your modem, first choose its vendor in the "
			       "list to the left, and then select the model from the "
			       "right list. If you dont know which modem you have, "
			       "you can try out one of the \"Generic\" modems."),
			this);
  l1->setAlignment(AlignLeft | WordBreak);
  l1->setFixedWidth(400);
  l1->setMinimumHeight(50);
  tl->addWidget(l1, 0);

  tl->addSpacing(10);

  QHBoxLayout *tl1 = new QHBoxLayout(10);
  tl->addLayout(tl1, 1);
  vendor = new QListBox(this);
  model  = new QListBox(this);
  vendor->setMinimumSize(200, 130);
  model->setMinimumSize(200, 130);
  tl1->addWidget(vendor, 2);
  tl1->addWidget(model, 3);

  KButtonBox *bbox = new KButtonBox(this);
  bbox->addStretch(1);
  ok = bbox->addButton(i18n("OK"));
  ok->setDefault(true);
  ok->setEnabled(false);
  cancel =   bbox->addButton(i18n("Cancel"));
  bbox->layout();
  tl->addWidget(bbox);
  setFixedSize(sizeHint());

  // setup modem database
  db = new ModemDatabase();

  // set up signal/slots
  connect(ok, SIGNAL(clicked()),
	  this, SLOT(reject()));
  connect(cancel, SIGNAL(clicked()),
	  this, SLOT(reject()));
  connect(vendor, SIGNAL(highlighted(int)),
	  this, SLOT(vendorSelected(int)));
  connect(model, SIGNAL(highlighted(int)),
	  this, SLOT(modelSelected(int)));
  connect(model, SIGNAL(selected(int)),
	  this, SLOT(selected(int)));

  // fill vendor list with life
  const QStrList *lvendor = db->vendors();
  for(uint i = 0; i < lvendor->count(); i++)
    vendor->insertItem(((QStrList *)lvendor)->at(i));

  vendor->setCurrentItem(0);
}

ModemSelector::~ModemSelector() {
  delete db;
}

void ModemSelector::vendorSelected(int idx) {
  ok->setEnabled(false);

  QString name = vendor->text(idx);
  QStrList *models = db->models(name);
  model->clear();
  for(uint i = 0; i < models->count(); i++)
    model->insertItem(models->at(i));

  // FIXME: work around Qt bug
  if(models->count() == 0)
    model->update();
  delete models;
}

void ModemSelector::modelSelected(int idx) {
  ok->setEnabled(true);
}

void ModemSelector::selected(int idx) {
  accept();
}

ModemDatabase::ModemDatabase() {
  load();
}

ModemDatabase::~ModemDatabase() {
  delete lvendors;
  delete modemDB;
}

const QStrList *ModemDatabase::vendors() {
  return lvendors;
}

QStrList *ModemDatabase::models(QString vendor) {
  QStrList *sl = new QStrList;
  QString s = i18n("<Generic>");
  if(vendor == s)
    vendor = i18n("<Generic>");

  for(uint i = 0; i < modems.count(); i++) {
    CharDict *dict = modems.at(i);
    if(dict->find("Vendor") != 0) {
      if(vendor == (*dict)["Vendor"] && (*dict)["Name"][0] != '!')
	sl->inSort((*dict)["Name"]);
    }
  }

  return sl;
}

void ModemDatabase::loadModem(const char *key, CharDict &dict) {
  //  KEntryIterator *it = modemDB->entryIterator(key);
  //  KEntryDictEntry *e;
  QMap <QString, QString> map;
  QMap <QString, QString>::Iterator it;
  //  KEntryMapConstIterator e;
  KEntry e;
  map = modemDB->entryMap(key);
  it = map.begin();

  // remove parent attribute
  dict.setAutoDelete(true);
  dict.remove("Parent");

  //  e = it->current();
  while(it.key() != QString::null) {
    if(dict.find(it.key()) == 0) {
      char *value = new char[it.data().length()+1];
      strcpy(value, it.data());
      dict.insert(it.key(), value);
    }
    it++;
  }

  // check name attribute
  if(dict["Name"] == 0 || key[0]=='!') {
    char *name = new char[strlen(key)+1];
    strcpy(name, key);
    dict.replace("Name", name);
  }

  // check parent attribute
  if(dict["Parent"] != 0)
    loadModem(dict["Parent"], dict);
  else
    // inherit common at last
    if(strcmp(key, "Common") != 0)
      loadModem("Common", dict);

}

void ModemDatabase::load() {
  modemDB = new KConfig("DB/modemDB.rc", QString::null);
  lvendors = new QStrList;
  lvendors->setAutoDelete(true);
  modems.setAutoDelete(true);

  QStringList list = modemDB->groupList();
  QStringList::Iterator it = list.begin();
  while(it != list.end()) {
    modemDB->setGroup(*it);
    CharDict *c = new CharDict;
    c->setAutoDelete(true);
    loadModem(it->latin1(), *c);

    //    if(strcmp(it->latin1(), "Common") == 0) {
    if(*it == "Common") {
      QString s = i18n("Hayes(tm) compatible modem");
      char *name = new char[s.length()+1];
      strcpy(name, s);
      c->replace("Name", name);

      s = i18n("<Generic>");
      char *vend = new char[s.length()+1];
      strcpy(vend, s);
      c->replace("Vendor", vend);
    }
    modems.append(c);

    if(modemDB->hasKey("Vendor")) {
      QString vendor = modemDB->readEntry("Vendor");
      if(lvendors->find(vendor) == -1)
	lvendors->inSort(vendor);
    }
    ++it;
  }

  lvendors->insert(0, i18n("<Generic>"));
}

void ModemDatabase::save(KConfig *) {
}

#include "modemdb.moc"
<commit_msg>Make it compile with recent Qt (iterator changes)<commit_after>//---------------------------------------------------------------------------
//
//             kPPP: A pppd front end for the KDE project
//
//---------------------------------------------------------------------------
//
// (c) 1997-1998 Bernd Johannes Wuebben <wuebben@kde.org>
// (c) 1997-1999 Mario Weilguni <mweilguni@kde.org>
// (c) 1998-1999 Harri Porten <porten@kde.org>
//
// derived from Jay Painters "ezppp"
//
//---------------------------------------------------------------------------
//
//  $Id$
//
//---------------------------------------------------------------------------
//
//  This program is free software; you can redistribute it and-or
//  modify it under the terms of the GNU Library 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
//  Library General Public License for more details.
//
//  You should have received a copy of the GNU Library General Public
//  License along with this program; if not, write to the Free
//  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//---------------------------------------------------------------------------

#include <qlabel.h>
#include <qlistbox.h>
#include <qstringlist.h>
#include <kbuttonbox.h>
#include <qlayout.h>
#include <kapp.h>
#include "modemdb.h"
#include "log.h"
#include <klocale.h>

ModemSelector::ModemSelector(QWidget *parent) : QDialog(parent, 0, true) {
  // set up widgets and such
  setCaption(i18n("Select modem type..."));
  QVBoxLayout *tl = new QVBoxLayout(this, 10, 10);
  QLabel *l1 = new QLabel(i18n("To setup your modem, first choose its vendor in the "
			       "list to the left, and then select the model from the "
			       "right list. If you dont know which modem you have, "
			       "you can try out one of the \"Generic\" modems."),
			this);
  l1->setAlignment(AlignLeft | WordBreak);
  l1->setFixedWidth(400);
  l1->setMinimumHeight(50);
  tl->addWidget(l1, 0);

  tl->addSpacing(10);

  QHBoxLayout *tl1 = new QHBoxLayout(10);
  tl->addLayout(tl1, 1);
  vendor = new QListBox(this);
  model  = new QListBox(this);
  vendor->setMinimumSize(200, 130);
  model->setMinimumSize(200, 130);
  tl1->addWidget(vendor, 2);
  tl1->addWidget(model, 3);

  KButtonBox *bbox = new KButtonBox(this);
  bbox->addStretch(1);
  ok = bbox->addButton(i18n("OK"));
  ok->setDefault(true);
  ok->setEnabled(false);
  cancel =   bbox->addButton(i18n("Cancel"));
  bbox->layout();
  tl->addWidget(bbox);
  setFixedSize(sizeHint());

  // setup modem database
  db = new ModemDatabase();

  // set up signal/slots
  connect(ok, SIGNAL(clicked()),
	  this, SLOT(reject()));
  connect(cancel, SIGNAL(clicked()),
	  this, SLOT(reject()));
  connect(vendor, SIGNAL(highlighted(int)),
	  this, SLOT(vendorSelected(int)));
  connect(model, SIGNAL(highlighted(int)),
	  this, SLOT(modelSelected(int)));
  connect(model, SIGNAL(selected(int)),
	  this, SLOT(selected(int)));

  // fill vendor list with life
  const QStrList *lvendor = db->vendors();
  for(uint i = 0; i < lvendor->count(); i++)
    vendor->insertItem(((QStrList *)lvendor)->at(i));

  vendor->setCurrentItem(0);
}

ModemSelector::~ModemSelector() {
  delete db;
}

void ModemSelector::vendorSelected(int idx) {
  ok->setEnabled(false);

  QString name = vendor->text(idx);
  QStrList *models = db->models(name);
  model->clear();
  for(uint i = 0; i < models->count(); i++)
    model->insertItem(models->at(i));

  // FIXME: work around Qt bug
  if(models->count() == 0)
    model->update();
  delete models;
}

void ModemSelector::modelSelected(int idx) {
  ok->setEnabled(true);
}

void ModemSelector::selected(int idx) {
  accept();
}

ModemDatabase::ModemDatabase() {
  load();
}

ModemDatabase::~ModemDatabase() {
  delete lvendors;
  delete modemDB;
}

const QStrList *ModemDatabase::vendors() {
  return lvendors;
}

QStrList *ModemDatabase::models(QString vendor) {
  QStrList *sl = new QStrList;
  QString s = i18n("<Generic>");
  if(vendor == s)
    vendor = i18n("<Generic>");

  for(uint i = 0; i < modems.count(); i++) {
    CharDict *dict = modems.at(i);
    if(dict->find("Vendor") != 0) {
      if(vendor == (*dict)["Vendor"] && (*dict)["Name"][0] != '!')
	sl->inSort((*dict)["Name"]);
    }
  }

  return sl;
}

void ModemDatabase::loadModem(const char *key, CharDict &dict) {
  //  KEntryIterator *it = modemDB->entryIterator(key);
  //  KEntryDictEntry *e;
  QMap <QString, QString> map;
  QMap <QString, QString>::Iterator it;
  //  KEntryMapConstIterator e;
  KEntry e;
  map = modemDB->entryMap(key);
  it = map.begin();

  // remove parent attribute
  dict.setAutoDelete(true);
  dict.remove("Parent");

  //  e = it->current();
  while(it.key() != QString::null) {
    if(dict.find(it.key()) == 0) {
      char *value = new char[it.data().length()+1];
      strcpy(value, it.data());
      dict.insert(it.key(), value);
    }
    it++;
  }

  // check name attribute
  if(dict["Name"] == 0 || key[0]=='!') {
    char *name = new char[strlen(key)+1];
    strcpy(name, key);
    dict.replace("Name", name);
  }

  // check parent attribute
  if(dict["Parent"] != 0)
    loadModem(dict["Parent"], dict);
  else
    // inherit common at last
    if(strcmp(key, "Common") != 0)
      loadModem("Common", dict);

}

void ModemDatabase::load() {
  modemDB = new KConfig("DB/modemDB.rc", QString::null);
  lvendors = new QStrList;
  lvendors->setAutoDelete(true);
  modems.setAutoDelete(true);

  QStringList list = modemDB->groupList();
  QStringList::Iterator it = list.begin();
  while(it != list.end()) {
    modemDB->setGroup(*it);
    CharDict *c = new CharDict;
    c->setAutoDelete(true);
    loadModem((*it).latin1(), *c);

    //    if(strcmp(it->latin1(), "Common") == 0) {
    if(*it == "Common") {
      QString s = i18n("Hayes(tm) compatible modem");
      char *name = new char[s.length()+1];
      strcpy(name, s);
      c->replace("Name", name);

      s = i18n("<Generic>");
      char *vend = new char[s.length()+1];
      strcpy(vend, s);
      c->replace("Vendor", vend);
    }
    modems.append(c);

    if(modemDB->hasKey("Vendor")) {
      QString vendor = modemDB->readEntry("Vendor");
      if(lvendors->find(vendor) == -1)
	lvendors->inSort(vendor);
    }
    ++it;
  }

  lvendors->insert(0, i18n("<Generic>"));
}

void ModemDatabase::save(KConfig *) {
}

#include "modemdb.moc"
<|endoftext|>


<commit_before>#include "UnitTest.h"
#include "../Source/Utility/Lock.h"

#define LOCK_TYPES ((vl::vint)vl::database::LockTargetAccess::NumbersOfLockTypes)

using namespace vl;
using namespace vl::database;
using namespace vl::collections;

const bool lockCompatibility
	[LOCK_TYPES] // Request
	[LOCK_TYPES] // Existing
= {
	{true,	true,	true,	true,	true,	false},
	{true,	true,	true,	false,	false,	false},
	{true,	true,	false,	false,	false,	false},
	{true,	false,	false,	true,	false,	false},
	{true,	false,	false,	false,	false,	false},
	{false,	false,	false,	false,	false,	false},
};

extern WString GetTempFolder();
#define TEMP_DIR GetTempFolder()+
#define KB *1024
#define MB *1024*1024

TEST_CASE(Utility_Lock_Registering)
{
	BufferManager bm(4 KB, 1024);
	auto sourceA = bm.LoadMemorySource();
	BufferSource sourceB{2};

	LockManager lm(&bm);
	BufferTable tableA{1};
	BufferTable tableB{2};
	BufferTransaction transA{1};
	BufferTransaction transB{2};

	// Registering table will fail using unexisting source
	TEST_ASSERT(lm.RegisterTable(tableA, sourceB) == false);

	// Registering table will success using existing source
	TEST_ASSERT(lm.RegisterTable(tableA, sourceA) == true);

	// Registering table twice will fail
	TEST_ASSERT(lm.RegisterTable(tableA, sourceA) == false);

	// Unregistering unexisting table will fail
	TEST_ASSERT(lm.UnregisterTable(tableB) == false);

	// Unregistering existing table will success
	TEST_ASSERT(lm.UnregisterTable(tableA) == true);
	TEST_ASSERT(lm.UnregisterTable(tableB) == false);
	TEST_ASSERT(lm.RegisterTable(tableA, sourceA) == true);

	// Registering transaction ibce will success
	TEST_ASSERT(lm.RegisterTransaction(transA, 0) == true);

	// Registering transaction twice will fail
	TEST_ASSERT(lm.RegisterTransaction(transA, 0) == false);

	// Unregistering unexisting transaction will fail
	TEST_ASSERT(lm.UnregisterTransaction(transB) == false);

	// Unregistering existing transaction will success
	TEST_ASSERT(lm.UnregisterTransaction(transA) == true);
	TEST_ASSERT(lm.UnregisterTransaction(transB) == false);
	TEST_ASSERT(lm.RegisterTransaction(transA, 0) == true);

}

#define INIT_LOCK_MANAGER									\
	BufferManager bm(4 KB, 1024);							\
	auto source = bm.LoadMemorySource();					\
	LockManager lm(&bm);									\
	BufferTable tableA{1}, tableB{2};						\
	BufferTransaction transA{1}, transB{2};					\
	BufferPage pageA = bm.AllocatePage(source);				\
	BufferPage pageB = bm.AllocatePage(source);				\
	TEST_ASSERT(lm.RegisterTable(tableA, source) == true);	\
	TEST_ASSERT(lm.RegisterTable(tableB, source) == true);	\
	TEST_ASSERT(lm.RegisterTransaction(transA, 0) == true);	\
	TEST_ASSERT(lm.RegisterTransaction(transB, 0) == true);	\
	BufferTransaction lo;									\
	LockTarget lt;											\
	LockResult lr;											\

#define TABLE LockTargetType::Table
#define PAGE LockTargetType::Page
#define ROW LockTargetType::Row
#define SLOCK LockTargetAccess::Shared
#define XLOCK LockTargetAccess::Exclusive

namespace general_lock_testing
{
	void TestLock(
		LockManager& lm,
		BufferTransaction loA,
		BufferTransaction loB,
		Func<LockTarget(vint)> ltAGen,
		Func<LockTarget(vint)> ltBGen
		)
	{
		LockResult lr, lrA, lrB;

		// Check lock compatibility
		for (vint i = 0; i < LOCK_TYPES; i++)
		{
			auto ltA = ltAGen(i);
			TEST_ASSERT(lm.AcquireLock(loA, ltA, lrA) == true);
			TEST_ASSERT(lrA.blocked == false);

			for (vint j = 0; j < LOCK_TYPES; j++)
			{
				auto ltB = ltAGen(j);
				TEST_ASSERT(lm.AcquireLock(loB, ltB, lrB) == true);
				TEST_ASSERT(lrB.blocked == !lockCompatibility[j][i]);
				TEST_ASSERT(lm.ReleaseLock(loB, ltB) == true);
			}

			TEST_ASSERT(lm.ReleaseLock(loA, ltA) == true);
		}

		// Check unrelated lock
		for (vint i = 0; i < LOCK_TYPES; i++)
		{
			auto ltA = ltAGen(i);
			TEST_ASSERT(lm.AcquireLock(loA, ltA, lrA) == true);
			TEST_ASSERT(lrA.blocked == false);

			for (vint j = 0; j < LOCK_TYPES; j++)
			{
				auto ltB = ltBGen(j);
				TEST_ASSERT(lm.AcquireLock(loB, ltB, lrB) == true);
				TEST_ASSERT(lrB.blocked == false);
				TEST_ASSERT(lm.ReleaseLock(loB, ltB) == true);
			}

			TEST_ASSERT(lm.ReleaseLock(loA, ltA) == true);
		}

		// Check upgrade lock
		for (vint i = 0; i < LOCK_TYPES; i++)
		{
			auto ltA = ltAGen(i);
			TEST_ASSERT(lm.AcquireLock(loA, ltA, lrA) == true);
			TEST_ASSERT(lrA.blocked == false);

			for (vint j = 0; j < LOCK_TYPES; j++)
			{
				auto ltB = ltAGen(j);
				TEST_ASSERT(lm.UpgradeLock(loB, ltA, ltB.access, lrB) == true);
				TEST_ASSERT(lrB.blocked == false);
				TEST_ASSERT(lm.ReleaseLock(loB, ltB) == true);
			}

			TEST_ASSERT(lm.ReleaseLock(loA, ltA) == true);
		}

		// Check upgrade lock compatibility
		for (vint i = 0; i < LOCK_TYPES; i++)
		{
			auto ltA = ltAGen(i);
			TEST_ASSERT(lm.AcquireLock(loA, ltA, lrA) == true);
			TEST_ASSERT(lrA.blocked == false);

			for (vint j = 0; j < LOCK_TYPES; j++)
			{
				for (vint k = 0; k < LOCK_TYPES; k++)
				{
					auto ltB = ltAGen(j);
					TEST_ASSERT(lm.AcquireLock(loB, ltB, lrB) == true);
					TEST_ASSERT(lrB.blocked == !lockCompatibility[j][i]);

					auto lt = ltAGen(k);
					if (lrB.blocked)
					{
						TEST_ASSERT(lm.UpgradeLock(loB, ltB, lt.access, lr) == false);
						TEST_ASSERT(lm.ReleaseLock(loB, ltB) == true);
					}
					else
					{
						TEST_ASSERT(lm.UpgradeLock(loB, ltB, lt.access, lr) == true);
						TEST_ASSERT(lr.blocked == !lockCompatibility[k][i]);
						TEST_ASSERT(lm.ReleaseLock(loB, lt) == true);
					}
				}
			}

			TEST_ASSERT(lm.ReleaseLock(loA, ltA) == true);
		}
	}
}
using namespace general_lock_testing;

TEST_CASE(Utility_Lock_Table)
{
	INIT_LOCK_MANAGER;

	// Lock invalid table will fail
	lo = transA;
	lt = {SLOCK, BufferTable::Invalid()};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);

	// Lock using invalid transaction will fail
	lo = BufferTransaction::Invalid();
	lt = {SLOCK, tableA};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);

	// Unlock unexisting lock will fail
	lo = transA;
	lt = {SLOCK, tableA};
	TEST_ASSERT(lm.ReleaseLock(lo, lt) == false);

	TestLock(
		lm,
		transA,
		transB,
		[=](vint a){ return LockTarget{(LockTargetAccess)a, tableA}; },
		[=](vint a){ return LockTarget{(LockTargetAccess)a, tableB}; }
		);

	// Ensure lock released
	TEST_ASSERT(lm.TableHasLocks(tableA) == false);
	TEST_ASSERT(lm.TableHasLocks(tableB) == false);
}

TEST_CASE(Utility_Lock_Page)
{
	INIT_LOCK_MANAGER;

	// Lock invalid table or page will fail
	lo = transA;
	lt = {SLOCK, BufferTable::Invalid(), pageA};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);
	lt = {SLOCK, tableA, BufferPage::Invalid()};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);

	// Lock using invalid transaction will fail
	lo = BufferTransaction::Invalid();
	lt = {SLOCK, tableA, pageA};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);

	// Unlock unexisting lock will fail
	lo = transA;
	lt = {SLOCK, tableA, pageA};
	TEST_ASSERT(lm.ReleaseLock(lo, lt) == false);

	TestLock(
		lm,
		transA,
		transB,
		[=](vint a){ return LockTarget{(LockTargetAccess)a, tableA, pageA}; },
		[=](vint a){ return LockTarget{(LockTargetAccess)a, tableA, pageB}; }
		);

	// Ensure lock released
	TEST_ASSERT(lm.TableHasLocks(tableA) == false);
	TEST_ASSERT(lm.TableHasLocks(tableB) == false);
}

TEST_CASE(Utility_Lock_Row)
{
	INIT_LOCK_MANAGER;
	BufferPointer addA, addB;
	TEST_ASSERT(bm.EncodePointer(addA, pageA, 0));
	TEST_ASSERT(bm.EncodePointer(addB, pageB, 0));

	// Lock invalid table or address will fail
	lo = transA;
	lt = {SLOCK, BufferTable::Invalid(), addA};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);
	lt = {SLOCK, tableA, BufferPointer::Invalid()};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);

	// Lock using invalid transaction will fail
	lo = BufferTransaction::Invalid();
	lt = {SLOCK, tableA, addA};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);

	// Unlock unexisting lock will fail
	lo = transA;
	lt = {SLOCK, tableA, addA};
	TEST_ASSERT(lm.ReleaseLock(lo, lt) == false);

	TestLock(
		lm,
		transA,
		transB,
		[=](vint a){ return LockTarget{(LockTargetAccess)a, tableA, addA}; },
		[=](vint a){ return LockTarget{(LockTargetAccess)a, tableA, addB}; }
		);

	// Ensure lock released
	TEST_ASSERT(lm.TableHasLocks(tableA) == false);
	TEST_ASSERT(lm.TableHasLocks(tableB) == false);
}
<commit_msg>Test case for Upgrade<commit_after>#include "UnitTest.h"
#include "../Source/Utility/Lock.h"

#define LOCK_TYPES ((vl::vint)vl::database::LockTargetAccess::NumbersOfLockTypes)

using namespace vl;
using namespace vl::database;
using namespace vl::collections;

const bool lockCompatibility
	[LOCK_TYPES] // Request
	[LOCK_TYPES] // Existing
= {
	{true,	true,	true,	true,	true,	false},
	{true,	true,	true,	false,	false,	false},
	{true,	true,	false,	false,	false,	false},
	{true,	false,	false,	true,	false,	false},
	{true,	false,	false,	false,	false,	false},
	{false,	false,	false,	false,	false,	false},
};

extern WString GetTempFolder();
#define TEMP_DIR GetTempFolder()+
#define KB *1024
#define MB *1024*1024

TEST_CASE(Utility_Lock_Registering)
{
	BufferManager bm(4 KB, 1024);
	auto sourceA = bm.LoadMemorySource();
	BufferSource sourceB{2};

	LockManager lm(&bm);
	BufferTable tableA{1};
	BufferTable tableB{2};
	BufferTransaction transA{1};
	BufferTransaction transB{2};

	// Registering table will fail using unexisting source
	TEST_ASSERT(lm.RegisterTable(tableA, sourceB) == false);

	// Registering table will success using existing source
	TEST_ASSERT(lm.RegisterTable(tableA, sourceA) == true);

	// Registering table twice will fail
	TEST_ASSERT(lm.RegisterTable(tableA, sourceA) == false);

	// Unregistering unexisting table will fail
	TEST_ASSERT(lm.UnregisterTable(tableB) == false);

	// Unregistering existing table will success
	TEST_ASSERT(lm.UnregisterTable(tableA) == true);
	TEST_ASSERT(lm.UnregisterTable(tableB) == false);
	TEST_ASSERT(lm.RegisterTable(tableA, sourceA) == true);

	// Registering transaction ibce will success
	TEST_ASSERT(lm.RegisterTransaction(transA, 0) == true);

	// Registering transaction twice will fail
	TEST_ASSERT(lm.RegisterTransaction(transA, 0) == false);

	// Unregistering unexisting transaction will fail
	TEST_ASSERT(lm.UnregisterTransaction(transB) == false);

	// Unregistering existing transaction will success
	TEST_ASSERT(lm.UnregisterTransaction(transA) == true);
	TEST_ASSERT(lm.UnregisterTransaction(transB) == false);
	TEST_ASSERT(lm.RegisterTransaction(transA, 0) == true);

}

#define INIT_LOCK_MANAGER									\
	BufferManager bm(4 KB, 1024);							\
	auto source = bm.LoadMemorySource();					\
	LockManager lm(&bm);									\
	BufferTable tableA{1}, tableB{2};						\
	BufferTransaction transA{1}, transB{2};					\
	BufferPage pageA = bm.AllocatePage(source);				\
	BufferPage pageB = bm.AllocatePage(source);				\
	TEST_ASSERT(lm.RegisterTable(tableA, source) == true);	\
	TEST_ASSERT(lm.RegisterTable(tableB, source) == true);	\
	TEST_ASSERT(lm.RegisterTransaction(transA, 0) == true);	\
	TEST_ASSERT(lm.RegisterTransaction(transB, 0) == true);	\
	BufferTransaction lo;									\
	LockTarget lt;											\
	LockResult lr;											\

#define TABLE LockTargetType::Table
#define PAGE LockTargetType::Page
#define ROW LockTargetType::Row
#define SLOCK LockTargetAccess::Shared
#define XLOCK LockTargetAccess::Exclusive

namespace general_lock_testing
{
	void TestLock(
		LockManager& lm,
		BufferTransaction loA,
		BufferTransaction loB,
		Func<LockTarget(vint)> ltAGen,
		Func<LockTarget(vint)> ltBGen
		)
	{
		LockResult lr, lrA, lrB;

		// Check lock compatibility
		for (vint i = 0; i < LOCK_TYPES; i++)
		{
			auto ltA = ltAGen(i);
			TEST_ASSERT(lm.AcquireLock(loA, ltA, lrA) == true);
			TEST_ASSERT(lrA.blocked == false);

			for (vint j = 0; j < LOCK_TYPES; j++)
			{
				auto ltB = ltAGen(j);
				TEST_ASSERT(lm.AcquireLock(loB, ltB, lrB) == true);
				TEST_ASSERT(lrB.blocked == !lockCompatibility[j][i]);
				TEST_ASSERT(lm.ReleaseLock(loB, ltB) == true);
			}

			TEST_ASSERT(lm.ReleaseLock(loA, ltA) == true);
		}

		// Check unrelated lock
		for (vint i = 0; i < LOCK_TYPES; i++)
		{
			auto ltA = ltAGen(i);
			TEST_ASSERT(lm.AcquireLock(loA, ltA, lrA) == true);
			TEST_ASSERT(lrA.blocked == false);

			for (vint j = 0; j < LOCK_TYPES; j++)
			{
				auto ltB = ltBGen(j);
				TEST_ASSERT(lm.AcquireLock(loB, ltB, lrB) == true);
				TEST_ASSERT(lrB.blocked == false);
				TEST_ASSERT(lm.ReleaseLock(loB, ltB) == true);
			}

			TEST_ASSERT(lm.ReleaseLock(loA, ltA) == true);
		}

		// Check upgrade lock
		for (vint i = 0; i < LOCK_TYPES; i++)
		{
			for (vint j = 0; j < LOCK_TYPES; j++)
			{
				auto ltA = ltAGen(i);
				TEST_ASSERT(lm.AcquireLock(loA, ltA, lrA) == true);
				TEST_ASSERT(lrA.blocked == false);

				auto ltB = ltAGen(j);
				TEST_ASSERT(lm.UpgradeLock(loA, ltA, ltB.access, lrB) == true);
				TEST_ASSERT(lrB.blocked == false);
				TEST_ASSERT(lm.ReleaseLock(loA, ltB) == true);
			}
		}

		// Check upgrade lock compatibility
		for (vint i = 0; i < LOCK_TYPES; i++)
		{
			auto ltA = ltAGen(i);
			TEST_ASSERT(lm.AcquireLock(loA, ltA, lrA) == true);
			TEST_ASSERT(lrA.blocked == false);

			for (vint j = 0; j < LOCK_TYPES; j++)
			{
				for (vint k = 0; k < LOCK_TYPES; k++)
				{
					auto ltB = ltAGen(j);
					TEST_ASSERT(lm.AcquireLock(loB, ltB, lrB) == true);
					TEST_ASSERT(lrB.blocked == !lockCompatibility[j][i]);

					auto lt = ltAGen(k);
					if (lrB.blocked)
					{
						TEST_ASSERT(lm.UpgradeLock(loB, ltB, lt.access, lr) == false);
						TEST_ASSERT(lm.ReleaseLock(loB, ltB) == true);
					}
					else
					{
						TEST_ASSERT(lm.UpgradeLock(loB, ltB, lt.access, lr) == true);
						TEST_ASSERT(lr.blocked == !lockCompatibility[k][i]);
						TEST_ASSERT(lm.ReleaseLock(loB, lt) == true);
					}
				}
			}

			TEST_ASSERT(lm.ReleaseLock(loA, ltA) == true);
		}
	}
}
using namespace general_lock_testing;

TEST_CASE(Utility_Lock_Table)
{
	INIT_LOCK_MANAGER;

	// Lock invalid table will fail
	lo = transA;
	lt = {SLOCK, BufferTable::Invalid()};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);

	// Lock using invalid transaction will fail
	lo = BufferTransaction::Invalid();
	lt = {SLOCK, tableA};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);

	// Unlock unexisting lock will fail
	lo = transA;
	lt = {SLOCK, tableA};
	TEST_ASSERT(lm.ReleaseLock(lo, lt) == false);

	TestLock(
		lm,
		transA,
		transB,
		[=](vint a){ return LockTarget{(LockTargetAccess)a, tableA}; },
		[=](vint a){ return LockTarget{(LockTargetAccess)a, tableB}; }
		);

	// Ensure lock released
	TEST_ASSERT(lm.TableHasLocks(tableA) == false);
	TEST_ASSERT(lm.TableHasLocks(tableB) == false);
}

TEST_CASE(Utility_Lock_Page)
{
	INIT_LOCK_MANAGER;

	// Lock invalid table or page will fail
	lo = transA;
	lt = {SLOCK, BufferTable::Invalid(), pageA};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);
	lt = {SLOCK, tableA, BufferPage::Invalid()};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);

	// Lock using invalid transaction will fail
	lo = BufferTransaction::Invalid();
	lt = {SLOCK, tableA, pageA};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);

	// Unlock unexisting lock will fail
	lo = transA;
	lt = {SLOCK, tableA, pageA};
	TEST_ASSERT(lm.ReleaseLock(lo, lt) == false);

	TestLock(
		lm,
		transA,
		transB,
		[=](vint a){ return LockTarget{(LockTargetAccess)a, tableA, pageA}; },
		[=](vint a){ return LockTarget{(LockTargetAccess)a, tableA, pageB}; }
		);

	// Ensure lock released
	TEST_ASSERT(lm.TableHasLocks(tableA) == false);
	TEST_ASSERT(lm.TableHasLocks(tableB) == false);
}

TEST_CASE(Utility_Lock_Row)
{
	INIT_LOCK_MANAGER;
	BufferPointer addA, addB;
	TEST_ASSERT(bm.EncodePointer(addA, pageA, 0));
	TEST_ASSERT(bm.EncodePointer(addB, pageB, 0));

	// Lock invalid table or address will fail
	lo = transA;
	lt = {SLOCK, BufferTable::Invalid(), addA};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);
	lt = {SLOCK, tableA, BufferPointer::Invalid()};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);

	// Lock using invalid transaction will fail
	lo = BufferTransaction::Invalid();
	lt = {SLOCK, tableA, addA};
	TEST_ASSERT(lm.AcquireLock(lo, lt, lr) == false);

	// Unlock unexisting lock will fail
	lo = transA;
	lt = {SLOCK, tableA, addA};
	TEST_ASSERT(lm.ReleaseLock(lo, lt) == false);

	TestLock(
		lm,
		transA,
		transB,
		[=](vint a){ return LockTarget{(LockTargetAccess)a, tableA, addA}; },
		[=](vint a){ return LockTarget{(LockTargetAccess)a, tableA, addB}; }
		);

	// Ensure lock released
	TEST_ASSERT(lm.TableHasLocks(tableA) == false);
	TEST_ASSERT(lm.TableHasLocks(tableB) == false);
}
<|endoftext|>