<commit_before>// fdp.hpp :  include file containing templated C++ interfaces to fused dot product
//
// Copyright (C) 2017-2019 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.

#include <vector>

namespace sw {
	namespace unum {

// dot product: the operator vector::x[index] is limited to uint32_t, so the arguments are limited to uint32_t as well
// since we do not support arbitrary posit configuration conversions, the element type of the vectors x and y are declared to be the same.
// TODO: investigate if the vector<> index is always a 32bit entity?
template<typename Ty>
Ty dot(size_t n, const std::vector<Ty>& x, size_t incx, const std::vector<Ty>& y, size_t incy) {
	Ty sum_of_products = 0;
	size_t cnt, ix, iy;
	for (cnt = 0, ix = 0, iy = 0; cnt < n && ix < x.size() && iy < y.size(); ++cnt, ix += incx, iy += incy) {
		Ty product = x[ix] * y[iy];
		sum_of_products += product;
	}
	return sum_of_products;
}

/// //////////////////////////////////////////////////////////////////
/// fused dot product operators
/// fdp_qc         fused dot product with quire continuation
/// fdp_stride     fused dot product with non-negative stride
/// fdp            fused dot product of two vectors

// Fused dot product with quire continuation
template<typename Qy, typename Vector>
void fdp_qc(Qy& sum_of_products, size_t n, const Vector& x, size_t incx, const Vector& y, size_t incy) {
	size_t ix, iy;
	for (ix = 0, iy = 0; ix < n && iy < n; ix = ix + incx, iy = iy + incy) {
		sum_of_products += sw::unum::quire_mul(x[ix], y[iy]);
	}
}

// Resolved fused dot product, with the option to control capacity bits in the quire
template<typename Vector, size_t capacity = 10>
typename Vector::value_type fdp_stride(size_t n, const Vector& x, size_t incx, const Vector& y, size_t incy) {
	constexpr size_t nbits = typename Vector::value_type::nbits;
	constexpr size_t es = typename Vector::value_type::es;
	quire<nbits, es, capacity> q = 0;
	size_t ix, iy;
	for (ix = 0, iy = 0; ix < n && iy < n; ix = ix + incx, iy = iy + incy) {
		q += sw::unum::quire_mul(x[ix], y[iy]);
		if (sw::unum::_trace_quire_add) std::cout << q << '\n';
	}
	typename Vector::value_type sum;
	convert(q.to_value(), sum);     // one and only rounding step of the fused-dot product
	return sum;
}

// Specialized resolved fused dot product that assumes unit stride and a standard vector,
// with the option to control capacity bits in the quire
template<typename Vector, size_t capacity = 10>
typename Vector::value_type fdp(const Vector& x, const Vector& y) {
	constexpr size_t nbits = typename Vector::value_type::nbits;
	constexpr size_t es = typename Vector::value_type::es;
	quire<nbits, es, capacity> q = 0;
	size_t ix, iy, n = size(x);
	for (ix = 0, iy = 0; ix < n && iy < n; ++ix, ++iy) {
		q += sw::unum::quire_mul(x[ix], y[iy]);
	}
	typename Vector::value_type sum;
	convert(q.to_value(), sum);     // one and only rounding step of the fused-dot product
	return sum;
}

#ifdef BLAS_L2
// LEVEL 2 BLAS operators
template<typename Ty>
void matvec(const std::vector<Ty>& A, const std::vector<Ty>& x, std::vector<Ty>& b) {
	// preconditions
	size_t d = x.size();
	assert(A.size() == d*d);
	assert(b.size() == d);
	for (size_t i = 0; i < d; ++i) {
		b[i] = 0;
		for (size_t j = 0; j < d; ++j) {
			//std::cout << "b[" << i << "] = " << b[i] << std::endl;
			//std::cout << "A[" << i << "][" << j << "] = " << A[i*d + j] << std::endl;
			//std::cout << "x[" << j << "] = " << x[j] << std::endl;
			b[i] = b[i] + A[i*d + j] * x[j];
		}
		//std::cout << "b[" << i << "] = " << b[i] << std::endl;
	}
}

// leverage template parameter inference to specialize matvec to use the quire when the inputs are posit vectors
template<size_t nbits, size_t es, size_t capacity = 10>
void matvec(const std::vector< posit<nbits, es> >& A, const std::vector< posit<nbits, es> >& x, std::vector< posit<nbits, es> >& b) {
	// preconditions
	size_t d = x.size();
	assert(A.size() == d*d);
	assert(b.size() == d);
	for (size_t i = 0; i < d; ++i) {
		b[i] = 0;
		quire<nbits, es, capacity> q;   // initialized to 0 by constructor
		for (size_t j = 0; j < d; ++j) {
			q += quire_mul(A[i*d + j], x[j]);
			if (sw::unum::_trace_quire_add) std::cout << q << '\n';
		}
		convert(q.to_value(), b[i]);  // one and only rounding step of the fused-dot product
		//std::cout << "b[" << i << "] = " << b[i] << std::endl;
	}
}
#endif  // BLAS_L2

#ifdef BLAS_L3
// LEVEL 3 BLAS operators

// matrix-matrix multiplication
template<typename Ty>
void matmul(const std::vector<Ty>& A, const std::vector<Ty>& B, std::vector<Ty>& C) {
	// preconditions
	size_t d = size_t(std::sqrt(A.size()));
	assert(A.size() == d*d);
	assert(B.size() == d*d);
	assert(C.size() == d*d);
	for (size_t i = 0; i < d; ++i) {
		for (size_t j = 0; j < d; ++j) {
			C[i*d + j] = Ty(0);
			for (size_t k = 0; k < d; ++k) {
				C[i*d + j] = C[i*d + j] + A[i*d + k] * B[k*d + j];
			}
		}
	}
}

// leverage template parameter inference to specialize matmul to use the quire when the inputs are posit vectors
template<size_t nbits, size_t es, size_t capacity = 10>
void matmul(const std::vector<posit<nbits,es> >& A, const std::vector< posit<nbits, es> >& B, std::vector< posit<nbits, es> >& C) {
	// preconditions
	size_t d = size_t(std::sqrt(A.size()));
	assert(A.size() == d*d);
	assert(B.size() == d*d);
	assert(C.size() == d*d);
	for (size_t i = 0; i < d; ++i) {
		for (size_t j = 0; j < d; ++j) {
			C[i*d + j] = 0;
			quire<nbits, es, capacity> q;   // initialized to 0 by constructor
			for (size_t k = 0; k < d; ++k) {
				// C[i*d + j] = C[i*d + j] + A[i*d + k] * B[k*d + j];
				q += quire_mul(A[i*d + k], B[k*d + j]);
				if (sw::unum::_trace_quire_add) std::cout << q << '\n';
			}
			convert(q.to_value(), C[i*d + j]);  // one and only rounding step of the fused-dot product
		}
	}
}

#endif  // BLAS_L3

} // namespace unum
} // namespace sw

<commit_msg>bug fix in extracting nbits and es from abstract type<commit_after>// fdp.hpp :  include file containing templated C++ interfaces to fused dot product
//
// Copyright (C) 2017-2019 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.

#include <vector>

namespace sw {
	namespace unum {

// dot product: the operator vector::x[index] is limited to uint32_t, so the arguments are limited to uint32_t as well
// since we do not support arbitrary posit configuration conversions, the element type of the vectors x and y are declared to be the same.
// TODO: investigate if the vector<> index is always a 32bit entity?
template<typename Ty>
Ty dot(size_t n, const std::vector<Ty>& x, size_t incx, const std::vector<Ty>& y, size_t incy) {
	Ty sum_of_products = 0;
	size_t cnt, ix, iy;
	for (cnt = 0, ix = 0, iy = 0; cnt < n && ix < x.size() && iy < y.size(); ++cnt, ix += incx, iy += incy) {
		Ty product = x[ix] * y[iy];
		sum_of_products += product;
	}
	return sum_of_products;
}

/// //////////////////////////////////////////////////////////////////
/// fused dot product operators
/// fdp_qc         fused dot product with quire continuation
/// fdp_stride     fused dot product with non-negative stride
/// fdp            fused dot product of two vectors

// Fused dot product with quire continuation
template<typename Qy, typename Vector>
void fdp_qc(Qy& sum_of_products, size_t n, const Vector& x, size_t incx, const Vector& y, size_t incy) {
	size_t ix, iy;
	for (ix = 0, iy = 0; ix < n && iy < n; ix = ix + incx, iy = iy + incy) {
		sum_of_products += sw::unum::quire_mul(x[ix], y[iy]);
	}
}

// Resolved fused dot product, with the option to control capacity bits in the quire
template<typename Vector, size_t capacity = 10>
typename Vector::value_type fdp_stride(size_t n, const Vector& x, size_t incx, const Vector& y, size_t incy) {
	constexpr size_t nbits = Vector::value_type::nbits;
	constexpr size_t es = Vector::value_type::es;
	quire<nbits, es, capacity> q = 0;
	size_t ix, iy;
	for (ix = 0, iy = 0; ix < n && iy < n; ix = ix + incx, iy = iy + incy) {
		q += sw::unum::quire_mul(x[ix], y[iy]);
		if (sw::unum::_trace_quire_add) std::cout << q << '\n';
	}
	typename Vector::value_type sum;
	convert(q.to_value(), sum);     // one and only rounding step of the fused-dot product
	return sum;
}

// Specialized resolved fused dot product that assumes unit stride and a standard vector,
// with the option to control capacity bits in the quire
template<typename Vector, size_t capacity = 10>
typename Vector::value_type fdp(const Vector& x, const Vector& y) {
	constexpr size_t nbits = Vector::value_type::nbits;
	constexpr size_t es = Vector::value_type::es;
	quire<nbits, es, capacity> q = 0;
	size_t ix, iy, n = size(x);
	for (ix = 0, iy = 0; ix < n && iy < n; ++ix, ++iy) {
		q += sw::unum::quire_mul(x[ix], y[iy]);
	}
	typename Vector::value_type sum;
	convert(q.to_value(), sum);     // one and only rounding step of the fused-dot product
	return sum;
}

#ifdef BLAS_L2
// LEVEL 2 BLAS operators
template<typename Ty>
void matvec(const std::vector<Ty>& A, const std::vector<Ty>& x, std::vector<Ty>& b) {
	// preconditions
	size_t d = x.size();
	assert(A.size() == d*d);
	assert(b.size() == d);
	for (size_t i = 0; i < d; ++i) {
		b[i] = 0;
		for (size_t j = 0; j < d; ++j) {
			//std::cout << "b[" << i << "] = " << b[i] << std::endl;
			//std::cout << "A[" << i << "][" << j << "] = " << A[i*d + j] << std::endl;
			//std::cout << "x[" << j << "] = " << x[j] << std::endl;
			b[i] = b[i] + A[i*d + j] * x[j];
		}
		//std::cout << "b[" << i << "] = " << b[i] << std::endl;
	}
}

// leverage template parameter inference to specialize matvec to use the quire when the inputs are posit vectors
template<size_t nbits, size_t es, size_t capacity = 10>
void matvec(const std::vector< posit<nbits, es> >& A, const std::vector< posit<nbits, es> >& x, std::vector< posit<nbits, es> >& b) {
	// preconditions
	size_t d = x.size();
	assert(A.size() == d*d);
	assert(b.size() == d);
	for (size_t i = 0; i < d; ++i) {
		b[i] = 0;
		quire<nbits, es, capacity> q;   // initialized to 0 by constructor
		for (size_t j = 0; j < d; ++j) {
			q += quire_mul(A[i*d + j], x[j]);
			if (sw::unum::_trace_quire_add) std::cout << q << '\n';
		}
		convert(q.to_value(), b[i]);  // one and only rounding step of the fused-dot product
		//std::cout << "b[" << i << "] = " << b[i] << std::endl;
	}
}
#endif  // BLAS_L2

#ifdef BLAS_L3
// LEVEL 3 BLAS operators

// matrix-matrix multiplication
template<typename Ty>
void matmul(const std::vector<Ty>& A, const std::vector<Ty>& B, std::vector<Ty>& C) {
	// preconditions
	size_t d = size_t(std::sqrt(A.size()));
	assert(A.size() == d*d);
	assert(B.size() == d*d);
	assert(C.size() == d*d);
	for (size_t i = 0; i < d; ++i) {
		for (size_t j = 0; j < d; ++j) {
			C[i*d + j] = Ty(0);
			for (size_t k = 0; k < d; ++k) {
				C[i*d + j] = C[i*d + j] + A[i*d + k] * B[k*d + j];
			}
		}
	}
}

// leverage template parameter inference to specialize matmul to use the quire when the inputs are posit vectors
template<size_t nbits, size_t es, size_t capacity = 10>
void matmul(const std::vector<posit<nbits,es> >& A, const std::vector< posit<nbits, es> >& B, std::vector< posit<nbits, es> >& C) {
	// preconditions
	size_t d = size_t(std::sqrt(A.size()));
	assert(A.size() == d*d);
	assert(B.size() == d*d);
	assert(C.size() == d*d);
	for (size_t i = 0; i < d; ++i) {
		for (size_t j = 0; j < d; ++j) {
			C[i*d + j] = 0;
			quire<nbits, es, capacity> q;   // initialized to 0 by constructor
			for (size_t k = 0; k < d; ++k) {
				// C[i*d + j] = C[i*d + j] + A[i*d + k] * B[k*d + j];
				q += quire_mul(A[i*d + k], B[k*d + j]);
				if (sw::unum::_trace_quire_add) std::cout << q << '\n';
			}
			convert(q.to_value(), C[i*d + j]);  // one and only rounding step of the fused-dot product
		}
	}
}

#endif  // BLAS_L3

} // namespace unum
} // namespace sw

<|endoftext|>


<commit_before>#ifndef __LOCAL_STORE_H
#define __LOCAL_STORE_H

#include <string>

#include "store-api.hh"

namespace nix {

class Transaction;

/* Nix store and database schema version.  Version 1 (or 0) was Nix <=
   0.7.  Version 2 was Nix 0.8 and 0.8.  Version 3 is Nix 0.10 and
   up. */
const int nixSchemaVersion = 3;

extern string drvsLogDir;

class LocalStore : public StoreAPI
{
public:

    /* Open the database environment.  If `reserveSpace' is true, make
       sure that a big empty file exists in /nix/var/nix/db/reserved.
       If `reserveSpace' is false, delete this file if it exists.  The
       idea is that on normal operation, the file exists; but when we
       run the garbage collector, it is deleted.  This is to ensure
       that the garbage collector has a small amount of disk space
       available, which is required to open the Berkeley DB
       environment. */
    LocalStore(bool reserveSpace);

    ~LocalStore();

    /* Implementations of abstract store API methods. */

    bool isValidPath(const Path & path);

    Substitutes querySubstitutes(const Path & srcPath);

    Hash queryPathHash(const Path & path);

    void queryReferences(const Path & path, PathSet & references);

    void queryReferrers(const Path & path, PathSet & referrers);

    Path addToStore(const Path & srcPath, bool fixed = false,
        bool recursive = false, string hashAlgo = "",
        PathFilter & filter = defaultPathFilter);

    Path addTextToStore(const string & suffix, const string & s,
        const PathSet & references);

    void exportPath(const Path & path, bool sign,
        Sink & sink);

    Path importPath(bool requireSignature, Source & source);

    void buildDerivations(const PathSet & drvPaths);

    void ensurePath(const Path & path);

    void addTempRoot(const Path & path);

    void addIndirectRoot(const Path & path);

    void syncWithGC();

    Roots findRoots();

    void collectGarbage(GCAction action, const PathSet & pathsToDelete,
        bool ignoreLiveness, PathSet & result, unsigned long long & bytesFreed);
};

/* Get a transaction object. */
void createStoreTransaction(Transaction & txn);

/* Copy a path recursively. */
void copyPath(const Path & src, const Path & dst);

/* Register a substitute. */
void registerSubstitute(const Transaction & txn,
    const Path & srcPath, const Substitute & sub);

/* Deregister all substitutes. */
void clearSubstitutes();

/* Register the validity of a path, i.e., that `path' exists, that the
   paths referenced by it exists, and in the case of an output path of
   a derivation, that it has been produced by a succesful execution of
   the derivation (or something equivalent).  Also register the hash
   of the file system contents of the path.  The hash must be a
   SHA-256 hash. */
void registerValidPath(const Transaction & txn,
    const Path & path, const Hash & hash, const PathSet & references,
    const Path & deriver);

struct ValidPathInfo
{
    Path path;
    Path deriver;
    Hash hash;
    PathSet references;
};

typedef list<ValidPathInfo> ValidPathInfos;

void registerValidPaths(const Transaction & txn,
    const ValidPathInfos & infos);

/* "Fix", or canonicalise, the meta-data of the files in a store path
   after it has been built.  In particular:
   - the last modification date on each file is set to 0 (i.e.,
     00:00:00 1/1/1970 UTC)
   - the permissions are set of 444 or 555 (i.e., read-only with or
     without execute permission; setuid bits etc. are cleared)
   - the owner and group are set to the Nix user and group, if we're
     in a setuid Nix installation. */
void canonicalisePathMetaData(const Path & path);

/* Checks whether a path is valid. */
bool isValidPathTxn(const Transaction & txn, const Path & path);

/* Sets the set of outgoing FS references for a store path.  Use with
   care! */
void setReferences(const Transaction & txn, const Path & path,
    const PathSet & references);

/* Sets the deriver of a store path.  Use with care! */
void setDeriver(const Transaction & txn, const Path & path,
    const Path & deriver);

/* Query the deriver of a store path.  Return the empty string if no
   deriver has been set. */
Path queryDeriver(const Transaction & txn, const Path & path);

/* Delete a value from the nixStore directory. */
void deleteFromStore(const Path & path, unsigned long long & bytesFreed);

MakeError(PathInUse, Error);

void verifyStore(bool checkContents);

/* Whether we are in build users mode. */
bool haveBuildUsers();

/* Whether we are root. */
bool amPrivileged();

/* Recursively change the ownership of `path' to the current uid. */
void getOwnership(const Path & path);

/* Like deletePath(), but changes the ownership of `path' using the
   setuid wrapper if necessary (and possible). */
void deletePathWrapped(const Path & path,
    unsigned long long & bytesFreed);

void deletePathWrapped(const Path & path);

}

#endif /* !__LOCAL_STORE_H */
<commit_msg>* Typo (reported by Marc Weber).<commit_after>#ifndef __LOCAL_STORE_H
#define __LOCAL_STORE_H

#include <string>

#include "store-api.hh"

namespace nix {

class Transaction;

/* Nix store and database schema version.  Version 1 (or 0) was Nix <=
   0.7.  Version 2 was Nix 0.8 and 0.9.  Version 3 is Nix 0.10 and
   up. */
const int nixSchemaVersion = 3;

extern string drvsLogDir;

class LocalStore : public StoreAPI
{
public:

    /* Open the database environment.  If `reserveSpace' is true, make
       sure that a big empty file exists in /nix/var/nix/db/reserved.
       If `reserveSpace' is false, delete this file if it exists.  The
       idea is that on normal operation, the file exists; but when we
       run the garbage collector, it is deleted.  This is to ensure
       that the garbage collector has a small amount of disk space
       available, which is required to open the Berkeley DB
       environment. */
    LocalStore(bool reserveSpace);

    ~LocalStore();

    /* Implementations of abstract store API methods. */

    bool isValidPath(const Path & path);

    Substitutes querySubstitutes(const Path & srcPath);

    Hash queryPathHash(const Path & path);

    void queryReferences(const Path & path, PathSet & references);

    void queryReferrers(const Path & path, PathSet & referrers);

    Path addToStore(const Path & srcPath, bool fixed = false,
        bool recursive = false, string hashAlgo = "",
        PathFilter & filter = defaultPathFilter);

    Path addTextToStore(const string & suffix, const string & s,
        const PathSet & references);

    void exportPath(const Path & path, bool sign,
        Sink & sink);

    Path importPath(bool requireSignature, Source & source);

    void buildDerivations(const PathSet & drvPaths);

    void ensurePath(const Path & path);

    void addTempRoot(const Path & path);

    void addIndirectRoot(const Path & path);

    void syncWithGC();

    Roots findRoots();

    void collectGarbage(GCAction action, const PathSet & pathsToDelete,
        bool ignoreLiveness, PathSet & result, unsigned long long & bytesFreed);
};

/* Get a transaction object. */
void createStoreTransaction(Transaction & txn);

/* Copy a path recursively. */
void copyPath(const Path & src, const Path & dst);

/* Register a substitute. */
void registerSubstitute(const Transaction & txn,
    const Path & srcPath, const Substitute & sub);

/* Deregister all substitutes. */
void clearSubstitutes();

/* Register the validity of a path, i.e., that `path' exists, that the
   paths referenced by it exists, and in the case of an output path of
   a derivation, that it has been produced by a succesful execution of
   the derivation (or something equivalent).  Also register the hash
   of the file system contents of the path.  The hash must be a
   SHA-256 hash. */
void registerValidPath(const Transaction & txn,
    const Path & path, const Hash & hash, const PathSet & references,
    const Path & deriver);

struct ValidPathInfo
{
    Path path;
    Path deriver;
    Hash hash;
    PathSet references;
};

typedef list<ValidPathInfo> ValidPathInfos;

void registerValidPaths(const Transaction & txn,
    const ValidPathInfos & infos);

/* "Fix", or canonicalise, the meta-data of the files in a store path
   after it has been built.  In particular:
   - the last modification date on each file is set to 0 (i.e.,
     00:00:00 1/1/1970 UTC)
   - the permissions are set of 444 or 555 (i.e., read-only with or
     without execute permission; setuid bits etc. are cleared)
   - the owner and group are set to the Nix user and group, if we're
     in a setuid Nix installation. */
void canonicalisePathMetaData(const Path & path);

/* Checks whether a path is valid. */
bool isValidPathTxn(const Transaction & txn, const Path & path);

/* Sets the set of outgoing FS references for a store path.  Use with
   care! */
void setReferences(const Transaction & txn, const Path & path,
    const PathSet & references);

/* Sets the deriver of a store path.  Use with care! */
void setDeriver(const Transaction & txn, const Path & path,
    const Path & deriver);

/* Query the deriver of a store path.  Return the empty string if no
   deriver has been set. */
Path queryDeriver(const Transaction & txn, const Path & path);

/* Delete a value from the nixStore directory. */
void deleteFromStore(const Path & path, unsigned long long & bytesFreed);

MakeError(PathInUse, Error);

void verifyStore(bool checkContents);

/* Whether we are in build users mode. */
bool haveBuildUsers();

/* Whether we are root. */
bool amPrivileged();

/* Recursively change the ownership of `path' to the current uid. */
void getOwnership(const Path & path);

/* Like deletePath(), but changes the ownership of `path' using the
   setuid wrapper if necessary (and possible). */
void deletePathWrapped(const Path & path,
    unsigned long long & bytesFreed);

void deletePathWrapped(const Path & path);

}

#endif /* !__LOCAL_STORE_H */
<|endoftext|>


<commit_before>#include "config.hh"
#include "args.hh"

#include <sstream>
#include <gtest/gtest.h>
#include <nlohmann/json.hpp>

namespace nix {

    /* ----------------------------------------------------------------------------
     * Config
     * --------------------------------------------------------------------------*/

    TEST(Config, setUndefinedSetting) {
        Config config;
        ASSERT_EQ(config.set("undefined-key", "value"), false);
    }

    TEST(Config, setDefinedSetting) {
        Config config;
        std::string value;
        Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};
        ASSERT_EQ(config.set("name-of-the-setting", "value"), true);
    }

    TEST(Config, getDefinedSetting) {
        Config config;
        std::string value;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};

        config.getSettings(settings, /* overridenOnly = */ false);
        const auto iter = settings.find("name-of-the-setting");
        ASSERT_NE(iter, settings.end());
        ASSERT_EQ(iter->second.value, "");
        ASSERT_EQ(iter->second.description, "description\n");
    }

    TEST(Config, getDefinedOverridenSettingNotSet) {
        Config config;
        std::string value;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};

        config.getSettings(settings, /* overridenOnly = */ true);
        const auto e = settings.find("name-of-the-setting");
        ASSERT_EQ(e, settings.end());
    }

    TEST(Config, getDefinedSettingSet1) {
        Config config;
        std::string value;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> setting{&config, value, "name-of-the-setting", "description"};

        setting.assign("value");

        config.getSettings(settings, /* overridenOnly = */ false);
        const auto iter = settings.find("name-of-the-setting");
        ASSERT_NE(iter, settings.end());
        ASSERT_EQ(iter->second.value, "value");
        ASSERT_EQ(iter->second.description, "description\n");
    }

    TEST(Config, getDefinedSettingSet2) {
        Config config;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};

        ASSERT_TRUE(config.set("name-of-the-setting", "value"));

        config.getSettings(settings, /* overridenOnly = */ false);
        const auto e = settings.find("name-of-the-setting");
        ASSERT_NE(e, settings.end());
        ASSERT_EQ(e->second.value, "value");
        ASSERT_EQ(e->second.description, "description\n");
    }

    TEST(Config, addSetting) {
        class TestSetting : public AbstractSetting {
            public:
            TestSetting() : AbstractSetting("test", "test", {}) {}
            void set(const std::string & value) {}
            std::string to_string() const { return {}; }
        };

        Config config;
        TestSetting setting;

        ASSERT_FALSE(config.set("test", "value"));
        config.addSetting(&setting);
        ASSERT_TRUE(config.set("test", "value"));
    }

    TEST(Config, withInitialValue) {
        const StringMap initials = {
            { "key", "value" },
        };
        Config config(initials);

        {
            std::map<std::string, Config::SettingInfo> settings;
            config.getSettings(settings, /* overridenOnly = */ false);
            ASSERT_EQ(settings.find("key"), settings.end());
        }

        Setting<std::string> setting{&config, "default-value", "key", "description"};

        {
            std::map<std::string, Config::SettingInfo> settings;
            config.getSettings(settings, /* overridenOnly = */ false);
            ASSERT_EQ(settings["key"].value, "value");
        }
    }

    TEST(Config, resetOverriden) {
        Config config;
        config.resetOverriden();
    }

    TEST(Config, resetOverridenWithSetting) {
        Config config;
        Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};

        {
            std::map<std::string, Config::SettingInfo> settings;

            setting.set("foo");
            ASSERT_EQ(setting.get(), "foo");
            config.getSettings(settings, /* overridenOnly = */ true);
            ASSERT_TRUE(settings.empty());
        }

        {
            std::map<std::string, Config::SettingInfo> settings;

            setting.override("bar");
            ASSERT_TRUE(setting.overriden);
            ASSERT_EQ(setting.get(), "bar");
            config.getSettings(settings, /* overridenOnly = */ true);
            ASSERT_FALSE(settings.empty());
        }

        {
            std::map<std::string, Config::SettingInfo> settings;

            config.resetOverriden();
            ASSERT_FALSE(setting.overriden);
            config.getSettings(settings, /* overridenOnly = */ true);
            ASSERT_TRUE(settings.empty());
        }
    }

    TEST(Config, toJSONOnEmptyConfig) {
        ASSERT_EQ(Config().toJSON().dump(), "{}");
    }

    TEST(Config, toJSONOnNonEmptyConfig) {
        Config config;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
        setting.assign("value");

        ASSERT_EQ(config.toJSON().dump(), R"#({"name-of-the-setting":{"aliases":[],"description":"description\n","value":"value"}})#");
    }

    TEST(Config, setSettingAlias) {
        Config config;
        Setting<std::string> setting{&config, "", "some-int", "best number", { "another-int" }};
        ASSERT_TRUE(config.set("some-int", "1"));
        ASSERT_EQ(setting.get(), "1");
        ASSERT_TRUE(config.set("another-int", "2"));
        ASSERT_EQ(setting.get(), "2");
        ASSERT_TRUE(config.set("some-int", "3"));
        ASSERT_EQ(setting.get(), "3");
    }

    /* FIXME: The reapplyUnknownSettings method doesn't seem to do anything
     * useful (these days).  Whenever we add a new setting to Config the
     * unknown settings are always considered.  In which case is this function
     * actually useful? Is there some way to register a Setting without calling
     * addSetting? */
    TEST(Config, DISABLED_reapplyUnknownSettings) {
        Config config;
        ASSERT_FALSE(config.set("name-of-the-setting", "unknownvalue"));
        Setting<std::string> setting{&config, "default", "name-of-the-setting", "description"};
        ASSERT_EQ(setting.get(), "default");
        config.reapplyUnknownSettings();
        ASSERT_EQ(setting.get(), "unknownvalue");
    }

    TEST(Config, applyConfigEmpty) {
        Config config;
        std::map<std::string, Config::SettingInfo> settings;
        config.applyConfig("");
        config.getSettings(settings);
        ASSERT_TRUE(settings.empty());
    }

    TEST(Config, applyConfigEmptyWithComment) {
        Config config;
        std::map<std::string, Config::SettingInfo> settings;
        config.applyConfig("# just a comment");
        config.getSettings(settings);
        ASSERT_TRUE(settings.empty());
    }

    TEST(Config, applyConfigAssignment) {
        Config config;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
        config.applyConfig(
            "name-of-the-setting = value-from-file #useful comment\n"
            "# name-of-the-setting = foo\n"
        );
        config.getSettings(settings);
        ASSERT_FALSE(settings.empty());
        ASSERT_EQ(settings["name-of-the-setting"].value, "value-from-file");
    }

    TEST(Config, applyConfigWithReassignedSetting) {
        Config config;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
        config.applyConfig(
            "name-of-the-setting = first-value\n"
            "name-of-the-setting = second-value\n"
        );
        config.getSettings(settings);
        ASSERT_FALSE(settings.empty());
        ASSERT_EQ(settings["name-of-the-setting"].value, "second-value");
    }

    TEST(Config, applyConfigFailsOnMissingIncludes) {
        Config config;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};

        ASSERT_THROW(config.applyConfig(
            "name-of-the-setting = value-from-file\n"
            "# name-of-the-setting = foo\n"
            "include /nix/store/does/not/exist.nix"
        ), Error);
    }

    TEST(Config, applyConfigInvalidThrows) {
        Config config;
        ASSERT_THROW(config.applyConfig("value == key"), UsageError);
        ASSERT_THROW(config.applyConfig("value "), UsageError);
    }
}
<commit_msg>fixup! Add a default value for the settings<commit_after>#include "config.hh"
#include "args.hh"

#include <sstream>
#include <gtest/gtest.h>
#include <nlohmann/json.hpp>

namespace nix {

    /* ----------------------------------------------------------------------------
     * Config
     * --------------------------------------------------------------------------*/

    TEST(Config, setUndefinedSetting) {
        Config config;
        ASSERT_EQ(config.set("undefined-key", "value"), false);
    }

    TEST(Config, setDefinedSetting) {
        Config config;
        std::string value;
        Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};
        ASSERT_EQ(config.set("name-of-the-setting", "value"), true);
    }

    TEST(Config, getDefinedSetting) {
        Config config;
        std::string value;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};

        config.getSettings(settings, /* overridenOnly = */ false);
        const auto iter = settings.find("name-of-the-setting");
        ASSERT_NE(iter, settings.end());
        ASSERT_EQ(iter->second.value, "");
        ASSERT_EQ(iter->second.description, "description\n");
    }

    TEST(Config, getDefinedOverridenSettingNotSet) {
        Config config;
        std::string value;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};

        config.getSettings(settings, /* overridenOnly = */ true);
        const auto e = settings.find("name-of-the-setting");
        ASSERT_EQ(e, settings.end());
    }

    TEST(Config, getDefinedSettingSet1) {
        Config config;
        std::string value;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> setting{&config, value, "name-of-the-setting", "description"};

        setting.assign("value");

        config.getSettings(settings, /* overridenOnly = */ false);
        const auto iter = settings.find("name-of-the-setting");
        ASSERT_NE(iter, settings.end());
        ASSERT_EQ(iter->second.value, "value");
        ASSERT_EQ(iter->second.description, "description\n");
    }

    TEST(Config, getDefinedSettingSet2) {
        Config config;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};

        ASSERT_TRUE(config.set("name-of-the-setting", "value"));

        config.getSettings(settings, /* overridenOnly = */ false);
        const auto e = settings.find("name-of-the-setting");
        ASSERT_NE(e, settings.end());
        ASSERT_EQ(e->second.value, "value");
        ASSERT_EQ(e->second.description, "description\n");
    }

    TEST(Config, addSetting) {
        class TestSetting : public AbstractSetting {
            public:
            TestSetting() : AbstractSetting("test", "test", {}) {}
            void set(const std::string & value) {}
            std::string to_string() const { return {}; }
        };

        Config config;
        TestSetting setting;

        ASSERT_FALSE(config.set("test", "value"));
        config.addSetting(&setting);
        ASSERT_TRUE(config.set("test", "value"));
    }

    TEST(Config, withInitialValue) {
        const StringMap initials = {
            { "key", "value" },
        };
        Config config(initials);

        {
            std::map<std::string, Config::SettingInfo> settings;
            config.getSettings(settings, /* overridenOnly = */ false);
            ASSERT_EQ(settings.find("key"), settings.end());
        }

        Setting<std::string> setting{&config, "default-value", "key", "description"};

        {
            std::map<std::string, Config::SettingInfo> settings;
            config.getSettings(settings, /* overridenOnly = */ false);
            ASSERT_EQ(settings["key"].value, "value");
        }
    }

    TEST(Config, resetOverriden) {
        Config config;
        config.resetOverriden();
    }

    TEST(Config, resetOverridenWithSetting) {
        Config config;
        Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};

        {
            std::map<std::string, Config::SettingInfo> settings;

            setting.set("foo");
            ASSERT_EQ(setting.get(), "foo");
            config.getSettings(settings, /* overridenOnly = */ true);
            ASSERT_TRUE(settings.empty());
        }

        {
            std::map<std::string, Config::SettingInfo> settings;

            setting.override("bar");
            ASSERT_TRUE(setting.overriden);
            ASSERT_EQ(setting.get(), "bar");
            config.getSettings(settings, /* overridenOnly = */ true);
            ASSERT_FALSE(settings.empty());
        }

        {
            std::map<std::string, Config::SettingInfo> settings;

            config.resetOverriden();
            ASSERT_FALSE(setting.overriden);
            config.getSettings(settings, /* overridenOnly = */ true);
            ASSERT_TRUE(settings.empty());
        }
    }

    TEST(Config, toJSONOnEmptyConfig) {
        ASSERT_EQ(Config().toJSON().dump(), "{}");
    }

    TEST(Config, toJSONOnNonEmptyConfig) {
        Config config;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
        setting.assign("value");

        ASSERT_EQ(config.toJSON().dump(), R"#({"name-of-the-setting":{"aliases":[],"defaultValue":"","description":"description\n","value":"value"}})#");
    }

    TEST(Config, setSettingAlias) {
        Config config;
        Setting<std::string> setting{&config, "", "some-int", "best number", { "another-int" }};
        ASSERT_TRUE(config.set("some-int", "1"));
        ASSERT_EQ(setting.get(), "1");
        ASSERT_TRUE(config.set("another-int", "2"));
        ASSERT_EQ(setting.get(), "2");
        ASSERT_TRUE(config.set("some-int", "3"));
        ASSERT_EQ(setting.get(), "3");
    }

    /* FIXME: The reapplyUnknownSettings method doesn't seem to do anything
     * useful (these days).  Whenever we add a new setting to Config the
     * unknown settings are always considered.  In which case is this function
     * actually useful? Is there some way to register a Setting without calling
     * addSetting? */
    TEST(Config, DISABLED_reapplyUnknownSettings) {
        Config config;
        ASSERT_FALSE(config.set("name-of-the-setting", "unknownvalue"));
        Setting<std::string> setting{&config, "default", "name-of-the-setting", "description"};
        ASSERT_EQ(setting.get(), "default");
        config.reapplyUnknownSettings();
        ASSERT_EQ(setting.get(), "unknownvalue");
    }

    TEST(Config, applyConfigEmpty) {
        Config config;
        std::map<std::string, Config::SettingInfo> settings;
        config.applyConfig("");
        config.getSettings(settings);
        ASSERT_TRUE(settings.empty());
    }

    TEST(Config, applyConfigEmptyWithComment) {
        Config config;
        std::map<std::string, Config::SettingInfo> settings;
        config.applyConfig("# just a comment");
        config.getSettings(settings);
        ASSERT_TRUE(settings.empty());
    }

    TEST(Config, applyConfigAssignment) {
        Config config;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
        config.applyConfig(
            "name-of-the-setting = value-from-file #useful comment\n"
            "# name-of-the-setting = foo\n"
        );
        config.getSettings(settings);
        ASSERT_FALSE(settings.empty());
        ASSERT_EQ(settings["name-of-the-setting"].value, "value-from-file");
    }

    TEST(Config, applyConfigWithReassignedSetting) {
        Config config;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
        config.applyConfig(
            "name-of-the-setting = first-value\n"
            "name-of-the-setting = second-value\n"
        );
        config.getSettings(settings);
        ASSERT_FALSE(settings.empty());
        ASSERT_EQ(settings["name-of-the-setting"].value, "second-value");
    }

    TEST(Config, applyConfigFailsOnMissingIncludes) {
        Config config;
        std::map<std::string, Config::SettingInfo> settings;
        Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};

        ASSERT_THROW(config.applyConfig(
            "name-of-the-setting = value-from-file\n"
            "# name-of-the-setting = foo\n"
            "include /nix/store/does/not/exist.nix"
        ), Error);
    }

    TEST(Config, applyConfigInvalidThrows) {
        Config config;
        ASSERT_THROW(config.applyConfig("value == key"), UsageError);
        ASSERT_THROW(config.applyConfig("value "), UsageError);
    }
}
<|endoftext|>


<commit_before>///
/// @file  pi_lmo_parallel.cpp
/// @brief Parallel implementation of the Lagarias-Miller-Odlyzko
///        prime counting algorithm using OpenMP. This implementation
///        uses load balancing and counts the number of unsieved
///        elements using POPCNT without using any special counting
///        tree data structure.
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <BitSieve.hpp>
#include <generate.hpp>
#include <generate_phi.hpp>
#include <LoadBalancer.hpp>
#include <min.hpp>
#include <imath.hpp>
#include <PhiTiny.hpp>
#include <PiTable.hpp>
#include <S1.hpp>
#include <Wheel.hpp>

#include <stdint.h>
#include <vector>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {

/// Cross-off the multiples of prime in the sieve array
int64_t cross_off(BitSieve& sieve,
                  int64_t low,
                  int64_t high,
                  int64_t prime,
                  WheelItem& w)
{
  int64_t count = 0;
  int64_t m = w.next_multiple;
  int64_t wheel_index = w.wheel_index;

  for (; m < high; m += prime * Wheel::next_multiple_factor(&wheel_index))
  {
    // +1 if m is unset the first time
    count += sieve[m - low];
    sieve.unset(m - low);
  }

  w.set(m, wheel_index);
  return count;
}

/// Compute the S2 contribution of the interval
/// [low, low + segments * segment_size[
///
int64_t S2_thread(int64_t x,
                  int64_t y,
                  int64_t z,
                  int64_t c,
                  int64_t low,
                  int64_t segments,
                  int64_t segment_size,
                  PiTable& pi,
                  vector<int32_t>& primes,
                  vector<int32_t>& lpf,
                  vector<int32_t>& mu,
                  Runtime& runtime)
{
  int64_t limit = min(low + segments * segment_size, z + 1);
  int64_t size = pi[min(isqrt(x / low), y)] + 1;
  int64_t pi_sqrty = pi[isqrt(y)];
  int64_t pi_y = pi[y];
  int64_t S2_thread = 0;

  if (c >= size - 1)
    return 0;

  runtime.init_start();
  BitSieve sieve(segment_size);
  Wheel wheel(primes, size, low);
  auto phi = generate_phi(low - 1, size - 1, primes, pi);
  runtime.init_stop();

  // segmented sieve of Eratosthenes
  for (; low < limit; low += segment_size)
  {
    // current segment = [low, high[
    int64_t high = min(low + segment_size, limit);
    int64_t b = c + 1;

    // pre-sieve multiples of first c primes
    sieve.pre_sieve(c, low);

    int64_t count_low_high = sieve.count((high - 1) - low);

    // For c + 1 <= b <= pi_sqrty
    // Find all special leaves: n = primes[b] * m
    // which satisfy:  mu[m] != 0 && primes[b] < lpf[m], low <= (x / n) < high
    for (; b <= min(pi_sqrty, size - 1); b++)
    {
      int64_t prime = primes[b];
      int64_t min_m = max(x / (prime * high), y / prime);
      int64_t max_m = min(x / (prime * low), y);
      int64_t count = 0;
      int64_t i = 0;

      if (prime >= max_m)
        goto next_segment;

      for (int64_t m = max_m; m > min_m; m--)
      {
        if (mu[m] != 0 && prime < lpf[m])
        {
          int64_t xn = x / (prime * m);
          int64_t stop = xn - low;
          count += sieve.count(i, stop);
          i = stop + 1;
          int64_t phi_xn = phi[b] + count;
          S2_thread -= mu[m] * phi_xn;
        }
      }

      phi[b] += count_low_high;
      count_low_high -= cross_off(sieve, low, high, prime, wheel[b]);
    }

    // For pi_sqrty < b < pi_y
    // Find all special leaves: n = primes[b] * prime2
    // which satisfy: low <= (x / n) < high
    for (; b < min(pi_y, size); b++)
    {
      int64_t prime = primes[b];
      int64_t l = pi[min(x / (prime * low), y)];
      int64_t min_m = max(x / (prime * high), prime);
      int64_t count = 0;
      int64_t i = 0;

      if (prime >= primes[l])
        goto next_segment;

      for (; primes[l] > min_m; l--)
      {
        int64_t xn = x / (prime * primes[l]);
        int64_t stop = xn - low;
        count += sieve.count(i, stop);
        i = stop + 1;
        int64_t phi_xn = phi[b] + count;
        S2_thread += phi_xn;
      }

      phi[b] += count_low_high;
      count_low_high -= cross_off(sieve, low, high, prime, wheel[b]);
    }

    next_segment:;
  }

  return S2_thread;
}

/// Calculate the contribution of the special leaves.
/// This is a parallel implementation with advanced load balancing.
/// As most special leaves tend to be in the first segments we
/// start off with a small segment size and few segments
/// per thread, after each iteration we dynamically increase
/// the segment size and the number of segments.
///
int64_t S2(int64_t x,
           int64_t y,
           int64_t z,
           int64_t c,
           int64_t s2_approx,
           vector<int32_t>& primes,
           vector<int32_t>& lpf,
           vector<int32_t>& mu,
           int threads)
{
  print("");
  print("=== S2(x, y) ===");
  print("Computation of the special leaves");

  double time = get_wtime();
  double alpha = get_alpha(x, y);
  threads = ideal_num_threads(threads, z);
  LoadBalancer loadBalancer(x, y, z, alpha, s2_approx);
  PiTable pi(y);

  #pragma omp parallel for num_threads(threads)
  for (int i = 0; i < threads; i++)
  {
    int64_t low = 0;
    int64_t segments = 0;
    int64_t segment_size = 0;
    int64_t S2 = 0;
    Runtime runtime;

    while (loadBalancer.get_work(&low, &segments, &segment_size, S2, runtime))
    {
      runtime.start();
      S2 = S2_thread(x, y, z, c, low, segments, segment_size, pi, primes, lpf, mu, runtime);
      runtime.stop();
    }
  }

  int64_t S2 = (int64_t) loadBalancer.get_result();
  print("S2", S2, time);

  return S2;
}

} // namespace

namespace primecount {

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm.
/// Run time: O(x^(2/3) / log x)
/// Memory usage: O(x^(1/3) * (log x)^2)
///
int64_t pi_lmo_parallel(int64_t x, int threads)
{
  if (x < 2)
    return 0;

  double alpha = get_alpha_lmo(x);
  int64_t x13 = iroot<3>(x);
  int64_t y = (int64_t) (x13 * alpha);
  int64_t z = x / y;
  int64_t c = PhiTiny::get_c(y);

  print("");
  print("=== pi_lmo_parallel(x) ===");
  print("pi(x) = S1 + S2 + pi(y) - 1 - P2");
  print(x, y, z, c, alpha, threads);

  int64_t p2 = P2(x, y, threads);
  auto primes = generate_primes<int32_t>(y);
  auto lpf = generate_lpf(y);
  auto mu = generate_moebius(y);

  int64_t pi_y = primes.size() - 1;
  int64_t s1 = S1(x, y, c, threads);
  int64_t s2_approx = S2_approx(x, pi_y, p2, s1);
  int64_t s2 = S2(x, y, z, c, s2_approx, primes, lpf, mu, threads);
  int64_t phi = s1 + s2;
  int64_t sum = phi + pi_y - 1 - p2;

  return sum;
}

} // namespace
<commit_msg>Remove unused variable<commit_after>///
/// @file  pi_lmo_parallel.cpp
/// @brief Parallel implementation of the Lagarias-Miller-Odlyzko
///        prime counting algorithm using OpenMP. This implementation
///        uses load balancing and counts the number of unsieved
///        elements using POPCNT without using any special counting
///        tree data structure.
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <BitSieve.hpp>
#include <generate.hpp>
#include <generate_phi.hpp>
#include <LoadBalancer.hpp>
#include <min.hpp>
#include <imath.hpp>
#include <PhiTiny.hpp>
#include <PiTable.hpp>
#include <S1.hpp>
#include <Wheel.hpp>

#include <stdint.h>
#include <vector>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {

/// Cross-off the multiples of prime in the sieve array
int64_t cross_off(BitSieve& sieve,
                  int64_t low,
                  int64_t high,
                  int64_t prime,
                  WheelItem& w)
{
  int64_t count = 0;
  int64_t m = w.next_multiple;
  int64_t wheel_index = w.wheel_index;

  for (; m < high; m += prime * Wheel::next_multiple_factor(&wheel_index))
  {
    // +1 if m is unset the first time
    count += sieve[m - low];
    sieve.unset(m - low);
  }

  w.set(m, wheel_index);
  return count;
}

/// Compute the S2 contribution of the interval
/// [low, low + segments * segment_size[
///
int64_t S2_thread(int64_t x,
                  int64_t y,
                  int64_t z,
                  int64_t c,
                  int64_t low,
                  int64_t segments,
                  int64_t segment_size,
                  PiTable& pi,
                  vector<int32_t>& primes,
                  vector<int32_t>& lpf,
                  vector<int32_t>& mu,
                  Runtime& runtime)
{
  int64_t limit = min(low + segments * segment_size, z + 1);
  int64_t size = pi[min(isqrt(x / low), y)] + 1;
  int64_t pi_sqrty = pi[isqrt(y)];
  int64_t pi_y = pi[y];
  int64_t S2_thread = 0;

  if (c >= size - 1)
    return 0;

  runtime.init_start();
  BitSieve sieve(segment_size);
  Wheel wheel(primes, size, low);
  auto phi = generate_phi(low - 1, size - 1, primes, pi);
  runtime.init_stop();

  // segmented sieve of Eratosthenes
  for (; low < limit; low += segment_size)
  {
    // current segment = [low, high[
    int64_t high = min(low + segment_size, limit);
    int64_t b = c + 1;

    // pre-sieve multiples of first c primes
    sieve.pre_sieve(c, low);

    int64_t count_low_high = sieve.count((high - 1) - low);

    // For c + 1 <= b <= pi_sqrty
    // Find all special leaves: n = primes[b] * m
    // which satisfy:  mu[m] != 0 && primes[b] < lpf[m], low <= (x / n) < high
    for (; b <= min(pi_sqrty, size - 1); b++)
    {
      int64_t prime = primes[b];
      int64_t min_m = max(x / (prime * high), y / prime);
      int64_t max_m = min(x / (prime * low), y);
      int64_t count = 0;
      int64_t i = 0;

      if (prime >= max_m)
        goto next_segment;

      for (int64_t m = max_m; m > min_m; m--)
      {
        if (mu[m] != 0 && prime < lpf[m])
        {
          int64_t xn = x / (prime * m);
          int64_t stop = xn - low;
          count += sieve.count(i, stop);
          i = stop + 1;
          int64_t phi_xn = phi[b] + count;
          S2_thread -= mu[m] * phi_xn;
        }
      }

      phi[b] += count_low_high;
      count_low_high -= cross_off(sieve, low, high, prime, wheel[b]);
    }

    // For pi_sqrty < b < pi_y
    // Find all special leaves: n = primes[b] * prime2
    // which satisfy: low <= (x / n) < high
    for (; b < min(pi_y, size); b++)
    {
      int64_t prime = primes[b];
      int64_t l = pi[min(x / (prime * low), y)];
      int64_t min_m = max(x / (prime * high), prime);
      int64_t count = 0;
      int64_t i = 0;

      if (prime >= primes[l])
        goto next_segment;

      for (; primes[l] > min_m; l--)
      {
        int64_t xn = x / (prime * primes[l]);
        int64_t stop = xn - low;
        count += sieve.count(i, stop);
        i = stop + 1;
        int64_t phi_xn = phi[b] + count;
        S2_thread += phi_xn;
      }

      phi[b] += count_low_high;
      count_low_high -= cross_off(sieve, low, high, prime, wheel[b]);
    }

    next_segment:;
  }

  return S2_thread;
}

/// Calculate the contribution of the special leaves.
/// This is a parallel implementation with advanced load balancing.
/// As most special leaves tend to be in the first segments we
/// start off with a small segment size and few segments
/// per thread, after each iteration we dynamically increase
/// the segment size and the number of segments.
///
int64_t S2(int64_t x,
           int64_t y,
           int64_t z,
           int64_t c,
           int64_t s2_approx,
           vector<int32_t>& primes,
           vector<int32_t>& lpf,
           vector<int32_t>& mu,
           int threads)
{
  print("");
  print("=== S2(x, y) ===");
  print("Computation of the special leaves");

  double time = get_wtime();
  threads = ideal_num_threads(threads, z);
  LoadBalancer loadBalancer(x, y, z, s2_approx);
  PiTable pi(y);

  #pragma omp parallel for num_threads(threads)
  for (int i = 0; i < threads; i++)
  {
    int64_t low = 0;
    int64_t segments = 0;
    int64_t segment_size = 0;
    int64_t S2 = 0;
    Runtime runtime;

    while (loadBalancer.get_work(&low, &segments, &segment_size, S2, runtime))
    {
      runtime.start();
      S2 = S2_thread(x, y, z, c, low, segments, segment_size, pi, primes, lpf, mu, runtime);
      runtime.stop();
    }
  }

  int64_t S2 = (int64_t) loadBalancer.get_result();
  print("S2", S2, time);

  return S2;
}

} // namespace

namespace primecount {

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm.
/// Run time: O(x^(2/3) / log x)
/// Memory usage: O(x^(1/3) * (log x)^2)
///
int64_t pi_lmo_parallel(int64_t x, int threads)
{
  if (x < 2)
    return 0;

  double alpha = get_alpha_lmo(x);
  int64_t x13 = iroot<3>(x);
  int64_t y = (int64_t) (x13 * alpha);
  int64_t z = x / y;
  int64_t c = PhiTiny::get_c(y);

  print("");
  print("=== pi_lmo_parallel(x) ===");
  print("pi(x) = S1 + S2 + pi(y) - 1 - P2");
  print(x, y, z, c, alpha, threads);

  int64_t p2 = P2(x, y, threads);
  auto primes = generate_primes<int32_t>(y);
  auto lpf = generate_lpf(y);
  auto mu = generate_moebius(y);

  int64_t pi_y = primes.size() - 1;
  int64_t s1 = S1(x, y, c, threads);
  int64_t s2_approx = S2_approx(x, pi_y, p2, s1);
  int64_t s2 = S2(x, y, z, c, s2_approx, primes, lpf, mu, threads);
  int64_t phi = s1 + s2;
  int64_t sum = phi + pi_y - 1 - p2;

  return sum;
}

} // namespace
<|endoftext|>


<commit_before>#include "maBiblio.h"

bool ValidationLigne(string, int);
int OptimiseLongueur(string);
vector<string> GrilleLettre(string, int);
vector<string> GrilleJeu(string, int);
void PromotionEspaceVide(vector<string>&);
void EspaceSort(vector<string>&, int, int,int);
int Partition(vector<string>&,int,int,int,int);
void EcrireFichier(vector<string>, vector<string>, int);
void AfficherJeu(vector<string>, vector<string>);
bool is_npos(int);

int main()
{
	srand(time(NULL));
	setlocale(LC_ALL, "");
	ifstream ficIn;
	string nomFichier;
	string ligneCourante;
	int nbLigne = 0;
	int nbrColonnes = 0;
   int nbGenerer = 0;
   string cadreHaut = "╔═";
   string cadreCote = "║";
   string cadreBas = "╚";

	do
	{
		cout << "Veuillez entrer le nom du fichier contenant les citations : ";

		cin >> nomFichier;
		ficIn.open(nomFichier);

		//Un peu comme Assert, si le fichie n'ouvre pas il affiche un message d'erreur.
	} while (!ficIn.is_open() && (cout << "Erreur de lecture.\n"));

	cout << "Fichier :" << nomFichier << " est en mode lecture.\n";

	while (ficIn.good())
	{
		nbLigne++;
		getline(ficIn, ligneCourante);
		/*
		int pos = ligneCourante.find_first_not_of("\n ");
		//find_first_not_of peut retourner string::npos (constante évalué à -1) si rien n'a été trouvé.
		//Si c'est le cas, ligne vide ou mal formaté, break à l'extérieur du for pour prendre la prochaine ligne.
		if (pos == string::npos)
		{
			cout << "Erreur ligne " << nbLigne << " citation vide.\n";
			continue;
		}

		ligneCourante = ligneCourante.substr(pos);
		*/

		if (!ValidationLigne(ligneCourante, nbLigne))
			continue;
		nbrColonnes = OptimiseLongueur(ligneCourante);
		vector<string> grilleLettre = GrilleLettre(ligneCourante, nbrColonnes);
		vector<string> grilleJeu= GrilleJeu(ligneCourante, nbrColonnes);

		PromotionEspaceVide(grilleLettre);
      nbGenerer++;
	  AfficherJeu(grilleLettre, grilleJeu);
      EcrireFichier(grilleLettre, grilleJeu, nbGenerer);
	  system("pause");

	}

	ficIn.close();
	cout << "Programme terminé\n";
	system("pause");
	return 0;
}

void AfficherJeu(vector<string> haut, vector<string> bas)
{
	cout << endl << endl;

	for (string s : haut)
	{
		cout << s << endl;
	}

	cout << endl;

	for (string s : bas)
	{
		cout << s << endl;
	}

	cout << endl << endl;
}

void EcrireFichier(vector<string> sup, vector<string> inf, int nb)
{
   ofstream ficOut;
   stringstream ss;

   ss << "Citation" << nb << ".txt";

   ficOut.open(ss.str(), ios::out);

   ficOut << endl;
   ficOut << endl;
   for (string s : sup)
   {
      ficOut << s;
      ficOut << endl;
   }
   for (string s : inf)
   {
      ficOut << endl;
      ficOut << s;
      ficOut << endl;
   }
   ficOut.close();

   cout << "Grille enregistrée à : " << ss.str() << endl;;
   ss.str(string());
}

bool ValidationLigne(string ligne, int nbr)
{
	for (char c : ligne)
	{
		int i = c;
		if (i >= 128 || i < 0)
		{
			cout << "Erreur ligne " << nbr << " la citation contient des caractères illegaux.\n";
			return false;
		}
	}

	if (ligne.length() < 35)
	{
		cout << "Erreur ligne " << nbr << " la citation contient moins que 35 caractères.\n";
		return false;
	}

	if (ligne.length() > 100)
	{
		cout << "Erreur ligne " << nbr << " la citation contient plus que 100 caractères.\n";
		return false;
	}

	bool bon = is_npos(ligne.find("  ")) &
              is_npos(ligne.find("--")) &
              is_npos(ligne.find("''")) &
              is_npos(ligne.find("..")) &
              is_npos(ligne.find(",,"));

	if (!bon)
	{

		cout << "Erreur ligne " << nbr << " séparateur de mot consécutifs dans la citation.\n";
		return false;
	}

	return true;
}

bool is_npos(int i)
{
   if (i == string::npos)
      return true;
   return false;
}

int OptimiseLongueur(string ligne)
{
	int colonnes = 0;
	int meilleurTronquage = 9999;

	for (int i = 13; i < 18; i++)
	{
		int motTronquer = 0;
		int times = ceil((double)ligne.length() /i);
		for (int t = 1; t <= times; t++)
		{
			if ((ligne.length() > ((t * i))) && (ligne[t*i] != ' ') && (ligne[(t*i) -1] != ' '))
			{
				motTronquer++;
			}
		}
		if (motTronquer < meilleurTronquage)
		{
			meilleurTronquage = motTronquer;
			colonnes = i;
		}
	}

	return colonnes;
}

vector<string> GrilleLettre(string ligne, int colonne)
{
	vector<string> grilleLettre;

	while (ligne.length() != 0)
	{
		grilleLettre.push_back(ligne.substr(0, colonne));
		ligne = ligne.substr(ligne.length() <= colonne ? ligne.length() : colonne);
	}
	if (grilleLettre[grilleLettre.size() - 1].length() < colonne)
	{
		int i = colonne - grilleLettre[grilleLettre.size() - 1].length();
		string s(i, ' ');
		grilleLettre[grilleLettre.size() - 1] += s;
	}

	for (int i = 0; i < colonne; i++)
	{
		int nbrEchange = rand() % 50 + 1;
		for (int r = 0; r < nbrEchange; r++)
		{
			int premier = rand() % grilleLettre.size();;
			int deuxieme = rand() % grilleLettre.size();;

			swap(grilleLettre[premier][i],grilleLettre[deuxieme][i]);
		}
	}
	for (int i = 0; i < grilleLettre.size(); i++)
	{
      transform(grilleLettre[i].begin(), grilleLettre[i].end(), grilleLettre[i].begin(), toupper);
	}
	return  grilleLettre;
}

vector<string> GrilleJeu(string ligne, int colonne)
{
	vector<string> grilleJeu;

	for (int i = 0; i < ligne.length();i++)
	{
		if (isalnum(ligne[i]))
		{
			ligne[i] = '-';
		}
		else
			ligne[i] = ' ';
	}

	while (ligne.length() != 0)
	{
		grilleJeu.push_back(ligne.substr(0, colonne));
		ligne = ligne.substr(ligne.length() <= colonne ? ligne.length() : colonne);
	}

	return grilleJeu;
}

void PromotionEspaceVide(vector<string>& grille)
{
	for (int i = 0; i < grille[0].length(); i++)
	{
		EspaceSort(grille, 0, grille.size() - 1, i);
	}

}

void EspaceSort(vector<string>& vecteur, int debut, int fin, int ligne)
{
	if (fin <= debut)
		return;

		int indexPivot = rand() % (fin - debut) + debut;
		indexPivot = Partition(vecteur, debut, fin, indexPivot, ligne);
		EspaceSort(vecteur, debut, indexPivot - 1, ligne);
		EspaceSort(vecteur, indexPivot + 1, fin, ligne);

}

int Partition(vector<string>& vecteur, int debut, int fin, int pivot, int ligne)
{
	char cpivot = vecteur[pivot][ligne];
	swap(vecteur[pivot][ligne], vecteur[fin][ligne]);

	int pivpost = debut;
	for (int i = debut; i < fin;i++)
	{
		if (vecteur[i][ligne] == ' ')
		{
			swap(vecteur[pivpost][ligne], vecteur[i][ligne]);
			pivpost += 1;
		}
	}
	swap(vecteur[pivpost][ligne], vecteur[fin][ligne]);
	return pivpost;
}<commit_msg>Rajout de commentaires<commit_after>#include "maBiblio.h"

bool ValidationLigne(string, int);
int OptimiseLongueur(string);
vector<string> GrilleLettre(string, int);
vector<string> GrilleJeu(string, int);
void PromotionEspaceVide(vector<string>&);
void EspaceSort(vector<string>&, int, int,int);
int Partition(vector<string>&,int,int,int,int);
void EcrireFichier(vector<string>, vector<string>, int);
void AfficherJeu(vector<string>, vector<string>);
bool is_npos(int);

int main()
{
	srand(time(NULL));
	setlocale(LC_ALL, "");
	ifstream ficIn;
	string nomFichier;
	string ligneCourante;
	int nbLigne = 0;
	int nbrColonnes = 0;
   int nbGenerer = 0;
   string cadreHaut = "╔═";
   string cadreCote = "║";
   string cadreBas = "╚";

	do
	{
		cout << "Veuillez entrer le nom du fichier contenant les citations : ";

		cin >> nomFichier;
		ficIn.open(nomFichier);

		//Un peu comme Assert, si le fichie n'ouvre pas il affiche un message d'erreur.
	} while (!ficIn.is_open() && (cout << "Erreur de lecture.\n"));

	cout << "Fichier :" << nomFichier << " est en mode lecture.\n";

	while (ficIn.good())
	{
		nbLigne++;
		getline(ficIn, ligneCourante);
		/*
		int pos = ligneCourante.find_first_not_of("\n ");
		//find_first_not_of peut retourner string::npos (constante évalué à -1) si rien n'a été trouvé.
		//Si c'est le cas, ligne vide ou mal formaté, break à l'extérieur du for pour prendre la prochaine ligne.
		if (pos == string::npos)
		{
			cout << "Erreur ligne " << nbLigne << " citation vide.\n";
			continue;
		}

		ligneCourante = ligneCourante.substr(pos);
		*/

      //Si la ligne n'est pas valide, continue à la prochaine boucle.
      //À pour effet d'aller chercher la prochaine ligne.
		if (!ValidationLigne(ligneCourante, nbLigne))
			continue;

      //Le nombre de colonnes qui sera utilisé pour la grille de jeu de cette citation.
		nbrColonnes = OptimiseLongueur(ligneCourante);
      //Chaque string du vector est une ligne différente de la grille.
      //grilleLettre a les lettres de la grille supérieur.
      //grilleJeu a la représentation du jeu, l'emplacement où les lettres doivent aller.
		vector<string> grilleLettre = GrilleLettre(ligneCourante, nbrColonnes);
		vector<string> grilleJeu= GrilleJeu(ligneCourante, nbrColonnes);

		PromotionEspaceVide(grilleLettre);
      //Nombre de grille généré par le programme.
      nbGenerer++;
	   AfficherJeu(grilleLettre, grilleJeu);
      EcrireFichier(grilleLettre, grilleJeu, nbGenerer);
	   system("pause");

	}

	ficIn.close();
	cout << "Programme terminé\n";
	system("pause");

   //Si aucune citation a été généré, retourne le code 1.
   if (nbGenerer == 0)
      return 1;
	return 0;
}

/*
Fonction qui prend en paramètre deux vector<string> et qui affiche leur contenue.
Pour visualiser les grilles du jeu sur la console.
*/
void AfficherJeu(vector<string> haut, vector<string> bas)
{
	cout << endl << endl;

	for (string s : haut)
	{
		cout << s << endl;
	}

	cout << endl;

	for (string s : bas)
	{
		cout << s << endl;
	}

	cout << endl << endl;
}

/*
Fonction qui prend deux vector<string> et un int pour enregistrer le contenue des deux vector dans un fichier.
Pour enregistrer les grilles du jeu dans un fichier. Le nom du fichier est en fonction du int qui lui donne le nombre de la citation.
*/
void EcrireFichier(vector<string> sup, vector<string> inf, int nb)
{
   ofstream ficOut;
   stringstream ss;
   //Utilisation de stringstream pour construire un objet string avec un string litteral et une variable int.
   ss << "Citation" << nb << ".txt";

   ficOut.open(ss.str(), ios::out);
   //Enregistre ligne par ligne le contenue des vector dans le fichier.
   ficOut << endl;
   ficOut << endl;
   for (string s : sup)
   {
      ficOut << s;
      ficOut << endl;
   }
   for (string s : inf)
   {
      ficOut << endl;
      ficOut << s;
      ficOut << endl;
   }
   ficOut.close();

   cout << "Grille enregistrée à : " << ss.str() << endl;;
   //Vide le stringstream
   ss.str(string());
}

/*
Fonction qui prend un string et un int pour valider le string.
Le int est utilisé pour afficher un message d'erreur à l'utilisateur.
Valide une citation.
Retourne false si incorrect. True pour valide.
*/
bool ValidationLigne(string ligne, int nbr)
{
	for (char c : ligne)
	{
      //Prend le code ascii du char
		int i = c;
      //Vérifie si le char est un charactère du ascii de base.
		if (i >= 128 || i < 0)
		{
			cout << "Erreur ligne " << nbr << " la citation contient des caractères illegaux.\n";
			return false;
		}
	}

	if (ligne.length() < 35)
	{
		cout << "Erreur ligne " << nbr << " la citation contient moins que 35 caractères.\n";
		return false;
	}

	if (ligne.length() > 100)
	{
		cout << "Erreur ligne " << nbr << " la citation contient plus que 100 caractères.\n";
		return false;
	}

   /*
   Utilise l'opérateur AND bit-à-bit pour déterminer si deux caractères d'espacement ce situe un à côté de l'autre.
   La réponse est en un bit (bool). Si une des fonctions retourne un False, le résultat final sera un False.
   Alors que pour que "bon" soit True, il faut que toutes les fonctions retourne True.
   string.find() retourne la constante npos s'il n'y a aucun résultat dans la string, ce qui est le cas s'il n'y a pas de
   dédoublement de caractères d'espacement. is_npos retourne True si, en effet, il n'est pas présent.
   Permet d'avoir une condition if assez petite.
   */
	bool bon = is_npos(ligne.find("  ")) &
              is_npos(ligne.find("--")) &
              is_npos(ligne.find("''")) &
              is_npos(ligne.find("..")) &
              is_npos(ligne.find(",,"));

	if (!bon)
	{

		cout << "Erreur ligne " << nbr << " séparateur de mot consécutifs dans la citation.\n";
		return false;
	}

	return true;
}

//Retourne true is i est la constante string::npos
bool is_npos(int i)
{
   if (i == string::npos)
      return true;
   return false;
}

/*
À partir d'un string, détermine le nombre de colonnes qui minimise les mots tronqués.
Retourne le int qui en résulte.
*/
int OptimiseLongueur(string ligne)
{
	int colonnes = 0;
   //Valeur arbitrairement grosse pour être presque certain (dans la majorité des cas d'utilisation)
   //qu'un meilleur résultat sera trouvé.
	int meilleurTronquage = 9999;

   //Vérifie selon la longueur minimale de 13 caractères par ligne jusqu'au maximum de 17 inclusivement.
	for (int i = 13; i < 18; i++)
	{
      //Compteur de mots tronqués.
		int motTronquer = 0;
      //Le nombres de lignes. ceil est pour l'arrondir au plus grand entier supérieur.
		int times = ceil((double)ligne.length() /i);
		for (int t = 1; t <= times; t++)
		{
         /*
         Si la longueur de la ligne est plus petite ou égal que le nombre de caractère par ligne * le nombre de ligne, nous pouvons l'écrire sur une ligne au complet
         donc pas de mot tronqué.

         */
			if ((ligne.length() > ((t * i))) && (ligne[t*i] != ' ') && (ligne[(t*i) -1] != ' '))
			{
				motTronquer++;
			}
		}
      //Trouvé un meilleur résultat
		if (motTronquer < meilleurTronquage)
		{
			meilleurTronquage = motTronquer;
			colonnes = i;
		}
	}

	return colonnes;
}

/*
Créer la grille de lettre à partir d'un string et du nombre de colonnes.
Retourne le résultat sour la forme d'un vector<string> ou chaque string est une ligne différente.
*/
vector<string> GrilleLettre(string ligne, int colonne)
{
	vector<string> grilleLettre;

   //Retire des lettres de ligne au fure et à mesure pour les rajouter dans le vector grilleLettre.
	while (ligne.length() != 0)
	{
      //Retire la première ligne de la grille et la rajoute dans le vector.
		grilleLettre.push_back(ligne.substr(0, colonne));
      //Lorsqu'il ne reste pas assez de caractères à la string pour former une ligne au complète (selon le int colonne)
      //prend le restant de la string au complet. Pour éviter les erreurs d'exécution.
		ligne = ligne.substr(ligne.length() <= colonne ? ligne.length() : colonne);
	}
   //Rajoute des espacements vide à la dernière ligne de la grille pour avoir des string de taille uniforme.
	if (grilleLettre[grilleLettre.size() - 1].length() < colonne)
	{
		int i = colonne - grilleLettre[grilleLettre.size() - 1].length();
		string s(i, ' ');
		grilleLettre[grilleLettre.size() - 1] += s;
	}

   //Mélange les caractères des colonnes
	for (int i = 0; i < colonne; i++)
	{
		int nbrEchange = rand() % 50 + 1;
		for (int r = 0; r < nbrEchange; r++)
		{
			int premier = rand() % grilleLettre.size();;
			int deuxieme = rand() % grilleLettre.size();;
	      //Fonction permuter disponible dans la librairie algorithm.
			swap(grilleLettre[premier][i],grilleLettre[deuxieme][i]);
		}
	}
   //Utilisation des itérateurs pour transformer chaque char en majuscule.
	for (int i = 0; i < grilleLettre.size(); i++)
	{
      transform(grilleLettre[i].begin(), grilleLettre[i].end(), grilleLettre[i].begin(), toupper);
	}
	return  grilleLettre;
}

/*
Créer la grille de jeu avec des emplacements vides ou des emplacements pour écrire des lettres du nombre de colonnes données.
Retourne un vector<string> qui est la grille formaté où chaque string est une ligne.
*/
vector<string> GrilleJeu(string ligne, int colonne)
{
	vector<string> grilleJeu;

	for (int i = 0; i < ligne.length();i++)
	{
      //Si le caractère est alpha-numérique, on le remplace par un emplacement lettre.
		if (isalnum(ligne[i]))
		{
			ligne[i] = '-';
		}
      //Sinon, devient un emplacement vide.
		else
			ligne[i] = ' ';
	}

   //Rajoute les lignes dans la grilleJeu.
	while (ligne.length() != 0)
	{
		grilleJeu.push_back(ligne.substr(0, colonne));
      //Lorsqu'il ne reste pas assez de caractères à la string pour former une ligne au complète (selon le int colonne)
      //prend le restant de la string au complet. Pour éviter les erreurs d'exécution.
		ligne = ligne.substr(ligne.length() <= colonne ? ligne.length() : colonne);
	}

	return grilleJeu;
}

/*
Fonction pour créer un meilleur visuel.
Utilise un QuickSort implémenté pour travailler avec les colonnes d'un vector<string> dans le but de positionner les
emplacements vide au dessus des emplacements lettre.
Lors du mélange des caractères sur la colonnes, les emplacements vide pouvaient ce trouver n'importe où.
Puisque QuickSort est un algorithme instable, l'ordre des lettres n'est pas garantit.
*/
void PromotionEspaceVide(vector<string>& grille)
{
   //Pour chaque colonnes
	for (int i = 0; i < grille[0].length(); i++)
	{
      //Lance EspaceSort, envois le data, l'index du début, l'index de la fin et le numéro de la colonne traité.
		EspaceSort(grille, 0, grille.size() - 1, i);
	}

}

void EspaceSort(vector<string>& vecteur, int debut, int fin, int ligne)
{
	if (fin <= debut)
		return;

		int indexPivot = rand() % (fin - debut) + debut;
		indexPivot = Partition(vecteur, debut, fin, indexPivot, ligne);
		EspaceSort(vecteur, debut, indexPivot - 1, ligne);
		EspaceSort(vecteur, indexPivot + 1, fin, ligne);

}

int Partition(vector<string>& vecteur, int debut, int fin, int pivot, int ligne)
{
	char cpivot = vecteur[pivot][ligne];
	swap(vecteur[pivot][ligne], vecteur[fin][ligne]);

	int pivpost = debut;
	for (int i = debut; i < fin;i++)
	{
		if (vecteur[i][ligne] == ' ')
		{
			swap(vecteur[pivpost][ligne], vecteur[i][ligne]);
			pivpost += 1;
		}
	}
	swap(vecteur[pivpost][ligne], vecteur[fin][ligne]);
	return pivpost;
}<|endoftext|>


<commit_before>/*
 Copyright (c) 2019, Ford Motor Company, Livio
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

 Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.

 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following
 disclaimer in the documentation and/or other materials provided with the
 distribution.

 Neither the name of the the copyright holders nor the names of their
 contributors may be used to endorse or promote products derived from this
 software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 */

#include "app_service_rpc_plugin/app_service_mobile_command_factory.h"

#include "application_manager/message.h"
#include "interfaces/MOBILE_API.h"

#include "app_service_rpc_plugin/commands/mobile/get_app_service_data_request.h"
#include "app_service_rpc_plugin/commands/mobile/get_app_service_data_request_to_mobile.h"
#include "app_service_rpc_plugin/commands/mobile/get_app_service_data_response.h"
#include "app_service_rpc_plugin/commands/mobile/get_app_service_data_response_from_mobile.h"
#include "app_service_rpc_plugin/commands/mobile/on_app_service_data_notification.h"
#include "app_service_rpc_plugin/commands/mobile/on_app_service_data_notification_from_mobile.h"
#include "app_service_rpc_plugin/commands/mobile/perform_app_service_interaction_request.h"
#include "app_service_rpc_plugin/commands/mobile/perform_app_service_interaction_request_to_mobile.h"
#include "app_service_rpc_plugin/commands/mobile/perform_app_service_interaction_response.h"
#include "app_service_rpc_plugin/commands/mobile/perform_app_service_interaction_response_from_mobile.h"
#include "app_service_rpc_plugin/commands/mobile/publish_app_service_request.h"
#include "app_service_rpc_plugin/commands/mobile/publish_app_service_response.h"

CREATE_LOGGERPTR_GLOBAL(logger_, "AppServiceRpcPlugin")

namespace app_service_rpc_plugin {
namespace strings = app_mngr::strings;

AppServiceMobileCommandFactory::AppServiceMobileCommandFactory(
    application_manager::ApplicationManager& application_manager,
    application_manager::rpc_service::RPCService& rpc_service,
    application_manager::HMICapabilities& hmi_capabilities,
    policy::PolicyHandlerInterface& policy_handler)
    : application_manager_(application_manager)
    , rpc_service_(rpc_service)
    , hmi_capabilities_(hmi_capabilities)
    , policy_handler_(policy_handler) {
  LOG4CXX_AUTO_TRACE(logger_);
}

app_mngr::CommandSharedPtr AppServiceMobileCommandFactory::CreateCommand(
    const app_mngr::commands::MessageSharedPtr& message,
    app_mngr::commands::Command::CommandSource source) {
  UNUSED(source);

  const mobile_apis::FunctionID::eType function_id =
      static_cast<mobile_apis::FunctionID::eType>(
          (*message)[strings::params][strings::function_id].asInt());

  const mobile_apis::messageType::eType message_type =
      static_cast<mobile_apis::messageType::eType>(
          (*message)[strings::params][strings::message_type].asInt());

  auto message_type_str = "request";
  if (mobile_apis::messageType::response == message_type) {
    message_type_str = "response";
  } else if (mobile_apis::messageType::notification == message_type) {
    message_type_str = "notification";
  }

  UNUSED(message_type_str);
  LOG4CXX_DEBUG(logger_,
                "HMICommandFactory::CreateCommand function_id: "
                    << function_id << ", message type: " << message_type_str);

  return buildCommandCreator(function_id, message_type, source).create(message);
}

bool AppServiceMobileCommandFactory::IsAbleToProcess(
    const int32_t function_id,
    const app_mngr::commands::Command::CommandSource source) const {
  UNUSED(source);
  return buildCommandCreator(function_id,
                             mobile_apis::messageType::INVALID_ENUM,
                             source).CanBeCreated();
}

app_mngr::CommandCreator& AppServiceMobileCommandFactory::buildCommandCreator(
    const int32_t function_id,
    const int32_t message_type,
    const app_mngr::commands::Command::CommandSource source) const {
  auto factory = app_mngr::CommandCreatorFactory(
      application_manager_, rpc_service_, hmi_capabilities_, policy_handler_);

  switch (function_id) {
    case mobile_apis::FunctionID::PublishAppServiceID:
      return mobile_apis::messageType::request == message_type
                 ? factory.GetCreator<commands::PublishAppServiceRequest>()
                 : factory.GetCreator<commands::PublishAppServiceResponse>();
    case mobile_apis::FunctionID::OnAppServiceDataID:
      return app_mngr::commands::Command::CommandSource::SOURCE_MOBILE == source
                 ? factory.GetCreator<
                       commands::OnAppServiceDataNotificationFromMobile>()
                 : factory.GetCreator<commands::OnAppServiceDataNotification>();
    case mobile_apis::FunctionID::GetAppServiceDataID:
      if (app_mngr::commands::Command::CommandSource::SOURCE_MOBILE == source) {
        return mobile_apis::messageType::request == message_type
                   ? factory.GetCreator<commands::GetAppServiceDataRequest>()
                   : factory.GetCreator<
                         commands::GetAppServiceDataResponseFromMobile>();
      } else if (app_mngr::commands::Command::CommandSource::SOURCE_SDL ==
                 source) {
        return mobile_apis::messageType::request == message_type
                   ? factory.GetCreator<
                         commands::GetAppServiceDataRequestToMobile>()
                   : factory.GetCreator<commands::GetAppServiceDataResponse>();
      }
      break;
    case mobile_apis::FunctionID::PerformAppServiceInteractionID:
      if (app_mngr::commands::Command::CommandSource::SOURCE_MOBILE == source) {
        return mobile_apis::messageType::request == message_type
                   ? factory.GetCreator<
                         commands::PerformAppServiceInteractionRequest>()
                   : factory.GetCreator<
                         commands::
                             PerformAppServiceInteractionResponseFromMobile>();
      } else if (app_mngr::commands::Command::CommandSource::SOURCE_SDL ==
                 source) {
        return mobile_apis::messageType::request == message_type
                   ? factory.GetCreator<
                         commands::
                             PerformAppServiceInteractionRequestToMobile>()
                   : factory.GetCreator<
                         commands::PerformAppServiceInteractionResponse>();
      }
      break;
    default:
      LOG4CXX_WARN(logger_, "Unsupported function_id: " << function_id);
  }
  return factory.GetCreator<app_mngr::InvalidCommand>();
}
}  // namespace vehicle_info_plugin
<commit_msg>Add missing check in App Service Command Factory<commit_after>/*
 Copyright (c) 2019, Ford Motor Company, Livio
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

 Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.

 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following
 disclaimer in the documentation and/or other materials provided with the
 distribution.

 Neither the name of the the copyright holders nor the names of their
 contributors may be used to endorse or promote products derived from this
 software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 */

#include "app_service_rpc_plugin/app_service_mobile_command_factory.h"

#include "application_manager/message.h"
#include "interfaces/MOBILE_API.h"

#include "app_service_rpc_plugin/commands/mobile/get_app_service_data_request.h"
#include "app_service_rpc_plugin/commands/mobile/get_app_service_data_request_to_mobile.h"
#include "app_service_rpc_plugin/commands/mobile/get_app_service_data_response.h"
#include "app_service_rpc_plugin/commands/mobile/get_app_service_data_response_from_mobile.h"
#include "app_service_rpc_plugin/commands/mobile/on_app_service_data_notification.h"
#include "app_service_rpc_plugin/commands/mobile/on_app_service_data_notification_from_mobile.h"
#include "app_service_rpc_plugin/commands/mobile/perform_app_service_interaction_request.h"
#include "app_service_rpc_plugin/commands/mobile/perform_app_service_interaction_request_to_mobile.h"
#include "app_service_rpc_plugin/commands/mobile/perform_app_service_interaction_response.h"
#include "app_service_rpc_plugin/commands/mobile/perform_app_service_interaction_response_from_mobile.h"
#include "app_service_rpc_plugin/commands/mobile/publish_app_service_request.h"
#include "app_service_rpc_plugin/commands/mobile/publish_app_service_response.h"

CREATE_LOGGERPTR_GLOBAL(logger_, "AppServiceRpcPlugin")

namespace app_service_rpc_plugin {
namespace strings = app_mngr::strings;

AppServiceMobileCommandFactory::AppServiceMobileCommandFactory(
    application_manager::ApplicationManager& application_manager,
    application_manager::rpc_service::RPCService& rpc_service,
    application_manager::HMICapabilities& hmi_capabilities,
    policy::PolicyHandlerInterface& policy_handler)
    : application_manager_(application_manager)
    , rpc_service_(rpc_service)
    , hmi_capabilities_(hmi_capabilities)
    , policy_handler_(policy_handler) {
  LOG4CXX_AUTO_TRACE(logger_);
}

app_mngr::CommandSharedPtr AppServiceMobileCommandFactory::CreateCommand(
    const app_mngr::commands::MessageSharedPtr& message,
    app_mngr::commands::Command::CommandSource source) {
  UNUSED(source);

  const mobile_apis::FunctionID::eType function_id =
      static_cast<mobile_apis::FunctionID::eType>(
          (*message)[strings::params][strings::function_id].asInt());

  const mobile_apis::messageType::eType message_type =
      static_cast<mobile_apis::messageType::eType>(
          (*message)[strings::params][strings::message_type].asInt());

  auto message_type_str = "request";
  if (mobile_apis::messageType::response == message_type) {
    message_type_str = "response";
  } else if (mobile_apis::messageType::notification == message_type) {
    message_type_str = "notification";
  }

  UNUSED(message_type_str);
  LOG4CXX_DEBUG(logger_,
                "HMICommandFactory::CreateCommand function_id: "
                    << function_id << ", message type: " << message_type_str);

  return buildCommandCreator(function_id, message_type, source).create(message);
}

bool AppServiceMobileCommandFactory::IsAbleToProcess(
    const int32_t function_id,
    const app_mngr::commands::Command::CommandSource source) const {
  UNUSED(source);
  return buildCommandCreator(function_id,
                             mobile_apis::messageType::INVALID_ENUM,
                             source).CanBeCreated();
}

app_mngr::CommandCreator& AppServiceMobileCommandFactory::buildCommandCreator(
    const int32_t function_id,
    const int32_t message_type,
    const app_mngr::commands::Command::CommandSource source) const {
  auto factory = app_mngr::CommandCreatorFactory(
      application_manager_, rpc_service_, hmi_capabilities_, policy_handler_);

  switch (function_id) {
    case mobile_apis::FunctionID::PublishAppServiceID:
      if (app_mngr::commands::Command::CommandSource::SOURCE_MOBILE == source) {
        return mobile_apis::messageType::request == message_type
                   ? factory.GetCreator<commands::PublishAppServiceRequest>()
                   : factory.GetCreator<commands::PublishAppServiceResponse>();
      }
      break;
    case mobile_apis::FunctionID::OnAppServiceDataID:
      return app_mngr::commands::Command::CommandSource::SOURCE_MOBILE == source
                 ? factory.GetCreator<
                       commands::OnAppServiceDataNotificationFromMobile>()
                 : factory.GetCreator<commands::OnAppServiceDataNotification>();
    case mobile_apis::FunctionID::GetAppServiceDataID:
      if (app_mngr::commands::Command::CommandSource::SOURCE_MOBILE == source) {
        return mobile_apis::messageType::request == message_type
                   ? factory.GetCreator<commands::GetAppServiceDataRequest>()
                   : factory.GetCreator<
                         commands::GetAppServiceDataResponseFromMobile>();
      } else if (app_mngr::commands::Command::CommandSource::SOURCE_SDL ==
                 source) {
        return mobile_apis::messageType::request == message_type
                   ? factory.GetCreator<
                         commands::GetAppServiceDataRequestToMobile>()
                   : factory.GetCreator<commands::GetAppServiceDataResponse>();
      }
      break;
    case mobile_apis::FunctionID::PerformAppServiceInteractionID:
      if (app_mngr::commands::Command::CommandSource::SOURCE_MOBILE == source) {
        return mobile_apis::messageType::request == message_type
                   ? factory.GetCreator<
                         commands::PerformAppServiceInteractionRequest>()
                   : factory.GetCreator<
                         commands::
                             PerformAppServiceInteractionResponseFromMobile>();
      } else if (app_mngr::commands::Command::CommandSource::SOURCE_SDL ==
                 source) {
        return mobile_apis::messageType::request == message_type
                   ? factory.GetCreator<
                         commands::
                             PerformAppServiceInteractionRequestToMobile>()
                   : factory.GetCreator<
                         commands::PerformAppServiceInteractionResponse>();
      }
      break;
    default:
      LOG4CXX_WARN(logger_, "Unsupported function_id: " << function_id);
  }
  return factory.GetCreator<app_mngr::InvalidCommand>();
}
}  // namespace vehicle_info_plugin
<|endoftext|>


<commit_before>#ifndef LUNAR_SLAB_ALLOCATOR
#define LUNAR_SLAB_ALLOCATOR

#include <new>
#include <limits>

#include <stdlib.h>

#include "slab.hpp"

namespace lunar {

template <typename T>
class slab_allocator {
public:
    typedef T         value_type;
    typedef size_t    size_type;
    typedef ptrdiff_t difference_type;
    typedef T*        pointer;
    typedef const T*  const_pointer;
    typedef T&        reference;
    typedef const T&  const_reference;

    template <class U> struct rebind { typedef slab_allocator<U> other; };
    slab_allocator() throw()
    {
        if (slab_allocator<T>::m_refcnt == 0)
            slab_init(&m_slab, sizeof(T));

        slab_allocator<T>::m_refcnt++;
    }
    slab_allocator(const slab_allocator&) throw()
    {
        if (slab_allocator<T>::m_refcnt == 0)
            slab_init(&m_slab, sizeof(T));

        slab_allocator<T>::m_refcnt++;
    }

    template <class U> slab_allocator(const slab_allocator<U>&) throw()
    {
        if (slab_allocator<U>::m_refcnt == 0)
            slab_init(&slab_allocator<U>::m_slab, sizeof(U));

        slab_allocator<U>::m_refcnt++;
    }

    ~slab_allocator() throw() {
        m_refcnt--;

        if (m_refcnt == 0)
            slab_destroy(&m_slab);
    }

    pointer address(reference x) const { return &x; }
    const_pointer address(const_reference x) const { return &x; }

    pointer allocate(size_type s, void const * = 0) {
        if (s == 1) {
            return (pointer)slab_alloc(&m_slab);
        } else if (s >= 1) {
            pointer temp = (pointer)malloc(sizeof(void*) + s * sizeof(T));
            if (temp == nullptr)
                return nullptr;

            void **vp = (void**)temp;
            *vp = (void*)~(uint64_t)0;

            return (pointer)((char*)temp + sizeof(void*));
        } else {
            return nullptr;
        }
    }

    void deallocate(pointer p, size_type) {
        void **vp = (void**)((char*)p - sizeof(void*));

        if (*vp == (void*)~(uint64_t)0)
            free(vp);
        else
            slab_free(&m_slab, p);
    }

    size_type max_size() const throw() {
        return std::numeric_limits<size_t>::max() / sizeof(T);
    }

    void construct(pointer p, const T& val) {
        new((void *)p) T(val);
    }

    void destroy(pointer p) {
        p->~T();
    }

    __thread static uint64_t   m_refcnt;
    __thread static slab_chain m_slab;
};

template <typename T> __thread uint64_t   slab_allocator<T>::m_refcnt = 0;
template <typename T> __thread slab_chain slab_allocator<T>::m_slab;

}

#endif // LUNAR_SLAB_ALLOCATOR<commit_msg>minor fix<commit_after>#ifndef LUNAR_SLAB_ALLOCATOR
#define LUNAR_SLAB_ALLOCATOR

#include <new>
#include <limits>

#include <stdlib.h>

#include "slab.hpp"

namespace lunar {

template <typename T>
class slab_allocator {
public:
    typedef T         value_type;
    typedef size_t    size_type;
    typedef ptrdiff_t difference_type;
    typedef T*        pointer;
    typedef const T*  const_pointer;
    typedef T&        reference;
    typedef const T&  const_reference;

    template <class U> struct rebind { typedef slab_allocator<U> other; };
    slab_allocator() throw()
    {
        if (slab_allocator<T>::m_refcnt == 0)
            slab_init(&m_slab, sizeof(T));

        slab_allocator<T>::m_refcnt++;
    }
    slab_allocator(const slab_allocator&) throw()
    {
        if (slab_allocator<T>::m_refcnt == 0)
            slab_init(&m_slab, sizeof(T));

        slab_allocator<T>::m_refcnt++;
    }

    template <class U> slab_allocator(const slab_allocator<U>&) throw()
    {
        if (slab_allocator<U>::m_refcnt == 0)
            slab_init(&slab_allocator<U>::m_slab, sizeof(U));

        slab_allocator<U>::m_refcnt++;
    }

    ~slab_allocator() throw() {
        m_refcnt--;

        if (m_refcnt == 0)
            slab_destroy(&m_slab);
    }

    pointer address(reference x) const { return &x; }
    const_pointer address(const_reference x) const { return &x; }

    pointer allocate(size_type s, void const * = 0) {
        if (s == 1) {
            return (pointer)slab_alloc(&m_slab);
        } else if (s >= 1) {
            pointer temp = (pointer)malloc(sizeof(void*) + s * sizeof(T));
            if (temp == nullptr)
                return nullptr;

            void **vp = (void**)temp;
            *vp = (void*)~(uint64_t)0;

            return (pointer)((char*)temp + sizeof(void*));
        } else {
            return nullptr;
        }
    }

    void deallocate(pointer p, size_type) {
        void **vp = (void**)((char*)p - sizeof(void*));

        if (*vp == (void*)~(uint64_t)0)
            free(vp);
        else
            slab_free(&m_slab, p);
    }

    size_type max_size() const throw() {
        return std::numeric_limits<size_t>::max() / sizeof(T);
    }

    void construct(pointer p, const T& val) {
        new((void *)p) T(val);
    }

    void destroy(pointer p) {
        p->~T();
    }

    static __thread uint64_t   m_refcnt;
    static __thread slab_chain m_slab;
};

template <typename T> __thread uint64_t   slab_allocator<T>::m_refcnt = 0;
template <typename T> __thread slab_chain slab_allocator<T>::m_slab;

}

#endif // LUNAR_SLAB_ALLOCATOR<|endoftext|>


<commit_before>#include "cpx/WindowsLibraryLoader.hpp"

#include "cpx/Exception.hpp"
#include "cpx/PluginFactory.hpp"

#include <iostream>

namespace cpx
{

WindowsLibraryLoader::WindowsLibraryLoader(cpx::PluginFactory* pluginFactory):
    _pluginFactory(pluginFactory)
{

}

void WindowsLibraryLoader::loadLibrary(std::string file)
{
    typedef void (__cdecl *InitFct)(cpx::PluginFactory*);
    if (_loadedLibHandles.find(file)==_loadedLibHandles.end())
    {
        HINSTANCE lib_handle = LoadLibrary(file.c_str());
        if (!lib_handle)
        {
            DWORD dwLastError = GetLastError();
            const unsigned int N = 256;
            TCHAR lpBuffer[N];
            if(dwLastError != 0)
            {
                FormatMessage(
                    FORMAT_MESSAGE_FROM_SYSTEM,                 // It's a system error
                    NULL,                                      // No string to be formatted needed
                    dwLastError,                               // Hey Windows: Please explain this error!
                    MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),  // Do it in the standard language
                    lpBuffer,              // Put the message here
                    N-1,                     // Number of bytes to store the message
                    NULL
                );
                cpx_throw("Error while opening file: '",file,"': ",lpBuffer);
            }
        }
        InitFct initFct = (InitFct) GetProcAddress(lib_handle, "init");
        if (!initFct)
        {
            DWORD dwLastError = GetLastError();
            const unsigned int N = 256;
            TCHAR lpBuffer[N];
            if(dwLastError != 0)
            {
                FormatMessage(
                    FORMAT_MESSAGE_FROM_SYSTEM,                 // It's a system error
                    NULL,                                      // No string to be formatted needed
                    dwLastError,                               // Hey Windows: Please explain this error!
                    MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),  // Do it in the standard language
                    lpBuffer,              // Put the message here
                    N-1,                     // Number of bytes to store the message
                    NULL
                );
                cpx_throw("Error while initializing file: '",file,"': ",lpBuffer);
            }
        }
        (initFct)(_pluginFactory);
        _loadedLibHandles[file]=lib_handle;
    }
    else
    {
        cpx_throw("Plugin file '",file,"' already loaded");
    }
}

WindowsLibraryLoader::~WindowsLibraryLoader()
{
    for (auto handle: _loadedLibHandles)
    {
        FreeLibrary(handle.second);
    }
}

}
<commit_msg>try /->\ replacement<commit_after>#include "cpx/WindowsLibraryLoader.hpp"

#include "cpx/Exception.hpp"
#include "cpx/PluginFactory.hpp"

#include <iostream>
#include <algorithm>

namespace cpx
{

WindowsLibraryLoader::WindowsLibraryLoader(cpx::PluginFactory* pluginFactory):
    _pluginFactory(pluginFactory)
{

}

void WindowsLibraryLoader::loadLibrary(std::string file)
{
    typedef void (__cdecl *InitFct)(cpx::PluginFactory*);

    std::replace( file.begin(), file.end(), '/', '\\');

    if (_loadedLibHandles.find(file)==_loadedLibHandles.end())
    {
        HINSTANCE lib_handle = LoadLibraryEx(file.c_str(),NULL,LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
        if (!lib_handle)
        {
            DWORD dwLastError = GetLastError();
            const unsigned int N = 256;
            TCHAR lpBuffer[N];
            if(dwLastError != 0)
            {
                FormatMessage(
                    FORMAT_MESSAGE_FROM_SYSTEM,                 // It's a system error
                    NULL,                                      // No string to be formatted needed
                    dwLastError,                               // Hey Windows: Please explain this error!
                    MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),  // Do it in the standard language
                    lpBuffer,              // Put the message here
                    N-1,                     // Number of bytes to store the message
                    NULL
                );
                cpx_throw("Error while opening file: '",file,"': ",lpBuffer);
            }
        }
        InitFct initFct = (InitFct) GetProcAddress(lib_handle, "init");
        if (!initFct)
        {
            DWORD dwLastError = GetLastError();
            const unsigned int N = 256;
            TCHAR lpBuffer[N];
            if(dwLastError != 0)
            {
                FormatMessage(
                    FORMAT_MESSAGE_FROM_SYSTEM,                 // It's a system error
                    NULL,                                      // No string to be formatted needed
                    dwLastError,                               // Hey Windows: Please explain this error!
                    MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),  // Do it in the standard language
                    lpBuffer,              // Put the message here
                    N-1,                     // Number of bytes to store the message
                    NULL
                );
                cpx_throw("Error while initializing file: '",file,"': ",lpBuffer);
            }
        }
        (initFct)(_pluginFactory);
        _loadedLibHandles[file]=lib_handle;
    }
    else
    {
        cpx_throw("Plugin file '",file,"' already loaded");
    }
}

WindowsLibraryLoader::~WindowsLibraryLoader()
{
    for (auto handle: _loadedLibHandles)
    {
        FreeLibrary(handle.second);
    }
}

}
<|endoftext|>