<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"

#include "debug.h"
#include "condor_daemon_core.h"

debug_level_t debug_level    = DEBUG_NORMAL;
const char *        debug_progname = NULL;

/*--------------------------------------------------------------------------*/
void
debug_printf( debug_level_t level, char *fmt, ... ) {
	if( DEBUG_LEVEL( level ) ) {
		va_list args;
		va_start( args, fmt );
		_condor_dprintf_va( D_ALWAYS, fmt, args );
		va_end( args );
	}
}

/*--------------------------------------------------------------------------*/
void
debug_dprintf( int flags, debug_level_t level, char *fmt, ... ) {
	if( DEBUG_LEVEL( level ) ) {
		va_list args;
		va_start( args, fmt );
		_condor_dprintf_va( flags, fmt, args );
		va_end( args );
	}
}

/*--------------------------------------------------------------------------*/
void
debug_error( int error, debug_level_t level, char *fmt, ... ) {
    if( DEBUG_LEVEL( level ) ) {
        va_list args;
        va_start( args, fmt );
        _condor_dprintf_va( D_ALWAYS, fmt, args );
        va_end( args );
    }
	DC_Exit( error );
}
<commit_msg>Partial implementation of open/close caching layer.<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"

#include "debug.h"
#include "condor_daemon_core.h"
#include "MyString.h"

#define DEFAULT_CACHE_SIZE ((1024 * 1024) * 5)

debug_level_t debug_level    = DEBUG_NORMAL;
const char *        debug_progname = NULL;

// sometimes we want to keep a cache for our log message when DAGMan is
// emitting thousands of them quickly and we could be writing the log to
// and NFS server.
static bool cache_enabled = false;
static MyString cache;
static unsigned int cache_size = DEFAULT_CACHE_SIZE;

void debug_cache_disable(void);
void debug_cache_enable(void);
void debug_cache_flush(void);
void debug_cache_insert(int flags, const char *fmt, va_list args);

/*--------------------------------------------------------------------------*/
void
debug_printf( debug_level_t level, char *fmt, ... ) {
	if( DEBUG_LEVEL( level ) ) {
		if (cache_enabled == false) {
			va_list args;
			va_start( args, fmt );
			_condor_dprintf_va( D_ALWAYS, fmt, args );
			va_end( args );
		} else {
			va_list args;
			va_start( args, fmt );
			debug_cache_insert( D_ALWAYS, fmt, args );
			va_end( args );
		}
	}
}

/*--------------------------------------------------------------------------*/
void
debug_dprintf( int flags, debug_level_t level, char *fmt, ... ) {
	if( DEBUG_LEVEL( level ) ) {
		if (cache_enabled == false) {
			va_list args;
			va_start( args, fmt );
			_condor_dprintf_va( flags, fmt, args );
			va_end( args );
		} else {

		}
	}
}

/*--------------------------------------------------------------------------*/
void
debug_error( int error, debug_level_t level, char *fmt, ... ) {

	// make sure these come out before emitting the error
	debug_cache_flush();
	debug_cache_disable();

    if( DEBUG_LEVEL( level ) ) {
        va_list args;
        va_start( args, fmt );
        _condor_dprintf_va( D_ALWAYS, fmt, args );
        va_end( args );
    }
	DC_Exit( error );
}

/*--------------------------------------------------------------------------*/
void
debug_cache_enable(void)
{
	cache_enabled = true;
}

/*--------------------------------------------------------------------------*/
void
debug_cache_disable(void)
{
	debug_cache_flush();
	cache_enabled = false;
}

/*--------------------------------------------------------------------------*/
void
debug_cache_insert(int flags, const char *fmt, va_list args)
{
	// from condor_util_lib/dprintf.c
	extern int DebugUseTimestamps;

	/* create the header */

	// XXX TODO
	// Make the header, add it first to the string, then cache.vsnprintf the
	// args and crap into itself.

	// if the cache has surpassed the highwater mark, then flush it.
	if (cache.Length() > cache_size) {
		debug_cache_flush();
	}
}

/*--------------------------------------------------------------------------*/
void
debug_cache_flush(void)
{
	// This emits ONE dprintf call which could write out up to the maximum
	// size of the cache. The lines in the cache are newline delimited.

	if (cache != "") {
		dprintf(D_ALWAYS, "%s", cache.Value());
		cache = "";
	}
}

<|endoftext|>


<commit_before>/*** Copyright (c), The Regents of the University of California            ***
 *** For more information please refer to files in the COPYRIGHT directory ***/
/*
 * ibun - bundle files operation
*/
#include "irods_client_api_table.hpp"
#include "irods_pack_table.hpp"
#include "rodsClient.hpp"
#include "parseCommandLine.hpp"
#include "rodsPath.hpp"
#include "bunUtil.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 nArgv;

    optStr = "bhR:cxD:fZ"; // JMC - backport 4643

    status = parseCmdLineOpt( argc, argv, optStr, 1, &myRodsArgs ); // JMC - backport 4643

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

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

    nArgv = argc - optind;

    if ( nArgv != 2 ) {    /* must have 2 inputs */
        usage();
        exit( 1 );
    }

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

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

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

    // =-=-=-=-=-=-=-
    // 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, 1, &errMsg );

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

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

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

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

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

}

void
usage() {
    char *msgs[] = {
        "Usage : ibun -x [-hfb] [-R resource] structFilePath",
        "               irodsCollection",
        "Usage : ibun -c [-hf] [-R resource] [-D dataType] structFilePath",
        "               irodsCollection",
        "Usage : ibun --add [-h] structFilePath irodsCollection",

        " ",
        "Bundle file operations. This command allows structured files such as ",
        "tar files to be uploaded and downloaded to/from iRODS.",
        " ",
        "A tar file containing many small files can be created with normal unix",
        "tar command on the client and then uploaded to the iRODS server as a",
        "normal iRODS file. The 'ibun -x' command can then be used to extract/untar",
        "the uploaded tar file. The extracted subfiles and subdirectories will",
        "appeared as normal iRODS files and sub-collections. The 'ibun -c' command",
        "can be used to tar/bundle an iRODS collection into a tar file.",
        " ",
        "For example, to upload a directory mydir to iRODS:",
        " ",
        "    tar -chlf mydir.tar -C /x/y/z/mydir .",
        "    iput -Dtar mydir.tar .",
        "    ibun -x mydir.tar mydir",
        " ",
        "Note the use of -C option with the tar command which will tar the",
        "content of mydir but without including the directory mydir in the paths.",
        "The 'ibun -x' command extracts the tar file into the mydir collection.",
        "The target mydir collection does not have to exist nor be empty.",
        "If a subfile already exists in the target collection, the ingestion",
        "of this subfile will fail (unless the -f flag is set) but the process",
        "will continue.",
        " ",
        "It is generally a good practice to tag the tar file using the -Dtar flag",
        "when uploading the file using iput. But if the tag is not made,",
        "the server assumes it is a tar dataType. The dataType tag can be added",
        "afterward with the isysmeta command. For example:",
        "    isysmeta mod /tempZone/home/rods/mydir.tar datatype 'tar file'",
        " ",
        "The following command bundles the iRods collection mydir into a tar file:",
        " ",
        "    ibun -cDtar mydir1.tar mydir",
        " ",
        "If a copy of a file to be bundled does not exist on the target resource,",
        "a replica will automatically be made on the target resource.",
        "Again, if the -D flag is not used, the bundling will be done using tar.",
        " ",
        "The -b option when used with the -x option, specifies bulk registration",
        "which does up to 50 rgistrations at a time to reduce overhead.",
        " ",
        "Options are:",
        " -b  bulk registration when used with -x to reduce overhead",
        " -R  resource - specifies the resource to store to. This is optional",
        "     in your environment",
        " -D  dataType - the structFile data type. Valid only for -c option for",
        "     specifying the target data type. Valid dataTypes are - t|tar|'tar file'",
        "     for tar file. g|gzip|gzipTar for gzipped tar file, b|bzip2|bzip2Tar for",
        "     bzip2 file, and z|zip|zipFile for an archive using 'zip'.  If -D is not",
        "     specified, the default is the tar dataType",
        " -x  extract the structFile and register the extracted files and directories",
        "     under the input irodsCollection",
        " -c  bundle the files and sub-collection underneath the input irodsCollection",
        "     and store it in the structFilePath",
        " -f  force overwrite the structFile (-c) or the subfiles (-x).",
        " --add  add or append to existing structFile.",
        " -h  this help",
        ""
    };
    int i;
    for ( i = 0;; i++ ) {
        if ( strlen( msgs[i] ) == 0 ) {
            break;
        }
        printf( "%s\n", msgs[i] );
    }
    printReleaseInfo( "ibun" );
}
<commit_msg>[#858] spelling<commit_after>/*** Copyright (c), The Regents of the University of California            ***
 *** For more information please refer to files in the COPYRIGHT directory ***/
/*
 * ibun - bundle files operation
*/
#include "irods_client_api_table.hpp"
#include "irods_pack_table.hpp"
#include "rodsClient.hpp"
#include "parseCommandLine.hpp"
#include "rodsPath.hpp"
#include "bunUtil.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 nArgv;

    optStr = "bhR:cxD:fZ"; // JMC - backport 4643

    status = parseCmdLineOpt( argc, argv, optStr, 1, &myRodsArgs ); // JMC - backport 4643

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

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

    nArgv = argc - optind;

    if ( nArgv != 2 ) {    /* must have 2 inputs */
        usage();
        exit( 1 );
    }

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

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

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

    // =-=-=-=-=-=-=-
    // 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, 1, &errMsg );

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

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

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

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

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

}

void
usage() {
    char *msgs[] = {
        "Usage : ibun -x [-hfb] [-R resource] structFilePath",
        "               irodsCollection",
        "Usage : ibun -c [-hf] [-R resource] [-D dataType] structFilePath",
        "               irodsCollection",
        "Usage : ibun --add [-h] structFilePath irodsCollection",

        " ",
        "Bundle file operations. This command allows structured files such as ",
        "tar files to be uploaded and downloaded to/from iRODS.",
        " ",
        "A tar file containing many small files can be created with normal unix",
        "tar command on the client and then uploaded to the iRODS server as a",
        "normal iRODS file. The 'ibun -x' command can then be used to extract/untar",
        "the uploaded tar file. The extracted subfiles and subdirectories will",
        "appeared as normal iRODS files and sub-collections. The 'ibun -c' command",
        "can be used to tar/bundle an iRODS collection into a tar file.",
        " ",
        "For example, to upload a directory mydir to iRODS:",
        " ",
        "    tar -chlf mydir.tar -C /x/y/z/mydir .",
        "    iput -Dtar mydir.tar .",
        "    ibun -x mydir.tar mydir",
        " ",
        "Note the use of -C option with the tar command which will tar the",
        "content of mydir but without including the directory mydir in the paths.",
        "The 'ibun -x' command extracts the tar file into the mydir collection.",
        "The target mydir collection does not have to exist nor be empty.",
        "If a subfile already exists in the target collection, the ingestion",
        "of this subfile will fail (unless the -f flag is set) but the process",
        "will continue.",
        " ",
        "It is generally a good practice to tag the tar file using the -Dtar flag",
        "when uploading the file using iput. But if the tag is not made,",
        "the server assumes it is a tar dataType. The dataType tag can be added",
        "afterward with the isysmeta command. For example:",
        "    isysmeta mod /tempZone/home/rods/mydir.tar datatype 'tar file'",
        " ",
        "The following command bundles the iRods collection mydir into a tar file:",
        " ",
        "    ibun -cDtar mydir1.tar mydir",
        " ",
        "If a copy of a file to be bundled does not exist on the target resource,",
        "a replica will automatically be made on the target resource.",
        "Again, if the -D flag is not used, the bundling will be done using tar.",
        " ",
        "The -b option when used with the -x option, specifies bulk registration",
        "which does up to 50 registrations at a time to reduce overhead.",
        " ",
        "Options are:",
        " -b  bulk registration when used with -x to reduce overhead",
        " -R  resource - specifies the resource to store to. This is optional",
        "     in your environment",
        " -D  dataType - the structFile data type. Valid only for -c option for",
        "     specifying the target data type. Valid dataTypes are - t|tar|'tar file'",
        "     for tar file. g|gzip|gzipTar for gzipped tar file, b|bzip2|bzip2Tar for",
        "     bzip2 file, and z|zip|zipFile for an archive using 'zip'.  If -D is not",
        "     specified, the default is the tar dataType",
        " -x  extract the structFile and register the extracted files and directories",
        "     under the input irodsCollection",
        " -c  bundle the files and sub-collection underneath the input irodsCollection",
        "     and store it in the structFilePath",
        " -f  force overwrite the structFile (-c) or the subfiles (-x).",
        " --add  add or append to existing structFile.",
        " -h  this help",
        ""
    };
    int i;
    for ( i = 0;; i++ ) {
        if ( strlen( msgs[i] ) == 0 ) {
            break;
        }
        printf( "%s\n", msgs[i] );
    }
    printReleaseInfo( "ibun" );
}
<|endoftext|>


<commit_before>#include <opencv2/opencv.hpp>

namespace image_manip
{

// TODO(lucasw) mirror initUndistortRectifyMap as much as makes sense
// Add m1type parameter
// And R rectification matrix?
// Need to investigate non-floating point version.
void initDistortMap(const cv::Mat& cameraMatrix, const cv::Mat distCoeffs,
    const cv::Size size,
    cv::Mat& map1, cv::Mat& map2)
{
  cv::Mat pixel_locations_src = cv::Mat(size.width * size.height, 1, CV_32FC2);

  int ind = 0;
  for (int i = 0; i < size.height; i++) {
    for (int j = 0; j < size.width; j++) {
      // TODO(lucasw) maybe would want x and y offsets here to make the output
      // image bigger or smaller than the input?
      pixel_locations_src.at<cv::Point2f>(ind, 0) = cv::Point2f(j,i);
      ++ind;
    }
  }

  cv::Mat fractional_locations_dst = cv::Mat(pixel_locations_src.size(), CV_32FC2);
  cv::undistortPoints(pixel_locations_src, fractional_locations_dst, cameraMatrix, distCoeffs);

  const float fx = cameraMatrix.at<double>(0, 0);
  const float fy = cameraMatrix.at<double>(1, 1);
  const float cx = cameraMatrix.at<double>(0, 2);
  const float cy = cameraMatrix.at<double>(1, 2);

  // TODO(lucasw) is there a faster way to do this?
  // A matrix operation?
  // If the x and y were separate matrices it would be possible,
  // and remap does take separate x and y maps.
  cv::Mat pixel_locations_dst = cv::Mat(size, CV_32FC2);
  ind = 0;
  for (int i = 0; i < size.height; i++) {
    for (int j = 0; j < size.width; j++) {
      const float x = fractional_locations_dst.at<cv::Point2f>(ind, 0).x * fx + cx;
      const float y = fractional_locations_dst.at<cv::Point2f>(ind, 0).y * fy + cy;
      pixel_locations_dst.at<cv::Point2f>(i,j) = cv::Point2f(x,y);
      // if ((i == 0) && (j == 0))
      //  ROS_INFO_STREAM(ind << ": " << i << " " << j << ", " << y << " " << x);
      ++ind;
    }
  }

  map1 = pixel_locations_dst;
  map2 = cv::Mat();
}

// adapted from http://code.opencv.org/issues/1387 (which had errors)
// TODO(lucasw) I think this can make use of convertMaps to make it even more efficient
void distort(const cv::Mat& src, cv::Mat& image_dst,
    const cv::Mat& cameraMatrix, const cv::Mat& distCoeffs)
{
  cv::Mat map1;
  cv::Mat map2;

  // TODO(lucasw) will passing in a different size work as expected?
  // or will it require adjustment of cx/cy?
  initDistortMap(cameraMatrix, distCoeffs, src.size(), map1, map2);
  cv::remap(src, image_dst, map1, map2, CV_INTER_LINEAR);
}

}  // namespace image_manip
<commit_msg>OpenCV4 compatibility for noetic 20.04<commit_after>#include <opencv2/opencv.hpp>

namespace image_manip
{

// TODO(lucasw) mirror initUndistortRectifyMap as much as makes sense
// Add m1type parameter
// And R rectification matrix?
// Need to investigate non-floating point version.
void initDistortMap(const cv::Mat& cameraMatrix, const cv::Mat distCoeffs,
    const cv::Size size,
    cv::Mat& map1, cv::Mat& map2)
{
  cv::Mat pixel_locations_src = cv::Mat(size.width * size.height, 1, CV_32FC2);

  int ind = 0;
  for (int i = 0; i < size.height; i++) {
    for (int j = 0; j < size.width; j++) {
      // TODO(lucasw) maybe would want x and y offsets here to make the output
      // image bigger or smaller than the input?
      pixel_locations_src.at<cv::Point2f>(ind, 0) = cv::Point2f(j,i);
      ++ind;
    }
  }

  cv::Mat fractional_locations_dst = cv::Mat(pixel_locations_src.size(), CV_32FC2);
  cv::undistortPoints(pixel_locations_src, fractional_locations_dst, cameraMatrix, distCoeffs);

  const float fx = cameraMatrix.at<double>(0, 0);
  const float fy = cameraMatrix.at<double>(1, 1);
  const float cx = cameraMatrix.at<double>(0, 2);
  const float cy = cameraMatrix.at<double>(1, 2);

  // TODO(lucasw) is there a faster way to do this?
  // A matrix operation?
  // If the x and y were separate matrices it would be possible,
  // and remap does take separate x and y maps.
  cv::Mat pixel_locations_dst = cv::Mat(size, CV_32FC2);
  ind = 0;
  for (int i = 0; i < size.height; i++) {
    for (int j = 0; j < size.width; j++) {
      const float x = fractional_locations_dst.at<cv::Point2f>(ind, 0).x * fx + cx;
      const float y = fractional_locations_dst.at<cv::Point2f>(ind, 0).y * fy + cy;
      pixel_locations_dst.at<cv::Point2f>(i,j) = cv::Point2f(x,y);
      // if ((i == 0) && (j == 0))
      //  ROS_INFO_STREAM(ind << ": " << i << " " << j << ", " << y << " " << x);
      ++ind;
    }
  }

  map1 = pixel_locations_dst;
  map2 = cv::Mat();
}

// adapted from http://code.opencv.org/issues/1387 (which had errors)
// TODO(lucasw) I think this can make use of convertMaps to make it even more efficient
void distort(const cv::Mat& src, cv::Mat& image_dst,
    const cv::Mat& cameraMatrix, const cv::Mat& distCoeffs)
{
  cv::Mat map1;
  cv::Mat map2;

  // TODO(lucasw) will passing in a different size work as expected?
  // or will it require adjustment of cx/cy?
  initDistortMap(cameraMatrix, distCoeffs, src.size(), map1, map2);
  cv::remap(src, image_dst, map1, map2, cv::INTER_LINEAR);
}

}  // namespace image_manip
<|endoftext|>


<commit_before>namespace Bull
{
    template<typename T>
    Vector2<T> Vector2<T>::normalize(const Vector2<T>& vector)
    {
        return Vector2<T>(vector).normalize();
    }

    template<typename T>
    T Vector2<T>::dotProduct(const Vector2& left, const Vector2& right)
    {
        return (left.x * right.x) + (left.y * right.y);
    }

    template<typename T>
    Vector2<T>::Vector2()
    {
        set(0);
    }

    template<typename T>
    Vector2<T>::Vector2(T value)
    {
        set(value);
    }

    template<typename T>
    Vector2<T>::Vector2(T x, T y)
    {
        set(x, y);
    }

    template<typename T>
    Vector2<T>& Vector2<T>::set(T value)
    {
        x = y = value;

        return (*this);
    }

    template<typename T>
    Vector2<T>& Vector2<T>::set(T x, T y)
    {
        this->x = x;
        this->y = y;

        return (*this);
    }

    template<typename T>
    Vector2<T>& Vector2<T>::set(const Vector2<T>& copy)
    {
        x = copy.x;
        y = copy.y;

        return (*this);
    }

    template<typename T>
    float Vector2<T>::getLength() const
    {
        return std::sqrt(std::pow(x, 2) + std::pow(y, 2));
    }

    template<typename T>
    Vector2<T>& Vector2<T>::normalize()
    {
        x /= getLength();
        y /= getLength();

        return (*this);
    }

    template<typename T>
    T Vector2<T>::dotProduct(const Vector2& right)
    {
        return (x * right.x) + (y * right.y);
    }

    template<typename T>
    bool Vector2<T>::operator==(const Vector2& right) const
    {
        return (x == right.x) && (y == right.y);
    }

    template<typename T>
    bool Vector2<T>::operator!=(const Vector2& right) const
    {
        return !((*this) == right);
    }

    template<typename T>
    Vector2<T>& Vector2<T>::operator+=(const Vector2& right)
    {
        x += right.x;
        y += right.y;

        return (*this);
    }

    template<typename T>
    Vector2<T>& Vector2<T>::operator-=(const Vector2& right)
    {
        x -= right.x;
        y -= right.y;

        return (*this);
    }

    template<typename T>
    Vector2<T> operator+(const Vector2<T>& left, const Vector2<T>& right)
    {
        return Vector2<T>(left) += right;
    }

    template<typename T>
    Vector2<T> operator+(float left, const Vector2<T>& right)
    {
        return Vector2<T>(left) += right;
    }

    template<typename T>
    Vector2<T> operator+(const Vector2<T>& left, float right)
    {
        return Vector2<T>(left) += Vector2<T>(right);
    }

    template<typename T>
    Vector2<T> operator-(const Vector2<T>& left, const Vector2<T>& right)
    {
        return Vector2<T>(left) -= right;
    }

    template<typename T>
    Vector2<T> operator-(float left, const Vector2<T>& right)
    {
        return Vector2<T>(left) -= right;
    }

    template<typename T>
    Vector2<T> operator-(const Vector2<T>& left, float right)
    {
        return Vector2<T>(left) -= Vector2<T>(right);
    }
}
<commit_msg>Math/Vector2 Implement negation method<commit_after>namespace Bull
{
    template<typename T>
    Vector2<T> Vector2<T>::normalize(const Vector2<T>& vector)
    {
        return Vector2<T>(vector).normalize();
    }

    template<typename T>
    T Vector2<T>::dotProduct(const Vector2& left, const Vector2& right)
    {
        return (left.x * right.x) + (left.y * right.y);
    }

    template<typename T>
    Vector2<T>::Vector2()
    {
        set(0);
    }

    template<typename T>
    Vector2<T>::Vector2(T value)
    {
        set(value);
    }

    template<typename T>
    Vector2<T>::Vector2(T x, T y)
    {
        set(x, y);
    }

    template<typename T>
    Vector2<T>& Vector2<T>::set(T value)
    {
        x = y = value;

        return (*this);
    }

    template<typename T>
    Vector2<T>& Vector2<T>::set(T x, T y)
    {
        this->x = x;
        this->y = y;

        return (*this);
    }

    template<typename T>
    Vector2<T>& Vector2<T>::set(const Vector2<T>& copy)
    {
        x = copy.x;
        y = copy.y;

        return (*this);
    }

    template<typename T>
    float Vector2<T>::getLength() const
    {
        return std::sqrt(std::pow(x, 2) + std::pow(y, 2));
    }

    template<typename T>
    Vector2<T>& Vector2<T>::normalize()
    {
        x /= getLength();
        y /= getLength();

        return (*this);
    }

    template<typename T>
    T Vector2<T>::dotProduct(const Vector2& right)
    {
        return (x * right.x) + (y * right.y);
    }

    template<typename T>
    bool Vector2<T>::operator==(const Vector2& right) const
    {
        return (x == right.x) && (y == right.y);
    }

    template<typename T>
    bool Vector2<T>::operator!=(const Vector2& right) const
    {
        return !((*this) == right);
    }

    template<typename T>
    Vector2<T>& Vector2<T>::operator+=(const Vector2& right)
    {
        x += right.x;
        y += right.y;

        return (*this);
    }

    template<typename T>
    Vector2<T> Vector2<T>::operator-() const
    {
        return Vector2<T>(-x, -y);
    }

    template<typename T>
    Vector2<T>& Vector2<T>::operator-=(const Vector2& right)
    {
        x -= right.x;
        y -= right.y;

        return (*this);
    }

    template<typename T>
    Vector2<T> operator+(const Vector2<T>& left, const Vector2<T>& right)
    {
        return Vector2<T>(left) += right;
    }

    template<typename T>
    Vector2<T> operator+(float left, const Vector2<T>& right)
    {
        return Vector2<T>(left) += right;
    }

    template<typename T>
    Vector2<T> operator+(const Vector2<T>& left, float right)
    {
        return Vector2<T>(left) += Vector2<T>(right);
    }

    template<typename T>
    Vector2<T> operator-(const Vector2<T>& left, const Vector2<T>& right)
    {
        return Vector2<T>(left) -= right;
    }

    template<typename T>
    Vector2<T> operator-(float left, const Vector2<T>& right)
    {
        return Vector2<T>(left) -= right;
    }

    template<typename T>
    Vector2<T> operator-(const Vector2<T>& left, float right)
    {
        return Vector2<T>(left) -= Vector2<T>(right);
    }
}
<|endoftext|>


<commit_before>//	Copyright 2017 Adam Smith
//	Licensed under the Apache License, Version 2.0 (the "License");
//	you may not use this file except in compliance with the License.
//	You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
//	Unless required by applicable law or agreed to in writing, software
//	distributed under the License is distributed on an "AS IS" BASIS,
//	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//	See the License for the specific language governing permissions and
//	limitations under the License.

#ifndef ASMITH_REFLECTION_MASTER_HPP
#define ASMITH_REFLECTION_MASTER_HPP

#include "reflection_class.hpp"
#include "reflection_constructor.hpp"
#include "reflection_destructor.hpp"
#include "reflection_function.hpp"
#include "reflection_variable.hpp"
#include "reflection_modifier.hpp"

namespace asmith {

	#define MACRO_JOIN2(a, b) a##b
#define MACRO_JOIN(a, b) MACRO_JOIN2(a , b)
#define MACRO_STRING(a) #a

#define ASMITH_BEGIN_REFLECTION \
	class MACRO_JOIN(ASMITH_REFLECTION_CLASS_NAME,_reflection) : public asmith::reflection_class {\
	const char* get_name() const override { return MACRO_STRING(ASMITH_REFLECTION_CLASS_NAME); };\
	size_t get_size() const override { return sizeof(ASMITH_REFLECTION_CLASS_NAME); }\
	size_t get_variable_count() const override { return ASMITH_REFLECTION_VARIABLE_COUNT; }\
	size_t get_constructor_count() const override { return ASMITH_REFLECTION_CONSTRUCTOR_COUNT; }\
	size_t get_function_count() const override { return ASMITH_REFLECTION_FUNCTION_COUNT; }\
	size_t get_parent_count() const override { return ASMITH_REFLECTION_PARENT_COUNT; }
#define ASMITH_END_REFLECTION };

#define ASMITH_REFLECTION_VARIABLE(aName, aMods) \
	class MACRO_JOIN(aName,_var_class) : public asmith::reflection_variable {\
	public:\
		typedef decltype(ASMITH_REFLECTION_CLASS_NAME::aName) type;\
		const asmith::reflection_class& get_class() const override { return asmith::get_reflection_class<type>(); }\
		const char* get_name() const override { return MACRO_STRING(aName); }\
		uint32_t get_modifiers() const override { return aMods; }\
		void set(void* aObject, const void* aInput) const override { static_cast<ASMITH_REFLECTION_CLASS_NAME*>(aObject)->*&ASMITH_REFLECTION_CLASS_NAME::aName = *static_cast<const type*>(aInput); }\
		void get(const void* aObject, void* aOutput) const override { *static_cast<type*>(aOutput), static_cast<const ASMITH_REFLECTION_CLASS_NAME*>(aObject)->*&ASMITH_REFLECTION_CLASS_NAME::aName; }\
	};\
	static MACRO_JOIN(aName,_var_class) MACRO_JOIN(aName,_var);\
	if(i == currentVar) return MACRO_JOIN(aName,_var);\
	++currentVar;

#define ASMITH_BEGIN_REFLECTION_VARIABLES const asmith::reflection_variable& get_variable(size_t i) const override { int currentVar = 0;
#define ASMITH_END_REFLECTION_VARIABLES throw std::runtime_error("asmith::reflection_variable::get_function : Index out of bounds"); }
#define ASMITH_REFLECTION_DESTRUCTOR(aMods)\
	const asmith::reflection_destructor& get_destructor() const override { \
		class destructor : public reflection_destructor {\
		public:\
			size_t get_modifiers() const override { return aMods; }\
			void call(void* aObject) const override { static_cast<ASMITH_REFLECTION_CLASS_NAME*>(aObject)->~ASMITH_REFLECTION_CLASS_NAME(); }\
		};\
		static destructor DESTRUCTOR;\
		return DESTRUCTOR;\
	}

#define ASMITH_BEGIN_REFLECTION_CONSTRUCTORS const asmith::reflection_constructor& get_constructor(size_t i) const override { int currentConstructor = 0;
#define ASMITH_END_REFLECTION_CONSTRUCTORS throw std::runtime_error("asmith::reflection_variable::get_constructor : Index out of bounds"); }

	namespace implementation {
		template<class C, uint32_t MODS, class ...PARAMS>
		class reflection_constructor_implementation : public reflection_constructor {
		private:
			template<class A>
			void call__(void* aObject, const void* aParams) {
				const A* a = static_cast<const A*>(reinterpret_cast<const uint8_t*>(aParams) + 0);
				new(aObject) C(*a);
			}

			template<class A, class B>
			void call__(void* aObject, const void* aParams) {
				const A* a = static_cast<const A*>(reinterpret_cast<const uint8_t*>(aParams) + 0);
				const B* b = static_cast<const B*>(reinterpret_cast<const uint8_t*>(a) + sizeof(A));
				new(aObject) C(*a, *b);
			}

			template<class A, class B, class C>
			void call__(void* aObject, const void* aParams) {
				const A* a = static_cast<const A*>(reinterpret_cast<const uint8_t*>(aParams) + 0);
				const B* b = static_cast<const B*>(reinterpret_cast<const uint8_t*>(a) + sizeof(A));
				const C* c = static_cast<const C*>(reinterpret_cast<const uint8_t*>(b) + sizeof(B));
				new(aObject) C(*a, *b, *c);
			}

			template<class A, class B, class C, class D>
			void call__(void* aObject, const void* aParams) {
				const A* a = static_cast<const A*>(reinterpret_cast<const uint8_t*>(aParams) + 0);
				const B* b = static_cast<const B*>(reinterpret_cast<const uint8_t*>(a) + sizeof(A));
				const C* c = static_cast<const C*>(reinterpret_cast<const uint8_t*>(b) + sizeof(B));
				const D* d = static_cast<const D*>(reinterpret_cast<const uint8_t*>(c) + sizeof(C));
				new(aObject) C(*a, *b, *c, *d);
			}

			template<class A, class B, class C, class D, class E>
			void call__(void* aObject, const void* aParams) {
				const A* a = static_cast<const A*>(reinterpret_cast<const uint8_t*>(aParams) + 0);
				const B* b = static_cast<const B*>(reinterpret_cast<const uint8_t*>(a) + sizeof(A));
				const C* c = static_cast<const C*>(reinterpret_cast<const uint8_t*>(b) + sizeof(B));
				const D* d = static_cast<const D*>(reinterpret_cast<const uint8_t*>(c) + sizeof(C));
				const E* e = static_cast<const E*>(reinterpret_cast<const uint8_t*>(d) + sizeof(D));
				new(aObject) C(*a, *b, *c, *d, *e);
			}

			template<class A, class B, class C, class D, class E, class F>
			void call__(void* aObject, const void* aParams) {
				const A* a = static_cast<const A*>(reinterpret_cast<const uint8_t*>(aParams) + 0);
				const B* b = static_cast<const B*>(reinterpret_cast<const uint8_t*>(a) + sizeof(A));
				const C* c = static_cast<const C*>(reinterpret_cast<const uint8_t*>(b) + sizeof(B));
				const D* d = static_cast<const D*>(reinterpret_cast<const uint8_t*>(c) + sizeof(C));
				const E* e = static_cast<const E*>(reinterpret_cast<const uint8_t*>(d) + sizeof(D));
				const F* f = static_cast<const F*>(reinterpret_cast<const uint8_t*>(e) + sizeof(E));
				new(aObject) C(*a, *b, *c, *d, *e, *f);
			}

			template<size_t I = sizeof...(PARAMS)>
			typename std::enable_if<I == 0, void>::type call_(void* aObject, const void* aParams) const {
				new(aObject) C();
			}

			template<size_t I = sizeof...(PARAMS)>
			typename std::enable_if<I != 0, void>::type call_(void* aObject, const void* aParams) const {
				call__<PARAMS...>(aObject, aParams);
			}
		public:
			// Inherited from reflection_constructor
			size_t get_parameter_count() const override {
				return sizeof...(PARAMS);
			}

			const asmith::reflection_class& get_parameter(size_t i) const override {
				//! \todo Implement
				throw std::runtime_error("asmith::reflection_constructor_implementation::get_parameter : Not yet implemented");
			}

			size_t get_modifiers() const override {
				return MODS;
			}

			void call(void* aObject, const void* aParams) const override {
				call_<PARAMS...>(aObject, aParams);
			}
		};
	}

#define ASMITH_REFLECTION_TRIVIAL_CONSTRUCTOR(aMods) \
	static implementation::reflection_constructor_implementation<ASMITH_REFLECTION_CLASS_NAME, aMods> trivial_constructor;\
	if(i == currentConstructor) return trivial_constructor;\
	++currentConstructor;

	class reflection_test {
	private:
		std::string name;
		int dimensions;
		float lower_bound;
		float upper_bound;
	public:
		std::string get_name() { return name; }
		int get_dimensions() { return dimensions; }
		float get_lower_bound() { return lower_bound; }
		float get_upper_bound() { return upper_bound; }

		#define ASMITH_REFLECTION_CLASS_NAME reflection_test
		#define ASMITH_REFLECTION_VARIABLE_COUNT 4
		#define ASMITH_REFLECTION_CONSTRUCTOR_COUNT 0
		#define ASMITH_REFLECTION_FUNCTION_COUNT 0
		#define ASMITH_REFLECTION_PARENT_COUNT 0
		ASMITH_BEGIN_REFLECTION
			const asmith::reflection_function& get_function(size_t) const override { throw 0; }
			const reflection_class& get_parent_class(size_t) const override { throw 0; }

			ASMITH_REFLECTION_DESTRUCTOR(REFLECTION_PUBLIC)

			ASMITH_BEGIN_REFLECTION_CONSTRUCTORS
				ASMITH_REFLECTION_TRIVIAL_CONSTRUCTOR(REFLECTION_PUBLIC)
			ASMITH_END_REFLECTION_CONSTRUCTORS

			ASMITH_BEGIN_REFLECTION_VARIABLES
				ASMITH_REFLECTION_VARIABLE(name,		REFLECTION_PRIVATE);
				ASMITH_REFLECTION_VARIABLE(dimensions,	REFLECTION_PRIVATE);
				ASMITH_REFLECTION_VARIABLE(lower_bound,	REFLECTION_PRIVATE);
				ASMITH_REFLECTION_VARIABLE(upper_bound,	REFLECTION_PRIVATE);
			ASMITH_END_REFLECTION_VARIABLES
		ASMITH_END_REFLECTION

		#undef ASMITH_REFLECTION_CLASS_NAME
		#undef ASMITH_REFLECTION_VARIABLE_COUNT
		#undef ASMITH_REFLECTION_CONSTRUCTOR_COUNT
		#undef ASMITH_REFLECTION_FUNCTION_COUNT
		#undef ASMITH_REFLECTION_PARENT_COUNT
	};
}

#endif<commit_msg>Fixed constructors with arguments<commit_after>//	Copyright 2017 Adam Smith
//	Licensed under the Apache License, Version 2.0 (the "License");
//	you may not use this file except in compliance with the License.
//	You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
//	Unless required by applicable law or agreed to in writing, software
//	distributed under the License is distributed on an "AS IS" BASIS,
//	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//	See the License for the specific language governing permissions and
//	limitations under the License.

#ifndef ASMITH_REFLECTION_MASTER_HPP
#define ASMITH_REFLECTION_MASTER_HPP

#include "reflection_class.hpp"
#include "reflection_constructor.hpp"
#include "reflection_destructor.hpp"
#include "reflection_function.hpp"
#include "reflection_variable.hpp"
#include "reflection_modifier.hpp"

namespace asmith {

	#define MACRO_JOIN2(a, b) a##b
#define MACRO_JOIN(a, b) MACRO_JOIN2(a , b)
#define MACRO_STRING(a) #a

#define ASMITH_BEGIN_REFLECTION \
	class MACRO_JOIN(ASMITH_REFLECTION_CLASS_NAME,_reflection) : public asmith::reflection_class {\
	const char* get_name() const override { return MACRO_STRING(ASMITH_REFLECTION_CLASS_NAME); };\
	size_t get_size() const override { return sizeof(ASMITH_REFLECTION_CLASS_NAME); }\
	size_t get_variable_count() const override { return ASMITH_REFLECTION_VARIABLE_COUNT; }\
	size_t get_constructor_count() const override { return ASMITH_REFLECTION_CONSTRUCTOR_COUNT; }\
	size_t get_function_count() const override { return ASMITH_REFLECTION_FUNCTION_COUNT; }\
	size_t get_parent_count() const override { return ASMITH_REFLECTION_PARENT_COUNT; }
#define ASMITH_END_REFLECTION };

#define ASMITH_REFLECTION_VARIABLE(aName, aMods) \
	class MACRO_JOIN(aName,_var_class) : public asmith::reflection_variable {\
	public:\
		typedef decltype(ASMITH_REFLECTION_CLASS_NAME::aName) type;\
		const asmith::reflection_class& get_class() const override { return asmith::get_reflection_class<type>(); }\
		const char* get_name() const override { return MACRO_STRING(aName); }\
		uint32_t get_modifiers() const override { return aMods; }\
		void set(void* aObject, const void* aInput) const override { static_cast<ASMITH_REFLECTION_CLASS_NAME*>(aObject)->*&ASMITH_REFLECTION_CLASS_NAME::aName = *static_cast<const type*>(aInput); }\
		void get(const void* aObject, void* aOutput) const override { *static_cast<type*>(aOutput), static_cast<const ASMITH_REFLECTION_CLASS_NAME*>(aObject)->*&ASMITH_REFLECTION_CLASS_NAME::aName; }\
	};\
	static MACRO_JOIN(aName,_var_class) MACRO_JOIN(aName,_var);\
	if(i == currentVar) return MACRO_JOIN(aName,_var);\
	++currentVar;

#define ASMITH_BEGIN_REFLECTION_VARIABLES const asmith::reflection_variable& get_variable(size_t i) const override { int currentVar = 0;
#define ASMITH_END_REFLECTION_VARIABLES throw std::runtime_error("asmith::reflection_variable::get_function : Index out of bounds"); }
#define ASMITH_REFLECTION_DESTRUCTOR(aMods)\
	const asmith::reflection_destructor& get_destructor() const override { \
		class destructor : public reflection_destructor {\
		public:\
			size_t get_modifiers() const override { return aMods; }\
			void call(void* aObject) const override { static_cast<ASMITH_REFLECTION_CLASS_NAME*>(aObject)->~ASMITH_REFLECTION_CLASS_NAME(); }\
		};\
		static destructor DESTRUCTOR;\
		return DESTRUCTOR;\
	}

#define ASMITH_BEGIN_REFLECTION_CONSTRUCTORS const asmith::reflection_constructor& get_constructor(size_t i) const override { int currentConstructor = 0;
#define ASMITH_END_REFLECTION_CONSTRUCTORS throw std::runtime_error("asmith::reflection_variable::get_constructor : Index out of bounds"); }

	namespace implementation {
		template<class C, uint32_t MODS, class ...PARAMS>
		class reflection_constructor_implementation : public reflection_constructor {
		private:
			template<class A>
			void call__(void* aObject, const void* aParams) const {
				const A* a = reinterpret_cast<const A*>(reinterpret_cast<const uint8_t*>(aParams) + 0);
				new(aObject) C(*a);
			}

			template<class A, class B>
			void call__(void* aObject, const void* aParams) const {
				const A* a = reinterpret_cast<const A*>(reinterpret_cast<const uint8_t*>(aParams) + 0);
				const B* b = reinterpret_cast<const B*>(reinterpret_cast<const uint8_t*>(a) + sizeof(A));
				new(aObject) C(*a, *b);
			}

			template<class A, class B, class C>
			void call__(void* aObject, const void* aParams) const {
				const A* a = reinterpret_cast<const A*>(reinterpret_cast<const uint8_t*>(aParams) + 0);
				const B* b = reinterpret_cast<const B*>(reinterpret_cast<const uint8_t*>(a) + sizeof(A));
				const C* c = reinterpret_cast<const C*>(reinterpret_cast<const uint8_t*>(b) + sizeof(B));
				new(aObject) C(*a, *b, *c);
			}

			template<class A, class B, class C, class D>
			void call__(void* aObject, const void* aParams) const {
				const A* a = reinterpret_cast<const A*>(reinterpret_cast<const uint8_t*>(aParams) + 0);
				const B* b = reinterpret_cast<const B*>(reinterpret_cast<const uint8_t*>(a) + sizeof(A));
				const C* c = reinterpret_cast<const C*>(reinterpret_cast<const uint8_t*>(b) + sizeof(B));
				const D* d = reinterpret_cast<const D*>(reinterpret_cast<const uint8_t*>(c) + sizeof(C));
				new(aObject) C(*a, *b, *c, *d);
			}

			template<class A, class B, class C, class D, class E>
			void call__(void* aObject, const void* aParams) const {
				const A* a = reinterpret_cast<const A*>(reinterpret_cast<const uint8_t*>(aParams) + 0);
				const B* b = reinterpret_cast<const B*>(reinterpret_cast<const uint8_t*>(a) + sizeof(A));
				const C* c = reinterpret_cast<const C*>(reinterpret_cast<const uint8_t*>(b) + sizeof(B));
				const D* d = reinterpret_cast<const D*>(reinterpret_cast<const uint8_t*>(c) + sizeof(C));
				const E* e = reinterpret_cast<const E*>(reinterpret_cast<const uint8_t*>(d) + sizeof(D));
				new(aObject) C(*a, *b, *c, *d, *e);
			}

			template<class A, class B, class C, class D, class E, class F>
			void call__(void* aObject, const void* aParams) const {
				const A* a = reinterpret_cast<const A*>(reinterpret_cast<const uint8_t*>(aParams) + 0);
				const B* b = reinterpret_cast<const B*>(reinterpret_cast<const uint8_t*>(a) + sizeof(A));
				const C* c = reinterpret_cast<const C*>(reinterpret_cast<const uint8_t*>(b) + sizeof(B));
				const D* d = reinterpret_cast<const D*>(reinterpret_cast<const uint8_t*>(c) + sizeof(C));
				const E* e = reinterpret_cast<const E*>(reinterpret_cast<const uint8_t*>(d) + sizeof(D));
				const F* f = reinterpret_cast<const F*>(reinterpret_cast<const uint8_t*>(e) + sizeof(E));
				new(aObject) C(*a, *b, *c, *d, *e, *f);
			}

			template<class... P>
			typename std::enable_if<sizeof...(P) == 0, void>::type call_(void* aObject, const void* aParams) const {
				new(aObject) C();
			}

			template<class... P>
			typename std::enable_if<sizeof...(P) != 0, void>::type call_(void* aObject, const void* aParams) const {
				call__<P...>(aObject, aParams);
			}
		public:
			// Inherited from reflection_constructor
			size_t get_parameter_count() const override {
				return sizeof...(PARAMS);
			}

			const asmith::reflection_class& get_parameter(size_t i) const override {
				//! \todo Implement
				throw std::runtime_error("asmith::reflection_constructor_implementation::get_parameter : Not yet implemented");
			}

			size_t get_modifiers() const override {
				return MODS;
			}

			void call(void* aObject, const void* aParams) const override {
				call_<PARAMS...>(aObject, aParams);
			}
		};
	}

#define ASMITH_REFLECTION_TRIVIAL_CONSTRUCTOR(aMods) \
	if(i == currentConstructor) {\
		static implementation::reflection_constructor_implementation<ASMITH_REFLECTION_CLASS_NAME, aMods> constructor; \
		return constructor; \
	}\
	++currentConstructor;

#define ASMITH_REFLECTION_CONSTRUCTOR(aMods, aParams) \
	if(i == currentConstructor) {\
		static implementation::reflection_constructor_implementation<ASMITH_REFLECTION_CLASS_NAME, aMods, aParams> constructor; \
		return constructor; \
	}\
	++currentConstructor;

#define ASMITH_REFLECTION_COPY_CONSTRUCTOR(aMods) ASMITH_REFLECTION_CONSTRUCTOR(aMods, ASMITH_REFLECTION_CLASS_NAME)

	class reflection_test {
	private:
		std::string name;
		int dimensions;
		float lower_bound;
		float upper_bound;
	public:
		std::string get_name() { return name; }
		int get_dimensions() { return dimensions; }
		float get_lower_bound() { return lower_bound; }
		float get_upper_bound() { return upper_bound; }

		#define ASMITH_REFLECTION_CLASS_NAME reflection_test
		#define ASMITH_REFLECTION_VARIABLE_COUNT 4
		#define ASMITH_REFLECTION_CONSTRUCTOR_COUNT 0
		#define ASMITH_REFLECTION_FUNCTION_COUNT 0
		#define ASMITH_REFLECTION_PARENT_COUNT 0
		ASMITH_BEGIN_REFLECTION
			const asmith::reflection_function& get_function(size_t) const override { throw 0; }
			const reflection_class& get_parent_class(size_t) const override { throw 0; }

			ASMITH_REFLECTION_DESTRUCTOR(REFLECTION_PUBLIC)

			ASMITH_BEGIN_REFLECTION_CONSTRUCTORS
				ASMITH_REFLECTION_TRIVIAL_CONSTRUCTOR(REFLECTION_PUBLIC)
				ASMITH_REFLECTION_COPY_CONSTRUCTOR(REFLECTION_PUBLIC)
			ASMITH_END_REFLECTION_CONSTRUCTORS

			ASMITH_BEGIN_REFLECTION_VARIABLES
				ASMITH_REFLECTION_VARIABLE(name,		REFLECTION_PRIVATE);
				ASMITH_REFLECTION_VARIABLE(dimensions,	REFLECTION_PRIVATE);
				ASMITH_REFLECTION_VARIABLE(lower_bound,	REFLECTION_PRIVATE);
				ASMITH_REFLECTION_VARIABLE(upper_bound,	REFLECTION_PRIVATE);
			ASMITH_END_REFLECTION_VARIABLES
		ASMITH_END_REFLECTION

		#undef ASMITH_REFLECTION_CLASS_NAME
		#undef ASMITH_REFLECTION_VARIABLE_COUNT
		#undef ASMITH_REFLECTION_CONSTRUCTOR_COUNT
		#undef ASMITH_REFLECTION_FUNCTION_COUNT
		#undef ASMITH_REFLECTION_PARENT_COUNT
	};
}

#endif<|endoftext|>


<commit_before>// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "rclcpp/context.hpp"

#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <vector>
#include <utility>

#include "rcl/init.h"
#include "rclcpp/detail/utilities.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/logging.hpp"
#include "rmw/impl/cpp/demangle.hpp"

/// Mutex to protect initialized contexts.
static std::mutex g_contexts_mutex;
/// Weak list of context to be shutdown by the signal handler.
static std::vector<std::weak_ptr<rclcpp::Context>> g_contexts;

using rclcpp::Context;

Context::Context()
: rcl_context_(nullptr), shutdown_reason_("") {}

Context::~Context()
{
  // acquire the init lock to prevent race conditions with init and shutdown
  // this will not prevent errors, but will maybe make them easier to reproduce
  std::lock_guard<std::recursive_mutex> lock(init_mutex_);
  try {
    this->shutdown("context destructor was called while still not shutdown");
    // at this point it is shutdown and cannot reinit
    // clean_up will finalize the rcl context
    this->clean_up();
  } catch (const std::exception & exc) {
    RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "unhandled exception in ~Context(): %s", exc.what());
  } catch (...) {
    RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "unhandled exception in ~Context()");
  }
}

RCLCPP_LOCAL
void
__delete_context(rcl_context_t * context)
{
  if (context) {
    if (rcl_context_is_valid(context)) {
      RCLCPP_ERROR(
        rclcpp::get_logger("rclcpp"), "rcl context unexpectedly not shutdown during cleanup");
    } else {
      // if context pointer is not null and is shutdown, then it's ready for fini
      rcl_ret_t ret = rcl_context_fini(context);
      if (RCL_RET_OK != ret) {
        RCLCPP_ERROR(
          rclcpp::get_logger("rclcpp"),
          "failed to finalize context: %s", rcl_get_error_string().str);
        rcl_reset_error();
      }
    }
    delete context;
  }
}

void
Context::init(
  int argc,
  char const * const argv[],
  const rclcpp::InitOptions & init_options)
{
  std::lock_guard<std::recursive_mutex> init_lock(init_mutex_);
  if (this->is_valid()) {
    throw rclcpp::ContextAlreadyInitialized();
  }
  this->clean_up();
  rcl_context_.reset(new rcl_context_t, __delete_context);
  *rcl_context_.get() = rcl_get_zero_initialized_context();
  rcl_ret_t ret = rcl_init(argc, argv, init_options.get_rcl_init_options(), rcl_context_.get());
  if (RCL_RET_OK != ret) {
    rcl_context_.reset();
    rclcpp::exceptions::throw_from_rcl_error(ret, "failed to initialize rcl");
  }
  try {
    std::vector<std::string> unparsed_ros_arguments =
      detail::get_unparsed_ros_arguments(argc, argv,
        &(rcl_context_->global_arguments),
        rcl_get_default_allocator());
    if (!unparsed_ros_arguments.empty()) {
      throw exceptions::UnknownROSArgsError(std::move(unparsed_ros_arguments));
    }

    init_options_ = init_options;

    std::lock_guard<std::mutex> lock(g_contexts_mutex);
    g_contexts.push_back(this->shared_from_this());
  } catch (const std::exception & e) {
    ret = rcl_shutdown(rcl_context_.get());
    rcl_context_.reset();
    if (RCL_RET_OK != ret) {
      std::ostringstream oss;
      oss << "While handling: " << e.what() << std::endl <<
        "    another exception was thrown";
      rclcpp::exceptions::throw_from_rcl_error(ret, oss.str());
    }
    throw;
  }
}

bool
Context::is_valid() const
{
  // Take a local copy of the shared pointer to avoid it getting nulled under our feet.
  auto local_rcl_context = rcl_context_;
  if (!local_rcl_context) {
    return false;
  }
  return rcl_context_is_valid(local_rcl_context.get());
}

const rclcpp::InitOptions &
Context::get_init_options() const
{
  return init_options_;
}

rclcpp::InitOptions
Context::get_init_options()
{
  return init_options_;
}

std::string
Context::shutdown_reason()
{
  std::lock_guard<std::recursive_mutex> lock(init_mutex_);
  return shutdown_reason_;
}

bool
Context::shutdown(const std::string & reason)
{
  // prevent races
  std::lock_guard<std::recursive_mutex> init_lock(init_mutex_);
  // ensure validity
  if (!this->is_valid()) {
    // if it is not valid, then it cannot be shutdown
    return false;
  }
  // rcl shutdown
  rcl_ret_t ret = rcl_shutdown(rcl_context_.get());
  if (RCL_RET_OK != ret) {
    rclcpp::exceptions::throw_from_rcl_error(ret);
  }
  // set shutdown reason
  shutdown_reason_ = reason;
  // call each shutdown callback
  for (const auto & callback : on_shutdown_callbacks_) {
    callback();
  }
  // interrupt all blocking sleep_for() and all blocking executors or wait sets
  this->interrupt_all_sleep_for();
  this->interrupt_all_wait_sets();
  // remove self from the global contexts
  std::lock_guard<std::mutex> context_lock(g_contexts_mutex);
  for (auto it = g_contexts.begin(); it != g_contexts.end(); ) {
    auto shared_context = it->lock();
    if (shared_context.get() == this) {
      it = g_contexts.erase(it);
      break;
    } else {
      ++it;
    }
  }
  return true;
}

rclcpp::Context::OnShutdownCallback
Context::on_shutdown(OnShutdownCallback callback)
{
  on_shutdown_callbacks_.push_back(callback);
  return callback;
}

const std::vector<rclcpp::Context::OnShutdownCallback> &
Context::get_on_shutdown_callbacks() const
{
  return on_shutdown_callbacks_;
}

std::vector<rclcpp::Context::OnShutdownCallback> &
Context::get_on_shutdown_callbacks()
{
  return on_shutdown_callbacks_;
}

std::shared_ptr<rcl_context_t>
Context::get_rcl_context()
{
  return rcl_context_;
}

bool
Context::sleep_for(const std::chrono::nanoseconds & nanoseconds)
{
  std::chrono::nanoseconds time_left = nanoseconds;
  {
    std::unique_lock<std::mutex> lock(interrupt_mutex_);
    auto start = std::chrono::steady_clock::now();
    // this will release the lock while waiting
    interrupt_condition_variable_.wait_for(lock, nanoseconds);
    time_left -= std::chrono::steady_clock::now() - start;
  }
  if (time_left > std::chrono::nanoseconds::zero() && this->is_valid()) {
    return sleep_for(time_left);
  }
  // Return true if the timeout elapsed successfully, otherwise false.
  return this->is_valid();
}

void
Context::interrupt_all_sleep_for()
{
  interrupt_condition_variable_.notify_all();
}

rcl_guard_condition_t *
Context::get_interrupt_guard_condition(rcl_wait_set_t * wait_set)
{
  std::lock_guard<std::mutex> lock(interrupt_guard_cond_handles_mutex_);
  auto kv = interrupt_guard_cond_handles_.find(wait_set);
  if (kv != interrupt_guard_cond_handles_.end()) {
    return &kv->second;
  } else {
    rcl_guard_condition_t handle = rcl_get_zero_initialized_guard_condition();
    rcl_guard_condition_options_t options = rcl_guard_condition_get_default_options();
    auto ret = rcl_guard_condition_init(&handle, this->get_rcl_context().get(), options);
    if (RCL_RET_OK != ret) {
      rclcpp::exceptions::throw_from_rcl_error(ret, "Couldn't initialize guard condition");
    }
    interrupt_guard_cond_handles_.emplace(wait_set, handle);
    return &interrupt_guard_cond_handles_[wait_set];
  }
}

void
Context::release_interrupt_guard_condition(rcl_wait_set_t * wait_set)
{
  std::lock_guard<std::mutex> lock(interrupt_guard_cond_handles_mutex_);
  auto kv = interrupt_guard_cond_handles_.find(wait_set);
  if (kv != interrupt_guard_cond_handles_.end()) {
    rcl_ret_t ret = rcl_guard_condition_fini(&kv->second);
    if (RCL_RET_OK != ret) {
      rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to destroy sigint guard condition");
    }
    interrupt_guard_cond_handles_.erase(kv);
  } else {
    throw std::runtime_error("Tried to release sigint guard condition for nonexistent wait set");
  }
}

void
Context::release_interrupt_guard_condition(
  rcl_wait_set_t * wait_set,
  const std::nothrow_t &) noexcept
{
  try {
    this->release_interrupt_guard_condition(wait_set);
  } catch (const std::exception & exc) {
    RCLCPP_ERROR(
      rclcpp::get_logger("rclcpp"),
      "caught %s exception when releasing interrupt guard condition: %s",
      rmw::impl::cpp::demangle(exc).c_str(), exc.what());
  } catch (...) {
    RCLCPP_ERROR(
      rclcpp::get_logger("rclcpp"),
      "caught unknown exception when releasing interrupt guard condition");
  }
}

void
Context::interrupt_all_wait_sets()
{
  std::lock_guard<std::mutex> lock(interrupt_guard_cond_handles_mutex_);
  for (auto & kv : interrupt_guard_cond_handles_) {
    rcl_ret_t status = rcl_trigger_guard_condition(&(kv.second));
    if (status != RCL_RET_OK) {
      RCUTILS_LOG_ERROR_NAMED(
        "rclcpp",
        "failed to trigger guard condition in Context::interrupt_all_wait_sets(): %s",
        rcl_get_error_string().str);
    }
  }
}

void
Context::clean_up()
{
  shutdown_reason_ = "";
  rcl_context_.reset();
}

std::vector<Context::SharedPtr>
rclcpp::get_contexts()
{
  std::lock_guard<std::mutex> lock(g_contexts_mutex);
  std::vector<Context::SharedPtr> shared_contexts;
  for (auto it = g_contexts.begin(); it != g_contexts.end(); /* noop */) {
    auto context_ptr = it->lock();
    if (!context_ptr) {
      // remove invalid weak context pointers
      it = g_contexts.erase(it);
    } else {
      ++it;
      shared_contexts.push_back(context_ptr);
    }
  }
  return shared_contexts;
}
<commit_msg>Clear sub contexts when starting another init-shutdown cycle (#947)<commit_after>// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "rclcpp/context.hpp"

#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <vector>
#include <utility>

#include "rcl/init.h"
#include "rclcpp/detail/utilities.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/logging.hpp"
#include "rmw/impl/cpp/demangle.hpp"

/// Mutex to protect initialized contexts.
static std::mutex g_contexts_mutex;
/// Weak list of context to be shutdown by the signal handler.
static std::vector<std::weak_ptr<rclcpp::Context>> g_contexts;

using rclcpp::Context;

Context::Context()
: rcl_context_(nullptr), shutdown_reason_("") {}

Context::~Context()
{
  // acquire the init lock to prevent race conditions with init and shutdown
  // this will not prevent errors, but will maybe make them easier to reproduce
  std::lock_guard<std::recursive_mutex> lock(init_mutex_);
  try {
    this->shutdown("context destructor was called while still not shutdown");
    // at this point it is shutdown and cannot reinit
    // clean_up will finalize the rcl context
    this->clean_up();
  } catch (const std::exception & exc) {
    RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "unhandled exception in ~Context(): %s", exc.what());
  } catch (...) {
    RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "unhandled exception in ~Context()");
  }
}

RCLCPP_LOCAL
void
__delete_context(rcl_context_t * context)
{
  if (context) {
    if (rcl_context_is_valid(context)) {
      RCLCPP_ERROR(
        rclcpp::get_logger("rclcpp"), "rcl context unexpectedly not shutdown during cleanup");
    } else {
      // if context pointer is not null and is shutdown, then it's ready for fini
      rcl_ret_t ret = rcl_context_fini(context);
      if (RCL_RET_OK != ret) {
        RCLCPP_ERROR(
          rclcpp::get_logger("rclcpp"),
          "failed to finalize context: %s", rcl_get_error_string().str);
        rcl_reset_error();
      }
    }
    delete context;
  }
}

void
Context::init(
  int argc,
  char const * const argv[],
  const rclcpp::InitOptions & init_options)
{
  std::lock_guard<std::recursive_mutex> init_lock(init_mutex_);
  if (this->is_valid()) {
    throw rclcpp::ContextAlreadyInitialized();
  }
  this->clean_up();
  rcl_context_.reset(new rcl_context_t, __delete_context);
  *rcl_context_.get() = rcl_get_zero_initialized_context();
  rcl_ret_t ret = rcl_init(argc, argv, init_options.get_rcl_init_options(), rcl_context_.get());
  if (RCL_RET_OK != ret) {
    rcl_context_.reset();
    rclcpp::exceptions::throw_from_rcl_error(ret, "failed to initialize rcl");
  }
  try {
    std::vector<std::string> unparsed_ros_arguments =
      detail::get_unparsed_ros_arguments(argc, argv,
        &(rcl_context_->global_arguments),
        rcl_get_default_allocator());
    if (!unparsed_ros_arguments.empty()) {
      throw exceptions::UnknownROSArgsError(std::move(unparsed_ros_arguments));
    }

    init_options_ = init_options;

    std::lock_guard<std::mutex> lock(g_contexts_mutex);
    g_contexts.push_back(this->shared_from_this());
  } catch (const std::exception & e) {
    ret = rcl_shutdown(rcl_context_.get());
    rcl_context_.reset();
    if (RCL_RET_OK != ret) {
      std::ostringstream oss;
      oss << "While handling: " << e.what() << std::endl <<
        "    another exception was thrown";
      rclcpp::exceptions::throw_from_rcl_error(ret, oss.str());
    }
    throw;
  }
}

bool
Context::is_valid() const
{
  // Take a local copy of the shared pointer to avoid it getting nulled under our feet.
  auto local_rcl_context = rcl_context_;
  if (!local_rcl_context) {
    return false;
  }
  return rcl_context_is_valid(local_rcl_context.get());
}

const rclcpp::InitOptions &
Context::get_init_options() const
{
  return init_options_;
}

rclcpp::InitOptions
Context::get_init_options()
{
  return init_options_;
}

std::string
Context::shutdown_reason()
{
  std::lock_guard<std::recursive_mutex> lock(init_mutex_);
  return shutdown_reason_;
}

bool
Context::shutdown(const std::string & reason)
{
  // prevent races
  std::lock_guard<std::recursive_mutex> init_lock(init_mutex_);
  // ensure validity
  if (!this->is_valid()) {
    // if it is not valid, then it cannot be shutdown
    return false;
  }
  // rcl shutdown
  rcl_ret_t ret = rcl_shutdown(rcl_context_.get());
  if (RCL_RET_OK != ret) {
    rclcpp::exceptions::throw_from_rcl_error(ret);
  }
  // set shutdown reason
  shutdown_reason_ = reason;
  // call each shutdown callback
  for (const auto & callback : on_shutdown_callbacks_) {
    callback();
  }
  // interrupt all blocking sleep_for() and all blocking executors or wait sets
  this->interrupt_all_sleep_for();
  this->interrupt_all_wait_sets();
  // remove self from the global contexts
  std::lock_guard<std::mutex> context_lock(g_contexts_mutex);
  for (auto it = g_contexts.begin(); it != g_contexts.end(); ) {
    auto shared_context = it->lock();
    if (shared_context.get() == this) {
      it = g_contexts.erase(it);
      break;
    } else {
      ++it;
    }
  }
  return true;
}

rclcpp::Context::OnShutdownCallback
Context::on_shutdown(OnShutdownCallback callback)
{
  on_shutdown_callbacks_.push_back(callback);
  return callback;
}

const std::vector<rclcpp::Context::OnShutdownCallback> &
Context::get_on_shutdown_callbacks() const
{
  return on_shutdown_callbacks_;
}

std::vector<rclcpp::Context::OnShutdownCallback> &
Context::get_on_shutdown_callbacks()
{
  return on_shutdown_callbacks_;
}

std::shared_ptr<rcl_context_t>
Context::get_rcl_context()
{
  return rcl_context_;
}

bool
Context::sleep_for(const std::chrono::nanoseconds & nanoseconds)
{
  std::chrono::nanoseconds time_left = nanoseconds;
  {
    std::unique_lock<std::mutex> lock(interrupt_mutex_);
    auto start = std::chrono::steady_clock::now();
    // this will release the lock while waiting
    interrupt_condition_variable_.wait_for(lock, nanoseconds);
    time_left -= std::chrono::steady_clock::now() - start;
  }
  if (time_left > std::chrono::nanoseconds::zero() && this->is_valid()) {
    return sleep_for(time_left);
  }
  // Return true if the timeout elapsed successfully, otherwise false.
  return this->is_valid();
}

void
Context::interrupt_all_sleep_for()
{
  interrupt_condition_variable_.notify_all();
}

rcl_guard_condition_t *
Context::get_interrupt_guard_condition(rcl_wait_set_t * wait_set)
{
  std::lock_guard<std::mutex> lock(interrupt_guard_cond_handles_mutex_);
  auto kv = interrupt_guard_cond_handles_.find(wait_set);
  if (kv != interrupt_guard_cond_handles_.end()) {
    return &kv->second;
  } else {
    rcl_guard_condition_t handle = rcl_get_zero_initialized_guard_condition();
    rcl_guard_condition_options_t options = rcl_guard_condition_get_default_options();
    auto ret = rcl_guard_condition_init(&handle, this->get_rcl_context().get(), options);
    if (RCL_RET_OK != ret) {
      rclcpp::exceptions::throw_from_rcl_error(ret, "Couldn't initialize guard condition");
    }
    interrupt_guard_cond_handles_.emplace(wait_set, handle);
    return &interrupt_guard_cond_handles_[wait_set];
  }
}

void
Context::release_interrupt_guard_condition(rcl_wait_set_t * wait_set)
{
  std::lock_guard<std::mutex> lock(interrupt_guard_cond_handles_mutex_);
  auto kv = interrupt_guard_cond_handles_.find(wait_set);
  if (kv != interrupt_guard_cond_handles_.end()) {
    rcl_ret_t ret = rcl_guard_condition_fini(&kv->second);
    if (RCL_RET_OK != ret) {
      rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to destroy sigint guard condition");
    }
    interrupt_guard_cond_handles_.erase(kv);
  } else {
    throw std::runtime_error("Tried to release sigint guard condition for nonexistent wait set");
  }
}

void
Context::release_interrupt_guard_condition(
  rcl_wait_set_t * wait_set,
  const std::nothrow_t &) noexcept
{
  try {
    this->release_interrupt_guard_condition(wait_set);
  } catch (const std::exception & exc) {
    RCLCPP_ERROR(
      rclcpp::get_logger("rclcpp"),
      "caught %s exception when releasing interrupt guard condition: %s",
      rmw::impl::cpp::demangle(exc).c_str(), exc.what());
  } catch (...) {
    RCLCPP_ERROR(
      rclcpp::get_logger("rclcpp"),
      "caught unknown exception when releasing interrupt guard condition");
  }
}

void
Context::interrupt_all_wait_sets()
{
  std::lock_guard<std::mutex> lock(interrupt_guard_cond_handles_mutex_);
  for (auto & kv : interrupt_guard_cond_handles_) {
    rcl_ret_t status = rcl_trigger_guard_condition(&(kv.second));
    if (status != RCL_RET_OK) {
      RCUTILS_LOG_ERROR_NAMED(
        "rclcpp",
        "failed to trigger guard condition in Context::interrupt_all_wait_sets(): %s",
        rcl_get_error_string().str);
    }
  }
}

void
Context::clean_up()
{
  shutdown_reason_ = "";
  rcl_context_.reset();
  sub_contexts_.clear();
}

std::vector<Context::SharedPtr>
rclcpp::get_contexts()
{
  std::lock_guard<std::mutex> lock(g_contexts_mutex);
  std::vector<Context::SharedPtr> shared_contexts;
  for (auto it = g_contexts.begin(); it != g_contexts.end(); /* noop */) {
    auto context_ptr = it->lock();
    if (!context_ptr) {
      // remove invalid weak context pointers
      it = g_contexts.erase(it);
    } else {
      ++it;
      shared_contexts.push_back(context_ptr);
    }
  }
  return shared_contexts;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2006, Arvid Norberg
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 author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

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

*/

#ifndef NODE_HPP
#define NODE_HPP

#include <algorithm>
#include <map>
#include <set>

#include <libtorrent/config.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/node_id.hpp>
#include <libtorrent/kademlia/msg.hpp>
#include <libtorrent/kademlia/find_data.hpp>

#include <libtorrent/io.hpp>
#include <libtorrent/session_settings.hpp>
#include <libtorrent/assert.hpp>
#include <libtorrent/thread.hpp>
#include <libtorrent/bloom_filter.hpp>

#include <boost/cstdint.hpp>
#include <boost/ref.hpp>

#include "libtorrent/socket.hpp"

namespace libtorrent {
	class alert_manager;
	struct alert_dispatcher;
}

namespace libtorrent { namespace dht
{

#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DECLARE_LOG(node);
#endif

struct traversal_algorithm;

struct key_desc_t
{
	char const* name;
	int type;
	int size;
	int flags;

	enum {
		// this argument is optional, parsing will not
		// fail if it's not present
		optional = 1,
		// for dictionaries, the following entries refer
		// to child nodes to this node, up until and including
		// the next item that has the last_child flag set.
		// these flags are nestable
		parse_children = 2,
		// this is the last item in a child dictionary
		last_child = 4,
		// the size argument refers to that the size
		// has to be divisible by the number, instead
		// of having that exact size
		size_divisible = 8
	};
};

bool TORRENT_EXTRA_EXPORT verify_message(lazy_entry const* msg, key_desc_t const desc[]
	, lazy_entry const* ret[], int size , char* error, int error_size);

// this is the entry for every peer
// the timestamp is there to make it possible
// to remove stale peers
struct peer_entry
{
	tcp::endpoint addr;
	ptime added;
	bool seed;
};

// this is a group. It contains a set of group members
struct torrent_entry
{
	std::string name;
	std::set<peer_entry> peers;
};

struct dht_immutable_item
{
	dht_immutable_item() : value(0), num_announcers(0) {}
	// malloced space for the actual value
	char* value;
	// this counts the number of IPs we have seen
	// announcing this item, this is used to determine
	// popularity if we reach the limit of items to store
	bloom_filter<128> ips;
	// the last time we heard about this
	ptime last_seen;
	// number of IPs in the bloom filter
	int num_announcers;
	// size of malloced space pointed to by value
	int size;
};

struct dht_mutable_item : dht_immutable_item
{
	char sig[256];
	int seq;
};

struct rsa_key { char bytes[268]; };

inline bool operator<(rsa_key const& lhs, rsa_key const& rhs)
{
	return memcmp(lhs.bytes, rhs.bytes, sizeof(lhs.bytes)) < 0;
}

inline bool operator<(peer_entry const& lhs, peer_entry const& rhs)
{
	return lhs.addr.address() == rhs.addr.address()
		? lhs.addr.port() < rhs.addr.port()
		: lhs.addr.address() < rhs.addr.address();
}

struct null_type {};

class announce_observer : public observer
{
public:
	announce_observer(boost::intrusive_ptr<traversal_algorithm> const& algo
		, udp::endpoint const& ep, node_id const& id)
		: observer(algo, ep, id)
	{}

	void reply(msg const&) { flags |= flag_done; }
};

struct count_peers
{
	int& count;
	count_peers(int& c): count(c) {}
	void operator()(std::pair<libtorrent::dht::node_id
		, libtorrent::dht::torrent_entry> const& t)
	{
		count += t.second.peers.size();
	}
};

struct udp_socket_interface
{
	virtual bool send_packet(entry& e, udp::endpoint const& addr, int flags) = 0;
};

class TORRENT_EXTRA_EXPORT node_impl : boost::noncopyable
{
typedef std::map<node_id, torrent_entry> table_t;
typedef std::map<node_id, dht_immutable_item> dht_immutable_table_t;
typedef std::map<rsa_key, dht_mutable_item> dht_mutable_table_t;

public:
	node_impl(alert_dispatcher* alert_disp, udp_socket_interface* sock
		, dht_settings const& settings, node_id nid, address const& external_address
		, dht_observer* observer);

	virtual ~node_impl() {}

	void tick();
	void refresh(node_id const& id, find_data::nodes_callback const& f);
	void bootstrap(std::vector<udp::endpoint> const& nodes
		, find_data::nodes_callback const& f);
	void add_router_node(udp::endpoint router);

	void unreachable(udp::endpoint const& ep);
	void incoming(msg const& m);

	int num_torrents() const { return m_map.size(); }
	int num_peers() const
	{
		int ret = 0;
		std::for_each(m_map.begin(), m_map.end(), count_peers(ret));
		return ret;
	}

	int bucket_size(int bucket);

	node_id const& nid() const { return m_id; }

	boost::tuple<int, int> size() const{ return m_table.size(); }
	size_type num_global_nodes() const
	{ return m_table.num_global_nodes(); }

	int data_size() const { return int(m_map.size()); }

#ifdef TORRENT_DHT_VERBOSE_LOGGING
	void print_state(std::ostream& os) const
	{ m_table.print_state(os); }
#endif

	void announce(sha1_hash const& info_hash, int listen_port, bool seed
		, boost::function<void(std::vector<tcp::endpoint> const&)> f);

	bool verify_token(std::string const& token, char const* info_hash
		, udp::endpoint const& addr);

	std::string generate_token(udp::endpoint const& addr, char const* info_hash);

	// the returned time is the delay until connection_timeout()
	// should be called again the next time
	time_duration connection_timeout();

	// generates a new secret number used to generate write tokens
	void new_write_key();

	// pings the given node, and adds it to
	// the routing table if it respons and if the
	// bucket is not full.
	void add_node(udp::endpoint node);

	void replacement_cache(bucket_t& nodes) const
	{ m_table.replacement_cache(nodes); }

	int branch_factor() const { return m_settings.search_branching; }

	void add_traversal_algorithm(traversal_algorithm* a)
	{
		mutex_t::scoped_lock l(m_mutex);
		m_running_requests.insert(a);
	}

	void remove_traversal_algorithm(traversal_algorithm* a)
	{
		mutex_t::scoped_lock l(m_mutex);
		m_running_requests.erase(a);
	}

	void status(libtorrent::session_status& s);

	dht_settings const& settings() const { return m_settings; }

protected:

	void lookup_peers(sha1_hash const& info_hash, int prefix, entry& reply
		, bool noseed, bool scrape) const;
	bool lookup_torrents(sha1_hash const& target, entry& reply
		, char* tags) const;

	dht_settings const& m_settings;

private:
	typedef libtorrent::mutex mutex_t;
	mutex_t m_mutex;

	// this list must be destructed after the rpc manager
	// since it might have references to it
	std::set<traversal_algorithm*> m_running_requests;

	void incoming_request(msg const& h, entry& e);

	node_id m_id;

public:
	routing_table m_table;
	rpc_manager m_rpc;

private:
	table_t m_map;
	dht_immutable_table_t m_immutable_table;
	dht_mutable_table_t m_mutable_table;

	ptime m_last_tracker_tick;

	// secret random numbers used to create write tokens
	int m_secret[2];

	alert_dispatcher* m_post_alert;
	udp_socket_interface* m_sock;
};

} } // namespace libtorrent::dht

#endif // NODE_HPP

<commit_msg>one more uninitialized member<commit_after>/*

Copyright (c) 2006, Arvid Norberg
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 author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

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

*/

#ifndef NODE_HPP
#define NODE_HPP

#include <algorithm>
#include <map>
#include <set>

#include <libtorrent/config.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/kademlia/node_id.hpp>
#include <libtorrent/kademlia/msg.hpp>
#include <libtorrent/kademlia/find_data.hpp>

#include <libtorrent/io.hpp>
#include <libtorrent/session_settings.hpp>
#include <libtorrent/assert.hpp>
#include <libtorrent/thread.hpp>
#include <libtorrent/bloom_filter.hpp>

#include <boost/cstdint.hpp>
#include <boost/ref.hpp>

#include "libtorrent/socket.hpp"

namespace libtorrent {
	class alert_manager;
	struct alert_dispatcher;
}

namespace libtorrent { namespace dht
{

#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DECLARE_LOG(node);
#endif

struct traversal_algorithm;

struct key_desc_t
{
	char const* name;
	int type;
	int size;
	int flags;

	enum {
		// this argument is optional, parsing will not
		// fail if it's not present
		optional = 1,
		// for dictionaries, the following entries refer
		// to child nodes to this node, up until and including
		// the next item that has the last_child flag set.
		// these flags are nestable
		parse_children = 2,
		// this is the last item in a child dictionary
		last_child = 4,
		// the size argument refers to that the size
		// has to be divisible by the number, instead
		// of having that exact size
		size_divisible = 8
	};
};

bool TORRENT_EXTRA_EXPORT verify_message(lazy_entry const* msg, key_desc_t const desc[]
	, lazy_entry const* ret[], int size , char* error, int error_size);

// this is the entry for every peer
// the timestamp is there to make it possible
// to remove stale peers
struct peer_entry
{
	tcp::endpoint addr;
	ptime added;
	bool seed;
};

// this is a group. It contains a set of group members
struct torrent_entry
{
	std::string name;
	std::set<peer_entry> peers;
};

struct dht_immutable_item
{
	dht_immutable_item() : value(0), num_announcers(0), size(0) {}
	// malloced space for the actual value
	char* value;
	// this counts the number of IPs we have seen
	// announcing this item, this is used to determine
	// popularity if we reach the limit of items to store
	bloom_filter<128> ips;
	// the last time we heard about this
	ptime last_seen;
	// number of IPs in the bloom filter
	int num_announcers;
	// size of malloced space pointed to by value
	int size;
};

struct dht_mutable_item : dht_immutable_item
{
	char sig[256];
	int seq;
};

struct rsa_key { char bytes[268]; };

inline bool operator<(rsa_key const& lhs, rsa_key const& rhs)
{
	return memcmp(lhs.bytes, rhs.bytes, sizeof(lhs.bytes)) < 0;
}

inline bool operator<(peer_entry const& lhs, peer_entry const& rhs)
{
	return lhs.addr.address() == rhs.addr.address()
		? lhs.addr.port() < rhs.addr.port()
		: lhs.addr.address() < rhs.addr.address();
}

struct null_type {};

class announce_observer : public observer
{
public:
	announce_observer(boost::intrusive_ptr<traversal_algorithm> const& algo
		, udp::endpoint const& ep, node_id const& id)
		: observer(algo, ep, id)
	{}

	void reply(msg const&) { flags |= flag_done; }
};

struct count_peers
{
	int& count;
	count_peers(int& c): count(c) {}
	void operator()(std::pair<libtorrent::dht::node_id
		, libtorrent::dht::torrent_entry> const& t)
	{
		count += t.second.peers.size();
	}
};

struct udp_socket_interface
{
	virtual bool send_packet(entry& e, udp::endpoint const& addr, int flags) = 0;
};

class TORRENT_EXTRA_EXPORT node_impl : boost::noncopyable
{
typedef std::map<node_id, torrent_entry> table_t;
typedef std::map<node_id, dht_immutable_item> dht_immutable_table_t;
typedef std::map<rsa_key, dht_mutable_item> dht_mutable_table_t;

public:
	node_impl(alert_dispatcher* alert_disp, udp_socket_interface* sock
		, dht_settings const& settings, node_id nid, address const& external_address
		, dht_observer* observer);

	virtual ~node_impl() {}

	void tick();
	void refresh(node_id const& id, find_data::nodes_callback const& f);
	void bootstrap(std::vector<udp::endpoint> const& nodes
		, find_data::nodes_callback const& f);
	void add_router_node(udp::endpoint router);

	void unreachable(udp::endpoint const& ep);
	void incoming(msg const& m);

	int num_torrents() const { return m_map.size(); }
	int num_peers() const
	{
		int ret = 0;
		std::for_each(m_map.begin(), m_map.end(), count_peers(ret));
		return ret;
	}

	int bucket_size(int bucket);

	node_id const& nid() const { return m_id; }

	boost::tuple<int, int> size() const{ return m_table.size(); }
	size_type num_global_nodes() const
	{ return m_table.num_global_nodes(); }

	int data_size() const { return int(m_map.size()); }

#ifdef TORRENT_DHT_VERBOSE_LOGGING
	void print_state(std::ostream& os) const
	{ m_table.print_state(os); }
#endif

	void announce(sha1_hash const& info_hash, int listen_port, bool seed
		, boost::function<void(std::vector<tcp::endpoint> const&)> f);

	bool verify_token(std::string const& token, char const* info_hash
		, udp::endpoint const& addr);

	std::string generate_token(udp::endpoint const& addr, char const* info_hash);

	// the returned time is the delay until connection_timeout()
	// should be called again the next time
	time_duration connection_timeout();

	// generates a new secret number used to generate write tokens
	void new_write_key();

	// pings the given node, and adds it to
	// the routing table if it respons and if the
	// bucket is not full.
	void add_node(udp::endpoint node);

	void replacement_cache(bucket_t& nodes) const
	{ m_table.replacement_cache(nodes); }

	int branch_factor() const { return m_settings.search_branching; }

	void add_traversal_algorithm(traversal_algorithm* a)
	{
		mutex_t::scoped_lock l(m_mutex);
		m_running_requests.insert(a);
	}

	void remove_traversal_algorithm(traversal_algorithm* a)
	{
		mutex_t::scoped_lock l(m_mutex);
		m_running_requests.erase(a);
	}

	void status(libtorrent::session_status& s);

	dht_settings const& settings() const { return m_settings; }

protected:

	void lookup_peers(sha1_hash const& info_hash, int prefix, entry& reply
		, bool noseed, bool scrape) const;
	bool lookup_torrents(sha1_hash const& target, entry& reply
		, char* tags) const;

	dht_settings const& m_settings;

private:
	typedef libtorrent::mutex mutex_t;
	mutex_t m_mutex;

	// this list must be destructed after the rpc manager
	// since it might have references to it
	std::set<traversal_algorithm*> m_running_requests;

	void incoming_request(msg const& h, entry& e);

	node_id m_id;

public:
	routing_table m_table;
	rpc_manager m_rpc;

private:
	table_t m_map;
	dht_immutable_table_t m_immutable_table;
	dht_mutable_table_t m_mutable_table;

	ptime m_last_tracker_tick;

	// secret random numbers used to create write tokens
	int m_secret[2];

	alert_dispatcher* m_post_alert;
	udp_socket_interface* m_sock;
};

} } // namespace libtorrent::dht

#endif // NODE_HPP

<|endoftext|>