<commit_before>/*** Copyright (c), The Regents of the University of California            ***
 *** For more information please refer to files in the COPYRIGHT directory ***/
/*
 * iput - The irods put utility
*/

#include "rodsClient.hpp"
#include "parseCommandLine.hpp"
#include "rodsPath.hpp"
#include "putUtil.hpp"
#include "irods_client_api_table.hpp"
#include "irods_pack_table.hpp"

void usage();

int
main( int argc, char **argv ) {
    int status;
    rodsEnv myEnv;
    rErrMsg_t errMsg;
    rcComm_t *conn;
    rodsArguments_t myRodsArgs;
    char *optStr;
    rodsPathInp_t rodsPathInp;
    int reconnFlag;

    optStr = "abD:fhIkKn:N:p:Prt:R:QTvVX:Z";

    status = parseCmdLineOpt( argc, argv, optStr, 1, &myRodsArgs );

    if ( status < 0 ) {
        printf( "use -h for help.\n" );
        exit( 1 );
    }

    if ( myRodsArgs.help == True ) {
        usage();
        exit( 0 );
    }

    status = getRodsEnv( &myEnv );
    if ( status < 0 ) {
        rodsLogError( LOG_ERROR, status, "main: getRodsEnv error. " );
        exit( 1 );
    }

    status = parseCmdLinePath( argc, argv, optind, &myEnv,
                               UNKNOWN_FILE_T, UNKNOWN_OBJ_T, 0, &rodsPathInp );

    if ( status < 0 ) {
        rodsLogError( LOG_ERROR, status, "main: parseCmdLinePath error. " );
        printf( "use -h for help.\n" );
        exit( 1 );
    }

    if ( myRodsArgs.reconnect == True ) {
        reconnFlag = RECONN_TIMEOUT;
    }
    else {
        reconnFlag = NO_RECONN;
    }

    // =-=-=-=-=-=-=-
    // initialize pluggable api table
    irods::api_entry_table&  api_tbl = irods::get_client_api_table();
    irods::pack_entry_table& pk_tbl  = irods::get_pack_table();
    init_api_table( api_tbl, pk_tbl );

    conn = rcConnect( myEnv.rodsHost, myEnv.rodsPort, myEnv.rodsUserName,
                      myEnv.rodsZone, reconnFlag, &errMsg );

    if ( conn == NULL ) {
        exit( 2 );
    }

    status = clientLogin( conn );
    if ( status != 0 ) {
        rcDisconnect( conn );
        exit( 7 );
    }

    if ( myRodsArgs.progressFlag == True ) {
        gGuiProgressCB = ( irodsGuiProgressCallbak ) iCommandProgStat;
    }

    status = putUtil( &conn, &myEnv, &myRodsArgs, &rodsPathInp );

    printErrorStack( conn->rError );
    rcDisconnect( conn );

    if ( status < 0 ) {
        exit( 3 );
    }
    else {
        exit( 0 );
    }

}

void
usage() {
    char *msgs[] = {
        "Usage : iput [-abfIkKPQrtTUvV] [-D dataType] [-N numThreads] [-n replNum]",
        "             [-p physicalPath] [-R resource] [-X restartFile] [--link]",
        "             [--lfrestart lfRestartFile] [--retries count] [--wlock]",
        "             [--purgec]",
        "               localSrcFile|localSrcDir ...  destDataObj|destColl",
        "Usage : iput [-abfIkKPQtTUvV] [-D dataType] [-N numThreads] [-n replNum] ",
        "             [-p physicalPath] [-R resource] [-X restartFile] [--link]",
        "             [--lfrestart lfRestartFile] [--retries count] [--wlock]",
        "             [--purgec]",
        "               localSrcFile",
        " ",
        "Store a file into iRODS.  If the destination data-object or collection are",
        "not provided, the current iRODS directory and the input file name are used.",
        " ",
        "The -X option specifies that the restart option is on and the operation",
        "is restartable. The restartFile input specifies a local file that contains",
        "the restart information. If the restartFile does not exist, it will be created",
        "and used for recording subsequent restart information. If it exists and is not",
        "empty, the restart information contained in this file will be used to restart",
        "the operation. Note that the operation is not restarted automatically",
        "when it failed. Another iput -X run must be made to continue from where",
        "it left off using the restart information. But the -X option can be used in",
        "conjunction with the --retries option to automatically restart the operation",
        "in case of failure. Also note that the restart operation only works for",
        "uploading directories and the path input must be identical to the one",
        "that generated the restart file.",
        " ",
        "The --lfrestart option specifies that the large file restart option is on",
        "and the lfRestartFile input specifies a local file that contains the restart",
        "information. Currently, only files larger than 32 Mbytes will be restarted.",
        "The --lfrestart option can be used together with the -X option to do large",
        "file transfer restart as part of the overall directory upload restart.",
        " ",
        "If the -f option is used to overwrite an existing data-object, the copy",
        "in the resource specified by the -R option will be picked if it exists.",
        "Otherwise, one of the copies in the other resources will be picked for the",
        "overwrite. Note that a copy will not be made in the specified resource",
        "if a copy in the specified resource does not already exist. The irepl",
        "command should be used to make a replica of an existing copy.",
        " ",
        "The -I option specifies the redirection of the connection so that it can",
        "be connected directly to the resource server. This option can improve",
        "the performance of uploading a large number of small (<32 Mbytes) files.",
        "This option is only effective if the source is a directory and the -f ",
        "option is not used.",
        " ",
        "The -Q option specifies the use of the RBUDP transfer mechanism which uses",
        "the UDP protocol for data transfer. The UDP protocol is very efficient",
        "if the network is very robust with few packet losses. Two environment",
        "variables - rbudpSendRate and rbudpPackSize are used to tune the RBUDP",
        "data transfer. rbudpSendRate is used to throttle the send rate in ",
        "kbits/sec. The default rbudpSendRate is 600,000. rbudpPackSize is used",
        "to set the packet size. The default rbudpPackSize is 8192. The -V option",
        "can be used to show the loss rate of the transfer. If the loss rate is",
        "more than a few %, the rbudpSendRate should be reduced.",
        " ",
        "The -T option will renew the socket connection between the client and ",
        "server after 10 minutes of connection. This gets around the problem of",
        "sockets getting timed out by the server firewall as reported by some users.",
        " ",
        "The -b option specifies the bulk upload operation which can do up to 50 uploads",
        "at a time to reduce overhead. If the -b option is specified with the -f option",
        "to overwrite existing files, the operation will work only if there is no",
        "existing copy at all or if there is an existing copy in the target resource.",
        "The operation will fail if there are existing copies but not in the",
        "target resource because this type of operation requires a replication",
        "operation and bulk replication has not been implemented yet.",
        "The bulk option does work for mounted collections which may represent the",
        "quickest way to upload a large number of small files.",
        " ",
        "Options are:",
        " -a  all - update all existing copies",
        " -b  bulk upload to reduce overhead",
        " -D  dataType - the data type string",
        " -f  force - write data-object even it exists already; overwrite it",
        " -I  redirect connection - redirect the connection to connect directly",
        "       to the resource server.",
        " -k  checksum - calculate a checksum on the data",
        " -K  verify checksum - calculate and verify the checksum on the data",
        " --link - ignore symlink.",
        " -n  replNum  - the replica to be replaced, typically not needed",
        " -N  numThreads - the number of threads to use for the transfer. A value of",
        "       0 means no threading. By default (-N option not used) the server ",
        "       decides the number of threads to use.",
        " --purgec  Purge the staged cache copy after uploading an object to a", // JMC - backport 4537
        "     COMPOUND resource",
        " -p  physicalPath - the absolute physical path of the uploaded file on the server ",
        " -P  output the progress of the upload.",
        " -Q  use RBUDP (datagram) protocol for the data transfer",
        " -R  resource - specifies the resource to store to. This can also be specified",
        "     in your environment or via a rule set up by the administrator.",
        " -r  recursive - store the whole subdirectory",
        " -t  ticket - ticket (string) to use for ticket-based access",
        " -T  renew socket connection after 10 minutes",
        " -v  verbose",
        " -V  Very verbose",
        " -X  restartFile - specifies that the restart option is on and the restartFile",
        "       input specifies a local file that contains the restart information.",
        "--retries count - Retry the iput in case of error. The 'count' input",
        "       specifies the number of times to retry. It must be used with the",
        "       -X option",
        " --lfrestart lfRestartFile - specifies that the large file restart option is",
        "       on and the lfRestartFile input specifies a local file that contains",
        "       the restart information.",
        " --wlock - use advisory write (exclusive) lock for the upload",
        " -h  this help",
        ""
    };
    int i;
    for ( i = 0;; i++ ) {
        if ( strlen( msgs[i] ) == 0 ) {
            break;
        }
        printf( "%s\n", msgs[i] );
    }
    printReleaseInfo( "iput" );
}
<commit_msg>[#2386] update iput help regarding checksums<commit_after>/*** Copyright (c), The Regents of the University of California            ***
 *** For more information please refer to files in the COPYRIGHT directory ***/
/*
 * iput - The irods put utility
*/

#include "rodsClient.hpp"
#include "parseCommandLine.hpp"
#include "rodsPath.hpp"
#include "putUtil.hpp"
#include "irods_client_api_table.hpp"
#include "irods_pack_table.hpp"

void usage();

int
main( int argc, char **argv ) {
    int status;
    rodsEnv myEnv;
    rErrMsg_t errMsg;
    rcComm_t *conn;
    rodsArguments_t myRodsArgs;
    char *optStr;
    rodsPathInp_t rodsPathInp;
    int reconnFlag;

    optStr = "abD:fhIkKn:N:p:Prt:R:QTvVX:Z";

    status = parseCmdLineOpt( argc, argv, optStr, 1, &myRodsArgs );

    if ( status < 0 ) {
        printf( "use -h for help.\n" );
        exit( 1 );
    }

    if ( myRodsArgs.help == True ) {
        usage();
        exit( 0 );
    }

    status = getRodsEnv( &myEnv );
    if ( status < 0 ) {
        rodsLogError( LOG_ERROR, status, "main: getRodsEnv error. " );
        exit( 1 );
    }

    status = parseCmdLinePath( argc, argv, optind, &myEnv,
                               UNKNOWN_FILE_T, UNKNOWN_OBJ_T, 0, &rodsPathInp );

    if ( status < 0 ) {
        rodsLogError( LOG_ERROR, status, "main: parseCmdLinePath error. " );
        printf( "use -h for help.\n" );
        exit( 1 );
    }

    if ( myRodsArgs.reconnect == True ) {
        reconnFlag = RECONN_TIMEOUT;
    }
    else {
        reconnFlag = NO_RECONN;
    }

    // =-=-=-=-=-=-=-
    // initialize pluggable api table
    irods::api_entry_table&  api_tbl = irods::get_client_api_table();
    irods::pack_entry_table& pk_tbl  = irods::get_pack_table();
    init_api_table( api_tbl, pk_tbl );

    conn = rcConnect( myEnv.rodsHost, myEnv.rodsPort, myEnv.rodsUserName,
                      myEnv.rodsZone, reconnFlag, &errMsg );

    if ( conn == NULL ) {
        exit( 2 );
    }

    status = clientLogin( conn );
    if ( status != 0 ) {
        rcDisconnect( conn );
        exit( 7 );
    }

    if ( myRodsArgs.progressFlag == True ) {
        gGuiProgressCB = ( irodsGuiProgressCallbak ) iCommandProgStat;
    }

    status = putUtil( &conn, &myEnv, &myRodsArgs, &rodsPathInp );

    printErrorStack( conn->rError );
    rcDisconnect( conn );

    if ( status < 0 ) {
        exit( 3 );
    }
    else {
        exit( 0 );
    }

}

void
usage() {
    char *msgs[] = {
        "Usage : iput [-abfIkKPQrtTUvV] [-D dataType] [-N numThreads] [-n replNum]",
        "             [-p physicalPath] [-R resource] [-X restartFile] [--link]",
        "             [--lfrestart lfRestartFile] [--retries count] [--wlock]",
        "             [--purgec]",
        "               localSrcFile|localSrcDir ...  destDataObj|destColl",
        "Usage : iput [-abfIkKPQtTUvV] [-D dataType] [-N numThreads] [-n replNum] ",
        "             [-p physicalPath] [-R resource] [-X restartFile] [--link]",
        "             [--lfrestart lfRestartFile] [--retries count] [--wlock]",
        "             [--purgec]",
        "               localSrcFile",
        " ",
        "Store a file into iRODS.  If the destination data-object or collection are",
        "not provided, the current iRODS directory and the input file name are used.",
        " ",
        "The -X option specifies that the restart option is on and the operation",
        "is restartable. The restartFile input specifies a local file that contains",
        "the restart information. If the restartFile does not exist, it will be created",
        "and used for recording subsequent restart information. If it exists and is not",
        "empty, the restart information contained in this file will be used to restart",
        "the operation. Note that the operation is not restarted automatically",
        "when it failed. Another iput -X run must be made to continue from where",
        "it left off using the restart information. But the -X option can be used in",
        "conjunction with the --retries option to automatically restart the operation",
        "in case of failure. Also note that the restart operation only works for",
        "uploading directories and the path input must be identical to the one",
        "that generated the restart file.",
        " ",
        "The --lfrestart option specifies that the large file restart option is on",
        "and the lfRestartFile input specifies a local file that contains the restart",
        "information. Currently, only files larger than 32 Mbytes will be restarted.",
        "The --lfrestart option can be used together with the -X option to do large",
        "file transfer restart as part of the overall directory upload restart.",
        " ",
        "If the -f option is used to overwrite an existing data-object, the copy",
        "in the resource specified by the -R option will be picked if it exists.",
        "Otherwise, one of the copies in the other resources will be picked for the",
        "overwrite. Note that a copy will not be made in the specified resource",
        "if a copy in the specified resource does not already exist. The irepl",
        "command should be used to make a replica of an existing copy.",
        " ",
        "The -I option specifies the redirection of the connection so that it can",
        "be connected directly to the resource server. This option can improve",
        "the performance of uploading a large number of small (<32 Mbytes) files.",
        "This option is only effective if the source is a directory and the -f ",
        "option is not used.",
        " ",
        "The -Q option specifies the use of the RBUDP transfer mechanism which uses",
        "the UDP protocol for data transfer. The UDP protocol is very efficient",
        "if the network is very robust with few packet losses. Two environment",
        "variables - rbudpSendRate and rbudpPackSize are used to tune the RBUDP",
        "data transfer. rbudpSendRate is used to throttle the send rate in ",
        "kbits/sec. The default rbudpSendRate is 600,000. rbudpPackSize is used",
        "to set the packet size. The default rbudpPackSize is 8192. The -V option",
        "can be used to show the loss rate of the transfer. If the loss rate is",
        "more than a few %, the rbudpSendRate should be reduced.",
        " ",
        "The -T option will renew the socket connection between the client and ",
        "server after 10 minutes of connection. This gets around the problem of",
        "sockets getting timed out by the server firewall as reported by some users.",
        " ",
        "The -b option specifies the bulk upload operation which can do up to 50 uploads",
        "at a time to reduce overhead. If the -b option is specified with the -f option",
        "to overwrite existing files, the operation will work only if there is no",
        "existing copy at all or if there is an existing copy in the target resource.",
        "The operation will fail if there are existing copies but not in the",
        "target resource because this type of operation requires a replication",
        "operation and bulk replication has not been implemented yet.",
        "The bulk option does work for mounted collections which may represent the",
        "quickest way to upload a large number of small files.",
        " ",
        "Options are:",
        " -a  all - update all existing copies",
        " -b  bulk upload to reduce overhead",
        " -D  dataType - the data type string",
        " -f  force - write data-object even it exists already; overwrite it",
        " -I  redirect connection - redirect the connection to connect directly",
        "       to the resource server.",
        " -k  checksum - calculate a checksum on the data server-side, and store",
        "       it in the catalog"
        " -K  verify checksum - calculate and verify the checksum on the data, both",
        "       client-side and server-side, without storing in the catalog.",
        " --link - ignore symlink.",
        " -n  replNum  - the replica to be replaced, typically not needed",
        " -N  numThreads - the number of threads to use for the transfer. A value of",
        "       0 means no threading. By default (-N option not used) the server ",
        "       decides the number of threads to use.",
        " --purgec  Purge the staged cache copy after uploading an object to a", // JMC - backport 4537
        "     COMPOUND resource",
        " -p  physicalPath - the absolute physical path of the uploaded file on the server ",
        " -P  output the progress of the upload.",
        " -Q  use RBUDP (datagram) protocol for the data transfer",
        " -R  resource - specifies the resource to store to. This can also be specified",
        "     in your environment or via a rule set up by the administrator.",
        " -r  recursive - store the whole subdirectory",
        " -t  ticket - ticket (string) to use for ticket-based access",
        " -T  renew socket connection after 10 minutes",
        " -v  verbose",
        " -V  Very verbose",
        " -X  restartFile - specifies that the restart option is on and the restartFile",
        "       input specifies a local file that contains the restart information.",
        "--retries count - Retry the iput in case of error. The 'count' input",
        "       specifies the number of times to retry. It must be used with the",
        "       -X option",
        " --lfrestart lfRestartFile - specifies that the large file restart option is",
        "       on and the lfRestartFile input specifies a local file that contains",
        "       the restart information.",
        " --wlock - use advisory write (exclusive) lock for the upload",
        " -h  this help",
        ""
    };
    int i;
    for ( i = 0;; i++ ) {
        if ( strlen( msgs[i] ) == 0 ) {
            break;
        }
        printf( "%s\n", msgs[i] );
    }
    printReleaseInfo( "iput" );
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/test/unittest_test_suite.h"

#include "base/logging.h"
#include "base/test/test_suite.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebKitPlatformSupport.h"

// A stubbed out WebKit platform support impl.
class UnitTestTestSuite::UnitTestWebKitPlatformSupport
    : public WebKit::WebKitPlatformSupport {
 public:
  UnitTestWebKitPlatformSupport() {}
  virtual ~UnitTestWebKitPlatformSupport() {}
  virtual void cryptographicallyRandomValues(unsigned char* buffer,
                                             size_t length) OVERRIDE {
    memset(buffer, 0, length);
  }
};

UnitTestTestSuite::UnitTestTestSuite(base::TestSuite* test_suite)
    : test_suite_(test_suite) {
  DCHECK(test_suite);
  webkit_platform_support_.reset(new UnitTestWebKitPlatformSupport);
  WebKit::initialize(webkit_platform_support_.get());
}

UnitTestTestSuite::~UnitTestTestSuite() {
  WebKit::shutdown();
}

int UnitTestTestSuite::Run() {
  return test_suite_->Run();
}
<commit_msg>Implement required tracing API for UnitTestWebKitPlatformSupport.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/test/unittest_test_suite.h"

#include "base/logging.h"
#include "base/test/test_suite.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebKitPlatformSupport.h"

// A stubbed out WebKit platform support impl.
class UnitTestTestSuite::UnitTestWebKitPlatformSupport
    : public WebKit::WebKitPlatformSupport {
 public:
  UnitTestWebKitPlatformSupport() {}
  virtual ~UnitTestWebKitPlatformSupport() {}
  virtual void cryptographicallyRandomValues(unsigned char* buffer,
                                             size_t length) OVERRIDE {
    memset(buffer, 0, length);
  }
  virtual const unsigned char* getTraceCategoryEnabledFlag(
      const char* categoryName) {
    // Causes tracing macros to be disabled.
    static const unsigned char kEnabled = 0;
    return &kEnabled;
  }
};

UnitTestTestSuite::UnitTestTestSuite(base::TestSuite* test_suite)
    : test_suite_(test_suite) {
  DCHECK(test_suite);
  webkit_platform_support_.reset(new UnitTestWebKitPlatformSupport);
  WebKit::initialize(webkit_platform_support_.get());
}

UnitTestTestSuite::~UnitTestTestSuite() {
  WebKit::shutdown();
}

int UnitTestTestSuite::Run() {
  return test_suite_->Run();
}
<|endoftext|>


<commit_before>#include "JIT.h"

#include <mutex>

#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h>
#include <llvm/ADT/StringSwitch.h>
#include <llvm/ADT/Triple.h>
#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/ManagedStatic.h>
#include "preprocessor/llvm_includes_end.h"

#include "Compiler.h"
#include "Optimizer.h"
#include "Cache.h"
#include "ExecStats.h"
#include "Utils.h"
#include "BuildInfo.gen.h"

static_assert(sizeof(evm_uint256be) == 32, "evm_uint256be is too big");
static_assert(sizeof(evm_uint160be) == 20, "evm_uint160be is too big");
static_assert(sizeof(evm_result) <= 64, "evm_result does not fit cache line");

// Check enums match int size.
// On GCC/clang the underlying type should be unsigned int, on MSVC int
static_assert(sizeof(evm_query_key)  == sizeof(int), "Enum `evm_query_key` is not the size of int");
static_assert(sizeof(evm_update_key) == sizeof(int), "Enum `evm_update_key` is not the size of int");
static_assert(sizeof(evm_call_kind)  == sizeof(int), "Enum `evm_call_kind` is not the size of int");
static_assert(sizeof(evm_mode)       == sizeof(int), "Enum `evm_mode` is not the size of int");

namespace dev
{
namespace evmjit
{
using namespace eth::jit;

namespace
{
using ExecFunc = ReturnCode(*)(ExecutionContext*);

/// Combine code hash and compatibility mode into a printable code identifier.
std::string makeCodeId(evm_uint256be codeHash, evm_mode mode)
{
	static const auto hexChars = "0123456789abcdef";
	std::string str;
	str.reserve(sizeof(codeHash) * 2 + 1);
	for (auto b: codeHash.bytes)
	{
		str.push_back(hexChars[b & 0xf]);
		str.push_back(hexChars[b >> 4]);
	}
	str.push_back(mode == EVM_FRONTIER ? 'F' : 'H');
	return str;
}

void printVersion()
{
	std::cout << "Ethereum EVM JIT Compiler (http://github.com/ethereum/evmjit):\n"
			  << "  EVMJIT version " << EVMJIT_VERSION << "\n"
#ifdef NDEBUG
			  << "  Optimized build, "
#else
			  << "  DEBUG build, "
#endif
			  << __DATE__ << " (" << __TIME__ << ")\n"
			  << std::endl;
}

namespace cl = llvm::cl;
cl::opt<bool> g_optimize{"O", cl::desc{"Optimize"}};
cl::opt<CacheMode> g_cache{"cache", cl::desc{"Cache compiled EVM code on disk"},
	cl::values(
		clEnumValN(CacheMode::off,   "0", "Disabled"),
		clEnumValN(CacheMode::on,    "1", "Enabled"),
		clEnumValN(CacheMode::read,  "r", "Read only. No new objects are added to cache."),
		clEnumValN(CacheMode::write, "w", "Write only. No objects are loaded from cache."),
		clEnumValN(CacheMode::clear, "c", "Clear the cache storage. Cache is disabled."),
		clEnumValN(CacheMode::preload, "p", "Preload all cached objects."),
		clEnumValEnd)};
cl::opt<bool> g_stats{"st", cl::desc{"Statistics"}};
cl::opt<bool> g_dump{"dump", cl::desc{"Dump LLVM IR module"}};

void parseOptions()
{
	static llvm::llvm_shutdown_obj shutdownObj{};
	cl::AddExtraVersionPrinter(printVersion);
	cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler");
}

class JITImpl
{
	std::unique_ptr<llvm::ExecutionEngine> m_engine;
	mutable std::mutex x_codeMap;
	std::unordered_map<std::string, ExecFunc> m_codeMap;

	static llvm::LLVMContext& getLLVMContext()
	{
		// TODO: This probably should be thread_local, but for now that causes
		// a crash when MCJIT is destroyed.
		static llvm::LLVMContext llvmContext;
		return llvmContext;
	}

public:
	static JITImpl& instance()
	{
		// We need to keep this a singleton.
		// so we only call changeVersion on it.
		static JITImpl s_instance;
		return s_instance;
	}

	JITImpl();

	llvm::ExecutionEngine& engine() { return *m_engine; }

	ExecFunc getExecFunc(std::string const& _codeIdentifier) const;
	void mapExecFunc(std::string const& _codeIdentifier, ExecFunc _funcAddr);

	ExecFunc compile(evm_mode _mode, byte const* _code, uint64_t _codeSize, std::string const& _codeIdentifier);

	evm_query_fn queryFn = nullptr;
	evm_update_fn updateFn = nullptr;
	evm_call_fn callFn = nullptr;
};

class SymbolResolver : public llvm::SectionMemoryManager
{
	llvm::RuntimeDyld::SymbolInfo findSymbol(std::string const& _name) override
	{
		auto& jit = JITImpl::instance();
		auto addr = llvm::StringSwitch<uint64_t>(_name)
			.Case("env_sha3", reinterpret_cast<uint64_t>(&keccak))
			.Case("evm.query", reinterpret_cast<uint64_t>(jit.queryFn))
			.Case("evm.update", reinterpret_cast<uint64_t>(jit.updateFn))
			.Case("evm.call", reinterpret_cast<uint64_t>(jit.callFn))
			.Default(0);
		if (addr)
			return {addr, llvm::JITSymbolFlags::Exported};

		// Fallback to default implementation that would search for the symbol
		// in the current process.
		// TODO: In the future we should control the whole set of requested
		//       symbols (like memcpy, memset, etc) to improve performance.
		return llvm::SectionMemoryManager::findSymbol(_name);
	}
};

JITImpl::JITImpl()
{
	parseOptions();

	bool preloadCache = g_cache == CacheMode::preload;
	if (preloadCache)
		g_cache = CacheMode::on;

	llvm::InitializeNativeTarget();
	llvm::InitializeNativeTargetAsmPrinter();

	auto module = llvm::make_unique<llvm::Module>("", getLLVMContext());

	// FIXME: LLVM 3.7: test on Windows
	auto triple = llvm::Triple(llvm::sys::getProcessTriple());
	if (triple.getOS() == llvm::Triple::OSType::Win32)
		triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF);  // MCJIT does not support COFF format
	module->setTargetTriple(triple.str());

	llvm::EngineBuilder builder(std::move(module));
	builder.setEngineKind(llvm::EngineKind::JIT);
	builder.setMCJITMemoryManager(llvm::make_unique<SymbolResolver>());
	builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None);
	#ifndef NDEBUG
	builder.setVerifyModules(true);
	#endif

	m_engine.reset(builder.create());

	// TODO: Update cache listener
	m_engine->setObjectCache(Cache::init(g_cache, nullptr));

	// FIXME: Disabled during API changes
	//if (preloadCache)
	//	Cache::preload(*m_engine, funcCache);
}

ExecFunc JITImpl::getExecFunc(std::string const& _codeIdentifier) const
{
	std::lock_guard<std::mutex> lock{x_codeMap};
	auto it = m_codeMap.find(_codeIdentifier);
	if (it != m_codeMap.end())
		return it->second;
	return nullptr;
}

void JITImpl::mapExecFunc(std::string const& _codeIdentifier, ExecFunc _funcAddr)
{
	std::lock_guard<std::mutex> lock{x_codeMap};
	m_codeMap.emplace(_codeIdentifier, _funcAddr);
}

ExecFunc JITImpl::compile(evm_mode _mode, byte const* _code, uint64_t _codeSize,
	std::string const& _codeIdentifier)
{
	auto module = Cache::getObject(_codeIdentifier, getLLVMContext());
	if (!module)
	{
		// TODO: Listener support must be redesigned. These should be a feature of JITImpl
		//listener->stateChanged(ExecState::Compilation);
		assert(_code || !_codeSize);
		//TODO: Can the Compiler be stateless?
		module = Compiler({}, _mode, getLLVMContext()).compile(_code, _code + _codeSize, _codeIdentifier);

		if (g_optimize)
		{
			//listener->stateChanged(ExecState::Optimization);
			optimize(*module);
		}

		prepare(*module);
	}
	if (g_dump)
		module->dump();

	m_engine->addModule(std::move(module));
	//listener->stateChanged(ExecState::CodeGen);
	return (ExecFunc)m_engine->getFunctionAddress(_codeIdentifier);
}

} // anonymous namespace

ExecutionContext::~ExecutionContext() noexcept
{
	if (m_memData)
		std::free(m_memData); // Use helper free to check memory leaks
}

bytes_ref ExecutionContext::getReturnData() const
{
	auto data = m_data->callData;
	auto size = static_cast<size_t>(m_data->callDataSize);

	if (data < m_memData || data >= m_memData + m_memSize || size == 0)
	{
		assert(size == 0); // data can be an invalid pointer only if size is 0
		m_data->callData = nullptr;
		return {};
	}

	return bytes_ref{data, size};
}

extern "C"
{

static evm_instance* create(evm_query_fn queryFn, evm_update_fn updateFn,
	evm_call_fn callFn)
{
	// Let's always return the same instance. It's a bit of faking, but actually
	// this might be a compliant implementation.
	auto& jit = JITImpl::instance();
	jit.queryFn = queryFn;
	jit.updateFn = updateFn;
	jit.callFn = callFn;
	return reinterpret_cast<evm_instance*>(&jit);
}

static void destroy(evm_instance* instance)
{
    (void)instance;
	assert(instance == static_cast<void*>(&JITImpl::instance()));
}

static void release_result(evm_result const* result)
{
	if (result->internal_memory)
		std::free(result->internal_memory);
}

static evm_result execute(evm_instance* instance, evm_env* env, evm_mode mode,
	evm_uint256be code_hash, uint8_t const* code, size_t code_size,
	int64_t gas, uint8_t const* input, size_t input_size, evm_uint256be value)
{
	auto& jit = *reinterpret_cast<JITImpl*>(instance);

	RuntimeData rt;
	rt.code = code;
	rt.codeSize = code_size;
	rt.gas = gas;
	rt.callData = input;
	rt.callDataSize = input_size;
	std::memcpy(&rt.apparentValue, &value, sizeof(value));

	ExecutionContext ctx{rt, env};

	evm_result result;
	result.code = EVM_SUCCESS;
	result.gas_left = 0;
	result.output_data = nullptr;
	result.output_size = 0;
	result.internal_memory = nullptr;
	result.release = release_result;

	auto codeIdentifier = makeCodeId(code_hash, mode);
	auto execFunc = jit.getExecFunc(codeIdentifier);
	if (!execFunc)
	{
		execFunc = jit.compile(mode, ctx.code(), ctx.codeSize(), codeIdentifier);
		if (!execFunc)
			return result;
		jit.mapExecFunc(codeIdentifier, execFunc);
	}

	auto returnCode = execFunc(&ctx);

	if (returnCode == ReturnCode::OutOfGas)
	{
		// EVMJIT does not provide information what exactly type of failure
		// it was, so use generic EVM_FAILURE.
		result.code = EVM_FAILURE;
	}
	else
	{
		// In case of success return the amount of gas left.
		result.gas_left = rt.gas;
	}

	if (returnCode == ReturnCode::Return)
	{
		auto out = ctx.getReturnData();
		result.output_data = std::get<0>(out);
		result.output_size = std::get<1>(out);
	}

	// Take care of the internal memory.
	result.internal_memory = ctx.m_memData;
	ctx.m_memData = nullptr;

	return result;
}

static int set_option(evm_instance* instance, char const* name,
	char const* value)
{
	(void)instance, (void)name, (void)value;
	return 0;
}

static evm_code_status get_code_status(evm_instance* instance,
	evm_mode mode, evm_uint256be code_hash)
{
	auto& jit = *reinterpret_cast<JITImpl*>(instance);
	auto codeIdentifier = makeCodeId(code_hash, mode);
	if (jit.getExecFunc(codeIdentifier) != nullptr)
		return EVM_READY;
	// TODO: Add support for EVM_CACHED.
	return EVM_UNKNOWN;
}

static void prepare_code(evm_instance* instance, evm_mode mode,
	evm_uint256be code_hash, unsigned char const* code, size_t code_size)
{
	auto& jit = *reinterpret_cast<JITImpl*>(instance);
	auto codeIdentifier = makeCodeId(code_hash, mode);
	auto execFunc = jit.compile(mode, code, code_size, codeIdentifier);
	if (execFunc) // FIXME: What with error?
		jit.mapExecFunc(codeIdentifier, execFunc);
}

EXPORT evm_interface evmjit_get_interface()
{
	return {EVM_ABI_VERSION, create, destroy, execute,
			get_code_status, prepare_code, set_option};
}

}  // extern "C"
}
}
<commit_msg>Print stats about memory usage<commit_after>#include "JIT.h"

#include <mutex>

#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h>
#include <llvm/ADT/StringSwitch.h>
#include <llvm/ADT/Triple.h>
#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/ManagedStatic.h>
#include "preprocessor/llvm_includes_end.h"

#include "Compiler.h"
#include "Optimizer.h"
#include "Cache.h"
#include "ExecStats.h"
#include "Utils.h"
#include "BuildInfo.gen.h"

static_assert(sizeof(evm_uint256be) == 32, "evm_uint256be is too big");
static_assert(sizeof(evm_uint160be) == 20, "evm_uint160be is too big");
static_assert(sizeof(evm_result) <= 64, "evm_result does not fit cache line");

// Check enums match int size.
// On GCC/clang the underlying type should be unsigned int, on MSVC int
static_assert(sizeof(evm_query_key)  == sizeof(int), "Enum `evm_query_key` is not the size of int");
static_assert(sizeof(evm_update_key) == sizeof(int), "Enum `evm_update_key` is not the size of int");
static_assert(sizeof(evm_call_kind)  == sizeof(int), "Enum `evm_call_kind` is not the size of int");
static_assert(sizeof(evm_mode)       == sizeof(int), "Enum `evm_mode` is not the size of int");

namespace dev
{
namespace evmjit
{
using namespace eth::jit;

namespace
{
using ExecFunc = ReturnCode(*)(ExecutionContext*);

/// Combine code hash and compatibility mode into a printable code identifier.
std::string makeCodeId(evm_uint256be codeHash, evm_mode mode)
{
	static const auto hexChars = "0123456789abcdef";
	std::string str;
	str.reserve(sizeof(codeHash) * 2 + 1);
	for (auto b: codeHash.bytes)
	{
		str.push_back(hexChars[b & 0xf]);
		str.push_back(hexChars[b >> 4]);
	}
	str.push_back(mode == EVM_FRONTIER ? 'F' : 'H');
	return str;
}

void printVersion()
{
	std::cout << "Ethereum EVM JIT Compiler (http://github.com/ethereum/evmjit):\n"
			  << "  EVMJIT version " << EVMJIT_VERSION << "\n"
#ifdef NDEBUG
			  << "  Optimized build, "
#else
			  << "  DEBUG build, "
#endif
			  << __DATE__ << " (" << __TIME__ << ")\n"
			  << std::endl;
}

namespace cl = llvm::cl;
cl::opt<bool> g_optimize{"O", cl::desc{"Optimize"}};
cl::opt<CacheMode> g_cache{"cache", cl::desc{"Cache compiled EVM code on disk"},
	cl::values(
		clEnumValN(CacheMode::off,   "0", "Disabled"),
		clEnumValN(CacheMode::on,    "1", "Enabled"),
		clEnumValN(CacheMode::read,  "r", "Read only. No new objects are added to cache."),
		clEnumValN(CacheMode::write, "w", "Write only. No objects are loaded from cache."),
		clEnumValN(CacheMode::clear, "c", "Clear the cache storage. Cache is disabled."),
		clEnumValN(CacheMode::preload, "p", "Preload all cached objects."),
		clEnumValEnd)};
cl::opt<bool> g_stats{"st", cl::desc{"Statistics"}};
cl::opt<bool> g_dump{"dump", cl::desc{"Dump LLVM IR module"}};

void parseOptions()
{
	static llvm::llvm_shutdown_obj shutdownObj{};
	cl::AddExtraVersionPrinter(printVersion);
	cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler");
}

class JITImpl
{
	std::unique_ptr<llvm::ExecutionEngine> m_engine;
	mutable std::mutex x_codeMap;
	std::unordered_map<std::string, ExecFunc> m_codeMap;

	static llvm::LLVMContext& getLLVMContext()
	{
		// TODO: This probably should be thread_local, but for now that causes
		// a crash when MCJIT is destroyed.
		static llvm::LLVMContext llvmContext;
		return llvmContext;
	}

public:
	static JITImpl& instance()
	{
		// We need to keep this a singleton.
		// so we only call changeVersion on it.
		static JITImpl s_instance;
		return s_instance;
	}

	JITImpl();

	llvm::ExecutionEngine& engine() { return *m_engine; }

	ExecFunc getExecFunc(std::string const& _codeIdentifier) const;
	void mapExecFunc(std::string const& _codeIdentifier, ExecFunc _funcAddr);

	ExecFunc compile(evm_mode _mode, byte const* _code, uint64_t _codeSize, std::string const& _codeIdentifier);

	evm_query_fn queryFn = nullptr;
	evm_update_fn updateFn = nullptr;
	evm_call_fn callFn = nullptr;
};

class SymbolResolver : public llvm::SectionMemoryManager
{
	llvm::RuntimeDyld::SymbolInfo findSymbol(std::string const& _name) override
	{
		auto& jit = JITImpl::instance();
		auto addr = llvm::StringSwitch<uint64_t>(_name)
			.Case("env_sha3", reinterpret_cast<uint64_t>(&keccak))
			.Case("evm.query", reinterpret_cast<uint64_t>(jit.queryFn))
			.Case("evm.update", reinterpret_cast<uint64_t>(jit.updateFn))
			.Case("evm.call", reinterpret_cast<uint64_t>(jit.callFn))
			.Default(0);
		if (addr)
			return {addr, llvm::JITSymbolFlags::Exported};

		// Fallback to default implementation that would search for the symbol
		// in the current process.
		// TODO: In the future we should control the whole set of requested
		//       symbols (like memcpy, memset, etc) to improve performance.
		return llvm::SectionMemoryManager::findSymbol(_name);
	}

	void reportMemorySize(size_t _addedSize)
	{
		if (!g_stats)
			return;

		m_totalMemorySize += _addedSize;
		if (m_totalMemorySize >= m_printMemoryLimit)
		{
			static const auto M = 1024 * 1024;
			auto value = double(m_totalMemorySize) / M;
			std::cerr << "EVMJIT total memory size: " << value << '\n';
			m_printMemoryLimit += M;
		}
	}

	uint8_t* allocateCodeSection(uintptr_t _size, unsigned _a, unsigned _id,
	                             llvm::StringRef _name) override
	{
		reportMemorySize(_size);
		return llvm::SectionMemoryManager::allocateCodeSection(_size, _a, _id, _name);
	}

	uint8_t* allocateDataSection(uintptr_t _size, unsigned _a, unsigned _id,
	                             llvm::StringRef _name, bool _ro) override
	{
		reportMemorySize(_size);
		return llvm::SectionMemoryManager::allocateDataSection(_size, _a, _id, _name, _ro);
	}

	size_t m_totalMemorySize = 0;
	size_t m_printMemoryLimit = 1024 * 1024;
};

JITImpl::JITImpl()
{
	parseOptions();

	bool preloadCache = g_cache == CacheMode::preload;
	if (preloadCache)
		g_cache = CacheMode::on;

	llvm::InitializeNativeTarget();
	llvm::InitializeNativeTargetAsmPrinter();

	auto module = llvm::make_unique<llvm::Module>("", getLLVMContext());

	// FIXME: LLVM 3.7: test on Windows
	auto triple = llvm::Triple(llvm::sys::getProcessTriple());
	if (triple.getOS() == llvm::Triple::OSType::Win32)
		triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF);  // MCJIT does not support COFF format
	module->setTargetTriple(triple.str());

	llvm::EngineBuilder builder(std::move(module));
	builder.setEngineKind(llvm::EngineKind::JIT);
	builder.setMCJITMemoryManager(llvm::make_unique<SymbolResolver>());
	builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None);
	#ifndef NDEBUG
	builder.setVerifyModules(true);
	#endif

	m_engine.reset(builder.create());

	// TODO: Update cache listener
	m_engine->setObjectCache(Cache::init(g_cache, nullptr));

	// FIXME: Disabled during API changes
	//if (preloadCache)
	//	Cache::preload(*m_engine, funcCache);
}

ExecFunc JITImpl::getExecFunc(std::string const& _codeIdentifier) const
{
	std::lock_guard<std::mutex> lock{x_codeMap};
	auto it = m_codeMap.find(_codeIdentifier);
	if (it != m_codeMap.end())
		return it->second;
	return nullptr;
}

void JITImpl::mapExecFunc(std::string const& _codeIdentifier, ExecFunc _funcAddr)
{
	std::lock_guard<std::mutex> lock{x_codeMap};
	m_codeMap.emplace(_codeIdentifier, _funcAddr);
}

ExecFunc JITImpl::compile(evm_mode _mode, byte const* _code, uint64_t _codeSize,
	std::string const& _codeIdentifier)
{
	auto module = Cache::getObject(_codeIdentifier, getLLVMContext());
	if (!module)
	{
		// TODO: Listener support must be redesigned. These should be a feature of JITImpl
		//listener->stateChanged(ExecState::Compilation);
		assert(_code || !_codeSize);
		//TODO: Can the Compiler be stateless?
		module = Compiler({}, _mode, getLLVMContext()).compile(_code, _code + _codeSize, _codeIdentifier);

		if (g_optimize)
		{
			//listener->stateChanged(ExecState::Optimization);
			optimize(*module);
		}

		prepare(*module);
	}
	if (g_dump)
		module->dump();

	m_engine->addModule(std::move(module));
	//listener->stateChanged(ExecState::CodeGen);
	return (ExecFunc)m_engine->getFunctionAddress(_codeIdentifier);
}

} // anonymous namespace

ExecutionContext::~ExecutionContext() noexcept
{
	if (m_memData)
		std::free(m_memData); // Use helper free to check memory leaks
}

bytes_ref ExecutionContext::getReturnData() const
{
	auto data = m_data->callData;
	auto size = static_cast<size_t>(m_data->callDataSize);

	if (data < m_memData || data >= m_memData + m_memSize || size == 0)
	{
		assert(size == 0); // data can be an invalid pointer only if size is 0
		m_data->callData = nullptr;
		return {};
	}

	return bytes_ref{data, size};
}

extern "C"
{

static evm_instance* create(evm_query_fn queryFn, evm_update_fn updateFn,
	evm_call_fn callFn)
{
	// Let's always return the same instance. It's a bit of faking, but actually
	// this might be a compliant implementation.
	auto& jit = JITImpl::instance();
	jit.queryFn = queryFn;
	jit.updateFn = updateFn;
	jit.callFn = callFn;
	return reinterpret_cast<evm_instance*>(&jit);
}

static void destroy(evm_instance* instance)
{
    (void)instance;
	assert(instance == static_cast<void*>(&JITImpl::instance()));
}

static void release_result(evm_result const* result)
{
	if (result->internal_memory)
		std::free(result->internal_memory);
}

static evm_result execute(evm_instance* instance, evm_env* env, evm_mode mode,
	evm_uint256be code_hash, uint8_t const* code, size_t code_size,
	int64_t gas, uint8_t const* input, size_t input_size, evm_uint256be value)
{
	auto& jit = *reinterpret_cast<JITImpl*>(instance);

	RuntimeData rt;
	rt.code = code;
	rt.codeSize = code_size;
	rt.gas = gas;
	rt.callData = input;
	rt.callDataSize = input_size;
	std::memcpy(&rt.apparentValue, &value, sizeof(value));

	ExecutionContext ctx{rt, env};

	evm_result result;
	result.code = EVM_SUCCESS;
	result.gas_left = 0;
	result.output_data = nullptr;
	result.output_size = 0;
	result.internal_memory = nullptr;
	result.release = release_result;

	auto codeIdentifier = makeCodeId(code_hash, mode);
	auto execFunc = jit.getExecFunc(codeIdentifier);
	if (!execFunc)
	{
		execFunc = jit.compile(mode, ctx.code(), ctx.codeSize(), codeIdentifier);
		if (!execFunc)
			return result;
		jit.mapExecFunc(codeIdentifier, execFunc);
	}

	auto returnCode = execFunc(&ctx);

	if (returnCode == ReturnCode::OutOfGas)
	{
		// EVMJIT does not provide information what exactly type of failure
		// it was, so use generic EVM_FAILURE.
		result.code = EVM_FAILURE;
	}
	else
	{
		// In case of success return the amount of gas left.
		result.gas_left = rt.gas;
	}

	if (returnCode == ReturnCode::Return)
	{
		auto out = ctx.getReturnData();
		result.output_data = std::get<0>(out);
		result.output_size = std::get<1>(out);
	}

	// Take care of the internal memory.
	result.internal_memory = ctx.m_memData;
	ctx.m_memData = nullptr;

	return result;
}

static int set_option(evm_instance* instance, char const* name,
	char const* value)
{
	(void)instance, (void)name, (void)value;
	return 0;
}

static evm_code_status get_code_status(evm_instance* instance,
	evm_mode mode, evm_uint256be code_hash)
{
	auto& jit = *reinterpret_cast<JITImpl*>(instance);
	auto codeIdentifier = makeCodeId(code_hash, mode);
	if (jit.getExecFunc(codeIdentifier) != nullptr)
		return EVM_READY;
	// TODO: Add support for EVM_CACHED.
	return EVM_UNKNOWN;
}

static void prepare_code(evm_instance* instance, evm_mode mode,
	evm_uint256be code_hash, unsigned char const* code, size_t code_size)
{
	auto& jit = *reinterpret_cast<JITImpl*>(instance);
	auto codeIdentifier = makeCodeId(code_hash, mode);
	auto execFunc = jit.compile(mode, code, code_size, codeIdentifier);
	if (execFunc) // FIXME: What with error?
		jit.mapExecFunc(codeIdentifier, execFunc);
}

EXPORT evm_interface evmjit_get_interface()
{
	return {EVM_ABI_VERSION, create, destroy, execute,
			get_code_status, prepare_code, set_option};
}

}  // extern "C"
}
}
<|endoftext|>


<commit_before>/***************************************************************************\
|* Function Parser for C++ v4.5                                            *|
|*-------------------------------------------------------------------------*|
|* Copyright: Juha Nieminen, Joel Yliluoma                                 *|
|*                                                                         *|
|* This library is distributed under the terms of the                      *|
|* GNU Lesser General Public License version 3.                            *|
|* (See lgpl.txt and gpl.txt for the license text.)                        *|
\***************************************************************************/

// NOTE:
// This file contains only internal types for the function parser library.
// You don't need to include this file in your code. Include "fparser.hh"
// only.

#ifndef ONCE_FPARSER_TYPES_H_
#define ONCE_FPARSER_TYPES_H_

#include "../fpconfig.hh"
#include <cstring>

#ifdef ONCE_FPARSER_H_
#include <map>
#endif

namespace FUNCTIONPARSERTYPES
{
    enum OPCODE
    {
// The order of opcodes in the function list must
// match that which is in the Functions[] array.
        cAbs,
        cAcos, cAcosh,
        cArg,   /* get the phase angle of a complex value */
        cAsin, cAsinh,
        cAtan, cAtan2, cAtanh,
        cCbrt, cCeil,
        cConj,  /* get the complex conjugate of a complex value */
        cCos, cCosh, cCot, cCsc,
        cExp, cExp2, cFloor, cHypot,
        cIf,
        cImag,  /* get imaginary part of a complex value */
        cInt, cLog, cLog10, cLog2, cMax, cMin,
        cPolar, /* create a complex number from polar coordinates */
        cPow,
        cReal,  /* get real part of a complex value */
        cSec, cSin, cSinh, cSqrt, cTan, cTanh,
        cTrunc,

// These do not need any ordering:
// Except that if you change the order of {eq,neq,lt,le,gt,ge}, you
// must also change the order in ConstantFolding_ComparisonOperations().
        cImmed, cJump,
        cNeg, cAdd, cSub, cMul, cDiv, cMod,
        cEqual, cNEqual, cLess, cLessOrEq, cGreater, cGreaterOrEq,
        cNot, cAnd, cOr,
        cNotNot, /* Protects the double-not sequence from optimizations */

        cDeg, cRad, /* Multiplication and division by 180 / pi */

        cFCall, cPCall,

#ifdef FP_SUPPORT_OPTIMIZER
        cPopNMov, /* cPopNMov(x,y) moves [y] to [x] and deletes anything
                   * above [x]. Used for disposing of temporaries.
                   */
        cLog2by, /* log2by(x,y) = log2(x) * y */
        cNop,    /* Used by fpoptimizer internally; should not occur in bytecode */
#endif

        cSinCos,   /* sin(x) followed by cos(x) (two values are pushed to stack) */
        cSinhCosh, /* hyperbolic equivalent of sincos */
        cAbsAnd,    /* As cAnd,       but assume both operands are absolute values */
        cAbsOr,     /* As cOr,        but assume both operands are absolute values */
        cAbsNot,    /* As cAbsNot,    but assume the operand is an absolute value */
        cAbsNotNot, /* As cAbsNotNot, but assume the operand is an absolute value */
        cAbsIf,     /* As cAbsIf,     but assume the 1st operand is an absolute value */

        cDup,   /* Duplicates the last value in the stack: Push [Stacktop] */
        cFetch, /* Same as Dup, except with absolute index
                 * (next value is index) */
        cInv,   /* Inverts the last value in the stack (x = 1/x) */
        cSqr,   /* squares the last operand in the stack, no push/pop */
        cRDiv,  /* reverse division (not x/y, but y/x) */
        cRSub,  /* reverse subtraction (not x-y, but y-x) */
        cRSqrt, /* inverse square-root (1/sqrt(x)) */

        VarBegin
    };

#ifdef ONCE_FPARSER_H_
    struct FuncDefinition
    {
        enum FunctionFlags
        {
            Enabled     = 0x01,
            AngleIn     = 0x02,
            AngleOut    = 0x04,
            OkForInt    = 0x08,
            ComplexOnly = 0x10
        };

#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
        const char name[8];
#else
        struct name { } name;
#endif
        unsigned params : 8;
        unsigned flags  : 8;

        inline bool okForInt() const { return (flags & OkForInt) != 0; }
        inline bool complexOnly() const { return (flags & ComplexOnly) != 0; }
    };

#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
# define FP_FNAME(n) n
#else
# define FP_FNAME(n) {}
#endif
// This list must be in the same order as that in OPCODE enum,
// because the opcode value is used to index this array, and
// the pointer to array element is used for generating the opcode.
    const FuncDefinition Functions[]=
    {
        /*cAbs  */ { FP_FNAME("abs"),   1, FuncDefinition::OkForInt },
        /*cAcos */ { FP_FNAME("acos"),  1, FuncDefinition::AngleOut },
        /*cAcosh*/ { FP_FNAME("acosh"), 1, FuncDefinition::AngleOut },
        /*cArg */  { FP_FNAME("arg"),   1, FuncDefinition::AngleOut | FuncDefinition::ComplexOnly },
        /*cAsin */ { FP_FNAME("asin"),  1, FuncDefinition::AngleOut },
        /*cAsinh*/ { FP_FNAME("asinh"), 1, FuncDefinition::AngleOut },
        /*cAtan */ { FP_FNAME("atan"),  1, FuncDefinition::AngleOut },
        /*cAtan2*/ { FP_FNAME("atan2"), 2, FuncDefinition::AngleOut },
        /*cAtanh*/ { FP_FNAME("atanh"), 1, 0 },
        /*cCbrt */ { FP_FNAME("cbrt"),  1, 0 },
        /*cCeil */ { FP_FNAME("ceil"),  1, 0 },
        /*cConj */ { FP_FNAME("conj"),  1, FuncDefinition::ComplexOnly },
        /*cCos  */ { FP_FNAME("cos"),   1, FuncDefinition::AngleIn },
        /*cCosh */ { FP_FNAME("cosh"),  1, FuncDefinition::AngleIn },
        /*cCot  */ { FP_FNAME("cot"),   1, FuncDefinition::AngleIn },
        /*cCsc  */ { FP_FNAME("csc"),   1, FuncDefinition::AngleIn },
        /*cExp  */ { FP_FNAME("exp"),   1, 0 },
        /*cExp2 */ { FP_FNAME("exp2"),  1, 0 },
        /*cFloor*/ { FP_FNAME("floor"), 1, 0 },
        /*cHypot*/ { FP_FNAME("hypot"), 2, 0 },
        /*cIf   */ { FP_FNAME("if"),    0, FuncDefinition::OkForInt },
        /*cImag */ { FP_FNAME("imag"),  1, FuncDefinition::ComplexOnly },
        /*cInt  */ { FP_FNAME("int"),   1, 0 },
        /*cLog  */ { FP_FNAME("log"),   1, 0 },
        /*cLog10*/ { FP_FNAME("log10"), 1, 0 },
        /*cLog2 */ { FP_FNAME("log2"),  1, 0 },
        /*cMax  */ { FP_FNAME("max"),   2, FuncDefinition::OkForInt },
        /*cMin  */ { FP_FNAME("min"),   2, FuncDefinition::OkForInt },
        /*cPolar */{ FP_FNAME("polar"), 2, FuncDefinition::ComplexOnly | FuncDefinition::AngleIn },
        /*cPow  */ { FP_FNAME("pow"),   2, 0 },
        /*cReal */ { FP_FNAME("real"),  1, FuncDefinition::ComplexOnly },
        /*cSec  */ { FP_FNAME("sec"),   1, FuncDefinition::AngleIn },
        /*cSin  */ { FP_FNAME("sin"),   1, FuncDefinition::AngleIn },
        /*cSinh */ { FP_FNAME("sinh"),  1, FuncDefinition::AngleIn },
        /*cSqrt */ { FP_FNAME("sqrt"),  1, 0 },
        /*cTan  */ { FP_FNAME("tan"),   1, FuncDefinition::AngleIn },
        /*cTanh */ { FP_FNAME("tanh"),  1, FuncDefinition::AngleIn },
        /*cTrunc*/ { FP_FNAME("trunc"), 1, 0 }
    };
#undef FP_FNAME

    struct NamePtr
    {
        const char* name;
        unsigned nameLength;

        NamePtr(const char* n, unsigned l): name(n), nameLength(l) {}

        inline bool operator==(const NamePtr& rhs) const
        {
            return nameLength == rhs.nameLength
                && std::memcmp(name, rhs.name, nameLength) == 0;
        }
        inline bool operator<(const NamePtr& rhs) const
        {
            for(unsigned i = 0; i < nameLength; ++i)
            {
                if(i == rhs.nameLength) return false;
                const char c1 = name[i], c2 = rhs.name[i];
                if(c1 < c2) return true;
                if(c2 < c1) return false;
            }
            return nameLength < rhs.nameLength;
        }
    };

    template<typename Value_t>
    struct NameData
    {
        enum DataType { CONSTANT, UNIT, FUNC_PTR, PARSER_PTR, VARIABLE };
        DataType type;
        unsigned index;
        Value_t value;

        NameData(DataType t, unsigned v) : type(t), index(v), value() { }
        NameData(DataType t, Value_t v) : type(t), index(), value(v) { }
        NameData() { }
    };

    template<typename Value_t>
    class NamePtrsMap: public
    std::map<FUNCTIONPARSERTYPES::NamePtr,
             FUNCTIONPARSERTYPES::NameData<Value_t> >
    {
    };

    const unsigned FUNC_AMOUNT = sizeof(Functions)/sizeof(Functions[0]);
#endif // ONCE_FPARSER_H_
}

#ifdef ONCE_FPARSER_H_
#include <vector>

template<typename Value_t>
struct FunctionParserBase<Value_t>::Data
{
    unsigned mReferenceCounter;

    char mDelimiterChar;
    ParseErrorType mParseErrorType;
    int mEvalErrorType;
    bool mUseDegreeConversion;
    bool mHasByteCodeFlags;
    const char* mErrorLocation;

    unsigned mVariablesAmount;
    std::string mVariablesString;
    FUNCTIONPARSERTYPES::NamePtrsMap<Value_t> mNamePtrs;

    struct InlineVariable
    {
        FUNCTIONPARSERTYPES::NamePtr mName;
        unsigned mFetchIndex;
    };

    typedef std::vector<InlineVariable> InlineVarNamesContainer;
    InlineVarNamesContainer mInlineVarNames;

    struct FuncWrapperPtrData
    {
        /* Only one of the pointers will point to a function, the other
           will be null. (The raw function pointer could be implemented
           as a FunctionWrapper specialization, but it's done like this
           for efficiency.) */
        FunctionPtr mRawFuncPtr;
        FunctionWrapper* mFuncWrapperPtr;
        unsigned mParams;

        FuncWrapperPtrData();
        ~FuncWrapperPtrData();
        FuncWrapperPtrData(const FuncWrapperPtrData&);
        FuncWrapperPtrData& operator=(const FuncWrapperPtrData&);
    };

    struct FuncParserPtrData
    {
        FunctionParserBase<Value_t>* mParserPtr;
        unsigned mParams;
    };

    std::vector<FuncWrapperPtrData> mFuncPtrs;
    std::vector<FuncParserPtrData> mFuncParsers;

    std::vector<unsigned> mByteCode;
    std::vector<Value_t> mImmed;

#if !defined(FP_USE_THREAD_SAFE_EVAL) && \
    !defined(FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA)
    std::vector<Value_t> mStack;
    // Note: When mStack exists,
    //       mStack.size() and mStackSize are mutually redundant.
#endif

    unsigned mStackSize;

    Data();
    Data(const Data&);
    Data& operator=(const Data&); // not implemented on purpose
    ~Data();
};
#endif

//#include "fpaux.hh"

#endif
<commit_msg>Define FP_USE_THREAD_SAFE_EVAL consistently<commit_after>/***************************************************************************\
|* Function Parser for C++ v4.5                                            *|
|*-------------------------------------------------------------------------*|
|* Copyright: Juha Nieminen, Joel Yliluoma                                 *|
|*                                                                         *|
|* This library is distributed under the terms of the                      *|
|* GNU Lesser General Public License version 3.                            *|
|* (See lgpl.txt and gpl.txt for the license text.)                        *|
\***************************************************************************/

// NOTE:
// This file contains only internal types for the function parser library.
// You don't need to include this file in your code. Include "fparser.hh"
// only.

#ifndef ONCE_FPARSER_TYPES_H_
#define ONCE_FPARSER_TYPES_H_

#include "libmesh_config.h"
// Communicate to fparser that threads are being utilized
#ifdef LIBMESH_USING_THREADS
#  define FP_USE_THREAD_SAFE_EVAL
#endif

#include "../fpconfig.hh"
#include <cstring>

#ifdef ONCE_FPARSER_H_
#include <map>
#endif

namespace FUNCTIONPARSERTYPES
{
    enum OPCODE
    {
// The order of opcodes in the function list must
// match that which is in the Functions[] array.
        cAbs,
        cAcos, cAcosh,
        cArg,   /* get the phase angle of a complex value */
        cAsin, cAsinh,
        cAtan, cAtan2, cAtanh,
        cCbrt, cCeil,
        cConj,  /* get the complex conjugate of a complex value */
        cCos, cCosh, cCot, cCsc,
        cExp, cExp2, cFloor, cHypot,
        cIf,
        cImag,  /* get imaginary part of a complex value */
        cInt, cLog, cLog10, cLog2, cMax, cMin,
        cPolar, /* create a complex number from polar coordinates */
        cPow,
        cReal,  /* get real part of a complex value */
        cSec, cSin, cSinh, cSqrt, cTan, cTanh,
        cTrunc,

// These do not need any ordering:
// Except that if you change the order of {eq,neq,lt,le,gt,ge}, you
// must also change the order in ConstantFolding_ComparisonOperations().
        cImmed, cJump,
        cNeg, cAdd, cSub, cMul, cDiv, cMod,
        cEqual, cNEqual, cLess, cLessOrEq, cGreater, cGreaterOrEq,
        cNot, cAnd, cOr,
        cNotNot, /* Protects the double-not sequence from optimizations */

        cDeg, cRad, /* Multiplication and division by 180 / pi */

        cFCall, cPCall,

#ifdef FP_SUPPORT_OPTIMIZER
        cPopNMov, /* cPopNMov(x,y) moves [y] to [x] and deletes anything
                   * above [x]. Used for disposing of temporaries.
                   */
        cLog2by, /* log2by(x,y) = log2(x) * y */
        cNop,    /* Used by fpoptimizer internally; should not occur in bytecode */
#endif

        cSinCos,   /* sin(x) followed by cos(x) (two values are pushed to stack) */
        cSinhCosh, /* hyperbolic equivalent of sincos */
        cAbsAnd,    /* As cAnd,       but assume both operands are absolute values */
        cAbsOr,     /* As cOr,        but assume both operands are absolute values */
        cAbsNot,    /* As cAbsNot,    but assume the operand is an absolute value */
        cAbsNotNot, /* As cAbsNotNot, but assume the operand is an absolute value */
        cAbsIf,     /* As cAbsIf,     but assume the 1st operand is an absolute value */

        cDup,   /* Duplicates the last value in the stack: Push [Stacktop] */
        cFetch, /* Same as Dup, except with absolute index
                 * (next value is index) */
        cInv,   /* Inverts the last value in the stack (x = 1/x) */
        cSqr,   /* squares the last operand in the stack, no push/pop */
        cRDiv,  /* reverse division (not x/y, but y/x) */
        cRSub,  /* reverse subtraction (not x-y, but y-x) */
        cRSqrt, /* inverse square-root (1/sqrt(x)) */

        VarBegin
    };

#ifdef ONCE_FPARSER_H_
    struct FuncDefinition
    {
        enum FunctionFlags
        {
            Enabled     = 0x01,
            AngleIn     = 0x02,
            AngleOut    = 0x04,
            OkForInt    = 0x08,
            ComplexOnly = 0x10
        };

#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
        const char name[8];
#else
        struct name { } name;
#endif
        unsigned params : 8;
        unsigned flags  : 8;

        inline bool okForInt() const { return (flags & OkForInt) != 0; }
        inline bool complexOnly() const { return (flags & ComplexOnly) != 0; }
    };

#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
# define FP_FNAME(n) n
#else
# define FP_FNAME(n) {}
#endif
// This list must be in the same order as that in OPCODE enum,
// because the opcode value is used to index this array, and
// the pointer to array element is used for generating the opcode.
    const FuncDefinition Functions[]=
    {
        /*cAbs  */ { FP_FNAME("abs"),   1, FuncDefinition::OkForInt },
        /*cAcos */ { FP_FNAME("acos"),  1, FuncDefinition::AngleOut },
        /*cAcosh*/ { FP_FNAME("acosh"), 1, FuncDefinition::AngleOut },
        /*cArg */  { FP_FNAME("arg"),   1, FuncDefinition::AngleOut | FuncDefinition::ComplexOnly },
        /*cAsin */ { FP_FNAME("asin"),  1, FuncDefinition::AngleOut },
        /*cAsinh*/ { FP_FNAME("asinh"), 1, FuncDefinition::AngleOut },
        /*cAtan */ { FP_FNAME("atan"),  1, FuncDefinition::AngleOut },
        /*cAtan2*/ { FP_FNAME("atan2"), 2, FuncDefinition::AngleOut },
        /*cAtanh*/ { FP_FNAME("atanh"), 1, 0 },
        /*cCbrt */ { FP_FNAME("cbrt"),  1, 0 },
        /*cCeil */ { FP_FNAME("ceil"),  1, 0 },
        /*cConj */ { FP_FNAME("conj"),  1, FuncDefinition::ComplexOnly },
        /*cCos  */ { FP_FNAME("cos"),   1, FuncDefinition::AngleIn },
        /*cCosh */ { FP_FNAME("cosh"),  1, FuncDefinition::AngleIn },
        /*cCot  */ { FP_FNAME("cot"),   1, FuncDefinition::AngleIn },
        /*cCsc  */ { FP_FNAME("csc"),   1, FuncDefinition::AngleIn },
        /*cExp  */ { FP_FNAME("exp"),   1, 0 },
        /*cExp2 */ { FP_FNAME("exp2"),  1, 0 },
        /*cFloor*/ { FP_FNAME("floor"), 1, 0 },
        /*cHypot*/ { FP_FNAME("hypot"), 2, 0 },
        /*cIf   */ { FP_FNAME("if"),    0, FuncDefinition::OkForInt },
        /*cImag */ { FP_FNAME("imag"),  1, FuncDefinition::ComplexOnly },
        /*cInt  */ { FP_FNAME("int"),   1, 0 },
        /*cLog  */ { FP_FNAME("log"),   1, 0 },
        /*cLog10*/ { FP_FNAME("log10"), 1, 0 },
        /*cLog2 */ { FP_FNAME("log2"),  1, 0 },
        /*cMax  */ { FP_FNAME("max"),   2, FuncDefinition::OkForInt },
        /*cMin  */ { FP_FNAME("min"),   2, FuncDefinition::OkForInt },
        /*cPolar */{ FP_FNAME("polar"), 2, FuncDefinition::ComplexOnly | FuncDefinition::AngleIn },
        /*cPow  */ { FP_FNAME("pow"),   2, 0 },
        /*cReal */ { FP_FNAME("real"),  1, FuncDefinition::ComplexOnly },
        /*cSec  */ { FP_FNAME("sec"),   1, FuncDefinition::AngleIn },
        /*cSin  */ { FP_FNAME("sin"),   1, FuncDefinition::AngleIn },
        /*cSinh */ { FP_FNAME("sinh"),  1, FuncDefinition::AngleIn },
        /*cSqrt */ { FP_FNAME("sqrt"),  1, 0 },
        /*cTan  */ { FP_FNAME("tan"),   1, FuncDefinition::AngleIn },
        /*cTanh */ { FP_FNAME("tanh"),  1, FuncDefinition::AngleIn },
        /*cTrunc*/ { FP_FNAME("trunc"), 1, 0 }
    };
#undef FP_FNAME

    struct NamePtr
    {
        const char* name;
        unsigned nameLength;

        NamePtr(const char* n, unsigned l): name(n), nameLength(l) {}

        inline bool operator==(const NamePtr& rhs) const
        {
            return nameLength == rhs.nameLength
                && std::memcmp(name, rhs.name, nameLength) == 0;
        }
        inline bool operator<(const NamePtr& rhs) const
        {
            for(unsigned i = 0; i < nameLength; ++i)
            {
                if(i == rhs.nameLength) return false;
                const char c1 = name[i], c2 = rhs.name[i];
                if(c1 < c2) return true;
                if(c2 < c1) return false;
            }
            return nameLength < rhs.nameLength;
        }
    };

    template<typename Value_t>
    struct NameData
    {
        enum DataType { CONSTANT, UNIT, FUNC_PTR, PARSER_PTR, VARIABLE };
        DataType type;
        unsigned index;
        Value_t value;

        NameData(DataType t, unsigned v) : type(t), index(v), value() { }
        NameData(DataType t, Value_t v) : type(t), index(), value(v) { }
        NameData() { }
    };

    template<typename Value_t>
    class NamePtrsMap: public
    std::map<FUNCTIONPARSERTYPES::NamePtr,
             FUNCTIONPARSERTYPES::NameData<Value_t> >
    {
    };

    const unsigned FUNC_AMOUNT = sizeof(Functions)/sizeof(Functions[0]);
#endif // ONCE_FPARSER_H_
}

#ifdef ONCE_FPARSER_H_
#include <vector>

template<typename Value_t>
struct FunctionParserBase<Value_t>::Data
{
    unsigned mReferenceCounter;

    char mDelimiterChar;
    ParseErrorType mParseErrorType;
    int mEvalErrorType;
    bool mUseDegreeConversion;
    bool mHasByteCodeFlags;
    const char* mErrorLocation;

    unsigned mVariablesAmount;
    std::string mVariablesString;
    FUNCTIONPARSERTYPES::NamePtrsMap<Value_t> mNamePtrs;

    struct InlineVariable
    {
        FUNCTIONPARSERTYPES::NamePtr mName;
        unsigned mFetchIndex;
    };

    typedef std::vector<InlineVariable> InlineVarNamesContainer;
    InlineVarNamesContainer mInlineVarNames;

    struct FuncWrapperPtrData
    {
        /* Only one of the pointers will point to a function, the other
           will be null. (The raw function pointer could be implemented
           as a FunctionWrapper specialization, but it's done like this
           for efficiency.) */
        FunctionPtr mRawFuncPtr;
        FunctionWrapper* mFuncWrapperPtr;
        unsigned mParams;

        FuncWrapperPtrData();
        ~FuncWrapperPtrData();
        FuncWrapperPtrData(const FuncWrapperPtrData&);
        FuncWrapperPtrData& operator=(const FuncWrapperPtrData&);
    };

    struct FuncParserPtrData
    {
        FunctionParserBase<Value_t>* mParserPtr;
        unsigned mParams;
    };

    std::vector<FuncWrapperPtrData> mFuncPtrs;
    std::vector<FuncParserPtrData> mFuncParsers;

    std::vector<unsigned> mByteCode;
    std::vector<Value_t> mImmed;

#if !defined(FP_USE_THREAD_SAFE_EVAL) && \
    !defined(FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA)
    std::vector<Value_t> mStack;
    // Note: When mStack exists,
    //       mStack.size() and mStackSize are mutually redundant.
#endif

    unsigned mStackSize;

    Data();
    Data(const Data&);
    Data& operator=(const Data&); // not implemented on purpose
    ~Data();
};
#endif

//#include "fpaux.hh"

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2015 Flowgrammable.org
// All rights reserved

#ifndef LIBMATCH_HASH_HPP
#define LIBMATCH_HASH_HPP

// The hashing module...
//
// TODO: Actually document the hash table.

#include <vector>

namespace hash_table
{

namespace data_store
{

// A simple key-value pair
template<typename K, typename V>
struct entry
{
  entry()
    : key(K()),val(V())
  { }

  entry(K const& k, V const& v)
    : key(k),val(v)
  { }

  K key;
  V val;
};

// A linked key-value pair
template<typename K, typename V>
struct list_entry : entry<K, V>
{
  list_entry()
    : entry<K, V>(), next(nullptr)
  { }

  list_entry(K const& k, V const& v)
    : entry<K, V>(k,v), next(nullptr)
  { }

  ~list_entry()
  {
    if (nullptr != next)
      delete next;
  }

  list_entry<K, V>* next;
};

// A tree node key-value pair
template<typename K, typename V>
struct tree_entry : entry<K, V>
{
  tree_entry()
    : entry<K, V>(), left(nullptr), right(nullptr)
  { }

  tree_entry(K const& k, V const& v)
    : entry<K, V>(k,v), left(nullptr), right(nullptr)
  { }

  tree_entry<K, V>* left;
  tree_entry<K, V>* right;
};

// A basic hash table bucket containing a single entry
template<typename K, typename V>
struct basic_bucket : public entry<K, V>
{
  basic_bucket()
    : entry<K, V>()
  { }

  basic_bucket(K const& k, V const& v)
    : entry<K, V>(k,v)
  { }
};

// A chained hash table bucket containing chained entries
template<typename K, typename V>
struct list_bucket
{
  list_bucket(int n)
    : size(n)
  {
    head = new list_entry<K, V>[n];
  }

  ~list_bucket()
  {
    delete head;
  }

  void
  add(K const& k, V const& v)
  {
    list_entry<K, V>* nh = new list_entry<K, V>(k,v);
    nh->next = head;
    head = nh;
  }

  list_entry<K, V>* head;
  int size;
};

// An array based hash table bucket
template<typename K, typename V>
struct array_bucket
{
  int size;
  array_bucket(int n)
    : size(n)
  {
    data = new entry<K, V>[n];
  }

  ~array_bucket()
  {
    delete[] data;
  }

  entry<K, V>* data;
};

// A tree based hash table bucket
template<typename K, typename V>
struct tree_bucket : tree_entry<K, V> { };

} // end namespace data_store

// Encapsulates the open addressing hash table family
namespace open
{

// A hash table with open addressing and linear probing for
// resolving collisions.
template<typename K, typename V, typename H, typename C>
class linear
{
  using store_type = std::vector<data_store::basic_bucket<K, V>>;
public:
  using value_type = data_store::basic_bucket<K, V>;

  using hasher = H;
  using compare = C;

  linear()
    : linear(17)
  { }

  linear(int n)
    : linear(n, hasher(), compare())
  { }

  linear(int n, hasher h, compare c)
    : size_(0), buckets_(n), hash_(h), cmp_(c), data_(n)
  { }

  // Observers
  int size() const { return size_; }
  int buckets() const { return buckets_; }
  bool empty() const { return size_ == 0; }

  // Lookup
  value_type const* find(K const&) const;

  // Mutators
  value_type* insert(K const&, V const&);
  void erase(K const&);

private:
  int get_hash_index(K const&) const;
  int get_entry_index(K const&) const;

  // Resizes the hash table when the load reaches a particular value
  void resize();

private:
  int        size_;    // Current number of entries
  int        buckets_; // Number of buckets
  hasher     hash_;    // Hash function
  compare    cmp_;     // Equality comparison
  store_type data_;    // Data store
};

// Retrieves a key-value pair from the data store
template<typename K, typename V, typename H, typename C>
auto
linear<K, V, H, C>::find(K const& key) const -> value_type const*
{
  int idx = get_entry_index(key);
  if (idx < 0)
    return nullptr;
  return &data_[idx];
}

// Inserts a new key-value pair into the data store.,
template<typename K, typename V, typename H, typename C>
auto
linear<K, V, H, C>::insert(K const& key, V const& value) -> value_type*
{
  int idx = get_entry_index(K());
  if (idx < 0)
    return nullptr;
  data_[idx] = data_store::basic_bucket<K, V>(key, value);
  ++size;
  return &data_[idx];
}

// Removes a key-value pair from the data store.
template<typename K, typename V, typename H, typename C>
void
linear<K, V, H, C>::erase(K const& key)
{
  int idx = get_entry_index(key);
  if (idx >= 0) {
    data_[idx] = data_store::basic_bucket<K, V>(K(), V());
    --size;
  }
}

// Returns the index in the table for the given key. This is the actual
// index in the table for the key.
template<typename K, typename V, typename H, typename C>
int
linear<K, V, H, C>::get_entry_index(K const& key) const
{
  int idx = get_hash_index(key);
  for (int i = 0; i < buckets; i++) {
    if (data_[idx].key == key) // FIXME: Use comp_?
      break;
    idx = (idx + 1 < buckets ? idx + 1 : 0);
  }
  return (data_[idx].key == key ? idx : -1);
}

// Returns an index in the table for a given key. This is not necessarily
// the actual index for the key.
template<typename K, typename V, typename H, typename C>
inline int
linear<K, V, H, C>::get_hash_index(K const& key) const
{
  return hash(key) % buckets;
}

} //end namespace open

namespace closed
{

} // end namespace closed

} // end namespace hash_table

#endif<commit_msg>Fleshed out bucket structs more, formatting fixes<commit_after>// Copyright (c) 2015 Flowgrammable.org
// All rights reserved

#ifndef LIBMATCH_HASH_HPP
#define LIBMATCH_HASH_HPP

// The hashing module...
//
// TODO: Actually document the hash table.

#include <vector>

namespace hash_table
{

namespace data_store
{

// A simple key-value pair
template<typename K, typename V>
struct entry
{
  entry()
    : key(K()),val(V())
  { }

  entry(K const& k, V const& v)
    : key(k),val(v)
  { }

  K key;
  V val;
};

// A linked key-value pair
template<typename K, typename V>
struct list_entry : entry<K, V>
{
  list_entry()
    : entry<K, V>(), next(nullptr)
  { }

  list_entry(K const& k, V const& v)
    : entry<K, V>(k, v), next(nullptr)
  { }

  ~list_entry()
  {
    if (nullptr != next)
      delete next;
  }

  list_entry<K, V>* next;
};

// A tree node key-value pair
template<typename K, typename V>
struct tree_entry : entry<K, V>
{
  tree_entry()
    : entry<K, V>(), left(nullptr), right(nullptr)
  { }

  tree_entry(K const& k, V const& v)
    : entry<K, V>(k, v), left(nullptr), right(nullptr)
  { }

  tree_entry<K, V>* left;
  tree_entry<K, V>* right;
};

// A basic hash table bucket containing a single entry
template<typename K, typename V>
struct basic_bucket : public entry<K, V>
{
  basic_bucket()
    : entry<K, V>(), empty(true)
  { }

  basic_bucket(K const& k, V const& v)
    : entry<K, V>(k, v), empty(false)
  { }

  bool
  is_empty()
  {
    return empty;
  }

  void
  add(K const& k, V const& v)
  {
    this->key = k;
    this->val = v;
    empty = false;
  }

  void
  clear()
  {
    empty = true;
  }

  bool empty;
};

// A chained hash table bucket containing chained entries
template<typename K, typename V>
struct list_bucket
{
  list_bucket()
    : head(nullptr), size(0), empty(true)
  { }

  ~list_bucket()
  {
    if (nullptr != head)
      delete head;
  }

  bool
  is_empty()
  {
    return empty;
  }

  void
  add(K const& k, V const& v)
  {
    list_entry<K, V>* nh = new list_entry<K, V>(k, v);
    nh->next = head;
    head = nh;
    empty = false;
    size++;
  }

  void
  clear()
  {
    // TODO: implement this
    empty = true;
    size = 0;
  }

  list_entry<K, V>* head;
  int size;
  bool empty;
};

// An array based hash table bucket
template<typename K, typename V>
struct array_bucket
{

  array_bucket()
    : size(0), capacity(7), empty(true)
  {
    data = new entry<K, V>[capacity];
  }

  array_bucket(int n)
    : size(0), capacity(n), empty(true)
  {
    data = new entry<K, V>[n];
  }

  ~array_bucket()
  {
    delete[] data;
  }

  void
  add(K const& k, V const& v)
  {
    if (size + 1 < capacity) {
      data[size++] = entry<K, V>(k, v);
      empty = false;
    }
  }

  bool
  is_empty()
  {
    return empty;
  }

  void
  clear()
  {
    // TODO: implement this
    empty = true;
    size = 0;
  }

  entry<K, V>* data;
  int size;
  int capacity;
  bool empty;
};

// A tree based hash table bucket
template<typename K, typename V>
struct tree_bucket : tree_entry<K, V>
{
  tree_bucket()
    : tree_entry<K, V>(), empty(true)
  { }

  tree_bucket(K const& k, V const& v)
    : tree_entry<K, V>(k, v), empty(false)
  { }

  ~tree_bucket()
  {
    // TODO: may need to do this different
    if (nullptr != this->left)
      delete this->left;
    if (nullptr != this->right)
      delete this->right;
  }

  void
  add(K const& k, V const& v)
  {
    // TODO: balance the tree when adding to it
    this->key = k;
    this->val = v;
    empty = false;
  }

  bool
  is_empty()
  {
    return empty;
  }

  void
  clear()
  {
    // TODO: implement this
    empty = true;
  }

  bool empty;
};

} // end namespace data_store

// Encapsulates the open addressing hash table family
namespace open
{

// A hash table with open addressing and linear probing for
// resolving collisions.
template<typename K, typename V, typename H, typename C>
class linear
{
public:
  using store_type = std::vector<data_store::basic_bucket<K, V>>;
  using value_type = data_store::basic_bucket<K, V>;
  using hasher = H;
  using compare = C;

  linear()
    : linear(17)
  { }

  linear(int n)
    : linear(n, hasher(), compare())
  { }

  linear(int n, hasher h, compare c)
    : size_(0), buckets_(n), hash_(h), cmp_(c), data_(n)
  { }

  // Observers
  int size() const { return size_; }
  int buckets() const { return buckets_; }
  bool empty() const { return size_ == 0; }

  // Lookup
  value_type const* find(K const&) const;

  // Mutators
  value_type* insert(K const&, V const&);
  void erase(K const&);

private:
  int get_hash_index(K const&) const;
  int get_entry_index(K const&) const;

  // Resizes the hash table when the load reaches a particular value
  void resize();

private:
  int        size_;    // Current number of entries
  int        buckets_; // Number of buckets
  hasher     hash_;    // Hash function
  compare    cmp_;     // Equality comparison
  store_type data_;    // Data store
};

// Retrieves a key-value pair from the data store
template<typename K, typename V, typename H, typename C>
auto
linear<K, V, H, C>::find(K const& key) const -> value_type const*
{
  int idx = get_entry_index(key);
  if (idx < 0)
    return nullptr;
  return &data_[idx];
}

// Inserts a new key-value pair into the data store.,
template<typename K, typename V, typename H, typename C>
auto
linear<K, V, H, C>::insert(K const& key, V const& value) -> value_type*
{
  int idx = get_entry_index(K());
  if (idx < 0)
    return nullptr;
  data_[idx] = data_store::basic_bucket<K, V>(key, value);
  ++size;
  return &data_[idx];
}

// Removes a key-value pair from the data store.
template<typename K, typename V, typename H, typename C>
void
linear<K, V, H, C>::erase(K const& key)
{
  int idx = get_entry_index(key);
  if (idx >= 0) {
    data_[idx] = data_store::basic_bucket<K, V>(K(), V());
    --size;
  }
}

// Returns the index in the table for the given key. This is the actual
// index in the table for the key.
template<typename K, typename V, typename H, typename C>
int
linear<K, V, H, C>::get_entry_index(K const& key) const
{
  int idx = get_hash_index(key);
  for (int i = 0; i < buckets; i++) {
    if (data_[idx].key == key) // FIXME: Use comp_?
      break;
    idx = (idx + 1 < buckets ? idx + 1 : 0);
  }
  return (data_[idx].key == key ? idx : -1);
}

// Returns an index in the table for a given key. This is not necessarily
// the actual index for the key.
template<typename K, typename V, typename H, typename C>
inline int
linear<K, V, H, C>::get_hash_index(K const& key) const
{
  return hash(key) % buckets;
}

} //end namespace open

namespace closed
{

} // end namespace closed

} // end namespace hash_table

#endif<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012-2013 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <assert.h>
#include <stdint.h>
#include <errno.h>

#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <string>

#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/safestack.h>

#ifdef OPENSSL_NO_SHA256
#error "SHA256 not supported!"
#endif

#include <oriutil/key.h>

using namespace std;

#define SIGBUF_LEN 2048

PublicKey::PublicKey()
    : x509(NULL), key(NULL)
{
}

PublicKey::~PublicKey()
{
    if (key)
        EVP_PKEY_free(key);
}

void
PublicKey::open(const string &keyfile)
{
    FILE *f = fopen(keyfile.c_str(), "r");
    if (f == NULL)
        throw exception();

    x509 = PEM_read_X509(f, NULL, NULL, NULL);
    fclose(f);
    if (x509 == NULL)
    {
        // Error while attempting to read public key!
        throw exception();
    }

    key = X509_get_pubkey(x509);
    if (key == NULL)
    {
        // Cannot get public key from X509!
        throw exception();
    }

    return;
}

string
PublicKey::getName()
{
    assert(false);

    return "";
}

string
PublicKey::getEmail()
{
    string rval;
    STACK_OF(OPENSSL_STRING) *email;

    assert(x509 != NULL);

    email = X509_get1_email(x509);
    rval = sk_OPENSSL_STRING_value(email, 0);
    X509_email_free(email);

    return rval;
}

string
PublicKey::computeDigest()
{
    stringstream rval;
    unsigned int n;
    unsigned char md[EVP_MAX_MD_SIZE];

    assert(x509 != NULL);

    if (!X509_digest(x509, EVP_sha1(), md, &n))
    {
        throw exception();
    }

    // Generate hex string
    for (unsigned int i = 0; i < n; i++)
    {
        rval << hex << setw(2) << setfill('0') << (int)md[i];
    }

    return rval.str();
}

bool
PublicKey::verify(const string &blob,
                  const string &digest) const
{
    int err;
    EVP_MD_CTX * ctx = EVP_MD_CTX_new();
    if (!ctx) {
      throw exception();
      return false;
    }

    assert(x509 != NULL && key != NULL);

    EVP_VerifyInit(ctx, EVP_sha256());
    EVP_VerifyUpdate(ctx, blob.data(), blob.size());
    err = EVP_VerifyFinal(ctx, (const unsigned char *)digest.data(),
                          digest.length(), key);
    if (err != 1)
    {
        ERR_print_errors_fp(stderr);
        EVP_MD_CTX_free(ctx);
        throw exception();
        return false;
    }

    // Prepend 8-byte public key digest

    EVP_MD_CTX_free(ctx);
    return true;
}

PrivateKey::PrivateKey()
    : key(NULL)
{
}

PrivateKey::~PrivateKey()
{
    if (key)
        EVP_PKEY_free(key);
}

void
PrivateKey::open(const string &keyfile)
{
    FILE *f = fopen(keyfile.c_str(), "r");
    if (f == NULL)
        throw exception();
    key = PEM_read_PrivateKey(f, NULL, NULL, NULL);
    fclose(f);
    if (key == NULL)
    {
        ERR_print_errors_fp(stderr);
        throw exception();
    }

    return;
}

string
PrivateKey::sign(const string &blob) const
{
    int err;
    unsigned int sigLen = SIGBUF_LEN;
    char sigBuf[SIGBUF_LEN];
    EVP_MD_CTX * ctx = EVP_MD_CTX_new();
    if (!ctx) {
      throw exception();
    }

    EVP_SignInit(ctx, EVP_sha256());
    EVP_SignUpdate(ctx, blob.data(), blob.size());
    err = EVP_SignFinal(ctx, (unsigned char *)sigBuf, &sigLen, key);
    if (err != 1)
    {
        ERR_print_errors_fp(stderr);
        EVP_MD_CTX_free(ctx);
        throw exception();
    }

    // XXX: Prepend 8-byte public key digest

    EVP_MD_CTX_free(ctx);
    return string().assign(sigBuf, sigLen);
}

/*
 * This function returns whether the key specified is public or private.
 */
KeyType::KeyType_t
Key_GetType(const string &keyfile)
{
    EVP_PKEY *key;
    X509 *x509;
    FILE *f = fopen(keyfile.c_str(), "r");
    if (f == NULL)
    {
        // File open failed
        return KeyType::Invalid;
    }

    key = PEM_read_PrivateKey(f, NULL, NULL, NULL);
    if (key != NULL) {
        fclose(f);
        EVP_PKEY_free(key);
        return KeyType::Private;
    }

    rewind(f);

    x509 = PEM_read_X509(f, NULL, NULL, NULL);
    fclose(f);
    if (x509 == NULL)
    {
        // Error while attempting to read public key!
        return KeyType::Invalid;
    }

    key = X509_get_pubkey(x509);
    if (key != NULL)
    {
        return KeyType::Public;
    }

    // Error while attempting to extract the public key!
    return KeyType::Invalid;
}

int
Key_selfTest(void)
{
    string teststr = "test string";
    string sig;
    bool isValid;

    assert(Key_GetType("test_priv.pem") == KeyType::Private);
    assert(Key_GetType("test_pub.pem") == KeyType::Public);

    PrivateKey priv = PrivateKey();
    PublicKey pub = PublicKey();

    priv.open("test_priv.pem");
    pub.open("test_pub.pem");

    sig = priv.sign(teststr);
    isValid = pub.verify(teststr, sig);
    assert(isValid);

    cout << pub.computeDigest() << endl;

    return 0;
}

<commit_msg>Ensure we still build against OpenSSL 1.0.x<commit_after>/*
 * Copyright (c) 2012-2013 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <assert.h>
#include <stdint.h>
#include <errno.h>

#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <string>

#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/safestack.h>

#ifdef OPENSSL_NO_SHA256
#error "SHA256 not supported!"
#endif

#include <oriutil/key.h>

using namespace std;

#define SIGBUF_LEN 2048

PublicKey::PublicKey()
    : x509(NULL), key(NULL)
{
}

PublicKey::~PublicKey()
{
    if (key)
        EVP_PKEY_free(key);
}

void
PublicKey::open(const string &keyfile)
{
    FILE *f = fopen(keyfile.c_str(), "r");
    if (f == NULL)
        throw exception();

    x509 = PEM_read_X509(f, NULL, NULL, NULL);
    fclose(f);
    if (x509 == NULL)
    {
        // Error while attempting to read public key!
        throw exception();
    }

    key = X509_get_pubkey(x509);
    if (key == NULL)
    {
        // Cannot get public key from X509!
        throw exception();
    }

    return;
}

string
PublicKey::getName()
{
    assert(false);

    return "";
}

string
PublicKey::getEmail()
{
    string rval;
    STACK_OF(OPENSSL_STRING) *email;

    assert(x509 != NULL);

    email = X509_get1_email(x509);
    rval = sk_OPENSSL_STRING_value(email, 0);
    X509_email_free(email);

    return rval;
}

string
PublicKey::computeDigest()
{
    stringstream rval;
    unsigned int n;
    unsigned char md[EVP_MAX_MD_SIZE];

    assert(x509 != NULL);

    if (!X509_digest(x509, EVP_sha1(), md, &n))
    {
        throw exception();
    }

    // Generate hex string
    for (unsigned int i = 0; i < n; i++)
    {
        rval << hex << setw(2) << setfill('0') << (int)md[i];
    }

    return rval.str();
}

bool
PublicKey::verify(const string &blob,
                  const string &digest) const
{
    int err;
    EVP_MD_CTX * ctx = new EVP_MD_CTX(); // XXX: openssl 1.1+ EVP_MD_CTX_new();
    if (!ctx) {
      throw system_error(ENOMEM, std::generic_category(), "Could not allocate EVP_MD_CTX");
      return false;
    }

    assert(x509 != NULL && key != NULL);

    EVP_VerifyInit(ctx, EVP_sha256());
    EVP_VerifyUpdate(ctx, blob.data(), blob.size());
    err = EVP_VerifyFinal(ctx, (const unsigned char *)digest.data(),
                          digest.length(), key);
    if (err != 1)
    {
        ERR_print_errors_fp(stderr);
        delete ctx; // XXX: openssl 1.1+ EVP_MD_CTX_free(ctx);
        throw exception();
        return false;
    }

    // Prepend 8-byte public key digest

    delete ctx; // XXX: openssl 1.1+ EVP_MD_CTX_free(ctx);
    return true;
}

PrivateKey::PrivateKey()
    : key(NULL)
{
}

PrivateKey::~PrivateKey()
{
    if (key)
        EVP_PKEY_free(key);
}

void
PrivateKey::open(const string &keyfile)
{
    FILE *f = fopen(keyfile.c_str(), "r");
    if (f == NULL)
        throw exception();
    key = PEM_read_PrivateKey(f, NULL, NULL, NULL);
    fclose(f);
    if (key == NULL)
    {
        ERR_print_errors_fp(stderr);
        throw exception();
    }

    return;
}

string
PrivateKey::sign(const string &blob) const
{
    int err;
    unsigned int sigLen = SIGBUF_LEN;
    char sigBuf[SIGBUF_LEN];
    EVP_MD_CTX * ctx = new EVP_MD_CTX(); // XXX: openssl 1.1+ EVP_MD_CTX_new();
    if (!ctx) {
      throw system_error(ENOMEM, std::generic_category(), "Could not allocate EVP_MD_CTX");
    }

    EVP_SignInit(ctx, EVP_sha256());
    EVP_SignUpdate(ctx, blob.data(), blob.size());
    err = EVP_SignFinal(ctx, (unsigned char *)sigBuf, &sigLen, key);
    if (err != 1)
    {
        ERR_print_errors_fp(stderr);
        delete ctx; // XXX: openssl 1.1+ EVP_MD_CTX_free(ctx);
        throw exception();
    }

    // XXX: Prepend 8-byte public key digest

    delete ctx; // XXX: openssl 1.1+ EVP_MD_CTX_free(ctx);
    return string().assign(sigBuf, sigLen);
}

/*
 * This function returns whether the key specified is public or private.
 */
KeyType::KeyType_t
Key_GetType(const string &keyfile)
{
    EVP_PKEY *key;
    X509 *x509;
    FILE *f = fopen(keyfile.c_str(), "r");
    if (f == NULL)
    {
        // File open failed
        return KeyType::Invalid;
    }

    key = PEM_read_PrivateKey(f, NULL, NULL, NULL);
    if (key != NULL) {
        fclose(f);
        EVP_PKEY_free(key);
        return KeyType::Private;
    }

    rewind(f);

    x509 = PEM_read_X509(f, NULL, NULL, NULL);
    fclose(f);
    if (x509 == NULL)
    {
        // Error while attempting to read public key!
        return KeyType::Invalid;
    }

    key = X509_get_pubkey(x509);
    if (key != NULL)
    {
        return KeyType::Public;
    }

    // Error while attempting to extract the public key!
    return KeyType::Invalid;
}

int
Key_selfTest(void)
{
    string teststr = "test string";
    string sig;
    bool isValid;

    assert(Key_GetType("test_priv.pem") == KeyType::Private);
    assert(Key_GetType("test_pub.pem") == KeyType::Public);

    PrivateKey priv = PrivateKey();
    PublicKey pub = PublicKey();

    priv.open("test_priv.pem");
    pub.open("test_pub.pem");

    sig = priv.sign(teststr);
    isValid = pub.verify(teststr, sig);
    assert(isValid);

    cout << pub.computeDigest() << endl;

    return 0;
}

<|endoftext|>