<commit_before>#include "archive.hh"
#include "pool.hh"
#include "remote-store.hh"
#include "serve-protocol.hh"
#include "store-api.hh"
#include "worker-protocol.hh"
#include "ssh.hh"
#include "derivations.hh"

namespace nix {

static std::string uriScheme = "ssh://";

struct LegacySSHStore : public Store
{
    const Setting<int> maxConnections{this, 1, "max-connections", "maximum number of concurrent SSH connections"};
    const Setting<Path> sshKey{this, "", "ssh-key", "path to an SSH private key"};
    const Setting<bool> compress{this, false, "compress", "whether to compress the connection"};
    const Setting<Path> remoteProgram{this, "nix-store", "remote-program", "path to the nix-store executable on the remote system"};
    const Setting<std::string> remoteStore{this, "", "remote-store", "URI of the store on the remote system"};

    // Hack for getting remote build log output.
    const Setting<int> logFD{this, -1, "log-fd", "file descriptor to which SSH's stderr is connected"};

    struct Connection
    {
        std::unique_ptr<SSHMaster::Connection> sshConn;
        FdSink to;
        FdSource from;
        int remoteVersion;
        bool good = true;
    };

    std::string host;

    ref<Pool<Connection>> connections;

    SSHMaster master;

    LegacySSHStore(const string & host, const Params & params)
        : Store(params)
        , host(host)
        , connections(make_ref<Pool<Connection>>(
            std::max(1, (int) maxConnections),
            [this]() { return openConnection(); },
            [](const ref<Connection> & r) { return r->good; }
            ))
        , master(
            host,
            sshKey,
            // Use SSH master only if using more than 1 connection.
            connections->capacity() > 1,
            compress,
            logFD)
    {
    }

    ref<Connection> openConnection()
    {
        auto conn = make_ref<Connection>();
        conn->sshConn = master.startCommand(
            fmt("%s --serve --write", remoteProgram)
            + (remoteStore.get() == "" ? "" : " --store " + shellEscape(remoteStore.get())));
        conn->to = FdSink(conn->sshConn->in.get());
        conn->from = FdSource(conn->sshConn->out.get());

        try {
            conn->to << SERVE_MAGIC_1 << SERVE_PROTOCOL_VERSION;
            conn->to.flush();

            unsigned int magic = readInt(conn->from);
            if (magic != SERVE_MAGIC_2)
                throw Error("protocol mismatch with 'nix-store --serve' on '%s'", host);
            conn->remoteVersion = readInt(conn->from);
            if (GET_PROTOCOL_MAJOR(conn->remoteVersion) != 0x200)
                throw Error("unsupported 'nix-store --serve' protocol version on '%s'", host);

        } catch (EndOfFile & e) {
            throw Error("cannot connect to '%1%'", host);
        }

        return conn;
    };

    string getUri() override
    {
        return uriScheme + host;
    }

    void queryPathInfoUncached(const StorePath & path,
        Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override
    {
        try {
            auto conn(connections->get());

            debug("querying remote host '%s' for info on '%s'", host, printStorePath(path));

            conn->to << cmdQueryPathInfos << PathSet{printStorePath(path)};
            conn->to.flush();

            auto p = readString(conn->from);
            if (p.empty()) return callback(nullptr);
            auto info = std::make_shared<ValidPathInfo>(parseStorePath(p));
            assert(path == info->path);

            PathSet references;
            auto deriver = readString(conn->from);
            if (deriver != "")
                info->deriver = parseStorePath(deriver);
            info->references = readStorePaths<StorePathSet>(*this, conn->from);
            readLongLong(conn->from); // download size
            info->narSize = readLongLong(conn->from);

            if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 4) {
                auto s = readString(conn->from);
                info->narHash = s.empty() ? std::optional<Hash>{} : Hash::parseAnyPrefixed(s);
                info->ca = parseContentAddressOpt(readString(conn->from));
                info->sigs = readStrings<StringSet>(conn->from);
            }

            auto s = readString(conn->from);
            assert(s == "");

            callback(std::move(info));
        } catch (...) { callback.rethrow(); }
    }

    void addToStore(const ValidPathInfo & info, Source & source,
        RepairFlag repair, CheckSigsFlag checkSigs) override
    {
        debug("adding path '%s' to remote host '%s'", printStorePath(info.path), host);

        auto conn(connections->get());

        if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 5) {

            conn->to
                << cmdAddToStoreNar
                << printStorePath(info.path)
                << (info.deriver ? printStorePath(*info.deriver) : "")
                << info.narHash->to_string(Base16, false);
            writeStorePaths(*this, conn->to, info.references);
            conn->to
                << info.registrationTime
                << info.narSize
                << info.ultimate
                << info.sigs
                << renderContentAddress(info.ca);
            try {
                copyNAR(source, conn->to);
            } catch (...) {
                conn->good = false;
                throw;
            }
            conn->to.flush();

        } else {

            conn->to
                << cmdImportPaths
                << 1;
            try {
                copyNAR(source, conn->to);
            } catch (...) {
                conn->good = false;
                throw;
            }
            conn->to
                << exportMagic
                << printStorePath(info.path);
            writeStorePaths(*this, conn->to, info.references);
            conn->to
                << (info.deriver ? printStorePath(*info.deriver) : "")
                << 0
                << 0;
            conn->to.flush();

        }

        if (readInt(conn->from) != 1)
            throw Error("failed to add path '%s' to remote host '%s'", printStorePath(info.path), host);
    }

    void narFromPath(const StorePath & path, Sink & sink) override
    {
        auto conn(connections->get());

        conn->to << cmdDumpStorePath << printStorePath(path);
        conn->to.flush();
        copyNAR(conn->from, sink);
    }

    std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
    { unsupported("queryPathFromHashPart"); }

    StorePath addToStore(const string & name, const Path & srcPath,
        FileIngestionMethod method, HashType hashAlgo,
        PathFilter & filter, RepairFlag repair) override
    { unsupported("addToStore"); }

    StorePath addTextToStore(const string & name, const string & s,
        const StorePathSet & references, RepairFlag repair) override
    { unsupported("addTextToStore"); }

    BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
        BuildMode buildMode) override
    {
        auto conn(connections->get());

        conn->to
            << cmdBuildDerivation
            << printStorePath(drvPath);
        writeDerivation(conn->to, *this, drv);
        conn->to
            << settings.maxSilentTime
            << settings.buildTimeout;
        if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 2)
            conn->to
                << settings.maxLogSize;
        if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 3)
            conn->to
                << settings.buildRepeat
                << settings.enforceDeterminism;

        conn->to.flush();

        BuildResult status;
        status.status = (BuildResult::Status) readInt(conn->from);
        conn->from >> status.errorMsg;

        if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 3)
            conn->from >> status.timesBuilt >> status.isNonDeterministic >> status.startTime >> status.stopTime;

        return status;
    }

    void ensurePath(const StorePath & path) override
    { unsupported("ensurePath"); }

    void computeFSClosure(const StorePathSet & paths,
        StorePathSet & out, bool flipDirection = false,
        bool includeOutputs = false, bool includeDerivers = false) override
    {
        if (flipDirection || includeDerivers) {
            Store::computeFSClosure(paths, out, flipDirection, includeOutputs, includeDerivers);
            return;
        }

        auto conn(connections->get());

        conn->to
            << cmdQueryClosure
            << includeOutputs;
        writeStorePaths(*this, conn->to, paths);
        conn->to.flush();

        for (auto & i : readStorePaths<StorePathSet>(*this, conn->from))
            out.insert(i);
    }

    StorePathSet queryValidPaths(const StorePathSet & paths,
        SubstituteFlag maybeSubstitute = NoSubstitute) override
    {
        auto conn(connections->get());

        conn->to
            << cmdQueryValidPaths
            << false // lock
            << maybeSubstitute;
        writeStorePaths(*this, conn->to, paths);
        conn->to.flush();

        return readStorePaths<StorePathSet>(*this, conn->from);
    }

    void connect() override
    {
        auto conn(connections->get());
    }

    unsigned int getProtocol() override
    {
        auto conn(connections->get());
        return conn->remoteVersion;
    }
};

static RegisterStoreImplementation regStore([](
    const std::string & uri, const Store::Params & params)
    -> std::shared_ptr<Store>
{
    if (std::string(uri, 0, uriScheme.size()) != uriScheme) return 0;
    return std::make_shared<LegacySSHStore>(std::string(uri, uriScheme.size()), params);
});

}
<commit_msg>Define `LegacySSHStore::buildPaths` using `cmdBuildPaths`<commit_after>#include "archive.hh"
#include "pool.hh"
#include "remote-store.hh"
#include "serve-protocol.hh"
#include "store-api.hh"
#include "worker-protocol.hh"
#include "ssh.hh"
#include "derivations.hh"

namespace nix {

static std::string uriScheme = "ssh://";

struct LegacySSHStore : public Store
{
    const Setting<int> maxConnections{this, 1, "max-connections", "maximum number of concurrent SSH connections"};
    const Setting<Path> sshKey{this, "", "ssh-key", "path to an SSH private key"};
    const Setting<bool> compress{this, false, "compress", "whether to compress the connection"};
    const Setting<Path> remoteProgram{this, "nix-store", "remote-program", "path to the nix-store executable on the remote system"};
    const Setting<std::string> remoteStore{this, "", "remote-store", "URI of the store on the remote system"};

    // Hack for getting remote build log output.
    const Setting<int> logFD{this, -1, "log-fd", "file descriptor to which SSH's stderr is connected"};

    struct Connection
    {
        std::unique_ptr<SSHMaster::Connection> sshConn;
        FdSink to;
        FdSource from;
        int remoteVersion;
        bool good = true;
    };

    std::string host;

    ref<Pool<Connection>> connections;

    SSHMaster master;

    LegacySSHStore(const string & host, const Params & params)
        : Store(params)
        , host(host)
        , connections(make_ref<Pool<Connection>>(
            std::max(1, (int) maxConnections),
            [this]() { return openConnection(); },
            [](const ref<Connection> & r) { return r->good; }
            ))
        , master(
            host,
            sshKey,
            // Use SSH master only if using more than 1 connection.
            connections->capacity() > 1,
            compress,
            logFD)
    {
    }

    ref<Connection> openConnection()
    {
        auto conn = make_ref<Connection>();
        conn->sshConn = master.startCommand(
            fmt("%s --serve --write", remoteProgram)
            + (remoteStore.get() == "" ? "" : " --store " + shellEscape(remoteStore.get())));
        conn->to = FdSink(conn->sshConn->in.get());
        conn->from = FdSource(conn->sshConn->out.get());

        try {
            conn->to << SERVE_MAGIC_1 << SERVE_PROTOCOL_VERSION;
            conn->to.flush();

            unsigned int magic = readInt(conn->from);
            if (magic != SERVE_MAGIC_2)
                throw Error("protocol mismatch with 'nix-store --serve' on '%s'", host);
            conn->remoteVersion = readInt(conn->from);
            if (GET_PROTOCOL_MAJOR(conn->remoteVersion) != 0x200)
                throw Error("unsupported 'nix-store --serve' protocol version on '%s'", host);

        } catch (EndOfFile & e) {
            throw Error("cannot connect to '%1%'", host);
        }

        return conn;
    };

    string getUri() override
    {
        return uriScheme + host;
    }

    void queryPathInfoUncached(const StorePath & path,
        Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override
    {
        try {
            auto conn(connections->get());

            debug("querying remote host '%s' for info on '%s'", host, printStorePath(path));

            conn->to << cmdQueryPathInfos << PathSet{printStorePath(path)};
            conn->to.flush();

            auto p = readString(conn->from);
            if (p.empty()) return callback(nullptr);
            auto info = std::make_shared<ValidPathInfo>(parseStorePath(p));
            assert(path == info->path);

            PathSet references;
            auto deriver = readString(conn->from);
            if (deriver != "")
                info->deriver = parseStorePath(deriver);
            info->references = readStorePaths<StorePathSet>(*this, conn->from);
            readLongLong(conn->from); // download size
            info->narSize = readLongLong(conn->from);

            if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 4) {
                auto s = readString(conn->from);
                info->narHash = s.empty() ? std::optional<Hash>{} : Hash::parseAnyPrefixed(s);
                info->ca = parseContentAddressOpt(readString(conn->from));
                info->sigs = readStrings<StringSet>(conn->from);
            }

            auto s = readString(conn->from);
            assert(s == "");

            callback(std::move(info));
        } catch (...) { callback.rethrow(); }
    }

    void addToStore(const ValidPathInfo & info, Source & source,
        RepairFlag repair, CheckSigsFlag checkSigs) override
    {
        debug("adding path '%s' to remote host '%s'", printStorePath(info.path), host);

        auto conn(connections->get());

        if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 5) {

            conn->to
                << cmdAddToStoreNar
                << printStorePath(info.path)
                << (info.deriver ? printStorePath(*info.deriver) : "")
                << info.narHash->to_string(Base16, false);
            writeStorePaths(*this, conn->to, info.references);
            conn->to
                << info.registrationTime
                << info.narSize
                << info.ultimate
                << info.sigs
                << renderContentAddress(info.ca);
            try {
                copyNAR(source, conn->to);
            } catch (...) {
                conn->good = false;
                throw;
            }
            conn->to.flush();

        } else {

            conn->to
                << cmdImportPaths
                << 1;
            try {
                copyNAR(source, conn->to);
            } catch (...) {
                conn->good = false;
                throw;
            }
            conn->to
                << exportMagic
                << printStorePath(info.path);
            writeStorePaths(*this, conn->to, info.references);
            conn->to
                << (info.deriver ? printStorePath(*info.deriver) : "")
                << 0
                << 0;
            conn->to.flush();

        }

        if (readInt(conn->from) != 1)
            throw Error("failed to add path '%s' to remote host '%s'", printStorePath(info.path), host);
    }

    void narFromPath(const StorePath & path, Sink & sink) override
    {
        auto conn(connections->get());

        conn->to << cmdDumpStorePath << printStorePath(path);
        conn->to.flush();
        copyNAR(conn->from, sink);
    }

    std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
    { unsupported("queryPathFromHashPart"); }

    StorePath addToStore(const string & name, const Path & srcPath,
        FileIngestionMethod method, HashType hashAlgo,
        PathFilter & filter, RepairFlag repair) override
    { unsupported("addToStore"); }

    StorePath addTextToStore(const string & name, const string & s,
        const StorePathSet & references, RepairFlag repair) override
    { unsupported("addTextToStore"); }

private:

    void putBuildSettings(Connection & conn)
    {
        conn.to
            << settings.maxSilentTime
            << settings.buildTimeout;
        if (GET_PROTOCOL_MINOR(conn.remoteVersion) >= 2)
            conn.to
                << settings.maxLogSize;
        if (GET_PROTOCOL_MINOR(conn.remoteVersion) >= 3)
            conn.to
                << settings.buildRepeat
                << settings.enforceDeterminism;
    }

public:

    BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
        BuildMode buildMode) override
    {
        auto conn(connections->get());

        conn->to
            << cmdBuildDerivation
            << printStorePath(drvPath);
        writeDerivation(conn->to, *this, drv);

        putBuildSettings(*conn);

        conn->to.flush();

        BuildResult status;
        status.status = (BuildResult::Status) readInt(conn->from);
        conn->from >> status.errorMsg;

        if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 3)
            conn->from >> status.timesBuilt >> status.isNonDeterministic >> status.startTime >> status.stopTime;

        return status;
    }

    void buildPaths(const std::vector<StorePathWithOutputs> & drvPaths, BuildMode buildMode) override
    {
        auto conn(connections->get());

        conn->to << cmdBuildPaths;
        Strings ss;
        for (auto & p : drvPaths)
            ss.push_back(p.to_string(*this));
        conn->to << ss;

        putBuildSettings(*conn);

        conn->to.flush();

        BuildResult result;
        result.status = (BuildResult::Status) readInt(conn->from);

        if (!result.success()) {
            conn->from >> result.errorMsg;
            throw Error(result.status, result.errorMsg);
        }
    }

    void ensurePath(const StorePath & path) override
    { unsupported("ensurePath"); }

    void computeFSClosure(const StorePathSet & paths,
        StorePathSet & out, bool flipDirection = false,
        bool includeOutputs = false, bool includeDerivers = false) override
    {
        if (flipDirection || includeDerivers) {
            Store::computeFSClosure(paths, out, flipDirection, includeOutputs, includeDerivers);
            return;
        }

        auto conn(connections->get());

        conn->to
            << cmdQueryClosure
            << includeOutputs;
        writeStorePaths(*this, conn->to, paths);
        conn->to.flush();

        for (auto & i : readStorePaths<StorePathSet>(*this, conn->from))
            out.insert(i);
    }

    StorePathSet queryValidPaths(const StorePathSet & paths,
        SubstituteFlag maybeSubstitute = NoSubstitute) override
    {
        auto conn(connections->get());

        conn->to
            << cmdQueryValidPaths
            << false // lock
            << maybeSubstitute;
        writeStorePaths(*this, conn->to, paths);
        conn->to.flush();

        return readStorePaths<StorePathSet>(*this, conn->from);
    }

    void connect() override
    {
        auto conn(connections->get());
    }

    unsigned int getProtocol() override
    {
        auto conn(connections->get());
        return conn->remoteVersion;
    }
};

static RegisterStoreImplementation regStore([](
    const std::string & uri, const Store::Params & params)
    -> std::shared_ptr<Store>
{
    if (std::string(uri, 0, uriScheme.size()) != uriScheme) return 0;
    return std::make_shared<LegacySSHStore>(std::string(uri, uriScheme.size()), params);
});

}
<|endoftext|>


<commit_before>/*
 * Unit tests for the TTBuffer Object for Jamoma DSP
 * Copyright © 2012, Nathan Wolek
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTBuffer.h"

TTErr TTBuffer::test(TTValue& returnedTestInfo)
{
	int					errorCount = 0;
	int					testAssertionCount = 0;
	//int					badSampleCount = 0;

	// *** Tim's old list (we'll get there) ***
	// TODO: test filling with sine wave
	// TODO: test scaling (applying gain)
	// TODO: test normalizing (with optional arg, and also without an optional arg)

    this->init(1,"myFirstBuffer");
	this->setAttributeValue("lengthInSamples", 50);

	TTTestLog("\nTest checkout of first SampleMatrix...");

	// TEST 1: checking out a matrix returns something
	TTSampleMatrixPtr myFirstCheckOut = NULL;
	this->checkOutMatrix(myFirstCheckOut);

	TTBoolean result1 = { myFirstCheckOut != NULL };

	TTTestAssertion("checkOutMatrix returns a valid pointer",
					result1,
					testAssertionCount,
					errorCount);

	// TEST 2: how many channels does this matrix have?
	TTInt32 test2expect = 1;

	TTInt32 test2return = 0;
	myFirstCheckOut->getAttributeValue("numChannels", test2return);

	TTBoolean result2 = { test2expect == test2return };

	TTTestAssertion("numChannels is set properly",
					result2,
					testAssertionCount,
					errorCount);

	if(!result2)
	{
		TTTestLog("Expected a value of %i, but returned value was %i", test2expect, test2return);
	}

	// TEST 3: what is the user count?
	TTInt32 test3expect = 1;

	TTInt32 test3return = 0;
	myFirstCheckOut->getAttributeValue("userCount", test3return);

	TTBoolean result3 = { test2expect == test3return };

	TTTestAssertion("userCount reports proper value",
					result3,
					testAssertionCount,
					errorCount);

	if(!result3)
	{
		TTTestLog("Expected a value of %i, but returned value was %i", test3expect, test3return);
	}

	// TEST 4: what is the buffer stage?
	TTBoolean test4expect = true;

	TTBoolean test4return = false;
	test4return = myFirstCheckOut->isBufferPoolStage(kSM_Active);

	TTBoolean result4 = { test4expect == test4return };

	TTTestAssertion("bufferPoolStage reports proper value",
					result4,
					testAssertionCount,
					errorCount);

	if(!result4)
	{
		TTTestLog("Expected a value of %i, but returned value was %i", test4expect, test4return);
	}

	TTTestLog("\nTest second checkout of first SampleMatrix...");

	// TEST 5: checking out a matrix returns something
	TTSampleMatrixPtr myFirstCheckOut2 = NULL;
	this->checkOutMatrix(myFirstCheckOut2);

	TTBoolean result5 = { myFirstCheckOut == myFirstCheckOut2 };

	TTTestAssertion("checkOutMatrix returns the same pointer",
					result5,
					testAssertionCount,
					errorCount);

    // TEST 6: what is the user count after 2 checkouts?
	TTInt32 test6expect = 2;

	TTInt32 test6return = 0;
	myFirstCheckOut->getAttributeValue("userCount", test6return);

	TTBoolean result6 = { test6expect == test6return };

	TTTestAssertion("userCount reports proper value after second checkout",
					result6,
					testAssertionCount,
					errorCount);

	if(!result6)
	{
		TTTestLog("Expected a value of %i, but returned value was %i", test6expect, test6return);
	}

	TTTestLog("\nTest if changing lengthInSamples attribute spawns new SampleMatrix...");

	// TEST 7: changing length at TTBuffer should spawn a new matrix
	TTSampleMatrixPtr mySecondCheckOut = NULL;
	this->setAttributeValue("lengthInSamples", 100);
	this->checkOutMatrix(mySecondCheckOut);

	TTBoolean result7 = { mySecondCheckOut != myFirstCheckOut };

	TTTestAssertion("checkOutMatrix returns pointer to different SampleMatrix",
					result7,
					testAssertionCount,
					errorCount);

	// TEST 8: what is the user count on new checkout?
	TTInt32 test8expect = 1;

	TTInt32 test8return = 0;
	mySecondCheckOut->getAttributeValue("userCount", test8return);

	TTBoolean result8 = { test8expect == test8return };

	TTTestAssertion("userCount reports proper value",
					result8,
					testAssertionCount,
					errorCount);

	if(!result8)
	{
		TTTestLog("Expected a value of %i, but returned value was %i", test8expect, test8return);
	}

	TTTestLog("\nRepeat with numChannels attribute...");

	// TEST 9: changing numChannels at TTBuffer should spawn a new matrix
	TTSampleMatrixPtr myThirdCheckOut = NULL;
	this->setAttributeValue("numChannels", 2);
	this->checkOutMatrix(myThirdCheckOut);

	TTBoolean result9 = { mySecondCheckOut != myThirdCheckOut && myFirstCheckOut != myThirdCheckOut};

	TTTestAssertion("checkOutMatrix returns pointer to different SampleMatrix",
					result9,
					testAssertionCount,
					errorCount);

	// TEST 10: what is the user count on new checkout?
	TTInt32 test10expect = 1;

	TTInt32 test10return = 0;
	myThirdCheckOut->getAttributeValue("userCount", test10return);

	TTBoolean result10 = { test10expect == test10return };

	TTTestAssertion("userCount reports proper value",
					result10,
					testAssertionCount,
					errorCount);

	if(!result10)
	{
		TTTestLog("Expected a value of %i, but returned value was %i", test10expect, test10return);
	}

	/******/
	TTTestLog("\nAt this point, 3 SampleMatrix objects are checked out via 4 pointers:");
	TTTestLog("myFirstCheckOut: userCount %i, Active %i, Becoming Idle %i", myFirstCheckOut->getUserCount(), myFirstCheckOut->isBufferPoolStage(kSM_Active), myFirstCheckOut->isBufferPoolStage(kSM_BecomingIdle));
	TTTestLog("myFirstCheckOut2: userCount %i, Active %i, Becoming Idle %i", myFirstCheckOut2->getUserCount(), myFirstCheckOut2->isBufferPoolStage(kSM_Active), myFirstCheckOut2->isBufferPoolStage(kSM_BecomingIdle));
	TTTestLog("mySecondCheckOut: userCount %i, Active %i, Becoming Idle %i", mySecondCheckOut->getUserCount(), mySecondCheckOut->isBufferPoolStage(kSM_Active), mySecondCheckOut->isBufferPoolStage(kSM_BecomingIdle));
	TTTestLog("myThirdCheckOut: userCount %i, Active %i, Becoming Idle %i", myThirdCheckOut->getUserCount(), myThirdCheckOut->isBufferPoolStage(kSM_Active), myThirdCheckOut->isBufferPoolStage(kSM_BecomingIdle));
	/******/

	TTTestLog("\nTesting check in process...");

	// TEST 11: checking out a matrix returns NULL pointer
	this->checkInMatrix(myFirstCheckOut);

	TTBoolean result11 = { myFirstCheckOut == NULL };

	TTTestAssertion("checkInMatrix(myFirstCheckOut) resets pointer to NULL",
					result11,
					testAssertionCount,
					errorCount);

	// TEST 12: second pointer to first matrix is still valid
	TTBoolean result12 = { myFirstCheckOut2 != NULL };

	TTTestAssertion("myFirstCheckOut2 is still a valid pointer",
					result12,
					testAssertionCount,
					errorCount);

	// TEST 13: poke/peek a sample into first matrix
	TTSampleValue test13expect = TTRandom64();
	myFirstCheckOut2->poke(10,0,test13expect);

	TTSampleValue test13return;
	myFirstCheckOut2->peek(10,0,test13return);

	TTBoolean result13 = TTTestFloatEquivalence(test13expect,test13return);

	TTTestAssertion("poke/peek sample value still works",
					result13,
					testAssertionCount,
					errorCount);

	if(!result13)
	{
		TTTestLog("Expected a value of %i, but returned value was %i", test13expect, test13return);
	}

	// TEST 14: checking out a matrix returns NULL pointer
	this->checkInMatrix(myFirstCheckOut2);

	TTBoolean result14 = { myFirstCheckOut2 == NULL };

	TTTestAssertion("checkInMatrix(myFirstCheckOut2) resets pointer to NULL",
					result14,
					testAssertionCount,
					errorCount);

	// TEST 15: checking out a matrix returns NULL pointer
	this->checkInMatrix(mySecondCheckOut);

	TTBoolean result15 = { mySecondCheckOut == NULL };

	TTTestAssertion("checkInMatrix(mySecondCheckOut) resets pointer to NULL",
					result15,
					testAssertionCount,
					errorCount);

	// TEST 16: checking out a matrix returns NULL pointer
	this->checkInMatrix(myThirdCheckOut);

	TTBoolean result16 = { myThirdCheckOut == NULL };

	TTTestAssertion("checkInMatrix(myThirdCheckOut) resets pointer to NULL",
					result16,
					testAssertionCount,
					errorCount);

	// The following is effectively taken care of through check in...
	//TTObjectRelease(&myFirstCheckOut);
	//TTObjectRelease(&mySecondCheckOut);
	//TTObjectRelease(&myThirdCheckOut);

	// Wrap up the test results to pass back to whoever called this test
	return TTTestFinish(testAssertionCount, errorCount, returnedTestInfo);

}

<commit_msg>TTBuffer: unit test fix for problem (caught using static analysis in clang) where the test could crash if object instantiation failed.<commit_after>/*
 * Unit tests for the TTBuffer Object for Jamoma DSP
 * Copyright © 2012, Nathan Wolek
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTBuffer.h"

TTErr TTBuffer::test(TTValue& returnedTestInfo)
{
	int					errorCount = 0;
	int					testAssertionCount = 0;
	//int					badSampleCount = 0;

	// *** Tim's old list (we'll get there) ***
	// TODO: test filling with sine wave
	// TODO: test scaling (applying gain)
	// TODO: test normalizing (with optional arg, and also without an optional arg)

    this->init(1,"myFirstBuffer");
	this->setAttributeValue("lengthInSamples", 50);

	TTTestLog("\nTest checkout of first SampleMatrix...");

	// TEST 1: checking out a matrix returns something
	TTSampleMatrixPtr myFirstCheckOut = NULL;
	this->checkOutMatrix(myFirstCheckOut);

	TTBoolean result1 = { myFirstCheckOut != NULL };

	TTTestAssertion("checkOutMatrix returns a valid pointer",
					result1,
					testAssertionCount,
					errorCount);

	// if it failed then we need to abort further testing to avoid a crash dereferencing a bogus pointer
	if (!myFirstCheckOut)
		return TTTestFinish(testAssertionCount, errorCount, returnedTestInfo);

	// TEST 2: how many channels does this matrix have?
	TTInt32 test2expect = 1;

	TTInt32 test2return = 0;
	myFirstCheckOut->getAttributeValue("numChannels", test2return);

	TTBoolean result2 = { test2expect == test2return };

	TTTestAssertion("numChannels is set properly",
					result2,
					testAssertionCount,
					errorCount);

	if(!result2)
	{
		TTTestLog("Expected a value of %i, but returned value was %i", test2expect, test2return);
	}

	// TEST 3: what is the user count?
	TTInt32 test3expect = 1;

	TTInt32 test3return = 0;
	myFirstCheckOut->getAttributeValue("userCount", test3return);

	TTBoolean result3 = { test2expect == test3return };

	TTTestAssertion("userCount reports proper value",
					result3,
					testAssertionCount,
					errorCount);

	if(!result3)
	{
		TTTestLog("Expected a value of %i, but returned value was %i", test3expect, test3return);
	}

	// TEST 4: what is the buffer stage?
	TTBoolean test4expect = true;

	TTBoolean test4return = false;
	test4return = myFirstCheckOut->isBufferPoolStage(kSM_Active);

	TTBoolean result4 = { test4expect == test4return };

	TTTestAssertion("bufferPoolStage reports proper value",
					result4,
					testAssertionCount,
					errorCount);

	if(!result4)
	{
		TTTestLog("Expected a value of %i, but returned value was %i", test4expect, test4return);
	}

	TTTestLog("\nTest second checkout of first SampleMatrix...");

	// TEST 5: checking out a matrix returns something
	TTSampleMatrixPtr myFirstCheckOut2 = NULL;
	this->checkOutMatrix(myFirstCheckOut2);

	TTBoolean result5 = { myFirstCheckOut == myFirstCheckOut2 };

	TTTestAssertion("checkOutMatrix returns the same pointer",
					result5,
					testAssertionCount,
					errorCount);

    // TEST 6: what is the user count after 2 checkouts?
	TTInt32 test6expect = 2;

	TTInt32 test6return = 0;
	myFirstCheckOut->getAttributeValue("userCount", test6return);

	TTBoolean result6 = { test6expect == test6return };

	TTTestAssertion("userCount reports proper value after second checkout",
					result6,
					testAssertionCount,
					errorCount);

	if(!result6)
	{
		TTTestLog("Expected a value of %i, but returned value was %i", test6expect, test6return);
	}

	TTTestLog("\nTest if changing lengthInSamples attribute spawns new SampleMatrix...");

	// TEST 7: changing length at TTBuffer should spawn a new matrix
	TTSampleMatrixPtr mySecondCheckOut = NULL;
	this->setAttributeValue("lengthInSamples", 100);
	this->checkOutMatrix(mySecondCheckOut);

	TTBoolean result7 = { mySecondCheckOut != myFirstCheckOut };

	TTTestAssertion("checkOutMatrix returns pointer to different SampleMatrix",
					result7,
					testAssertionCount,
					errorCount);

	// TEST 8: what is the user count on new checkout?
	TTInt32 test8expect = 1;

	TTInt32 test8return = 0;
	mySecondCheckOut->getAttributeValue("userCount", test8return);

	TTBoolean result8 = { test8expect == test8return };

	TTTestAssertion("userCount reports proper value",
					result8,
					testAssertionCount,
					errorCount);

	if(!result8)
	{
		TTTestLog("Expected a value of %i, but returned value was %i", test8expect, test8return);
	}

	TTTestLog("\nRepeat with numChannels attribute...");

	// TEST 9: changing numChannels at TTBuffer should spawn a new matrix
	TTSampleMatrixPtr myThirdCheckOut = NULL;
	this->setAttributeValue("numChannels", 2);
	this->checkOutMatrix(myThirdCheckOut);

	TTBoolean result9 = { mySecondCheckOut != myThirdCheckOut && myFirstCheckOut != myThirdCheckOut};

	TTTestAssertion("checkOutMatrix returns pointer to different SampleMatrix",
					result9,
					testAssertionCount,
					errorCount);

	// TEST 10: what is the user count on new checkout?
	TTInt32 test10expect = 1;

	TTInt32 test10return = 0;
	myThirdCheckOut->getAttributeValue("userCount", test10return);

	TTBoolean result10 = { test10expect == test10return };

	TTTestAssertion("userCount reports proper value",
					result10,
					testAssertionCount,
					errorCount);

	if(!result10)
	{
		TTTestLog("Expected a value of %i, but returned value was %i", test10expect, test10return);
	}

	/******/
	TTTestLog("\nAt this point, 3 SampleMatrix objects are checked out via 4 pointers:");
	TTTestLog("myFirstCheckOut: userCount %i, Active %i, Becoming Idle %i", myFirstCheckOut->getUserCount(), myFirstCheckOut->isBufferPoolStage(kSM_Active), myFirstCheckOut->isBufferPoolStage(kSM_BecomingIdle));
	TTTestLog("myFirstCheckOut2: userCount %i, Active %i, Becoming Idle %i", myFirstCheckOut2->getUserCount(), myFirstCheckOut2->isBufferPoolStage(kSM_Active), myFirstCheckOut2->isBufferPoolStage(kSM_BecomingIdle));
	TTTestLog("mySecondCheckOut: userCount %i, Active %i, Becoming Idle %i", mySecondCheckOut->getUserCount(), mySecondCheckOut->isBufferPoolStage(kSM_Active), mySecondCheckOut->isBufferPoolStage(kSM_BecomingIdle));
	TTTestLog("myThirdCheckOut: userCount %i, Active %i, Becoming Idle %i", myThirdCheckOut->getUserCount(), myThirdCheckOut->isBufferPoolStage(kSM_Active), myThirdCheckOut->isBufferPoolStage(kSM_BecomingIdle));
	/******/

	TTTestLog("\nTesting check in process...");

	// TEST 11: checking out a matrix returns NULL pointer
	this->checkInMatrix(myFirstCheckOut);

	TTBoolean result11 = { myFirstCheckOut == NULL };

	TTTestAssertion("checkInMatrix(myFirstCheckOut) resets pointer to NULL",
					result11,
					testAssertionCount,
					errorCount);

	// TEST 12: second pointer to first matrix is still valid
	TTBoolean result12 = { myFirstCheckOut2 != NULL };

	TTTestAssertion("myFirstCheckOut2 is still a valid pointer",
					result12,
					testAssertionCount,
					errorCount);

	// TEST 13: poke/peek a sample into first matrix
	TTSampleValue test13expect = TTRandom64();
	myFirstCheckOut2->poke(10,0,test13expect);

	TTSampleValue test13return;
	myFirstCheckOut2->peek(10,0,test13return);

	TTBoolean result13 = TTTestFloatEquivalence(test13expect,test13return);

	TTTestAssertion("poke/peek sample value still works",
					result13,
					testAssertionCount,
					errorCount);

	if(!result13)
	{
		TTTestLog("Expected a value of %i, but returned value was %i", test13expect, test13return);
	}

	// TEST 14: checking out a matrix returns NULL pointer
	this->checkInMatrix(myFirstCheckOut2);

	TTBoolean result14 = { myFirstCheckOut2 == NULL };

	TTTestAssertion("checkInMatrix(myFirstCheckOut2) resets pointer to NULL",
					result14,
					testAssertionCount,
					errorCount);

	// TEST 15: checking out a matrix returns NULL pointer
	this->checkInMatrix(mySecondCheckOut);

	TTBoolean result15 = { mySecondCheckOut == NULL };

	TTTestAssertion("checkInMatrix(mySecondCheckOut) resets pointer to NULL",
					result15,
					testAssertionCount,
					errorCount);

	// TEST 16: checking out a matrix returns NULL pointer
	this->checkInMatrix(myThirdCheckOut);

	TTBoolean result16 = { myThirdCheckOut == NULL };

	TTTestAssertion("checkInMatrix(myThirdCheckOut) resets pointer to NULL",
					result16,
					testAssertionCount,
					errorCount);

	// The following is effectively taken care of through check in...
	//TTObjectRelease(&myFirstCheckOut);
	//TTObjectRelease(&mySecondCheckOut);
	//TTObjectRelease(&myThirdCheckOut);

	// Wrap up the test results to pass back to whoever called this test
	return TTTestFinish(testAssertionCount, errorCount, returnedTestInfo);

}

<|endoftext|>


<commit_before>// Copyright (C) 2016 xaizek <xaizek@openmailbox.org>
//
// This file is part of uncov.
//
// uncov is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// uncov 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with uncov.  If not, see <http://www.gnu.org/licenses/>.

#ifndef UNCOVER__REPOSITORY_HPP__
#define UNCOVER__REPOSITORY_HPP__

#include <string>
#include <unordered_set>

struct git_repository;
struct git_tree;

class LibGitUser
{
public:
    LibGitUser();
    LibGitUser(const LibGitUser &rhs) = delete;
    LibGitUser &operator=(const LibGitUser &rhs) = delete;
    ~LibGitUser();
};

class Repository
{
    template <typename T>
    class GitObjPtr;

public:
    explicit Repository(const std::string &path);
    Repository(const Repository &rhs) = delete;
    Repository &operator=(const Repository &rhs) = delete;
    ~Repository();

public:
    std::string getGitPath() const;
    std::string resolveRef(const std::string &ref) const;
    std::unordered_set<std::string> listFiles(const std::string &ref) const;
    std::string readFile(const std::string &ref, const std::string &path) const;

private:
    GitObjPtr<git_tree> getRefRoot(const std::string &ref) const;

public:
    git_repository *repo;
    const LibGitUser libgitUser;
};

#endif // UNCOVER__REPOSITORY_HPP__
<commit_msg>Fix spacing bit in Repository.hpp<commit_after>// Copyright (C) 2016 xaizek <xaizek@openmailbox.org>
//
// This file is part of uncov.
//
// uncov is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// uncov 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with uncov.  If not, see <http://www.gnu.org/licenses/>.

#ifndef UNCOVER__REPOSITORY_HPP__
#define UNCOVER__REPOSITORY_HPP__

#include <string>
#include <unordered_set>

struct git_repository;
struct git_tree;

class LibGitUser
{
public:
    LibGitUser();
    LibGitUser(const LibGitUser &rhs) = delete;
    LibGitUser & operator=(const LibGitUser &rhs) = delete;
    ~LibGitUser();
};

class Repository
{
    template <typename T>
    class GitObjPtr;

public:
    explicit Repository(const std::string &path);
    Repository(const Repository &rhs) = delete;
    Repository & operator=(const Repository &rhs) = delete;
    ~Repository();

public:
    std::string getGitPath() const;
    std::string resolveRef(const std::string &ref) const;
    std::unordered_set<std::string> listFiles(const std::string &ref) const;
    std::string readFile(const std::string &ref, const std::string &path) const;

private:
    GitObjPtr<git_tree> getRefRoot(const std::string &ref) const;

public:
    git_repository *repo;
    const LibGitUser libgitUser;
};

#endif // UNCOVER__REPOSITORY_HPP__
<|endoftext|>


<commit_before>/*
 *1006:   Biorhythms
 *
 *Description:
 *Some people believe that there are three cycles in a person's life that start the day he or she is born.
 *These three cycles are the physical, emotional, and intellectual cycles, and they have periods of lengths
 *23, 28, and 33 days, respectively. There is one peak in each period of a cycle. At the peak of a cycle,
 *a person performs at his or her best in the corresponding field (physical, emotional or mental). For example,
 *if it is the mental curve, thought processes will be sharper and concentration will be easier. Since the
 *three cycles have different periods, the peaks of the three cycles generally occur at different times. We
 *would like to determine when a triple peak occurs (the peaks of all three cycles occur in the same day) for
 *any person. For each cycle, you will be given the number of days from the beginning of the current year at
 *which one of its peaks (not necessarily the first) occurs. You will also be given a date expressed as the
 *number of days from the beginning of the current year. You task is to determine the number of days from the
 *given date to the next triple peak. The given date is not counted. For example, if the given date is 10 and
 *the next triple peak occurs on day 12, the answer is 2, not 3. If a triple peak occurs on the given date, you
 *should give the number of days to the next occurrence of a triple peak.
 *
 *Input:
 *You will be given a number of cases. The input for each case consists of one line of four integers p, e, i,
 *and d. The values p, e, and i are the number of days from the beginning of the current year at which the
 *physical, emotional, and intellectual cycles peak, respectively. The value d is the given date and may be
 *smaller than any of p, e, or i. All values are non-negative and at most 365, and you may assume that a triple
 *peak will occur within 21252 days of the given date. The end of input is indicated by a line in which p = e
 *= i = d = -1.
 *Output:
 *For each test case, print the case number followed by a message indicating the number of days to the next triple
 *peak, in the form:
 *Case 1: the next triple peak occurs in 1234 days.
 *Use the plural form ``days'' even if the answer is 1.
 *
 *Sample Input:
 *   0 0 0 0
 *   0 0 0 100
 *   5 20 34 325
 *   4 5 6 7
 *   283 102 23 320
 *   203 301 203 40
 *   -1 -1 -1 -1
 *Sample Output:
 *   Case 1: the next triple peak occurs in 21252 days.
 *   Case 2: the next triple peak occurs in 21152 days.
 *   Case 3: the next triple peak occurs in 19575 days.
 *   Case 4: the next triple peak occurs in 16994 days.
 *   Case 5: the next triple peak occurs in 8910 days.
 *   Case 6: the next triple peak occurs in 10789 days.
 **************************************************************************************************************
 *Particularly,notice the following edge cases:
 *   24 29 34 0    (The answer should be 1)
 *   24 29 34 1    (The answer should be 21252)
*/

#include <iostream>
using std::cin;
using std::cout;
using std::endl;

struct Case
{
	int p, e, i, d;
};

bool is_end(Case input)
{
	if (input.p == -1 && input.e == -1 && input.i == -1 && input.d == -1)
		return true;
	else
		return false;
}

int ocurrance(Case input)
{
	int m;
	unsigned occur;
	//d+occur=i+33*m=e+28*n=p+23*l, ocr>0
	//Get the minimun of min to keep occur positive
	m = (input.d - input.i) > 0 ?(input.d - input.i) / 33 + 1 :
	                             (input.d - input.i) / 33;  //Do not neglect negative integral divisions
	for (; m < 28 * 23; ++m)
	{
		if ((input.i + 33 * m - input.e) % 28 == 0
			&& (input.i + 33 * m - input.p) % 23 == 0)
		{
			occur = (input.i - input.d + 33 * m);
			if (occur == 0)                         //Get the NEXT one
				return 23 * 28 * 33;
			else
				return occur;
		}
	}
	return (23 * 28 * 33 + input.i - input.d);
}

int main()
{
	Case CaseVal;
	int cnt = 1;
	while (cin >> CaseVal.p >> CaseVal.e >> CaseVal.i >> CaseVal.d)
	{
		if (is_end(CaseVal))
			return 0;
		else
		{
			cout << "Case " << cnt << ": the next triple peak occurs in "
				<< ocurrance(CaseVal) << " days." << endl;
			++cnt;
		}
	}
	return 0;
}
<commit_msg>Update 1006_Biorhythms.cpp<commit_after>/*
 *1006:   Biorhythms
 *
 *Description:
 *Some people believe that there are three cycles in a person's life that start the day he or she is born.
 *These three cycles are the physical, emotional, and intellectual cycles, and they have periods of lengths
 *23, 28, and 33 days, respectively. There is one peak in each period of a cycle. At the peak of a cycle,
 *a person performs at his or her best in the corresponding field (physical, emotional or mental). For example,
 *if it is the mental curve, thought processes will be sharper and concentration will be easier. Since the
 *three cycles have different periods, the peaks of the three cycles generally occur at different times. We
 *would like to determine when a triple peak occurs (the peaks of all three cycles occur in the same day) for
 *any person. For each cycle, you will be given the number of days from the beginning of the current year at
 *which one of its peaks (not necessarily the first) occurs. You will also be given a date expressed as the
 *number of days from the beginning of the current year. You task is to determine the number of days from the
 *given date to the next triple peak. The given date is not counted. For example, if the given date is 10 and
 *the next triple peak occurs on day 12, the answer is 2, not 3. If a triple peak occurs on the given date, you
 *should give the number of days to the next occurrence of a triple peak.
 *
 *Input:
 *You will be given a number of cases. The input for each case consists of one line of four integers p, e, i,
 *and d. The values p, e, and i are the number of days from the beginning of the current year at which the
 *physical, emotional, and intellectual cycles peak, respectively. The value d is the given date and may be
 *smaller than any of p, e, or i. All values are non-negative and at most 365, and you may assume that a triple
 *peak will occur within 21252 days of the given date. The end of input is indicated by a line in which p = e
 *= i = d = -1.
 *Output:
 *For each test case, print the case number followed by a message indicating the number of days to the next triple
 *peak, in the form:
 *Case 1: the next triple peak occurs in 1234 days.
 *Use the plural form ``days'' even if the answer is 1.
 *
 *Sample Input:
 *   0 0 0 0
 *   0 0 0 100
 *   5 20 34 325
 *   4 5 6 7
 *   283 102 23 320
 *   203 301 203 40
 *   -1 -1 -1 -1
 *Sample Output:
 *   Case 1: the next triple peak occurs in 21252 days.
 *   Case 2: the next triple peak occurs in 21152 days.
 *   Case 3: the next triple peak occurs in 19575 days.
 *   Case 4: the next triple peak occurs in 16994 days.
 *   Case 5: the next triple peak occurs in 8910 days.
 *   Case 6: the next triple peak occurs in 10789 days.
 **************************************************************************************************************
 *Particularly,notice the following edge cases:
 *   24 29 34 0    (The answer should be 1)
 *   24 29 34 1    (The answer should be 21252)
*/

#include <iostream>
using std::cin;
using std::cout;
using std::endl;

struct Case
{
	int p, e, i, d;
};

bool is_end(const Case &input) const
{
	if (input.p == -1 && input.e == -1 && input.i == -1 && input.d == -1)
		return true;
	else
		return false;
}

int ocurrance(Case input)
{
	int m;
	unsigned occur;
	//d+occur=i+33*m=e+28*n=p+23*l, ocr>0
	//Get the minimun of min to keep occur positive
	m = (input.d - input.i) > 0 ?(input.d - input.i) / 33 + 1 :
	                             (input.d - input.i) / 33;  //Do not neglect negative integral divisions
	for (; m < 28 * 23; ++m)
	{
		if ((input.i + 33 * m - input.e) % 28 == 0
			&& (input.i + 33 * m - input.p) % 23 == 0)
		{
			occur = (input.i - input.d + 33 * m);
			if (occur == 0)                         //Get the NEXT one
				return 23 * 28 * 33;
			else
				return occur;
		}
	}
	return (23 * 28 * 33 + input.i - input.d);
}

int main()
{
	Case CaseVal;
	int cnt = 1;
	while (cin >> CaseVal.p >> CaseVal.e >> CaseVal.i >> CaseVal.d)
	{
		if (is_end(CaseVal))
			return 0;
		else
		{
			cout << "Case " << cnt << ": the next triple peak occurs in "
				<< ocurrance(CaseVal) << " days." << endl;
			++cnt;
		}
	}
	return 0;
}
<|endoftext|>


<commit_before>// AATreePlayground.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <stdexcept>
#include <cstdint>
#include <cassert>
#include <algorithm>
#include <chrono>
#include <iostream>
#include <vector>
#include <functional>

#include "SplayHeap.h"
#include "ListHeap.h"

static const size_t HEAP_SIZE = 1024 * 1024 * 32; // 32MB heap
static const size_t ALLOC_SIZE = 1024;
static const size_t CHUNKS = HEAP_SIZE / 16;

static const size_t RUNS = 5;
static const size_t WARMUP_RUNS = 2;

const char * const GetTypeString(const ListHeap&)
{
	return "ListHeap";
}

const char * const GetTypeString(const SplayHeap&)
{
	return "SplayHeap";
}

template <typename T>
void PureAllocationBenchmark(T& heap)
{
	std::vector<DefraggablePointerControlBlock> blas;
	blas.reserve(CHUNKS / 2);

	auto pre_benchmark = [&](){};

	auto benchmark = [&]()
	{
		// Allocate ALLOC_SIZES until we fail
		while (auto alloc = heap.Allocate(ALLOC_SIZE))
			blas.push_back(std::move(alloc));

	};

	auto post_benchmark = [&]()
	{
		// Return all allocated data to the heap
		for (auto &i : blas)
			heap.Free(i);

		// Clear blas
		blas.clear();
	};

	// Do two warmup runs of the benchmark
	for (auto i = 0U; i < WARMUP_RUNS; i++)
	{
		pre_benchmark();
		benchmark();
		post_benchmark();
	}

	// Run the actual benchmark
	std::vector<size_t> time_log;
	for (auto i = 0U; i < RUNS; i++)
	{
		pre_benchmark();

		auto start_time = std::chrono::high_resolution_clock::now();

		benchmark();

		auto end_time = std::chrono::high_resolution_clock::now();

		time_log.push_back(std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count());

		post_benchmark();
	}

	// Display results
	std::cout << "----- Pure Allocation Benchmark -----" << std::endl << std::endl;;
	std::cout << std::endl << "Heap Type: " << GetTypeString(heap) << std::endl << std::endl;

	for (auto i = 0U; i < RUNS; i++)
		std::cout << "Run " << i << ": " << time_log[i] << "ns" << std::endl << std::endl;

	size_t sum = 0;
	for (auto i : time_log)
		sum += i;
	sum /= RUNS;

	std::cout << "Average : " << sum << "ns" << std::endl << std::endl;

	std::cout << "-------------------------------------" << std::endl << std::endl;
}

template <typename T>
void FullDefragBenchmark(T& heap)
{
	std::vector<DefraggablePointerControlBlock> blas;
	blas.reserve(CHUNKS / 2);

	auto pre_benchmark = [&]()
	{
		// Allocate ALLOC_SIZES until we fail
		while (auto alloc = heap.Allocate(ALLOC_SIZE))
			blas.push_back(std::move(alloc));

		// Free every second block to maximize fragmentation
		size_t c = 0;
		for (auto& i : blas)
		{
			if ((c & 1) == 0)
			{
				heap.Free(i);
			}

			c++;
		}
	};

	auto benchmark = [&]()
	{
		heap.FullDefrag();
	};

	auto post_benchmark = [&]()
	{
		// Return all allocated data to the heap
		size_t c = 0;
		for (auto &i : blas)
		{
			if ((i & 1) == 1)
			{
				heap.Free(i);
			}

			c++;
		}

		// Clear blas
		blas.clear();
	};

	// Do two warmup runs of the benchmark
	for (auto i = 0U; i < WARMUP_RUNS; i++)
	{
		pre_benchmark();
		benchmark();
		post_benchmark();
	}

	// Run the actual benchmark
	std::vector<size_t> time_log;
	for (auto i = 0U; i < RUNS; i++)
	{
		pre_benchmark();

		auto start_time = std::chrono::high_resolution_clock::now();

		benchmark();

		auto end_time = std::chrono::high_resolution_clock::now();

		time_log.push_back(std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count());

		post_benchmark();
	}

	// Display results
	std::cout << "----- Full Defragmentation Benchmark -----" << std::endl << std::endl;;
	std::cout << std::endl << "Heap Type: " << GetTypeString(heap) << std::endl << std::endl;

	for (auto i = 0U; i < RUNS; i++)
		std::cout << "Run " << i << ": " << time_log[i] << "ns" << std::endl << std::endl;

	size_t sum = 0;
	for (auto i : time_log)
		sum += i;
	sum /= RUNS;

	std::cout << "Average : " << sum << "ns" << std::endl << std::endl;

	std::cout << "-------------------------------------" << std::endl << std::endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
	std::cout << "System ticks per second: " << std::chrono::high_resolution_clock::period::den << std::endl << std::endl;

	ListHeap list(HEAP_SIZE);
	SplayHeap splay(HEAP_SIZE);

	/**
		--- Pure Allocate Benchmark ---

		Benchmarks the performance of the Allocate function for the heaps.
	**/
	PureAllocationBenchmark(list);
	PureAllocationBenchmark(splay);

	/**
		--- Full Defragmentation Benchmark ---

		Benchmarks the performance of the Fully Defragment function for the heaps.
	**/
	FullDefragBenchmark(list);
	FullDefragBenchmark(splay);

	return 0;
}

<commit_msg>Added free benchmarks<commit_after>// AATreePlayground.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <stdexcept>
#include <cstdint>
#include <cassert>
#include <algorithm>
#include <chrono>
#include <iostream>
#include <vector>
#include <functional>

#include "SplayHeap.h"
#include "ListHeap.h"

static const size_t HEAP_SIZE = 1024 * 1024 * 32; // 32MB heap
static const size_t ALLOC_SIZE = 1024;
static const size_t CHUNKS = HEAP_SIZE / 16;

static const size_t RUNS = 5;
static const size_t WARMUP_RUNS = 2;

const char * const GetTypeString(const ListHeap&)
{
	return "ListHeap";
}

const char * const GetTypeString(const SplayHeap&)
{
	return "SplayHeap";
}

std::vector<uint32_t> EratosthenesSieve(uint32_t upper_bound)
{
	// Our list of from numbers
	std::vector<uint32_t> res;

	// Initialize the composite memoization array to false
	std::vector<bool> is_composite;
	for (uint32_t i = 0; i <= upper_bound + 1; i++)
		is_composite.push_back(0);

	// Calculate sqr for sqr optimization
	uint32_t sqr = uint32_t(sqrt((double)upper_bound));

	// Run the sieve of eratosthenes up to the square root of the upper bound
	for (int m = 2; m <= sqr; m++) {
		// If we have not visited this number before, we are prime
		if (!is_composite[m]) {

			// Add prime number to output list
			res.push_back(m);

			// Mark all composites of this prime
			for (int k = m * m; k <= upper_bound; k += m)
				is_composite[k] = true;
		}
	}

	// We have covered all composite numbers, add remaining primes to the output list
	for (int m = sqr; m <= upper_bound; m++)
		if (!is_composite[m])
			res.push_back(m);

	return res;
}

template <typename T>
void PureAllocationBenchmark(T& heap)
{
	std::vector<DefraggablePointerControlBlock> blas;
	blas.reserve(CHUNKS / 2);

	auto pre_benchmark = [&](){};

	auto benchmark = [&]()
	{
		// Allocate ALLOC_SIZES until we fail
		while (auto alloc = heap.Allocate(ALLOC_SIZE))
			blas.push_back(std::move(alloc));

	};

	auto post_benchmark = [&]()
	{
		// Return all allocated data to the heap
		for (auto &i : blas)
			heap.Free(i);

		// Clear blas
		blas.clear();
	};

	// Do two warmup runs of the benchmark
	for (auto i = 0U; i < WARMUP_RUNS; i++)
	{
		pre_benchmark();
		benchmark();
		post_benchmark();
	}

	// Run the actual benchmark
	std::vector<size_t> time_log;
	for (auto i = 0U; i < RUNS; i++)
	{
		pre_benchmark();

		auto start_time = std::chrono::high_resolution_clock::now();

		benchmark();

		auto end_time = std::chrono::high_resolution_clock::now();

		time_log.push_back(std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count());

		post_benchmark();
	}

	// Display results
	std::cout << "----- Pure Allocation Benchmark -----" << std::endl << std::endl;;
	std::cout << std::endl << "Heap Type: " << GetTypeString(heap) << std::endl << std::endl;

	for (auto i = 0U; i < RUNS; i++)
		std::cout << "Run " << i << ": " << time_log[i] << "ns" << std::endl << std::endl;

	size_t sum = 0;
	for (auto i : time_log)
		sum += i;
	sum /= RUNS;

	std::cout << "Average : " << sum << "ns" << std::endl << std::endl;

	std::cout << "-------------------------------------" << std::endl << std::endl;
}

template <typename T>
void PureFreeBenchmark(T& heap)
{
	std::vector<DefraggablePointerControlBlock> blas;
	blas.reserve(CHUNKS / 2);

	auto pre_benchmark = [&](){
		// Allocate ALLOC_SIZES until we fail
		while (auto alloc = heap.Allocate(ALLOC_SIZE))
			blas.push_back(std::move(alloc));
	};

	auto benchmark = [&]()
	{
		// Return all allocated data to the heap
		for (auto &i : blas)
			heap.Free(i);
	};

	auto post_benchmark = [&]()
	{
		// Clear blas
		blas.clear();
	};

	// Do two warmup runs of the benchmark
	for (auto i = 0U; i < WARMUP_RUNS; i++)
	{
		pre_benchmark();
		benchmark();
		post_benchmark();
	}

	// Run the actual benchmark
	std::vector<size_t> time_log;
	for (auto i = 0U; i < RUNS; i++)
	{
		pre_benchmark();

		auto start_time = std::chrono::high_resolution_clock::now();

		benchmark();

		auto end_time = std::chrono::high_resolution_clock::now();

		time_log.push_back(std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count());

		post_benchmark();
	}

	// Display results
	std::cout << "----- Pure Free Benchmark -----" << std::endl << std::endl;;
	std::cout << std::endl << "Heap Type: " << GetTypeString(heap) << std::endl << std::endl;

	for (auto i = 0U; i < RUNS; i++)
		std::cout << "Run " << i << ": " << time_log[i] << "ns" << std::endl << std::endl;

	size_t sum = 0;
	for (auto i : time_log)
		sum += i;
	sum /= RUNS;

	std::cout << "Average : " << sum << "ns" << std::endl << std::endl;

	std::cout << "-------------------------------------" << std::endl << std::endl;
}

template <typename T>
void PrimeStrideFreeBenchmark(T& heap)
{
	std::vector<DefraggablePointerControlBlock> blas;
	blas.reserve(CHUNKS / 2);
	const auto primes = EratosthenesSieve(CHUNKS / 2);

	auto pre_benchmark = [&](){
		// Allocate ALLOC_SIZES until we fail
		while (auto alloc = heap.Allocate(ALLOC_SIZE))
			blas.push_back(std::move(alloc));
	};

	auto benchmark = [&]()
	{
		// Free the first 2 items (non prime numbers)
		heap.Free(blas[0]);
		heap.Free(blas[1]);

		// For every prime
		for (auto p : primes)
		{
			if (p < blas.size())
			{
				// Return all allocated data to the heap in the strie
				for (auto i = p; i < blas.size(); i += p)
					heap.Free(blas[i]);
			}
		}
	};

	auto post_benchmark = [&]()
	{
		// Clear blas
		blas.clear();
	};

	// Do two warmup runs of the benchmark
	for (auto i = 0U; i < WARMUP_RUNS; i++)
	{
		std::cout << "-------------------------------------" << std::endl << std::endl;
		pre_benchmark();
		benchmark();
		post_benchmark();
	}

	// Run the actual benchmark
	std::vector<size_t> time_log;
	for (auto i = 0U; i < RUNS; i++)
	{
		pre_benchmark();

		auto start_time = std::chrono::high_resolution_clock::now();

		benchmark();

		auto end_time = std::chrono::high_resolution_clock::now();

		time_log.push_back(std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count());

		post_benchmark();
	}

	// Display results
	std::cout << "----- Prime Stride Free Benchmark -----" << std::endl << std::endl;;
	std::cout << std::endl << "Heap Type: " << GetTypeString(heap) << std::endl << std::endl;

	for (auto i = 0U; i < RUNS; i++)
		std::cout << "Run " << i << ": " << time_log[i] << "ns" << std::endl << std::endl;

	size_t sum = 0;
	for (auto i : time_log)
		sum += i;
	sum /= RUNS;

	std::cout << "Average : " << sum << "ns" << std::endl << std::endl;

	std::cout << "-------------------------------------" << std::endl << std::endl;
}

template <typename T>
void FullDefragBenchmark(T& heap)
{
	std::vector<DefraggablePointerControlBlock> blas;
	blas.reserve(CHUNKS / 2);

	auto pre_benchmark = [&]()
	{
		// Allocate ALLOC_SIZES until we fail
		while (auto alloc = heap.Allocate(ALLOC_SIZE))
			blas.push_back(std::move(alloc));

		// Free every second block to maximize fragmentation
		size_t c = 0;
		for (auto& i : blas)
		{
			if ((c & 1) == 0)
			{
				heap.Free(i);
			}

			c++;
		}
	};

	auto benchmark = [&]()
	{
		heap.FullDefrag();
	};

	auto post_benchmark = [&]()
	{
		// Return all allocated data to the heap
		size_t c = 0;
		for (auto &i : blas)
		{
			if ((i & 1) == 1)
			{
				heap.Free(i);
			}

			c++;
		}

		// Clear blas
		blas.clear();
	};

	// Do two warmup runs of the benchmark
	for (auto i = 0U; i < WARMUP_RUNS; i++)
	{
		pre_benchmark();
		benchmark();
		post_benchmark();
	}

	// Run the actual benchmark
	std::vector<size_t> time_log;
	for (auto i = 0U; i < RUNS; i++)
	{
		pre_benchmark();

		auto start_time = std::chrono::high_resolution_clock::now();

		benchmark();

		auto end_time = std::chrono::high_resolution_clock::now();

		time_log.push_back(std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count());

		post_benchmark();
	}

	// Display results
	std::cout << "----- Full Defragmentation Benchmark -----" << std::endl << std::endl;;
	std::cout << std::endl << "Heap Type: " << GetTypeString(heap) << std::endl << std::endl;

	for (auto i = 0U; i < RUNS; i++)
		std::cout << "Run " << i << ": " << time_log[i] << "ns" << std::endl << std::endl;

	size_t sum = 0;
	for (auto i : time_log)
		sum += i;
	sum /= RUNS;

	std::cout << "Average : " << sum << "ns" << std::endl << std::endl;

	std::cout << "-------------------------------------" << std::endl << std::endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
	std::cout << "System ticks per second: " << std::chrono::high_resolution_clock::period::den << std::endl << std::endl;

	ListHeap list(HEAP_SIZE);
	SplayHeap splay(HEAP_SIZE);

	/**
		--- Pure Allocate Benchmark ---

		Benchmarks the performance of the Allocate function for the heaps.
	**/
	//PureAllocationBenchmark(list);
	//PureAllocationBenchmark(splay);

	/**
		--- Full Defragmentation Benchmark ---

		Benchmarks the performance of the Fully Defragment function for the heaps.
	**/
	//FullDefragBenchmark(list);
	//FullDefragBenchmark(splay);

	/**
		--- Pure Free Benchmark ---

		Benchmarks the performance of the Free function for the heaps.
	**/
	//PureFreeBenchmark(list);
	//PureFreeBenchmark(splay);

	/**
		--- Prime Stride Free Benchmark ---

		Benchmarks the performance of the Free function for the heaps using prime strides.
	**/
	PrimeStrideFreeBenchmark(list);
	PrimeStrideFreeBenchmark(splay);

	return 0;
}<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
/**
******************************************************************************
* @author  Oivind H. Danielsen
* @date    Creation date: 2000-01-18
* @file
* Implementation of FastOS_UNIX_File methods.
*****************************************************************************/

#include <vespa/fastos/file.h>
#include <sys/vfs.h>
#include <sstream>
#include <stdexcept>

bool
FastOS_UNIX_File::SetPosition(int64_t desiredPosition)
{
    int64_t position = lseek(_filedes, desiredPosition, SEEK_SET);

    return (position == desiredPosition);
}

int64_t
FastOS_UNIX_File::GetPosition(void)
{
    return lseek(_filedes, 0, SEEK_CUR);
}

bool
FastOS_UNIX_File::Stat(const char *filename, FastOS_StatInfo *statInfo)
{
    bool rc = false;

    struct stat stbuf;
    int lstatres;

    do {
        lstatres = lstat(filename, &stbuf);
    } while (lstatres == -1 && errno == EINTR);
    if (lstatres == 0) {
        statInfo->_error = FastOS_StatInfo::Ok;
        statInfo->_isRegular = S_ISREG(stbuf.st_mode);
        statInfo->_isDirectory = S_ISDIR(stbuf.st_mode);
        statInfo->_size = static_cast<int64_t>(stbuf.st_size);
        statInfo->_modifiedTime = stbuf.st_mtime;
        statInfo->_modifiedTimeNS = stbuf.st_mtim.tv_sec;
        statInfo->_modifiedTimeNS *= 1000000000;
        statInfo->_modifiedTimeNS += stbuf.st_mtim.tv_nsec;
        rc = true;
    } else {
        if (errno == ENOENT) {
            statInfo->_error = FastOS_StatInfo::FileNotFound;
        } else {
            statInfo->_error = FastOS_StatInfo::Unknown;
        }
    }

    return rc;
}

int FastOS_UNIX_File::GetMaximumFilenameLength (const char *pathName)
{
    return pathconf(pathName, _PC_NAME_MAX);
}

int FastOS_UNIX_File::GetMaximumPathLength(const char *pathName)
{
    return pathconf(pathName, _PC_PATH_MAX);
}

bool
FastOS_UNIX_File::MakeDirectory (const char *name)
{
    return (mkdir(name, 0775) == 0);
}

void
FastOS_UNIX_File::RemoveDirectory (const char *name)
{
    if ((rmdir(name) != 0) && (ERR_ENOENT != GetLastError())) {
        std::ostringstream os;
        os << "Remove of directory '" << name << "' failed with error :'" << getLastErrorString() << "'";
        throw std::runtime_error(os.str());
    }
}

std::string
FastOS_UNIX_File::getCurrentDirectory(void)
{
    std::string res;
    int maxPathLen = FastOS_File::GetMaximumPathLength(".");
    if (maxPathLen == -1) {
        maxPathLen = 16384;
    } else if (maxPathLen < 512) {
        maxPathLen = 512;
    }

    char *currentDir = new char [maxPathLen + 1];

    if (getcwd(currentDir, maxPathLen) != nullptr) {
        res = currentDir;
    }
    delete [] currentDir;

    return res;
}

unsigned int
FastOS_UNIX_File::CalcAccessFlags(unsigned int openFlags)
{
    unsigned int accessFlags=0;

    if ((openFlags & (FASTOS_FILE_OPEN_READ | FASTOS_FILE_OPEN_DIRECTIO)) != 0) {
        if ((openFlags & FASTOS_FILE_OPEN_WRITE) != 0) {
            // Open for reading and writing
            accessFlags = O_RDWR;
        } else {
            // Open for reading only
            accessFlags = O_RDONLY;
        }
    } else {
        // Open for writing only
        accessFlags = O_WRONLY;
    }

    if (((openFlags & FASTOS_FILE_OPEN_EXISTING) == 0) && ((openFlags & FASTOS_FILE_OPEN_WRITE) != 0)) {
        // Create file if it does not exist
        accessFlags |= O_CREAT;
    }

#if defined(O_SYNC)
    if ((openFlags & FASTOS_FILE_OPEN_SYNCWRITES) != 0)
        accessFlags |= O_SYNC;
#elif defined(O_FSYNC)
    if ((openFlags & FASTOS_FILE_OPEN_SYNCWRITES) != 0)
        accessFlags |= O_FSYNC;
#endif

    if ((openFlags & FASTOS_FILE_OPEN_DIRECTIO) != 0) {
        accessFlags |= O_DIRECT | O_DSYNC | O_RSYNC;
    }

    if ((openFlags & FASTOS_FILE_OPEN_TRUNCATE) != 0) {
        // Truncate file on open
        accessFlags |= O_TRUNC;
    }
    return accessFlags;
}

constexpr int SUPPORTED_MMAP_FLAGS = ~MAP_HUGETLB;

bool
FastOS_UNIX_File::Open(unsigned int openFlags, const char *filename)
{
    bool rc = false;
    assert(_filedes == -1);

    if ((openFlags & FASTOS_FILE_OPEN_STDFLAGS) != 0) {
        FILE *file;

        switch(openFlags & FASTOS_FILE_OPEN_STDFLAGS) {
        case FASTOS_FILE_OPEN_STDIN:
            file = stdin;
            SetFileName("stdin");
            break;

        case FASTOS_FILE_OPEN_STDOUT:
            file = stdout;
            SetFileName("stdout");
            break;

        case FASTOS_FILE_OPEN_STDERR:
            file = stderr;
            SetFileName("stderr");
            break;

        default:
            file = nullptr;
            fprintf(stderr, "Invalid open-flags %08X\n", openFlags);
            abort();
        }

        _filedes = file->_fileno;
        _openFlags = openFlags;
        rc = true;
    } else {
        if (filename != nullptr) {
            SetFileName(filename);
        }
        unsigned int accessFlags = CalcAccessFlags(openFlags);

        _filedes = open(_filename, accessFlags, 0664);

        rc = (_filedes != -1);

        if (rc) {
            _openFlags = openFlags;
            if (_mmapEnabled) {
                int64_t filesize = GetSize();
                size_t mlen = static_cast<size_t>(filesize);
                if ((static_cast<int64_t>(mlen) == filesize) && (mlen > 0)) {
                    void *mbase = mmap(nullptr, mlen, PROT_READ, MAP_SHARED | _mmapFlags, _filedes, static_cast<off_t>(0));
                    if (static_cast<void *>(mbase) == reinterpret_cast<void *>(-1)) {
                        mbase = mmap(nullptr, mlen, PROT_READ, MAP_SHARED | (_mmapFlags & SUPPORTED_MMAP_FLAGS), _filedes, static_cast<off_t>(0));
                    }
                    if (static_cast<void *>(mbase) != reinterpret_cast<void *>(-1)) {
                        int fadviseOptions = getFAdviseOptions();
                        int eCode(0);
                        if (POSIX_FADV_RANDOM == fadviseOptions) {
                            eCode = posix_madvise(mbase, mlen, POSIX_MADV_RANDOM);
                        } else if (POSIX_FADV_SEQUENTIAL == fadviseOptions) {
                            eCode = posix_madvise(mbase, mlen, POSIX_MADV_SEQUENTIAL);
                        }
                        if (eCode != 0) {
                            fprintf(stderr, "Failed: posix_madvise(%p, %ld, %d) = %d\n", mbase, mlen, fadviseOptions, eCode);
                        }
                        _mmapbase = mbase;
                        _mmaplen = mlen;
                    } else {
                        close(_filedes);
                        _filedes = -1;
                        std::ostringstream os;
                        os << "mmap of file '" << GetFileName() << "' with flags '" << std::hex << (MAP_SHARED | _mmapFlags) << std::dec
                           << "' failed with error :'" << getErrorString(GetLastOSError()) << "'";
                        throw std::runtime_error(os.str());
                    }
                }
            }
        }

    }

    return rc;
}

void FastOS_UNIX_File::dropFromCache() const
{
    posix_fadvise(_filedes, 0, 0, POSIX_FADV_DONTNEED);
}

bool
FastOS_UNIX_File::Close(void)
{
    bool ok = true;

    if (_filedes >= 0) {
        if ((_openFlags & FASTOS_FILE_OPEN_STDFLAGS) != 0) {
            ok = true;
        } else {
            do {
                ok = (close(_filedes) == 0);
            } while (!ok && errno == EINTR);
        }

        if (_mmapbase != nullptr) {
            madvise(_mmapbase, _mmaplen, MADV_DONTNEED);
            munmap(static_cast<char *>(_mmapbase), _mmaplen);
            _mmapbase = nullptr;
            _mmaplen = 0;
        }

        _filedes = -1;
    }

    _openFlags = 0;

    return ok;
}

int64_t
FastOS_UNIX_File::GetSize(void)
{
    int64_t fileSize=-1;
    struct stat stbuf;

    assert(IsOpened());

    int res = fstat(_filedes, &stbuf);

    if (res == 0) {
        fileSize = stbuf.st_size;
    }

    return fileSize;
}

time_t
FastOS_UNIX_File::GetModificationTime(void)
{
    struct stat stbuf;
    int res;

    assert(IsOpened());

    res = fstat(_filedes, &stbuf);
    assert(res == 0);
    (void) res;

    return stbuf.st_mtime;
}

bool
FastOS_UNIX_File::Delete(const char *name)
{
    return (unlink(name) == 0);
}

bool
FastOS_UNIX_File::Delete(void)
{
    assert(!IsOpened());
    assert(_filename != nullptr);

    return (unlink(_filename) == 0);
}

bool FastOS_UNIX_File::Rename (const char *currentFileName, const char *newFileName)
{
    bool rc = false;

    // Enforce documentation. If the destination file exists,
    // fail Rename.
    FastOS_StatInfo statInfo;
    if (!FastOS_File::Stat(newFileName, &statInfo)) {
        rc = (rename(currentFileName, newFileName) == 0);
    } else {
        errno = EEXIST;
    }
    return rc;
}

bool
FastOS_UNIX_File::Sync(void)
{
    assert(IsOpened());

    return (fsync(_filedes) == 0);
}

bool
FastOS_UNIX_File::SetSize(int64_t newSize)
{
    bool rc = false;

    if (ftruncate(_filedes, static_cast<off_t>(newSize)) == 0) {
        rc = SetPosition(newSize);
    }

    return rc;
}

FastOS_File::Error
FastOS_UNIX_File::TranslateError (const int osError)
{
    switch(osError) {
    case ENOENT:     return ERR_NOENT;      // No such file or directory
    case ENOMEM:     return ERR_NOMEM;      // Not enough memory
    case EACCES:     return ERR_ACCES;      // Permission denied
    case EEXIST:     return ERR_EXIST;      // File exists
    case EINVAL:     return ERR_INVAL;      // Invalid argument
    case ENOSPC:     return ERR_NOSPC;      // No space left on device
    case EINTR:      return ERR_INTR;       // interrupt
    case EAGAIN:     return ERR_AGAIN;      // Resource unavailable, try again
    case EBUSY:      return ERR_BUSY;       // Device or resource busy
    case EIO:        return ERR_IO;         // I/O error
    case EPERM:      return ERR_PERM;       // Not owner
    case ENODEV:     return ERR_NODEV;      // No such device
    case ENXIO:      return ERR_NXIO;       // Device not configured
    }

    if (osError == FASTOS_ENFILE_VERIFIED)
        return ERR_NFILE;

    if (osError == FASTOS_EMFILE_VERIFIED)
        return ERR_MFILE;

    return ERR_UNKNOWN;
}

std::string
FastOS_UNIX_File::getErrorString(const int osError)
{
    char errorBuf[100];
    const char *errorString = strerror_r(osError, errorBuf, sizeof(errorBuf));

    return std::string(errorString);
}

int64_t FastOS_UNIX_File::GetFreeDiskSpace (const char *path)
{
    int64_t freeSpace = -1;

    struct statfs statBuf;
    int statVal = -1;
    statVal = statfs(path, &statBuf);
    if (statVal == 0) {
        freeSpace = int64_t(statBuf.f_bavail) * int64_t(statBuf.f_bsize);
    }

    return freeSpace;
}

FastOS_UNIX_DirectoryScan::FastOS_UNIX_DirectoryScan(const char *searchPath)
    : FastOS_DirectoryScanInterface(searchPath),
      _statRun(false),
      _isDirectory(false),
      _isRegular(false),
      _statName(nullptr),
      _statFilenameP(nullptr),
      _dir(nullptr),
      _dp(nullptr)
{
    _dir = opendir(searchPath);

    const int minimumLength = 512 + 1;
    const int defaultLength = 16384;

    int maxNameLength = FastOS_File::GetMaximumFilenameLength(searchPath);
    int maxPathLength = FastOS_File::GetMaximumPathLength(searchPath);
    int nameLength = maxNameLength + 1 + maxPathLength;

    if ((maxNameLength == -1) ||
       (maxPathLength == -1) ||
       (nameLength < minimumLength))
    {
        nameLength = defaultLength;
    }

    _statName = new char [nameLength + 1];  // Include null

    strcpy(_statName, searchPath);
    strcat(_statName, "/");

    _statFilenameP = &_statName[strlen(_statName)];
}

FastOS_UNIX_DirectoryScan::~FastOS_UNIX_DirectoryScan(void)
{
    if (_dir != nullptr) {
        closedir(_dir);
        _dir = nullptr;
    }
    delete [] _statName;
}

bool
FastOS_UNIX_DirectoryScan::ReadNext(void)
{
    bool rc = false;

    _statRun = false;

    if (_dir != nullptr) {
        _dp = readdir(_dir);
        rc = _dp != nullptr;
    }

    return rc;
}

void
FastOS_UNIX_DirectoryScan::DoStat(void)
{
    struct stat stbuf;

    assert(_dp != nullptr);

    strcpy(_statFilenameP, _dp->d_name);

    if (lstat(_statName, &stbuf) == 0) {
        _isRegular = S_ISREG(stbuf.st_mode);
        _isDirectory = S_ISDIR(stbuf.st_mode);
    } else {
        printf("lstat failed for [%s]\n", _dp->d_name);
        _isRegular = false;
        _isDirectory = false;
    }

    _statRun = true;
}

bool
FastOS_UNIX_DirectoryScan::IsDirectory(void)
{
    if (!_statRun) {
        DoStat();
    }

    return _isDirectory;
}

bool
FastOS_UNIX_DirectoryScan::IsRegular(void)
{
    if (!_statRun) {
        DoStat();
    }

    return _isRegular;
}

const char *
FastOS_UNIX_DirectoryScan::GetName(void)
{
    assert(_dp != nullptr);

    return static_cast<const char *>(_dp->d_name);
}

bool
FastOS_UNIX_DirectoryScan::IsValidScan(void) const
{
    return _dir != nullptr;
}
<commit_msg>Less us not overdo the casting ...<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
/**
******************************************************************************
* @author  Oivind H. Danielsen
* @date    Creation date: 2000-01-18
* @file
* Implementation of FastOS_UNIX_File methods.
*****************************************************************************/

#include <vespa/fastos/file.h>
#include <sys/vfs.h>
#include <sstream>
#include <stdexcept>

bool
FastOS_UNIX_File::SetPosition(int64_t desiredPosition)
{
    int64_t position = lseek(_filedes, desiredPosition, SEEK_SET);

    return (position == desiredPosition);
}

int64_t
FastOS_UNIX_File::GetPosition(void)
{
    return lseek(_filedes, 0, SEEK_CUR);
}

bool
FastOS_UNIX_File::Stat(const char *filename, FastOS_StatInfo *statInfo)
{
    bool rc = false;

    struct stat stbuf;
    int lstatres;

    do {
        lstatres = lstat(filename, &stbuf);
    } while (lstatres == -1 && errno == EINTR);
    if (lstatres == 0) {
        statInfo->_error = FastOS_StatInfo::Ok;
        statInfo->_isRegular = S_ISREG(stbuf.st_mode);
        statInfo->_isDirectory = S_ISDIR(stbuf.st_mode);
        statInfo->_size = static_cast<int64_t>(stbuf.st_size);
        statInfo->_modifiedTime = stbuf.st_mtime;
        statInfo->_modifiedTimeNS = stbuf.st_mtim.tv_sec;
        statInfo->_modifiedTimeNS *= 1000000000;
        statInfo->_modifiedTimeNS += stbuf.st_mtim.tv_nsec;
        rc = true;
    } else {
        if (errno == ENOENT) {
            statInfo->_error = FastOS_StatInfo::FileNotFound;
        } else {
            statInfo->_error = FastOS_StatInfo::Unknown;
        }
    }

    return rc;
}

int FastOS_UNIX_File::GetMaximumFilenameLength (const char *pathName)
{
    return pathconf(pathName, _PC_NAME_MAX);
}

int FastOS_UNIX_File::GetMaximumPathLength(const char *pathName)
{
    return pathconf(pathName, _PC_PATH_MAX);
}

bool
FastOS_UNIX_File::MakeDirectory (const char *name)
{
    return (mkdir(name, 0775) == 0);
}

void
FastOS_UNIX_File::RemoveDirectory (const char *name)
{
    if ((rmdir(name) != 0) && (ERR_ENOENT != GetLastError())) {
        std::ostringstream os;
        os << "Remove of directory '" << name << "' failed with error :'" << getLastErrorString() << "'";
        throw std::runtime_error(os.str());
    }
}

std::string
FastOS_UNIX_File::getCurrentDirectory(void)
{
    std::string res;
    int maxPathLen = FastOS_File::GetMaximumPathLength(".");
    if (maxPathLen == -1) {
        maxPathLen = 16384;
    } else if (maxPathLen < 512) {
        maxPathLen = 512;
    }

    char *currentDir = new char [maxPathLen + 1];

    if (getcwd(currentDir, maxPathLen) != nullptr) {
        res = currentDir;
    }
    delete [] currentDir;

    return res;
}

unsigned int
FastOS_UNIX_File::CalcAccessFlags(unsigned int openFlags)
{
    unsigned int accessFlags=0;

    if ((openFlags & (FASTOS_FILE_OPEN_READ | FASTOS_FILE_OPEN_DIRECTIO)) != 0) {
        if ((openFlags & FASTOS_FILE_OPEN_WRITE) != 0) {
            // Open for reading and writing
            accessFlags = O_RDWR;
        } else {
            // Open for reading only
            accessFlags = O_RDONLY;
        }
    } else {
        // Open for writing only
        accessFlags = O_WRONLY;
    }

    if (((openFlags & FASTOS_FILE_OPEN_EXISTING) == 0) && ((openFlags & FASTOS_FILE_OPEN_WRITE) != 0)) {
        // Create file if it does not exist
        accessFlags |= O_CREAT;
    }

#if defined(O_SYNC)
    if ((openFlags & FASTOS_FILE_OPEN_SYNCWRITES) != 0)
        accessFlags |= O_SYNC;
#elif defined(O_FSYNC)
    if ((openFlags & FASTOS_FILE_OPEN_SYNCWRITES) != 0)
        accessFlags |= O_FSYNC;
#endif

    if ((openFlags & FASTOS_FILE_OPEN_DIRECTIO) != 0) {
        accessFlags |= O_DIRECT | O_DSYNC | O_RSYNC;
    }

    if ((openFlags & FASTOS_FILE_OPEN_TRUNCATE) != 0) {
        // Truncate file on open
        accessFlags |= O_TRUNC;
    }
    return accessFlags;
}

constexpr int SUPPORTED_MMAP_FLAGS = ~MAP_HUGETLB;

bool
FastOS_UNIX_File::Open(unsigned int openFlags, const char *filename)
{
    bool rc = false;
    assert(_filedes == -1);

    if ((openFlags & FASTOS_FILE_OPEN_STDFLAGS) != 0) {
        FILE *file;

        switch(openFlags & FASTOS_FILE_OPEN_STDFLAGS) {
        case FASTOS_FILE_OPEN_STDIN:
            file = stdin;
            SetFileName("stdin");
            break;

        case FASTOS_FILE_OPEN_STDOUT:
            file = stdout;
            SetFileName("stdout");
            break;

        case FASTOS_FILE_OPEN_STDERR:
            file = stderr;
            SetFileName("stderr");
            break;

        default:
            file = nullptr;
            fprintf(stderr, "Invalid open-flags %08X\n", openFlags);
            abort();
        }

        _filedes = file->_fileno;
        _openFlags = openFlags;
        rc = true;
    } else {
        if (filename != nullptr) {
            SetFileName(filename);
        }
        unsigned int accessFlags = CalcAccessFlags(openFlags);

        _filedes = open(_filename, accessFlags, 0664);

        rc = (_filedes != -1);

        if (rc) {
            _openFlags = openFlags;
            if (_mmapEnabled) {
                int64_t filesize = GetSize();
                size_t mlen = static_cast<size_t>(filesize);
                if ((static_cast<int64_t>(mlen) == filesize) && (mlen > 0)) {
                    void *mbase = mmap(nullptr, mlen, PROT_READ, MAP_SHARED | _mmapFlags, _filedes, 0);
                    if (mbase == reinterpret_cast<void *>(-1)) {
                        mbase = mmap(nullptr, mlen, PROT_READ, MAP_SHARED | (_mmapFlags & SUPPORTED_MMAP_FLAGS), _filedes, 0);
                    }
                    if (mbase != reinterpret_cast<void *>(-1)) {
                        int fadviseOptions = getFAdviseOptions();
                        int eCode(0);
                        if (POSIX_FADV_RANDOM == fadviseOptions) {
                            eCode = posix_madvise(mbase, mlen, POSIX_MADV_RANDOM);
                        } else if (POSIX_FADV_SEQUENTIAL == fadviseOptions) {
                            eCode = posix_madvise(mbase, mlen, POSIX_MADV_SEQUENTIAL);
                        }
                        if (eCode != 0) {
                            fprintf(stderr, "Failed: posix_madvise(%p, %ld, %d) = %d\n", mbase, mlen, fadviseOptions, eCode);
                        }
                        _mmapbase = mbase;
                        _mmaplen = mlen;
                    } else {
                        close(_filedes);
                        _filedes = -1;
                        std::ostringstream os;
                        os << "mmap of file '" << GetFileName() << "' with flags '" << std::hex << (MAP_SHARED | _mmapFlags) << std::dec
                           << "' failed with error :'" << getErrorString(GetLastOSError()) << "'";
                        throw std::runtime_error(os.str());
                    }
                }
            }
        }

    }

    return rc;
}

void FastOS_UNIX_File::dropFromCache() const
{
    posix_fadvise(_filedes, 0, 0, POSIX_FADV_DONTNEED);
}

bool
FastOS_UNIX_File::Close(void)
{
    bool ok = true;

    if (_filedes >= 0) {
        if ((_openFlags & FASTOS_FILE_OPEN_STDFLAGS) != 0) {
            ok = true;
        } else {
            do {
                ok = (close(_filedes) == 0);
            } while (!ok && errno == EINTR);
        }

        if (_mmapbase != nullptr) {
            madvise(_mmapbase, _mmaplen, MADV_DONTNEED);
            munmap(static_cast<char *>(_mmapbase), _mmaplen);
            _mmapbase = nullptr;
            _mmaplen = 0;
        }

        _filedes = -1;
    }

    _openFlags = 0;

    return ok;
}

int64_t
FastOS_UNIX_File::GetSize(void)
{
    int64_t fileSize=-1;
    struct stat stbuf;

    assert(IsOpened());

    int res = fstat(_filedes, &stbuf);

    if (res == 0) {
        fileSize = stbuf.st_size;
    }

    return fileSize;
}

time_t
FastOS_UNIX_File::GetModificationTime(void)
{
    struct stat stbuf;
    int res;

    assert(IsOpened());

    res = fstat(_filedes, &stbuf);
    assert(res == 0);
    (void) res;

    return stbuf.st_mtime;
}

bool
FastOS_UNIX_File::Delete(const char *name)
{
    return (unlink(name) == 0);
}

bool
FastOS_UNIX_File::Delete(void)
{
    assert(!IsOpened());
    assert(_filename != nullptr);

    return (unlink(_filename) == 0);
}

bool FastOS_UNIX_File::Rename (const char *currentFileName, const char *newFileName)
{
    bool rc = false;

    // Enforce documentation. If the destination file exists,
    // fail Rename.
    FastOS_StatInfo statInfo;
    if (!FastOS_File::Stat(newFileName, &statInfo)) {
        rc = (rename(currentFileName, newFileName) == 0);
    } else {
        errno = EEXIST;
    }
    return rc;
}

bool
FastOS_UNIX_File::Sync(void)
{
    assert(IsOpened());

    return (fsync(_filedes) == 0);
}

bool
FastOS_UNIX_File::SetSize(int64_t newSize)
{
    bool rc = false;

    if (ftruncate(_filedes, static_cast<off_t>(newSize)) == 0) {
        rc = SetPosition(newSize);
    }

    return rc;
}

FastOS_File::Error
FastOS_UNIX_File::TranslateError (const int osError)
{
    switch(osError) {
    case ENOENT:     return ERR_NOENT;      // No such file or directory
    case ENOMEM:     return ERR_NOMEM;      // Not enough memory
    case EACCES:     return ERR_ACCES;      // Permission denied
    case EEXIST:     return ERR_EXIST;      // File exists
    case EINVAL:     return ERR_INVAL;      // Invalid argument
    case ENOSPC:     return ERR_NOSPC;      // No space left on device
    case EINTR:      return ERR_INTR;       // interrupt
    case EAGAIN:     return ERR_AGAIN;      // Resource unavailable, try again
    case EBUSY:      return ERR_BUSY;       // Device or resource busy
    case EIO:        return ERR_IO;         // I/O error
    case EPERM:      return ERR_PERM;       // Not owner
    case ENODEV:     return ERR_NODEV;      // No such device
    case ENXIO:      return ERR_NXIO;       // Device not configured
    }

    if (osError == FASTOS_ENFILE_VERIFIED)
        return ERR_NFILE;

    if (osError == FASTOS_EMFILE_VERIFIED)
        return ERR_MFILE;

    return ERR_UNKNOWN;
}

std::string
FastOS_UNIX_File::getErrorString(const int osError)
{
    char errorBuf[100];
    const char *errorString = strerror_r(osError, errorBuf, sizeof(errorBuf));

    return std::string(errorString);
}

int64_t FastOS_UNIX_File::GetFreeDiskSpace (const char *path)
{
    int64_t freeSpace = -1;

    struct statfs statBuf;
    int statVal = -1;
    statVal = statfs(path, &statBuf);
    if (statVal == 0) {
        freeSpace = int64_t(statBuf.f_bavail) * int64_t(statBuf.f_bsize);
    }

    return freeSpace;
}

FastOS_UNIX_DirectoryScan::FastOS_UNIX_DirectoryScan(const char *searchPath)
    : FastOS_DirectoryScanInterface(searchPath),
      _statRun(false),
      _isDirectory(false),
      _isRegular(false),
      _statName(nullptr),
      _statFilenameP(nullptr),
      _dir(nullptr),
      _dp(nullptr)
{
    _dir = opendir(searchPath);

    const int minimumLength = 512 + 1;
    const int defaultLength = 16384;

    int maxNameLength = FastOS_File::GetMaximumFilenameLength(searchPath);
    int maxPathLength = FastOS_File::GetMaximumPathLength(searchPath);
    int nameLength = maxNameLength + 1 + maxPathLength;

    if ((maxNameLength == -1) ||
       (maxPathLength == -1) ||
       (nameLength < minimumLength))
    {
        nameLength = defaultLength;
    }

    _statName = new char [nameLength + 1];  // Include null

    strcpy(_statName, searchPath);
    strcat(_statName, "/");

    _statFilenameP = &_statName[strlen(_statName)];
}

FastOS_UNIX_DirectoryScan::~FastOS_UNIX_DirectoryScan(void)
{
    if (_dir != nullptr) {
        closedir(_dir);
        _dir = nullptr;
    }
    delete [] _statName;
}

bool
FastOS_UNIX_DirectoryScan::ReadNext(void)
{
    bool rc = false;

    _statRun = false;

    if (_dir != nullptr) {
        _dp = readdir(_dir);
        rc = _dp != nullptr;
    }

    return rc;
}

void
FastOS_UNIX_DirectoryScan::DoStat(void)
{
    struct stat stbuf;

    assert(_dp != nullptr);

    strcpy(_statFilenameP, _dp->d_name);

    if (lstat(_statName, &stbuf) == 0) {
        _isRegular = S_ISREG(stbuf.st_mode);
        _isDirectory = S_ISDIR(stbuf.st_mode);
    } else {
        printf("lstat failed for [%s]\n", _dp->d_name);
        _isRegular = false;
        _isDirectory = false;
    }

    _statRun = true;
}

bool
FastOS_UNIX_DirectoryScan::IsDirectory(void)
{
    if (!_statRun) {
        DoStat();
    }

    return _isDirectory;
}

bool
FastOS_UNIX_DirectoryScan::IsRegular(void)
{
    if (!_statRun) {
        DoStat();
    }

    return _isRegular;
}

const char *
FastOS_UNIX_DirectoryScan::GetName(void)
{
    assert(_dp != nullptr);

    return static_cast<const char *>(_dp->d_name);
}

bool
FastOS_UNIX_DirectoryScan::IsValidScan(void) const
{
    return _dir != nullptr;
}
<|endoftext|>