<commit_before>#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <set>
#include <memory>
#include <tuple>
#include <iomanip>
#if __APPLE__
#include <sys/time.h>
#endif

#include "machines.hh"
#include "shared.hh"
#include "pathlocks.hh"
#include "globals.hh"
#include "serialise.hh"
#include "store-api.hh"
#include "derivations.hh"
#include "local-store.hh"

using namespace nix;
using std::cin;

static void handleAlarm(int sig) {
}

std::string escapeUri(std::string uri)
{
    std::replace(uri.begin(), uri.end(), '/', '_');
    return uri;
}

static string currentLoad;

static AutoCloseFD openSlotLock(const Machine & m, unsigned long long slot)
{
    return openLockFile(fmt("%s/%s-%d", currentLoad, escapeUri(m.storeUri), slot), true);
}

int main (int argc, char * * argv)
{
    return handleExceptions(argv[0], [&]() {
        initNix();

        logger = makeJSONLogger(*logger);

        /* Ensure we don't get any SSH passphrase or host key popups. */
        unsetenv("DISPLAY");
        unsetenv("SSH_ASKPASS");

        if (argc != 2)
            throw UsageError("called without required arguments");

        verbosity = (Verbosity) std::stoll(argv[1]);

        FdSource source(STDIN_FILENO);

        /* Read the parent's settings. */
        while (readInt(source)) {
            auto name = readString(source);
            auto value = readString(source);
            settings.set(name, value);
        }

        settings.maxBuildJobs.set("1"); // hack to make tests with local?root= work

        initPlugins();

        auto store = openStore().cast<LocalStore>();

        /* It would be more appropriate to use $XDG_RUNTIME_DIR, since
           that gets cleared on reboot, but it wouldn't work on macOS. */
        currentLoad = store->stateDir + "/current-load";

        std::shared_ptr<Store> sshStore;
        AutoCloseFD bestSlotLock;

        auto machines = getMachines();
        debug("got %d remote builders", machines.size());

        if (machines.empty()) {
            std::cerr << "# decline-permanently\n";
            return;
        }

        string drvPath;
        string storeUri;

        while (true) {

            try {
                auto s = readString(source);
                if (s != "try") return;
            } catch (EndOfFile &) { return; }

            auto amWilling = readInt(source);
            auto neededSystem = readString(source);
            source >> drvPath;
            auto requiredFeatures = readStrings<std::set<std::string>>(source);

            auto canBuildLocally = amWilling && (neededSystem == settings.thisSystem);

            /* Error ignored here, will be caught later */
            mkdir(currentLoad.c_str(), 0777);

            while (true) {
                bestSlotLock = -1;
                AutoCloseFD lock = openLockFile(currentLoad + "/main-lock", true);
                lockFile(lock.get(), ltWrite, true);

                bool rightType = false;

                Machine * bestMachine = nullptr;
                unsigned long long bestLoad = 0;
                for (auto & m : machines) {
                    debug("considering building on remote machine '%s'", m.storeUri);

                    if (m.enabled && std::find(m.systemTypes.begin(),
                            m.systemTypes.end(),
                            neededSystem) != m.systemTypes.end() &&
                        m.allSupported(requiredFeatures) &&
                        m.mandatoryMet(requiredFeatures)) {
                        rightType = true;
                        AutoCloseFD free;
                        unsigned long long load = 0;
                        for (unsigned long long slot = 0; slot < m.maxJobs; ++slot) {
                            auto slotLock = openSlotLock(m, slot);
                            if (lockFile(slotLock.get(), ltWrite, false)) {
                                if (!free) {
                                    free = std::move(slotLock);
                                }
                            } else {
                                ++load;
                            }
                        }
                        if (!free) {
                            continue;
                        }
                        bool best = false;
                        if (!bestSlotLock) {
                            best = true;
                        } else if (load / m.speedFactor < bestLoad / bestMachine->speedFactor) {
                            best = true;
                        } else if (load / m.speedFactor == bestLoad / bestMachine->speedFactor) {
                            if (m.speedFactor > bestMachine->speedFactor) {
                                best = true;
                            } else if (m.speedFactor == bestMachine->speedFactor) {
                                if (load < bestLoad) {
                                    best = true;
                                }
                            }
                        }
                        if (best) {
                            bestLoad = load;
                            bestSlotLock = std::move(free);
                            bestMachine = &m;
                        }
                    }
                }

                if (!bestSlotLock) {
                    if (rightType && !canBuildLocally)
                        std::cerr << "# postpone\n";
                    else
                        std::cerr << "# decline\n";
                    break;
                }

#if __APPLE__
                futimes(bestSlotLock.get(), NULL);
#else
                futimens(bestSlotLock.get(), NULL);
#endif

                lock = -1;

                try {

                    Activity act(*logger, lvlTalkative, actUnknown, fmt("connecting to '%s'", bestMachine->storeUri));

                    Store::Params storeParams;
                    if (hasPrefix(bestMachine->storeUri, "ssh://")) {
                        storeParams["max-connections"] ="1";
                        storeParams["log-fd"] = "4";
                        if (bestMachine->sshKey != "")
                            storeParams["ssh-key"] = bestMachine->sshKey;
                    }

                    sshStore = openStore(bestMachine->storeUri, storeParams);
                    sshStore->connect();
                    storeUri = bestMachine->storeUri;

                } catch (std::exception & e) {
                    printError("unable to open SSH connection to '%s': %s; trying other available machines...",
                        bestMachine->storeUri, e.what());
                    bestMachine->enabled = false;
                    continue;
                }

                goto connected;
            }
        }

connected:
        std::cerr << "# accept\n" << storeUri << "\n";

        auto inputs = readStrings<PathSet>(source);
        auto outputs = readStrings<PathSet>(source);

        AutoCloseFD uploadLock = openLockFile(currentLoad + "/" + escapeUri(storeUri) + ".upload-lock", true);

        {
            Activity act(*logger, lvlTalkative, actUnknown, fmt("waiting for the upload lock to '%s'", storeUri));

            auto old = signal(SIGALRM, handleAlarm);
            alarm(15 * 60);
            if (!lockFile(uploadLock.get(), ltWrite, true))
                printError("somebody is hogging the upload lock for '%s', continuing...");
            alarm(0);
            signal(SIGALRM, old);
        }

        auto substitute = settings.buildersUseSubstitutes ? Substitute : NoSubstitute;

        {
            Activity act(*logger, lvlTalkative, actUnknown, fmt("copying dependencies to '%s'", storeUri));
            copyPaths(store, ref<Store>(sshStore), inputs, NoRepair, NoCheckSigs, substitute);
        }

        uploadLock = -1;

        BasicDerivation drv(readDerivation(store->realStoreDir + "/" + baseNameOf(drvPath)));
        drv.inputSrcs = inputs;

        auto result = sshStore->buildDerivation(drvPath, drv);

        if (!result.success())
            throw Error("build of '%s' on '%s' failed: %s", drvPath, storeUri, result.errorMsg);

        PathSet missing;
        for (auto & path : outputs)
            if (!store->isValidPath(path)) missing.insert(path);

        if (!missing.empty()) {
            Activity act(*logger, lvlTalkative, actUnknown, fmt("copying outputs from '%s'", storeUri));
            store->locksHeld.insert(missing.begin(), missing.end()); /* FIXME: ugly */
            copyPaths(ref<Store>(sshStore), store, missing, NoRepair, NoCheckSigs, substitute);
        }

        return;
    });
}
<commit_msg>build-remote: Don't substitute the build result<commit_after>#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <set>
#include <memory>
#include <tuple>
#include <iomanip>
#if __APPLE__
#include <sys/time.h>
#endif

#include "machines.hh"
#include "shared.hh"
#include "pathlocks.hh"
#include "globals.hh"
#include "serialise.hh"
#include "store-api.hh"
#include "derivations.hh"
#include "local-store.hh"

using namespace nix;
using std::cin;

static void handleAlarm(int sig) {
}

std::string escapeUri(std::string uri)
{
    std::replace(uri.begin(), uri.end(), '/', '_');
    return uri;
}

static string currentLoad;

static AutoCloseFD openSlotLock(const Machine & m, unsigned long long slot)
{
    return openLockFile(fmt("%s/%s-%d", currentLoad, escapeUri(m.storeUri), slot), true);
}

int main (int argc, char * * argv)
{
    return handleExceptions(argv[0], [&]() {
        initNix();

        logger = makeJSONLogger(*logger);

        /* Ensure we don't get any SSH passphrase or host key popups. */
        unsetenv("DISPLAY");
        unsetenv("SSH_ASKPASS");

        if (argc != 2)
            throw UsageError("called without required arguments");

        verbosity = (Verbosity) std::stoll(argv[1]);

        FdSource source(STDIN_FILENO);

        /* Read the parent's settings. */
        while (readInt(source)) {
            auto name = readString(source);
            auto value = readString(source);
            settings.set(name, value);
        }

        settings.maxBuildJobs.set("1"); // hack to make tests with local?root= work

        initPlugins();

        auto store = openStore().cast<LocalStore>();

        /* It would be more appropriate to use $XDG_RUNTIME_DIR, since
           that gets cleared on reboot, but it wouldn't work on macOS. */
        currentLoad = store->stateDir + "/current-load";

        std::shared_ptr<Store> sshStore;
        AutoCloseFD bestSlotLock;

        auto machines = getMachines();
        debug("got %d remote builders", machines.size());

        if (machines.empty()) {
            std::cerr << "# decline-permanently\n";
            return;
        }

        string drvPath;
        string storeUri;

        while (true) {

            try {
                auto s = readString(source);
                if (s != "try") return;
            } catch (EndOfFile &) { return; }

            auto amWilling = readInt(source);
            auto neededSystem = readString(source);
            source >> drvPath;
            auto requiredFeatures = readStrings<std::set<std::string>>(source);

            auto canBuildLocally = amWilling && (neededSystem == settings.thisSystem);

            /* Error ignored here, will be caught later */
            mkdir(currentLoad.c_str(), 0777);

            while (true) {
                bestSlotLock = -1;
                AutoCloseFD lock = openLockFile(currentLoad + "/main-lock", true);
                lockFile(lock.get(), ltWrite, true);

                bool rightType = false;

                Machine * bestMachine = nullptr;
                unsigned long long bestLoad = 0;
                for (auto & m : machines) {
                    debug("considering building on remote machine '%s'", m.storeUri);

                    if (m.enabled && std::find(m.systemTypes.begin(),
                            m.systemTypes.end(),
                            neededSystem) != m.systemTypes.end() &&
                        m.allSupported(requiredFeatures) &&
                        m.mandatoryMet(requiredFeatures)) {
                        rightType = true;
                        AutoCloseFD free;
                        unsigned long long load = 0;
                        for (unsigned long long slot = 0; slot < m.maxJobs; ++slot) {
                            auto slotLock = openSlotLock(m, slot);
                            if (lockFile(slotLock.get(), ltWrite, false)) {
                                if (!free) {
                                    free = std::move(slotLock);
                                }
                            } else {
                                ++load;
                            }
                        }
                        if (!free) {
                            continue;
                        }
                        bool best = false;
                        if (!bestSlotLock) {
                            best = true;
                        } else if (load / m.speedFactor < bestLoad / bestMachine->speedFactor) {
                            best = true;
                        } else if (load / m.speedFactor == bestLoad / bestMachine->speedFactor) {
                            if (m.speedFactor > bestMachine->speedFactor) {
                                best = true;
                            } else if (m.speedFactor == bestMachine->speedFactor) {
                                if (load < bestLoad) {
                                    best = true;
                                }
                            }
                        }
                        if (best) {
                            bestLoad = load;
                            bestSlotLock = std::move(free);
                            bestMachine = &m;
                        }
                    }
                }

                if (!bestSlotLock) {
                    if (rightType && !canBuildLocally)
                        std::cerr << "# postpone\n";
                    else
                        std::cerr << "# decline\n";
                    break;
                }

#if __APPLE__
                futimes(bestSlotLock.get(), NULL);
#else
                futimens(bestSlotLock.get(), NULL);
#endif

                lock = -1;

                try {

                    Activity act(*logger, lvlTalkative, actUnknown, fmt("connecting to '%s'", bestMachine->storeUri));

                    Store::Params storeParams;
                    if (hasPrefix(bestMachine->storeUri, "ssh://")) {
                        storeParams["max-connections"] ="1";
                        storeParams["log-fd"] = "4";
                        if (bestMachine->sshKey != "")
                            storeParams["ssh-key"] = bestMachine->sshKey;
                    }

                    sshStore = openStore(bestMachine->storeUri, storeParams);
                    sshStore->connect();
                    storeUri = bestMachine->storeUri;

                } catch (std::exception & e) {
                    printError("unable to open SSH connection to '%s': %s; trying other available machines...",
                        bestMachine->storeUri, e.what());
                    bestMachine->enabled = false;
                    continue;
                }

                goto connected;
            }
        }

connected:
        std::cerr << "# accept\n" << storeUri << "\n";

        auto inputs = readStrings<PathSet>(source);
        auto outputs = readStrings<PathSet>(source);

        AutoCloseFD uploadLock = openLockFile(currentLoad + "/" + escapeUri(storeUri) + ".upload-lock", true);

        {
            Activity act(*logger, lvlTalkative, actUnknown, fmt("waiting for the upload lock to '%s'", storeUri));

            auto old = signal(SIGALRM, handleAlarm);
            alarm(15 * 60);
            if (!lockFile(uploadLock.get(), ltWrite, true))
                printError("somebody is hogging the upload lock for '%s', continuing...");
            alarm(0);
            signal(SIGALRM, old);
        }

        auto substitute = settings.buildersUseSubstitutes ? Substitute : NoSubstitute;

        {
            Activity act(*logger, lvlTalkative, actUnknown, fmt("copying dependencies to '%s'", storeUri));
            copyPaths(store, ref<Store>(sshStore), inputs, NoRepair, NoCheckSigs, substitute);
        }

        uploadLock = -1;

        BasicDerivation drv(readDerivation(store->realStoreDir + "/" + baseNameOf(drvPath)));
        drv.inputSrcs = inputs;

        auto result = sshStore->buildDerivation(drvPath, drv);

        if (!result.success())
            throw Error("build of '%s' on '%s' failed: %s", drvPath, storeUri, result.errorMsg);

        PathSet missing;
        for (auto & path : outputs)
            if (!store->isValidPath(path)) missing.insert(path);

        if (!missing.empty()) {
            Activity act(*logger, lvlTalkative, actUnknown, fmt("copying outputs from '%s'", storeUri));
            store->locksHeld.insert(missing.begin(), missing.end()); /* FIXME: ugly */
            copyPaths(ref<Store>(sshStore), store, missing, NoRepair, NoCheckSigs, NoSubstitute);
        }

        return;
    });
}
<|endoftext|>


<commit_before>// Copyright 2019-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include <gtest/gtest.h>
#include "embree3/rtcore.h"
#include "openvkl/openvkl.h"
#include "ospray/OSPEnums.h"

TEST(Enums, VKLLogLevel)
{
  ASSERT_LE(sizeof(OSPLogLevel), sizeof(VKLLogLevel));
  ASSERT_EQ(OSP_LOG_DEBUG, VKL_LOG_DEBUG);
  ASSERT_EQ(OSP_LOG_INFO, VKL_LOG_INFO);
  ASSERT_EQ(OSP_LOG_WARNING, VKL_LOG_WARNING);
  ASSERT_EQ(OSP_LOG_ERROR, VKL_LOG_ERROR);
  ASSERT_EQ(OSP_LOG_NONE, VKL_LOG_NONE);
}

TEST(Enums, VKLDataType)
{
  ASSERT_LE(sizeof(OSPDataType), sizeof(VKLDataType));
  ASSERT_EQ(OSP_BOOL, VKL_BOOL);
  ASSERT_EQ(OSP_CHAR, VKL_CHAR);
  ASSERT_EQ(OSP_UCHAR, VKL_UCHAR);
  ASSERT_EQ(OSP_VEC2UC, VKL_VEC2UC);
  ASSERT_EQ(OSP_VEC3UC, VKL_VEC3UC);
  ASSERT_EQ(OSP_VEC4UC, VKL_VEC4UC);
  ASSERT_EQ(OSP_SHORT, VKL_SHORT);
  ASSERT_EQ(OSP_USHORT, VKL_USHORT);
  ASSERT_EQ(OSP_INT, VKL_INT);
  ASSERT_EQ(OSP_VEC2I, VKL_VEC2I);
  ASSERT_EQ(OSP_VEC3I, VKL_VEC3I);
  ASSERT_EQ(OSP_VEC4I, VKL_VEC4I);
  ASSERT_EQ(OSP_UINT, VKL_UINT);
  ASSERT_EQ(OSP_VEC2UI, VKL_VEC2UI);
  ASSERT_EQ(OSP_VEC3UI, VKL_VEC3UI);
  ASSERT_EQ(OSP_VEC4UI, VKL_VEC4UI);
  ASSERT_EQ(OSP_LONG, VKL_LONG);
  ASSERT_EQ(OSP_VEC2L, VKL_VEC2L);
  ASSERT_EQ(OSP_VEC3L, VKL_VEC3L);
  ASSERT_EQ(OSP_VEC4L, VKL_VEC4L);
  ASSERT_EQ(OSP_ULONG, VKL_ULONG);
  ASSERT_EQ(OSP_VEC2UL, VKL_VEC2UL);
  ASSERT_EQ(OSP_VEC3UL, VKL_VEC3UL);
  ASSERT_EQ(OSP_VEC4UL, VKL_VEC4UL);
  ASSERT_EQ(OSP_FLOAT, VKL_FLOAT);
  ASSERT_EQ(OSP_VEC2F, VKL_VEC2F);
  ASSERT_EQ(OSP_VEC3F, VKL_VEC3F);
  ASSERT_EQ(OSP_VEC4F, VKL_VEC4F);
  ASSERT_EQ(OSP_DOUBLE, VKL_DOUBLE);
  ASSERT_EQ(OSP_BOX1I, VKL_BOX1I);
  ASSERT_EQ(OSP_BOX2I, VKL_BOX2I);
  ASSERT_EQ(OSP_BOX3I, VKL_BOX3I);
  ASSERT_EQ(OSP_BOX4I, VKL_BOX4I);
  ASSERT_EQ(OSP_BOX1F, VKL_BOX1F);
  ASSERT_EQ(OSP_BOX2F, VKL_BOX2F);
  ASSERT_EQ(OSP_BOX3F, VKL_BOX3F);
  ASSERT_EQ(OSP_BOX4F, VKL_BOX4F);
  ASSERT_EQ(OSP_DATA, VKL_DATA);
  ASSERT_EQ(OSP_LINEAR2F, VKL_LINEAR2F);
  ASSERT_EQ(OSP_LINEAR3F, VKL_LINEAR3F);
  ASSERT_EQ(OSP_AFFINE2F, VKL_AFFINE2F);
  ASSERT_EQ(OSP_AFFINE3F, VKL_AFFINE3F);
  ASSERT_EQ(OSP_RAW, VKL_RAW);
  ASSERT_EQ(OSP_BYTE, VKL_BYTE);
  ASSERT_EQ(OSP_VOID_PTR, VKL_VOID_PTR);
  ASSERT_EQ(OSP_STRING, VKL_STRING);
  ASSERT_EQ(OSP_OBJECT, VKL_OBJECT);
  // those are different object types:
  // ASSERT_EQ(OSP_VOLUME, VKL_VOLUME);
}

TEST(Enums, VKLUnstructuredCellType)
{
  ASSERT_LE(sizeof(OSPUnstructuredCellType), sizeof(VKLUnstructuredCellType));
  ASSERT_EQ(OSP_TETRAHEDRON, VKL_TETRAHEDRON);
  ASSERT_EQ(OSP_HEXAHEDRON, VKL_HEXAHEDRON);
  ASSERT_EQ(OSP_WEDGE, VKL_WEDGE);
  ASSERT_EQ(OSP_PYRAMID, VKL_PYRAMID);
}

TEST(Enums, VKLAMRMethod)
{
  ASSERT_LE(sizeof(OSPAMRMethod), sizeof(VKLAMRMethod));
  ASSERT_EQ(OSP_AMR_CURRENT, VKL_AMR_CURRENT);
  ASSERT_EQ(OSP_AMR_FINEST, VKL_AMR_FINEST);
  ASSERT_EQ(OSP_AMR_OCTANT, VKL_AMR_OCTANT);
}

TEST(Enums, VKLFilter)
{
  ASSERT_LE(sizeof(OSPVolumeFilter), sizeof(VKLFilter));
  ASSERT_EQ(OSP_VOLUME_FILTER_NEAREST, VKL_FILTER_NEAREST);
  ASSERT_EQ(OSP_VOLUME_FILTER_TRILINEAR, VKL_FILTER_TRILINEAR);
}

TEST(Enums, RTCSubdivisionMode)
{
  ASSERT_LE(sizeof(OSPSubdivisionMode), sizeof(RTCSubdivisionMode));
  ASSERT_EQ(OSP_SUBDIVISION_NO_BOUNDARY, RTC_SUBDIVISION_MODE_NO_BOUNDARY);
  ASSERT_EQ(
      OSP_SUBDIVISION_SMOOTH_BOUNDARY, RTC_SUBDIVISION_MODE_SMOOTH_BOUNDARY);
  ASSERT_EQ(OSP_SUBDIVISION_PIN_CORNERS, RTC_SUBDIVISION_MODE_PIN_CORNERS);
  ASSERT_EQ(OSP_SUBDIVISION_PIN_BOUNDARY, RTC_SUBDIVISION_MODE_PIN_BOUNDARY);
  ASSERT_EQ(OSP_SUBDIVISION_PIN_ALL, RTC_SUBDIVISION_MODE_PIN_ALL);
}
<commit_msg>update Open VKL data type enum conformance tests.<commit_after>// Copyright 2019-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include <gtest/gtest.h>
#include "embree3/rtcore.h"
#include "openvkl/openvkl.h"
#include "ospray/OSPEnums.h"

TEST(Enums, VKLLogLevel)
{
  ASSERT_LE(sizeof(OSPLogLevel), sizeof(VKLLogLevel));
  ASSERT_EQ(OSP_LOG_DEBUG, VKL_LOG_DEBUG);
  ASSERT_EQ(OSP_LOG_INFO, VKL_LOG_INFO);
  ASSERT_EQ(OSP_LOG_WARNING, VKL_LOG_WARNING);
  ASSERT_EQ(OSP_LOG_ERROR, VKL_LOG_ERROR);
  ASSERT_EQ(OSP_LOG_NONE, VKL_LOG_NONE);
}

TEST(Enums, VKLDataType)
{
  ASSERT_LE(sizeof(OSPDataType), sizeof(VKLDataType));
  ASSERT_EQ(OSP_BOOL, VKL_BOOL);
  ASSERT_EQ(OSP_CHAR, VKL_CHAR);
  ASSERT_EQ(OSP_VEC2C, VKL_VEC2C);
  ASSERT_EQ(OSP_VEC3C, VKL_VEC3C);
  ASSERT_EQ(OSP_VEC4C, VKL_VEC4C);
  ASSERT_EQ(OSP_UCHAR, VKL_UCHAR);
  ASSERT_EQ(OSP_VEC2UC, VKL_VEC2UC);
  ASSERT_EQ(OSP_VEC3UC, VKL_VEC3UC);
  ASSERT_EQ(OSP_VEC4UC, VKL_VEC4UC);
  ASSERT_EQ(OSP_SHORT, VKL_SHORT);
  ASSERT_EQ(OSP_VEC2S, VKL_VEC2S);
  ASSERT_EQ(OSP_VEC3S, VKL_VEC3S);
  ASSERT_EQ(OSP_VEC4S, VKL_VEC4S);
  ASSERT_EQ(OSP_USHORT, VKL_USHORT);
  ASSERT_EQ(OSP_VEC2US, VKL_VEC2US);
  ASSERT_EQ(OSP_VEC3US, VKL_VEC3US);
  ASSERT_EQ(OSP_VEC4US, VKL_VEC4US);
  ASSERT_EQ(OSP_INT, VKL_INT);
  ASSERT_EQ(OSP_VEC2I, VKL_VEC2I);
  ASSERT_EQ(OSP_VEC3I, VKL_VEC3I);
  ASSERT_EQ(OSP_VEC4I, VKL_VEC4I);
  ASSERT_EQ(OSP_UINT, VKL_UINT);
  ASSERT_EQ(OSP_VEC2UI, VKL_VEC2UI);
  ASSERT_EQ(OSP_VEC3UI, VKL_VEC3UI);
  ASSERT_EQ(OSP_VEC4UI, VKL_VEC4UI);
  ASSERT_EQ(OSP_LONG, VKL_LONG);
  ASSERT_EQ(OSP_VEC2L, VKL_VEC2L);
  ASSERT_EQ(OSP_VEC3L, VKL_VEC3L);
  ASSERT_EQ(OSP_VEC4L, VKL_VEC4L);
  ASSERT_EQ(OSP_ULONG, VKL_ULONG);
  ASSERT_EQ(OSP_VEC2UL, VKL_VEC2UL);
  ASSERT_EQ(OSP_VEC3UL, VKL_VEC3UL);
  ASSERT_EQ(OSP_VEC4UL, VKL_VEC4UL);
  ASSERT_EQ(OSP_FLOAT, VKL_FLOAT);
  ASSERT_EQ(OSP_VEC2F, VKL_VEC2F);
  ASSERT_EQ(OSP_VEC3F, VKL_VEC3F);
  ASSERT_EQ(OSP_VEC4F, VKL_VEC4F);
  ASSERT_EQ(OSP_DOUBLE, VKL_DOUBLE);
  ASSERT_EQ(OSP_VEC2D, VKL_VEC2D);
  ASSERT_EQ(OSP_VEC3D, VKL_VEC3D);
  ASSERT_EQ(OSP_VEC4D, VKL_VEC4D);
  ASSERT_EQ(OSP_BOX1I, VKL_BOX1I);
  ASSERT_EQ(OSP_BOX2I, VKL_BOX2I);
  ASSERT_EQ(OSP_BOX3I, VKL_BOX3I);
  ASSERT_EQ(OSP_BOX4I, VKL_BOX4I);
  ASSERT_EQ(OSP_BOX1F, VKL_BOX1F);
  ASSERT_EQ(OSP_BOX2F, VKL_BOX2F);
  ASSERT_EQ(OSP_BOX3F, VKL_BOX3F);
  ASSERT_EQ(OSP_BOX4F, VKL_BOX4F);
  ASSERT_EQ(OSP_DATA, VKL_DATA);
  ASSERT_EQ(OSP_LINEAR2F, VKL_LINEAR2F);
  ASSERT_EQ(OSP_LINEAR3F, VKL_LINEAR3F);
  ASSERT_EQ(OSP_AFFINE2F, VKL_AFFINE2F);
  ASSERT_EQ(OSP_AFFINE3F, VKL_AFFINE3F);
  ASSERT_EQ(OSP_RAW, VKL_RAW);
  ASSERT_EQ(OSP_BYTE, VKL_BYTE);
  ASSERT_EQ(OSP_VOID_PTR, VKL_VOID_PTR);
  ASSERT_EQ(OSP_STRING, VKL_STRING);
  ASSERT_EQ(OSP_OBJECT, VKL_OBJECT);
  // those are different object types:
  // ASSERT_EQ(OSP_VOLUME, VKL_VOLUME);
}

TEST(Enums, VKLUnstructuredCellType)
{
  ASSERT_LE(sizeof(OSPUnstructuredCellType), sizeof(VKLUnstructuredCellType));
  ASSERT_EQ(OSP_TETRAHEDRON, VKL_TETRAHEDRON);
  ASSERT_EQ(OSP_HEXAHEDRON, VKL_HEXAHEDRON);
  ASSERT_EQ(OSP_WEDGE, VKL_WEDGE);
  ASSERT_EQ(OSP_PYRAMID, VKL_PYRAMID);
}

TEST(Enums, VKLAMRMethod)
{
  ASSERT_LE(sizeof(OSPAMRMethod), sizeof(VKLAMRMethod));
  ASSERT_EQ(OSP_AMR_CURRENT, VKL_AMR_CURRENT);
  ASSERT_EQ(OSP_AMR_FINEST, VKL_AMR_FINEST);
  ASSERT_EQ(OSP_AMR_OCTANT, VKL_AMR_OCTANT);
}

TEST(Enums, VKLFilter)
{
  ASSERT_LE(sizeof(OSPVolumeFilter), sizeof(VKLFilter));
  ASSERT_EQ(OSP_VOLUME_FILTER_NEAREST, VKL_FILTER_NEAREST);
  ASSERT_EQ(OSP_VOLUME_FILTER_TRILINEAR, VKL_FILTER_TRILINEAR);
}

TEST(Enums, RTCSubdivisionMode)
{
  ASSERT_LE(sizeof(OSPSubdivisionMode), sizeof(RTCSubdivisionMode));
  ASSERT_EQ(OSP_SUBDIVISION_NO_BOUNDARY, RTC_SUBDIVISION_MODE_NO_BOUNDARY);
  ASSERT_EQ(
      OSP_SUBDIVISION_SMOOTH_BOUNDARY, RTC_SUBDIVISION_MODE_SMOOTH_BOUNDARY);
  ASSERT_EQ(OSP_SUBDIVISION_PIN_CORNERS, RTC_SUBDIVISION_MODE_PIN_CORNERS);
  ASSERT_EQ(OSP_SUBDIVISION_PIN_BOUNDARY, RTC_SUBDIVISION_MODE_PIN_BOUNDARY);
  ASSERT_EQ(OSP_SUBDIVISION_PIN_ALL, RTC_SUBDIVISION_MODE_PIN_ALL);
}
<|endoftext|>


<commit_before>//===--- TerminalReaderUnix.cpp - Input From UNIX Terminal ------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the interface reading from a UNIX terminal. It tries to
//  support all common terminal types.
//
//  Axel Naumann <axel@cern.ch>, 2011-05-12
//===----------------------------------------------------------------------===//

#ifndef WIN32

#include "textinput/StreamReaderUnix.h"

#include "textinput/TerminalConfigUnix.h"

#include <sys/uio.h>
#include <sys/select.h>
#include <unistd.h>
#include <termios.h>
#include <stdio.h>

#include <cctype>
#include <map>
#include <list>

namespace {
  using namespace textinput;

  class Rewind {
  public:
    Rewind(std::queue<char>& rab, InputData::EExtendedInput& ret):
    RAB(rab), Ret(ret) {}

    ~Rewind() {
      if (Ret != InputData::kEIUninitialized) return;
      // RAB.push(0x1b); already handled by ProcessCSI returning false.
      while (!Q.empty()) {
        RAB.push(Q.front());
        Q.pop();
      }
    }

    void push(char C) { Q.push(C); }

  private:
    std::queue<char> Q;
    std::queue<char>& RAB;
    InputData::EExtendedInput& Ret;
  };

  class ExtKeyMap {
  public:
    ExtKeyMap& operator[](char k) {
      std::map<char, ExtKeyMap*>::iterator I = Map.find(k);
      ExtKeyMap* N = 0;
      if (I == Map.end()) {
        N = &BumpAlloc();
        Map.insert(std::make_pair(k, N));
      } else {
        N = I->second;
      }
      return *N;
    }
    ExtKeyMap& operator=(InputData::EExtendedInput ei) {
      T.EI = ei; return *this; }
    void Set(InputData::EExtendedInput ei, char m = 0) {
      T.EI = ei; T.Mod = m; }

    bool empty() const { return Map.empty(); }
    bool haveSubTree() const { return !empty(); }
    bool haveExtInp() const { return empty(); }
    InputData::EExtendedInput getExtInp() const { return T.EI; }
    char getMod() const { return T.Mod; }

    ExtKeyMap* find(char c) const {
      std::map<char, ExtKeyMap*>::const_iterator I = Map.find(c);
      if (I == Map.end()) return 0;
      return I->second;
    }

    class EKMHolder {
    public:
      EKMHolder(): Watermark(kChunkSize) {}
      ~EKMHolder() {
        for (std::list<ExtKeyMap*>::iterator i = Heap.begin(), e = Heap.end();
             i != e; ++i) {
          delete [] *i;
        }
      }
      ExtKeyMap& next() {
        if (Watermark == kChunkSize) {
          ExtKeyMap* N = new ExtKeyMap[kChunkSize]();
          Heap.push_back(N);
          Watermark = 0;
        }
        return Heap.back()[Watermark++];
      }
    private:
      static const size_t kChunkSize = 100;
      std::list<ExtKeyMap*> Heap;
      size_t Watermark;
    };

    static ExtKeyMap& BumpAlloc() {
      static EKMHolder S;
      return S.next();
    }

  private:
    std::map<char, ExtKeyMap*> Map;
    struct T_ {
      T_(): EI(InputData::kEIUninitialized), Mod(0) {}
      InputData::EExtendedInput EI;
      char Mod;
    } T;
  };
} // unnamed namespace

namespace textinput {
  StreamReaderUnix::StreamReaderUnix():
    fHaveInputFocus(false), fIsTTY(isatty(fileno(stdin))) {
#ifdef TCSANOW
    TerminalConfigUnix::Get().TIOS()->c_iflag &= ~(ISTRIP|IXOFF);
    TerminalConfigUnix::Get().TIOS()->c_iflag |= BRKINT | INLCR;
    TerminalConfigUnix::Get().TIOS()->c_lflag &= ~(ICANON|ISIG|TOSTOP|IEXTEN);
    TerminalConfigUnix::Get().TIOS()->c_cc[VMIN] = 1;
    TerminalConfigUnix::Get().TIOS()->c_cc[VTIME] = 0;
#endif
  }

  StreamReaderUnix::~StreamReaderUnix() {
    ReleaseInputFocus();
  }

  void
  StreamReaderUnix::GrabInputFocus() {
    // set to raw i.e. unbuffered
    if (fHaveInputFocus) return;
    TerminalConfigUnix::Get().Attach();
    fHaveInputFocus = true;
  }

  void
  StreamReaderUnix::ReleaseInputFocus() {
    // set to buffered
    if (!fHaveInputFocus) return;
    TerminalConfigUnix::Get().Detach();
    fHaveInputFocus = false;
  }

  bool
  StreamReaderUnix::HavePendingInput() {
    if (!fReadAheadBuffer.empty())
      return true;
    fd_set PollSet;
    FD_ZERO(&PollSet);
    FD_SET(fileno(stdin), &PollSet);
    timeval timeout = {0,0}; // sec, musec
    int avail = select(fileno(stdin) /*fd*/ + 1, &PollSet, 0, 0, &timeout);
    return (avail == 1);
  }

  bool
  StreamReaderUnix::ProcessCSI(InputData& in) {
    static ExtKeyMap gExtKeyMap;
    if (gExtKeyMap.empty()) {
      // Gnome xterm
      gExtKeyMap['[']['A'] = InputData::kEIUp;
      gExtKeyMap['[']['B'] = InputData::kEIDown;
      gExtKeyMap['[']['C'] = InputData::kEIRight;
      gExtKeyMap['[']['D'] = InputData::kEILeft;
      gExtKeyMap['[']['O']['F'] = InputData::kEIEnd;
      gExtKeyMap['[']['O']['H'] = InputData::kEIHome;
      gExtKeyMap['[']['1']['~'] = InputData::kEIHome;
      gExtKeyMap['[']['2']['~'] = InputData::kEIIns;
      gExtKeyMap['[']['3']['~'] = InputData::kEIDel;
      gExtKeyMap['[']['4']['~'] = InputData::kEIEnd;
      gExtKeyMap['[']['5']['~'] = InputData::kEIPgUp;
      gExtKeyMap['[']['6']['~'] = InputData::kEIPgDown;
      gExtKeyMap['[']['1'][';']['5']['A'].Set(InputData::kEIUp,
                                         InputData::kModCtrl);
      gExtKeyMap['[']['1'][';']['5']['B'].Set(InputData::kEIDown,
                                         InputData::kModCtrl);
      gExtKeyMap['[']['1'][';']['5']['C'].Set(InputData::kEIRight,
                                         InputData::kModCtrl);
      gExtKeyMap['[']['1'][';']['5']['D'].Set(InputData::kEILeft,
                                         InputData::kModCtrl);

      // MacOS
      gExtKeyMap['O']['A'] = InputData::kEIUp;
      gExtKeyMap['O']['B'] = InputData::kEIDown;
      gExtKeyMap['O']['C'] = InputData::kEIRight;
      gExtKeyMap['O']['D'] = InputData::kEILeft;
      gExtKeyMap['O']['F'] = InputData::kEIEnd;
      gExtKeyMap['O']['H'] = InputData::kEIHome;
      gExtKeyMap['[']['5']['C'].Set(InputData::kEIRight, InputData::kModCtrl);
      gExtKeyMap['[']['5']['D'].Set(InputData::kEILeft, InputData::kModCtrl);
    }

    InputData::EExtendedInput ret = InputData::kEIUninitialized;
    char mod = 0;
    Rewind rwd(fReadAheadBuffer, ret);
    ExtKeyMap* EKM = &gExtKeyMap;
    while (EKM) {
      if (EKM->haveExtInp()) {
        ret = EKM->getExtInp();
        mod = EKM->getMod();
        EKM = 0;
      } else {
        char c1 = ReadRawCharacter();
        rwd.push(c1);
        EKM = EKM->find(c1);
      }
    }
    in.SetExtended(ret);
    in.SetModifier(mod);
    return ret != InputData::kEIUninitialized;
  }

  bool
  StreamReaderUnix::ReadInput(size_t& nRead, InputData& in) {
    int c = ReadRawCharacter();
    if (c == -1) {
      in.SetExtended(InputData::kEIEOF);
    } else if (c == 0x1b) {
      if (!ProcessCSI(in)) {
        in.SetExtended(InputData::kEIEsc);
      }
    } else if (isprint(c)) {
      in.SetRaw(c);
    } else if (c < 32 || c == (char)127 /* ^?, DEL on MacOS */) {
      if (c == 13) {
        in.SetExtended(InputData::kEIEnter);
      } else {
        in.SetRaw(c);
        in.SetModifier(InputData::kModCtrl);
      }
    } else {
      // woohoo, what's that?!
      in.SetRaw(c);
    }
    ++nRead;
    return true;
  }
  int
  StreamReaderUnix::ReadRawCharacter() {
    char buf;
    if (!fReadAheadBuffer.empty()) {
      buf = fReadAheadBuffer.front();
      fReadAheadBuffer.pop();
    } else {
       size_t ret = read(fileno(stdin), &buf, 1);
      if (ret != 1) return -1;
    }
    return buf;
  }
}

#endif // ifndef WIN32
<commit_msg>Solaris: FD_ZERO uses memset().<commit_after>//===--- TerminalReaderUnix.cpp - Input From UNIX Terminal ------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the interface reading from a UNIX terminal. It tries to
//  support all common terminal types.
//
//  Axel Naumann <axel@cern.ch>, 2011-05-12
//===----------------------------------------------------------------------===//

#ifndef WIN32

#include "textinput/StreamReaderUnix.h"

#include "textinput/TerminalConfigUnix.h"

#include <sys/uio.h>
#include <sys/select.h>
#include <unistd.h>
#include <termios.h>
#include <stdio.h>

#include <cctype>
#include <cstring>
#include <map>
#include <list>

namespace {
  using namespace textinput;
  using std::memset; // FD_ZERO

  class Rewind {
  public:
    Rewind(std::queue<char>& rab, InputData::EExtendedInput& ret):
    RAB(rab), Ret(ret) {}

    ~Rewind() {
      if (Ret != InputData::kEIUninitialized) return;
      // RAB.push(0x1b); already handled by ProcessCSI returning false.
      while (!Q.empty()) {
        RAB.push(Q.front());
        Q.pop();
      }
    }

    void push(char C) { Q.push(C); }

  private:
    std::queue<char> Q;
    std::queue<char>& RAB;
    InputData::EExtendedInput& Ret;
  };

  class ExtKeyMap {
  public:
    ExtKeyMap& operator[](char k) {
      std::map<char, ExtKeyMap*>::iterator I = Map.find(k);
      ExtKeyMap* N = 0;
      if (I == Map.end()) {
        N = &BumpAlloc();
        Map.insert(std::make_pair(k, N));
      } else {
        N = I->second;
      }
      return *N;
    }
    ExtKeyMap& operator=(InputData::EExtendedInput ei) {
      T.EI = ei; return *this; }
    void Set(InputData::EExtendedInput ei, char m = 0) {
      T.EI = ei; T.Mod = m; }

    bool empty() const { return Map.empty(); }
    bool haveSubTree() const { return !empty(); }
    bool haveExtInp() const { return empty(); }
    InputData::EExtendedInput getExtInp() const { return T.EI; }
    char getMod() const { return T.Mod; }

    ExtKeyMap* find(char c) const {
      std::map<char, ExtKeyMap*>::const_iterator I = Map.find(c);
      if (I == Map.end()) return 0;
      return I->second;
    }

    class EKMHolder {
    public:
      EKMHolder(): Watermark(kChunkSize) {}
      ~EKMHolder() {
        for (std::list<ExtKeyMap*>::iterator i = Heap.begin(), e = Heap.end();
             i != e; ++i) {
          delete [] *i;
        }
      }
      ExtKeyMap& next() {
        if (Watermark == kChunkSize) {
          ExtKeyMap* N = new ExtKeyMap[kChunkSize]();
          Heap.push_back(N);
          Watermark = 0;
        }
        return Heap.back()[Watermark++];
      }
    private:
      static const size_t kChunkSize = 100;
      std::list<ExtKeyMap*> Heap;
      size_t Watermark;
    };

    static ExtKeyMap& BumpAlloc() {
      static EKMHolder S;
      return S.next();
    }

  private:
    std::map<char, ExtKeyMap*> Map;
    struct T_ {
      T_(): EI(InputData::kEIUninitialized), Mod(0) {}
      InputData::EExtendedInput EI;
      char Mod;
    } T;
  };
} // unnamed namespace

namespace textinput {
  StreamReaderUnix::StreamReaderUnix():
    fHaveInputFocus(false), fIsTTY(isatty(fileno(stdin))) {
#ifdef TCSANOW
    TerminalConfigUnix::Get().TIOS()->c_iflag &= ~(ISTRIP|IXOFF);
    TerminalConfigUnix::Get().TIOS()->c_iflag |= BRKINT | INLCR;
    TerminalConfigUnix::Get().TIOS()->c_lflag &= ~(ICANON|ISIG|TOSTOP|IEXTEN);
    TerminalConfigUnix::Get().TIOS()->c_cc[VMIN] = 1;
    TerminalConfigUnix::Get().TIOS()->c_cc[VTIME] = 0;
#endif
  }

  StreamReaderUnix::~StreamReaderUnix() {
    ReleaseInputFocus();
  }

  void
  StreamReaderUnix::GrabInputFocus() {
    // set to raw i.e. unbuffered
    if (fHaveInputFocus) return;
    TerminalConfigUnix::Get().Attach();
    fHaveInputFocus = true;
  }

  void
  StreamReaderUnix::ReleaseInputFocus() {
    // set to buffered
    if (!fHaveInputFocus) return;
    TerminalConfigUnix::Get().Detach();
    fHaveInputFocus = false;
  }

  bool
  StreamReaderUnix::HavePendingInput() {
    if (!fReadAheadBuffer.empty())
      return true;
    fd_set PollSet;
    FD_ZERO(&PollSet);
    FD_SET(fileno(stdin), &PollSet);
    timeval timeout = {0,0}; // sec, musec
    int avail = select(fileno(stdin) /*fd*/ + 1, &PollSet, 0, 0, &timeout);
    return (avail == 1);
  }

  bool
  StreamReaderUnix::ProcessCSI(InputData& in) {
    static ExtKeyMap gExtKeyMap;
    if (gExtKeyMap.empty()) {
      // Gnome xterm
      gExtKeyMap['[']['A'] = InputData::kEIUp;
      gExtKeyMap['[']['B'] = InputData::kEIDown;
      gExtKeyMap['[']['C'] = InputData::kEIRight;
      gExtKeyMap['[']['D'] = InputData::kEILeft;
      gExtKeyMap['[']['O']['F'] = InputData::kEIEnd;
      gExtKeyMap['[']['O']['H'] = InputData::kEIHome;
      gExtKeyMap['[']['1']['~'] = InputData::kEIHome;
      gExtKeyMap['[']['2']['~'] = InputData::kEIIns;
      gExtKeyMap['[']['3']['~'] = InputData::kEIDel;
      gExtKeyMap['[']['4']['~'] = InputData::kEIEnd;
      gExtKeyMap['[']['5']['~'] = InputData::kEIPgUp;
      gExtKeyMap['[']['6']['~'] = InputData::kEIPgDown;
      gExtKeyMap['[']['1'][';']['5']['A'].Set(InputData::kEIUp,
                                         InputData::kModCtrl);
      gExtKeyMap['[']['1'][';']['5']['B'].Set(InputData::kEIDown,
                                         InputData::kModCtrl);
      gExtKeyMap['[']['1'][';']['5']['C'].Set(InputData::kEIRight,
                                         InputData::kModCtrl);
      gExtKeyMap['[']['1'][';']['5']['D'].Set(InputData::kEILeft,
                                         InputData::kModCtrl);

      // MacOS
      gExtKeyMap['O']['A'] = InputData::kEIUp;
      gExtKeyMap['O']['B'] = InputData::kEIDown;
      gExtKeyMap['O']['C'] = InputData::kEIRight;
      gExtKeyMap['O']['D'] = InputData::kEILeft;
      gExtKeyMap['O']['F'] = InputData::kEIEnd;
      gExtKeyMap['O']['H'] = InputData::kEIHome;
      gExtKeyMap['[']['5']['C'].Set(InputData::kEIRight, InputData::kModCtrl);
      gExtKeyMap['[']['5']['D'].Set(InputData::kEILeft, InputData::kModCtrl);
    }

    InputData::EExtendedInput ret = InputData::kEIUninitialized;
    char mod = 0;
    Rewind rwd(fReadAheadBuffer, ret);
    ExtKeyMap* EKM = &gExtKeyMap;
    while (EKM) {
      if (EKM->haveExtInp()) {
        ret = EKM->getExtInp();
        mod = EKM->getMod();
        EKM = 0;
      } else {
        char c1 = ReadRawCharacter();
        rwd.push(c1);
        EKM = EKM->find(c1);
      }
    }
    in.SetExtended(ret);
    in.SetModifier(mod);
    return ret != InputData::kEIUninitialized;
  }

  bool
  StreamReaderUnix::ReadInput(size_t& nRead, InputData& in) {
    int c = ReadRawCharacter();
    if (c == -1) {
      in.SetExtended(InputData::kEIEOF);
    } else if (c == 0x1b) {
      if (!ProcessCSI(in)) {
        in.SetExtended(InputData::kEIEsc);
      }
    } else if (isprint(c)) {
      in.SetRaw(c);
    } else if (c < 32 || c == (char)127 /* ^?, DEL on MacOS */) {
      if (c == 13) {
        in.SetExtended(InputData::kEIEnter);
      } else {
        in.SetRaw(c);
        in.SetModifier(InputData::kModCtrl);
      }
    } else {
      // woohoo, what's that?!
      in.SetRaw(c);
    }
    ++nRead;
    return true;
  }
  int
  StreamReaderUnix::ReadRawCharacter() {
    char buf;
    if (!fReadAheadBuffer.empty()) {
      buf = fReadAheadBuffer.front();
      fReadAheadBuffer.pop();
    } else {
       size_t ret = read(fileno(stdin), &buf, 1);
      if (ret != 1) return -1;
    }
    return buf;
  }
}

#endif // ifndef WIN32
<|endoftext|>


<commit_before>// This file is part of playd.
// playd is licensed under the MIT licence: see LICENSE.txt.

/**
 * @file
 * Implementation of the Mp3AudioSource class.
 * @see audio/sources/mp3.hpp
 */

#include <cassert>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>

extern "C" {
#include <mpg123.h>
}

#include "../../errors.hpp"
#include "../../messages.h"
#include "../audio_source.hpp"
#include "../sample_formats.hpp"
#include "mp3.hpp"

std::uint64_t Mp3AudioSource::instances = 0;

// Fix for the ancient 2010 version of mpg123 carried by Ubuntu 12.04 and pals,
// which doesn't have 24-bit support
// See http://www.mpg123.de/cgi-bin/scm/mpg123/trunk/NEWS?pathrev=2791
#if MPG123_API_VERSION < 28
// Let us be able to omit the check for 24-bit formats later.
#define HAVE_MPG123_24BIT 1

// Make the use of this when divining formats a no-op.
#define MPG123_ENC_SIGNED_24 0
#endif

// This value is somewhat arbitrary, but corresponds to the minimum buffer size
// used by ffmpeg, so it's probably sensible.
const size_t Mp3AudioSource::BUFFER_SIZE = 16384;

/* static */ std::unique_ptr<AudioSource> Mp3AudioSource::Build(const std::string &path)
{
	return std::unique_ptr<AudioSource>(new Mp3AudioSource(path));
}

Mp3AudioSource::Mp3AudioSource(const std::string &path)
    : AudioSource(path), buffer(BUFFER_SIZE), context(nullptr)
{
	if (Mp3AudioSource::instances++ == 0) mpg123_init();

	this->context = mpg123_new(nullptr, nullptr);
	mpg123_format_none(this->context);

	const long *rates = nullptr;
	size_t nrates = 0;
	mpg123_rates(&rates, &nrates);
	for (size_t r = 0; r < nrates; r++) {
		Debug() << "trying to enable formats at " << rates[r]
		        << std::endl;
		AddFormat(rates[r]);
	}

	if (mpg123_open(this->context, path.c_str()) == MPG123_ERR) {
		throw FileError("mp3: can't open " + path + ": " +
		                mpg123_strerror(this->context));
	}

	Debug() << "mp3: sample rate:" << this->SampleRate() << std::endl;
	Debug() << "mp3: bytes per sample:" << this->BytesPerSample()
	        << std::endl;
	Debug() << "mp3: channels:" << (int)this->ChannelCount() << std::endl;
	Debug() << "mp3: playd format:" << (int)this->OutputSampleFormat()
	        << std::endl;
}

Mp3AudioSource::~Mp3AudioSource()
{
	mpg123_delete(this->context);
	this->context = nullptr;

	if (--Mp3AudioSource::instances == 0) mpg123_exit();
}

void Mp3AudioSource::AddFormat(long rate)
{
	// The requested encodings correspond to the sample formats available in
	// the SampleFormat enum.
	if (mpg123_format(this->context, rate, MPG123_STEREO | MPG123_MONO,
	                  (MPG123_ENC_UNSIGNED_8 | MPG123_ENC_SIGNED_8 |
	                   MPG123_ENC_SIGNED_16 | MPG123_ENC_SIGNED_24 |
	                   MPG123_ENC_SIGNED_32 | MPG123_ENC_FLOAT_32)) ==
	    MPG123_ERR) {
		// Ignore the error for now -- another sample rate may be
		// available.
		// If no sample rates work, loading a file will fail anyway.
		Debug() << "can't support" << rate << std::endl;
	};
}

std::uint8_t Mp3AudioSource::ChannelCount() const
{
	assert(this->context != nullptr);

	int chans = 0;
	mpg123_getformat(this->context, nullptr, &chans, nullptr);
	assert(chans != 0);
	return static_cast<std::uint8_t>(chans);
}

std::uint32_t Mp3AudioSource::SampleRate() const
{
	assert(this->context != nullptr);

	long rate = 0;
	mpg123_getformat(this->context, &rate, nullptr, nullptr);

	assert(0 < rate);
	// INT32_MAX isn't a typo; if we compare against UINT32_MAX, we'll
	// set off sign-compare errors, and the sample rate shouldn't be above
	// INT32_MAX anyroad.
	assert(rate <= INT32_MAX);
	return static_cast<std::uint32_t>(rate);
}

std::uint64_t Mp3AudioSource::Seek(std::uint64_t in_samples)
{
	assert(this->context != nullptr);

	// See BytesPerSample() for an explanation of this ChannelCount().
	auto mono_samples = in_samples * this->ChannelCount();

	// Have we tried to seek past the end of the file?
	auto clen = static_cast<unsigned long>(mpg123_length(this->context));
	if (clen < mono_samples) {
		Debug() << "mp3: seek at" << mono_samples << "past EOF at"
		        << clen << std::endl;
		throw SeekError(MSG_SEEK_FAIL);
	}

	if (mpg123_seek(this->context, mono_samples, SEEK_SET) == MPG123_ERR) {
		Debug() << "mp3: seek failed:" << mpg123_strerror(this->context)
		        << std::endl;
		throw SeekError(MSG_SEEK_FAIL);
	}

	// The actual seek position may not be the same as the requested
	// position.
	// mpg123_tell gives us the exact mono-samples position.
	return mpg123_tell(this->context) / this->ChannelCount();
}

Mp3AudioSource::DecodeResult Mp3AudioSource::Decode()
{
	assert(this->context != nullptr);

	auto buf = reinterpret_cast<unsigned char *>(&this->buffer.front());
	size_t rbytes = 0;
	int err = mpg123_read(this->context, buf, this->buffer.size(), &rbytes);

	DecodeVector decoded;
	DecodeState decode_state;

	if (err == MPG123_DONE) {
		Debug() << "mp3: end of file" << std::endl;
		decode_state = DecodeState::END_OF_FILE;
	} else if (err != MPG123_OK && err != MPG123_NEW_FORMAT) {
		Debug() << "mp3: decode error:" << mpg123_strerror(this->context)
		        << std::endl;
		decode_state = DecodeState::END_OF_FILE;
	} else {
		decode_state = DecodeState::DECODING;

		// Copy only the bit of the buffer occupied by decoded data
		auto front = this->buffer.begin();
		decoded = DecodeVector(front, front + rbytes);
	}

	return std::make_pair(decode_state, decoded);
}

SampleFormat Mp3AudioSource::OutputSampleFormat() const
{
	assert(this->context != nullptr);

	int encoding = 0;
	mpg123_getformat(this->context, nullptr, nullptr, &encoding);

	switch (encoding) {
		case MPG123_ENC_UNSIGNED_8:
			return SampleFormat::PACKED_UNSIGNED_INT_8;
		case MPG123_ENC_SIGNED_8:
			return SampleFormat::PACKED_SIGNED_INT_8;
		case MPG123_ENC_SIGNED_16:
			return SampleFormat::PACKED_SIGNED_INT_16;
#ifdef HAVE_MPG123_24BIT
		case MPG123_ENC_SIGNED_24:
			return SampleFormat::PACKED_SIGNED_INT_24;
#endif
		case MPG123_ENC_SIGNED_32:
			return SampleFormat::PACKED_SIGNED_INT_32;
		case MPG123_ENC_FLOAT_32:
			return SampleFormat::PACKED_FLOAT_32;
		default:
			// We shouldn't get here, if the format was set up
			// correctly earlier.
			assert(false);
			return SampleFormat::PACKED_UNSIGNED_INT_8;
	}
}
<commit_msg>Remove 24-bit MP3 support.<commit_after>// This file is part of playd.
// playd is licensed under the MIT licence: see LICENSE.txt.

/**
 * @file
 * Implementation of the Mp3AudioSource class.
 * @see audio/sources/mp3.hpp
 */

#include <cassert>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>

extern "C" {
#include <mpg123.h>
}

#include "../../errors.hpp"
#include "../../messages.h"
#include "../audio_source.hpp"
#include "../sample_formats.hpp"
#include "mp3.hpp"

std::uint64_t Mp3AudioSource::instances = 0;

// This value is somewhat arbitrary, but corresponds to the minimum buffer size
// used by ffmpeg, so it's probably sensible.
const size_t Mp3AudioSource::BUFFER_SIZE = 16384;

/* static */ std::unique_ptr<AudioSource> Mp3AudioSource::Build(const std::string &path)
{
	return std::unique_ptr<AudioSource>(new Mp3AudioSource(path));
}

Mp3AudioSource::Mp3AudioSource(const std::string &path)
    : AudioSource(path), buffer(BUFFER_SIZE), context(nullptr)
{
	if (Mp3AudioSource::instances++ == 0) mpg123_init();

	this->context = mpg123_new(nullptr, nullptr);
	mpg123_format_none(this->context);

	const long *rates = nullptr;
	size_t nrates = 0;
	mpg123_rates(&rates, &nrates);
	for (size_t r = 0; r < nrates; r++) {
		Debug() << "trying to enable formats at " << rates[r]
		        << std::endl;
		AddFormat(rates[r]);
	}

	if (mpg123_open(this->context, path.c_str()) == MPG123_ERR) {
		throw FileError("mp3: can't open " + path + ": " +
		                mpg123_strerror(this->context));
	}

	Debug() << "mp3: sample rate:" << this->SampleRate() << std::endl;
	Debug() << "mp3: bytes per sample:" << this->BytesPerSample()
	        << std::endl;
	Debug() << "mp3: channels:" << (int)this->ChannelCount() << std::endl;
	Debug() << "mp3: playd format:" << (int)this->OutputSampleFormat()
	        << std::endl;
}

Mp3AudioSource::~Mp3AudioSource()
{
	mpg123_delete(this->context);
	this->context = nullptr;

	if (--Mp3AudioSource::instances == 0) mpg123_exit();
}

void Mp3AudioSource::AddFormat(long rate)
{
	// The requested encodings correspond to the sample formats available in
	// the SampleFormat enum.
	if (mpg123_format(this->context, rate, MPG123_STEREO | MPG123_MONO,
	                  (MPG123_ENC_UNSIGNED_8 | MPG123_ENC_SIGNED_8 |
	                   MPG123_ENC_SIGNED_16 | MPG123_ENC_SIGNED_32 | MPG123_ENC_FLOAT_32)) ==
	    MPG123_ERR) {
		// Ignore the error for now -- another sample rate may be
		// available.
		// If no sample rates work, loading a file will fail anyway.
		Debug() << "can't support" << rate << std::endl;
	};
}

std::uint8_t Mp3AudioSource::ChannelCount() const
{
	assert(this->context != nullptr);

	int chans = 0;
	mpg123_getformat(this->context, nullptr, &chans, nullptr);
	assert(chans != 0);
	return static_cast<std::uint8_t>(chans);
}

std::uint32_t Mp3AudioSource::SampleRate() const
{
	assert(this->context != nullptr);

	long rate = 0;
	mpg123_getformat(this->context, &rate, nullptr, nullptr);

	assert(0 < rate);
	// INT32_MAX isn't a typo; if we compare against UINT32_MAX, we'll
	// set off sign-compare errors, and the sample rate shouldn't be above
	// INT32_MAX anyroad.
	assert(rate <= INT32_MAX);
	return static_cast<std::uint32_t>(rate);
}

std::uint64_t Mp3AudioSource::Seek(std::uint64_t in_samples)
{
	assert(this->context != nullptr);

	// See BytesPerSample() for an explanation of this ChannelCount().
	auto mono_samples = in_samples * this->ChannelCount();

	// Have we tried to seek past the end of the file?
	auto clen = static_cast<unsigned long>(mpg123_length(this->context));
	if (clen < mono_samples) {
		Debug() << "mp3: seek at" << mono_samples << "past EOF at"
		        << clen << std::endl;
		throw SeekError(MSG_SEEK_FAIL);
	}

	if (mpg123_seek(this->context, mono_samples, SEEK_SET) == MPG123_ERR) {
		Debug() << "mp3: seek failed:" << mpg123_strerror(this->context)
		        << std::endl;
		throw SeekError(MSG_SEEK_FAIL);
	}

	// The actual seek position may not be the same as the requested
	// position.
	// mpg123_tell gives us the exact mono-samples position.
	return mpg123_tell(this->context) / this->ChannelCount();
}

Mp3AudioSource::DecodeResult Mp3AudioSource::Decode()
{
	assert(this->context != nullptr);

	auto buf = reinterpret_cast<unsigned char *>(&this->buffer.front());
	size_t rbytes = 0;
	int err = mpg123_read(this->context, buf, this->buffer.size(), &rbytes);

	DecodeVector decoded;
	DecodeState decode_state;

	if (err == MPG123_DONE) {
		Debug() << "mp3: end of file" << std::endl;
		decode_state = DecodeState::END_OF_FILE;
	} else if (err != MPG123_OK && err != MPG123_NEW_FORMAT) {
		Debug() << "mp3: decode error:" << mpg123_strerror(this->context)
		        << std::endl;
		decode_state = DecodeState::END_OF_FILE;
	} else {
		decode_state = DecodeState::DECODING;

		// Copy only the bit of the buffer occupied by decoded data
		auto front = this->buffer.begin();
		decoded = DecodeVector(front, front + rbytes);
	}

	return std::make_pair(decode_state, decoded);
}

SampleFormat Mp3AudioSource::OutputSampleFormat() const
{
	assert(this->context != nullptr);

	int encoding = 0;
	mpg123_getformat(this->context, nullptr, nullptr, &encoding);

	switch (encoding) {
		case MPG123_ENC_UNSIGNED_8:
			return SampleFormat::PACKED_UNSIGNED_INT_8;
		case MPG123_ENC_SIGNED_8:
			return SampleFormat::PACKED_SIGNED_INT_8;
		case MPG123_ENC_SIGNED_16:
			return SampleFormat::PACKED_SIGNED_INT_16;
		case MPG123_ENC_SIGNED_32:
			return SampleFormat::PACKED_SIGNED_INT_32;
		case MPG123_ENC_FLOAT_32:
			return SampleFormat::PACKED_FLOAT_32;
		default:
			// We shouldn't get here, if the format was set up
			// correctly earlier.
			assert(false);
			return SampleFormat::PACKED_UNSIGNED_INT_8;
	}
}
<|endoftext|>


<commit_before>/**
 *  @file server_2.cpp
 *  @author shae, CS5201 Section A
 *  @date Apr 27, 2016
 *  @brief Description:
 *  @details Details:
 */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>  /* define socket */
#include <netinet/in.h>  /* define internet socket */
#include <netdb.h>       /* define internet socket */

#define SERVER_PORT 9993        /* define a server port number */

int main()
{
    int sd, ns, k, pid;
    struct sockaddr_in server_addr = { AF_INET, htons( SERVER_PORT ) };
    struct sockaddr_in client_addr = { AF_INET };
    socklen_t client_len = sizeof( client_addr );
    char buf[512], *host;

    /* create a stream socket */
    if( ( sd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
    {
    perror( "server: socket failed" );
    exit( 1 );
    }

    /* bind the socket to an internet port */
    if( bind(sd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1 )
    {
    perror( "server: bind failed" );
    exit( 1 );
    }

    /* listen for clients */
    if( listen( sd, 1 ) == -1 )
    {
    perror( "server: listen failed" );
    exit( 1 );
    }

    printf("SERVER is listening for clients to establish a connection\n");

   if ( (pid=fork()) == 0 ){  /* child code begins */

    if( ( ns = accept( sd, (struct sockaddr*)&client_addr,
                       &client_len ) ) == -1 )
    {
        perror( "server: accept failed" );
        exit( 1 );
    }

    printf("Child accept() successful.. a client has connected to child ! waiting for a message\n");

    /* data transfer on connected socket ns */
    while( (k = read(ns, buf, sizeof(buf))) != 0)
    {    printf("SERVER(Child) RECEIVED: %s\n", buf);
         write(ns, buf, k);
    }
    close(ns);
    close(sd);
    }
    else {   /* Parent code */
    if( ( ns = accept( sd, (struct sockaddr*)&client_addr,
                       &client_len ) ) == -1 )
    {
        perror( "server: accept failed" );
        exit( 1 );
    }

    printf("Parent accept() successful.. a client has connected to Parent! waiting for a message\n");

    /* data transfer on connected socket ns */
    while( (k = read(ns, buf, sizeof(buf))) != 0)
    {    printf("SERVER(Parent) RECEIVED: %s\n", buf);
         write(ns, buf, k);
         write(ns, "ff", 2);
    }
    close(ns);
    close(sd);
    }

    unlink((const char*)&server_addr.sin_addr);

    return(0);
}
<commit_msg>Removed old server file<commit_after><|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2016, Microsoft

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include <array>

#include "gtest/gtest.h"

#include "BitFunnel/Index/Factories.h"
#include "BitFunnel/Index/IConfiguration.h"
#include "BitFunnel/Index/IIndexedIdfTable.h"
#include "Document.h"

namespace BitFunnel
{
    TEST(Document, ContainsTerm)
    {
        const Term::StreamId streamId = 0;
        const DocId docId = 0;
        const size_t gramSize = 1;

        auto idfTable = Factories::CreateIndexedIdfTable();
        auto config =
            Factories::CreateConfiguration(gramSize, false, *idfTable);
        Document d(*config, docId);

        std::array<char const *, 5> text {{
            "one",
            "two",
            "three",
            "four",
            "five"
         }};

        d.OpenStream(streamId);
        for (auto word : text)
        {
            d.AddTerm(word);
        }
        d.CloseStream();
        d.CloseDocument(0);

        for (auto word : text)
        {
            Term term(word, streamId, *config);
            EXPECT_TRUE(d.Contains(term));
        }

        // TODO: check other 2-grams.
        Term twoGram(text[0], streamId, *config);
        Term partTwo(text[1], streamId, *config);
        twoGram.AddTerm(partTwo, *config);
        EXPECT_FALSE(d.Contains(twoGram));

        Term unexpected("unexpected", streamId, *config);
        EXPECT_FALSE(d.Contains(unexpected));
    }

    TEST(Document, containsNGram)
    {
        const Term::StreamId streamId = 0;
        const DocId docId = 0;
        const size_t gramSize = 5;

        auto idfTable = Factories::CreateIndexedIdfTable();
        auto config =
            Factories::CreateConfiguration(gramSize, false, *idfTable);
        Document d(*config, docId);

        std::array<char const *, 5> text {{
            "one",
            "two",
            "three",
            "four",
            "five"
         }};

        d.OpenStream(streamId);
        for (auto word : text)
        {
            d.AddTerm(word);
        }
        d.CloseStream();
        d.CloseDocument(0);

        // TODO: This only checks for grams starting at [0] and doesn't check
        // other sub-grams.
        Term term(text[0], streamId, *config);
        for (size_t i = 1; i < text.size(); ++i)
        {
            Term subTerm(text[i], streamId, *config);
            term.AddTerm(subTerm, *config);
            EXPECT_TRUE(d.Contains(subTerm));
            EXPECT_TRUE(d.Contains(term));
        }

        Term unexpected("unexpected", streamId, *config);
        EXPECT_FALSE(d.Contains(unexpected));
    }
}
<commit_msg>Check all sub-n-grams.<commit_after>// The MIT License (MIT)

// Copyright (c) 2016, Microsoft

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include <array>

#include "gtest/gtest.h"

#include "BitFunnel/Index/Factories.h"
#include "BitFunnel/Index/IConfiguration.h"
#include "BitFunnel/Index/IIndexedIdfTable.h"
#include "Document.h"

namespace BitFunnel
{
    TEST(Document, ContainsTerm)
    {
        const Term::StreamId streamId = 0;
        const DocId docId = 0;
        const size_t gramSize = 1;

        auto idfTable = Factories::CreateIndexedIdfTable();
        auto config =
            Factories::CreateConfiguration(gramSize, false, *idfTable);
        Document d(*config, docId);

        std::array<char const *, 5> text {{
            "one",
            "two",
            "three",
            "four",
            "five"
         }};

        d.OpenStream(streamId);
        for (auto word : text)
        {
            d.AddTerm(word);
        }
        d.CloseStream();
        d.CloseDocument(0);

        for (auto word : text)
        {
            Term term(word, streamId, *config);
            EXPECT_TRUE(d.Contains(term));
        }

        // TODO: check other 2-grams.
        Term twoGram(text[0], streamId, *config);
        Term partTwo(text[1], streamId, *config);
        twoGram.AddTerm(partTwo, *config);
        EXPECT_FALSE(d.Contains(twoGram));

        Term unexpected("unexpected", streamId, *config);
        EXPECT_FALSE(d.Contains(unexpected));
    }

    TEST(Document, containsNGram)
    {
        const Term::StreamId streamId = 0;
        const DocId docId = 0;
        const size_t gramSize = 5;

        auto idfTable = Factories::CreateIndexedIdfTable();
        auto config =
            Factories::CreateConfiguration(gramSize, false, *idfTable);
        Document d(*config, docId);

        std::array<char const *, 5> text {{
            "one",
            "two",
            "three",
            "four",
            "five"
         }};

        d.OpenStream(streamId);
        for (auto word : text)
        {
            d.AddTerm(word);
        }
        d.CloseStream();
        d.CloseDocument(0);

        for (size_t i = 0; i < text.size(); i++)
        {
            Term term(text[i], streamId, *config);
            for (size_t j = i+1; j < text.size(); ++j)
            {
                Term subTerm(text[j], streamId, *config);
                term.AddTerm(subTerm, *config);
                EXPECT_TRUE(d.Contains(subTerm));
                EXPECT_TRUE(d.Contains(term));
            }
        }

        Term unexpected("unexpected", streamId, *config);
        EXPECT_FALSE(d.Contains(unexpected));
    }
}
<|endoftext|>


<commit_before>#include <ncurses.h>
#include <iostream>
#include <unistd.h>
#include <algorithm>

#include "display/Screen.h"
#include "display/Window.h"
#include "display/WindowManager.h"
#include "map/Level.h"
#include "map/filters/DrunkardsWalkFilter.h"
#include "actor/Actor.h"
#include "core/Rand.h"

void pause_curses(Screen& screen)
{
	screen.pause();

	std::cout << "Paused ncurses..." << std::endl;

	sleep(4);

	std::cout << "Resuming..." << std::endl;

	sleep(1);
}

bool move_pc(Actor& pc, Level& level, int& pc_x, int& pc_y, int dx, int dy)
{
	int new_x = pc_x + dx;
	int new_y = pc_y + dy;

	//Make sure it's in bounds
	if(0 <= new_x && new_x < level.getWidth() && 0 <= new_y && new_y < level.getHeight())
	{
		//Make sure it's passable terrain
		if(level[new_x][new_y].isPassable())
		{
			//Remove the PC from its old position
			level[pc_x][pc_y].removeActor();

			//Adjust PC's x,y coordinates
			pc_x += dx;
			pc_y += dy;

			//Place the PC at the new x,y coordinates
			level[pc_x][pc_y].addActor(&pc);

			return true;
		}
	}
	return false;
}

void spawn_npc(Actor& npc, Level& level, int& npc_x, int& npc_y, int pc_x, int pc_y, int max_dist = 35)
{
	Rand rand(time(NULL));

	int min_x = std::max(0, pc_x - max_dist);
	int max_x = std::min(level.getWidth()-1, pc_x + max_dist);

	int min_y = std::max(0, pc_y - max_dist);
	int max_y = std::min(level.getHeight()-1, pc_y + max_dist);

	do {
		npc_x = rand.randInt(min_x, max_x);
		npc_y = rand.randInt(min_y, max_y);
	} while(level[npc_x][npc_y] != FloorTile);
	level[npc_x][npc_y].addActor(&npc);
}

int main()
{
	Screen screen;

	int screen_y = screen.getHeight();
	int screen_x = screen.getWidth();

	//Make a map double the screen size
	int map_y = screen_y * 2;
	int map_x = screen_x * 2;
	//Generate a map
	Level cave(map_x, map_y);
	DrunkardsWalkFilter walk;
	walk.setSeed(time(NULL));
	walk.apply(cave);
	//Find a random FloorTile to put our PC on
	int pc_x, pc_y;
	Actor pc('@', "PC", 0x01);
	Rand rand(time(NULL));
	do {
		pc_x = rand.randInt(0, cave.getWidth()-1);
		pc_y = rand.randInt(0, cave.getHeight()-1);
	} while(cave[pc_x][pc_y] != FloorTile);
	cave[pc_x][pc_y].addActor(&pc);
	//Now put the map into our map window...
	Window level_window(&cave);
	//...and create a viewport looking into it.
	Window map(&level_window, screen_x-20, screen_y-3, 20, 3);

	Window top(screen_x, 3, 0, 0);
	Window left(20, screen_y-2, 0, 2);

	top.addBorder();
	left.addBorder();
	//map.addBorder(); //Dare I try it?
	//Push our windows into our WindowManager
	WindowManager wm;
	wm.addWindow(&top);
	wm.addWindow(&left);
	wm.addWindow(&map);

	wm.getWindow(0)->add(1, 0, "Message Panel");
	wm.getWindow(1)->add(1, 0, "Stat Panel");

	//Center the map viewport on the PC
	map.center(pc_x, pc_y);

	//Let's display some map display stats
	//Display our view's X and Y coordinates
	wm.getWindow(1)->add(1, 2, "View Position:");
	wm.getWindow(1)->add(1, 3, "X:     ");
	wm.getWindow(1)->addInt(4, 3, map.getViewX());
	wm.getWindow(1)->add(1, 4, "Y:     ");
	wm.getWindow(1)->addInt(4, 4, map.getViewY());

	//Display map size
	wm.getWindow(1)->add(1, 6, "Map Size:");
	wm.getWindow(1)->add(1, 7, "W:");
	wm.getWindow(1)->addInt(4, 7, cave.getWidth());
	wm.getWindow(1)->add(1, 8, "H:");
	wm.getWindow(1)->addInt(4, 8, cave.getHeight());

	//Display viewport size
	wm.getWindow(1)->add(1, 9, "View Size:");
	wm.getWindow(1)->add(1, 10, "W:");
	wm.getWindow(1)->addInt(4, 10, map.getViewWidth());
	wm.getWindow(1)->add(1, 11, "H:");
	wm.getWindow(1)->addInt(4, 11, map.getViewHeight());

	//Display PC's location
	wm.getWindow(1)->add(1, 12, "PC Position:");
	wm.getWindow(1)->add(1, 13, "X:     ");
	wm.getWindow(1)->addInt(4, 13, pc_x);
	wm.getWindow(1)->add(1, 14, "Y:     ");
	wm.getWindow(1)->addInt(4, 14, pc_y);

	//Find a random FloorTile to put our kobold on
	int npc_x, npc_y;
	Actor npc('k', "kobold", 0x00);
	spawn_npc(npc, cave, npc_x, npc_y, pc_x, pc_y, 50);

	//Now display everything
	wm.refresh();

	//Now we enter the "game loop"
	int ch;
	int key_pos = 8;
	int last_key_pos;
	int dx, dy;
	int pc_dx, pc_dy;
	bool run = true;
	while(run)
	{
		ch = getch();

		//Display the key code
		wm.getWindow(0)->add(key_pos, 1, "                                    ");
		wm.getWindow(0)->addInt(key_pos, 1, ch);

		dx = 0;
		dy = 0;
		pc_dx = 0;
		pc_dy = 0;

		wm.getWindow(0)->add(1, 1, "     ");
		last_key_pos = key_pos;
		key_pos = 8;
		switch(ch)
		{
			//Viewport movement
			case KEY_UP:
				wm.getWindow(0)->add(1, 1, "Up");
				dy = -1;
				break;
			case KEY_DOWN:
				wm.getWindow(0)->add(1, 1, "Down");
				dy = 1;
				break;
			case KEY_LEFT:
				wm.getWindow(0)->add(1, 1, "Left");
				dx = -1;
				break;
			case KEY_RIGHT:
				wm.getWindow(0)->add(1, 1, "Right");
				dx = 1;
				break;
			//Orthogonal movement
			case '8':
			case 'k':
				pc_dx = 0;
				pc_dy = -1;
				break;
			case '2':
			case 'j':
				pc_dx = 0;
				pc_dy = 1;
				break;
			case '4':
			case 'h':
				pc_dx = -1;
				pc_dy = 0;
				break;
			case '6':
			case 'l':
				pc_dx = 1;
				pc_dy = 0;
				break;
			//Diagonal movement
			case '7':
			case 'y':
				pc_dx = -1;
				pc_dy = -1;
				break;
			case '9':
			case 'u':
				pc_dx = 1;
				pc_dy = -1;
				break;
			case '1':
			case 'b':
				pc_dx = -1;
				pc_dy = 1;
				break;
			case '3':
			case 'n':
				pc_dx = 1;
				pc_dy = 1;
				break;
			//Other commands
			case 'c':
			case 'C':
				//Center the view on the PC
				wm.getWindow(2)->center(pc_x, pc_y);
				break;
			case 'p':
			case 'P':
				//Pause ncurses (just a useless demo of the ability)
				pause_curses(screen);
				break;
			case 'q':
			case 'Q':
				//Quit
				run = false;
				break;
			default:
				key_pos = last_key_pos + 4;
				if(key_pos > wm.getWindow(0)->getWidth())
				{
					key_pos = 8;
				}
				break;
		}

		//Move the PC
		if(pc_dx != 0 || pc_dy != 0)
		{
			move_pc(pc, cave, pc_x, pc_y, pc_dx, pc_dy);
		}

		//If the PC "killed" the kobold, spawn another
		if(npc_x == pc_x && npc_y == pc_y)
		{
			spawn_npc(npc, cave, npc_x, npc_y, pc_x, pc_y);
		}

		//Move the viewport
		map.moveBy(dx, dy);

		//Display our view's X and Y coordinates
		wm.getWindow(1)->add(1, 3, "X:     ");
		wm.getWindow(1)->addInt(4, 3, map.getViewX());
		wm.getWindow(1)->add(1, 4, "Y:     ");
		wm.getWindow(1)->addInt(4, 4, map.getViewY());

		//Re-display PC's position
		wm.getWindow(1)->add(1, 13, "X:     ");
		wm.getWindow(1)->addInt(4, 13, pc_x);
		wm.getWindow(1)->add(1, 14, "Y:     ");
		wm.getWindow(1)->addInt(4, 14, pc_y);

		//Display NPC's position
		wm.getWindow(1)->add(1, 15, "NPC Position:");
		wm.getWindow(1)->add(1, 16, "X:     ");
		wm.getWindow(1)->addInt(4, 16, npc_x);
		wm.getWindow(1)->add(1, 17, "Y:     ");
		wm.getWindow(1)->addInt(4, 17, npc_y);

		//Refresh the display
		wm.refresh();
	}
}
<commit_msg>Re-implemented "kill the kobold" as it was.<commit_after>#include <ncurses.h>
#include <iostream>
#include <unistd.h>
#include <algorithm>

#include "display/Screen.h"
#include "display/Window.h"
#include "display/WindowManager.h"
#include "map/Level.h"
#include "map/filters/DrunkardsWalkFilter.h"
#include "actor/Actor.h"
#include "core/Rand.h"

void pause_curses(Screen& screen)
{
	screen.pause();

	std::cout << "Paused ncurses..." << std::endl;

	sleep(4);

	std::cout << "Resuming..." << std::endl;

	sleep(1);
}

bool fight_npc(Actor& pc, Actor& npc, Window* msg_win)
{
	msg_win->add(1, 1, "There was a FIREFIGHT!");

	return true;
}

bool move_pc(Actor& pc, Level& level, int& pc_x, int& pc_y, int dx, int dy)
{
	int new_x = pc_x + dx;
	int new_y = pc_y + dy;

	//Make sure it's in bounds
	if(0 <= new_x && new_x < level.getWidth() && 0 <= new_y && new_y < level.getHeight())
	{
		//Make sure it's passable terrain
		if(level[new_x][new_y].isPassable())
		{
			//Remove the PC from its old position
			level[pc_x][pc_y].removeActor();

			//Adjust PC's x,y coordinates
			pc_x += dx;
			pc_y += dy;

			//Place the PC at the new x,y coordinates
			level[pc_x][pc_y].addActor(&pc);

			return true;
		}
	}
	return false;
}

void spawn_npc(Actor& npc, Level& level, int& npc_x, int& npc_y, int pc_x, int pc_y, int max_dist = 35)
{
	Rand rand(time(NULL));

	int min_x = std::max(0, pc_x - max_dist);
	int max_x = std::min(level.getWidth()-1, pc_x + max_dist);

	int min_y = std::max(0, pc_y - max_dist);
	int max_y = std::min(level.getHeight()-1, pc_y + max_dist);

	do {
		npc_x = rand.randInt(min_x, max_x);
		npc_y = rand.randInt(min_y, max_y);
	} while(level[npc_x][npc_y] != FloorTile);
	level[npc_x][npc_y].addActor(&npc);
}

int main()
{
	Screen screen;

	int screen_y = screen.getHeight();
	int screen_x = screen.getWidth();

	//Make a map double the screen size
	int map_y = screen_y * 2;
	int map_x = screen_x * 2;
	//Generate a map
	Level cave(map_x, map_y);
	DrunkardsWalkFilter walk;
	walk.setSeed(time(NULL));
	walk.apply(cave);
	//Find a random FloorTile to put our PC on
	int pc_x, pc_y;
	Actor pc('@', "PC", 0x01);
	Rand rand(time(NULL));
	do {
		pc_x = rand.randInt(0, cave.getWidth()-1);
		pc_y = rand.randInt(0, cave.getHeight()-1);
	} while(cave[pc_x][pc_y] != FloorTile);
	cave[pc_x][pc_y].addActor(&pc);
	//Now put the map into our map window...
	Window level_window(&cave);
	//...and create a viewport looking into it.
	Window map(&level_window, screen_x-20, screen_y-3, 20, 3);

	Window top(screen_x, 3, 0, 0);
	Window left(20, screen_y-2, 0, 2);

	top.addBorder();
	left.addBorder();
	//map.addBorder(); //Dare I try it?
	//Push our windows into our WindowManager
	WindowManager wm;
	wm.addWindow(&top);
	wm.addWindow(&left);
	wm.addWindow(&map);

	wm.getWindow(0)->add(1, 0, "Message Panel");
	wm.getWindow(1)->add(1, 0, "Stat Panel");

	//Center the map viewport on the PC
	map.center(pc_x, pc_y);

	//Let's display some map display stats
	//Display our view's X and Y coordinates
	wm.getWindow(1)->add(1, 2, "View Position:");
	wm.getWindow(1)->add(1, 3, "X:     ");
	wm.getWindow(1)->addInt(4, 3, map.getViewX());
	wm.getWindow(1)->add(1, 4, "Y:     ");
	wm.getWindow(1)->addInt(4, 4, map.getViewY());

	//Display map size
	wm.getWindow(1)->add(1, 6, "Map Size:");
	wm.getWindow(1)->add(1, 7, "W:");
	wm.getWindow(1)->addInt(4, 7, cave.getWidth());
	wm.getWindow(1)->add(1, 8, "H:");
	wm.getWindow(1)->addInt(4, 8, cave.getHeight());

	//Display viewport size
	wm.getWindow(1)->add(1, 9, "View Size:");
	wm.getWindow(1)->add(1, 10, "W:");
	wm.getWindow(1)->addInt(4, 10, map.getViewWidth());
	wm.getWindow(1)->add(1, 11, "H:");
	wm.getWindow(1)->addInt(4, 11, map.getViewHeight());

	//Display PC's location
	wm.getWindow(1)->add(1, 12, "PC Position:");
	wm.getWindow(1)->add(1, 13, "X:     ");
	wm.getWindow(1)->addInt(4, 13, pc_x);
	wm.getWindow(1)->add(1, 14, "Y:     ");
	wm.getWindow(1)->addInt(4, 14, pc_y);

	//Find a random FloorTile to put our kobold on
	int npc_x, npc_y;
	Actor npc('k', "kobold", 0x00);
	spawn_npc(npc, cave, npc_x, npc_y, pc_x, pc_y, 50);

	//Now display everything
	wm.refresh();

	//Now we enter the "game loop"
	int ch;
	int key_pos = 8;
	int last_key_pos;
	int dx, dy;
	int pc_dx, pc_dy;
	bool run = true;
	while(run)
	{
		ch = getch();

		//Display the key code
		wm.getWindow(0)->add(key_pos, 1, "                                    ");
		wm.getWindow(0)->addInt(key_pos, 1, ch);

		dx = 0;
		dy = 0;
		pc_dx = 0;
		pc_dy = 0;

		wm.getWindow(0)->add(1, 1, "     ");
		last_key_pos = key_pos;
		key_pos = 8;
		switch(ch)
		{
			//Viewport movement
			case KEY_UP:
				wm.getWindow(0)->add(1, 1, "Up");
				dy = -1;
				break;
			case KEY_DOWN:
				wm.getWindow(0)->add(1, 1, "Down");
				dy = 1;
				break;
			case KEY_LEFT:
				wm.getWindow(0)->add(1, 1, "Left");
				dx = -1;
				break;
			case KEY_RIGHT:
				wm.getWindow(0)->add(1, 1, "Right");
				dx = 1;
				break;
			//Orthogonal movement
			case '8':
			case 'k':
				pc_dx = 0;
				pc_dy = -1;
				break;
			case '2':
			case 'j':
				pc_dx = 0;
				pc_dy = 1;
				break;
			case '4':
			case 'h':
				pc_dx = -1;
				pc_dy = 0;
				break;
			case '6':
			case 'l':
				pc_dx = 1;
				pc_dy = 0;
				break;
			//Diagonal movement
			case '7':
			case 'y':
				pc_dx = -1;
				pc_dy = -1;
				break;
			case '9':
			case 'u':
				pc_dx = 1;
				pc_dy = -1;
				break;
			case '1':
			case 'b':
				pc_dx = -1;
				pc_dy = 1;
				break;
			case '3':
			case 'n':
				pc_dx = 1;
				pc_dy = 1;
				break;
			//Other commands
			case 'c':
			case 'C':
				//Center the view on the PC
				wm.getWindow(2)->center(pc_x, pc_y);
				break;
			case 'p':
			case 'P':
				//Pause ncurses (just a useless demo of the ability)
				pause_curses(screen);
				break;
			case 'q':
			case 'Q':
				//Quit
				run = false;
				break;
			default:
				key_pos = last_key_pos + 4;
				if(key_pos > wm.getWindow(0)->getWidth())
				{
					key_pos = 8;
				}
				break;
		}

		if(pc_dx != 0 || pc_dy != 0)
		{
			//Test if the NPC is there
			if(cave[pc_x + pc_dx][pc_y + pc_dy].isOccupied())
			{
				//FIGHT!
				if(fight_npc(pc, npc, wm.getWindow(0)))
				{
					//Kobold is dead, remove it from the map and spawn another
					cave[pc_x + pc_dx][pc_y + pc_dy].removeActor();
					spawn_npc(npc, cave, npc_x, npc_y, pc_x, pc_y);
				}
			} else {
				//Move the PC
				move_pc(pc, cave, pc_x, pc_y, pc_dx, pc_dy);
			}
		}

		//Move the viewport
		map.moveBy(dx, dy);

		//Display our view's X and Y coordinates
		wm.getWindow(1)->add(1, 3, "X:     ");
		wm.getWindow(1)->addInt(4, 3, map.getViewX());
		wm.getWindow(1)->add(1, 4, "Y:     ");
		wm.getWindow(1)->addInt(4, 4, map.getViewY());

		//Re-display PC's position
		wm.getWindow(1)->add(1, 13, "X:     ");
		wm.getWindow(1)->addInt(4, 13, pc_x);
		wm.getWindow(1)->add(1, 14, "Y:     ");
		wm.getWindow(1)->addInt(4, 14, pc_y);

		//Display NPC's position
		wm.getWindow(1)->add(1, 15, "NPC Position:");
		wm.getWindow(1)->add(1, 16, "X:     ");
		wm.getWindow(1)->addInt(4, 16, npc_x);
		wm.getWindow(1)->add(1, 17, "Y:     ");
		wm.getWindow(1)->addInt(4, 17, npc_y);

		//Refresh the display
		wm.refresh();
	}
}
<|endoftext|>