<commit_before>// =-=-=-=-=-=-=-
#include "apiHeaderAll.hpp"
#include "msParam.hpp"
#include "reGlobalsExtern.hpp"
#include "irods_ms_plugin.hpp"

// =-=-=-=-=-=-=-
// STL Includes
#include <string>
#include <iostream>

// =-=-=-=-=-=-=-
// cURL Includes
#include <curl/curl.h>
#include <curl/easy.h>

typedef struct writeDataInp_t {
    char objPath[MAX_NAME_LEN];
    int l1descInx;
    rsComm_t *rsComm;
} writeDataInp_t;

typedef struct readData_t {
  char sourcePath[MAX_NAME_LEN];
  FILE *fd;
} readData_t;

class irodsCurl {
private:
    // iRODS serv, char *destPath er handle
    rsComm_t *rsComm;

    // cURL handle
    CURL *curl;

public:
    irodsCurl( rsComm_t *comm ) {
        rsComm = comm;

        curl = curl_easy_init();
        if ( !curl ) {
            rodsLog( LOG_ERROR, "irodsCurl: %s", curl_easy_strerror( CURLE_FAILED_INIT ) );
        }
    }

    ~irodsCurl() {
        if ( curl ) {
            curl_easy_cleanup( curl );
        }
    }

    int get( char *url, char *sourcePath, char *destPath, char *ext) {

	CURL *curl;
	CURLcode res = CURLE_OK;
        writeDataInp_t writeDataInp;	// the "file descriptor" for our destination object
        openedDataObjInp_t openedDataObjInp;	// for closing iRODS object after writing

        readData_t readData;

        int status;

	FILE *fd;
	fd = fopen(sourcePath, "rb"); /* open file to upload */
	if(!fd) { return 1; /* can't continue */ }

	struct curl_httppost *formpost=NULL;
	struct curl_httppost *lastptr=NULL;

	curl_global_init(CURL_GLOBAL_ALL);

        /* Fill in the file upload field */
        curl_formadd(&formpost,
                &lastptr,
                CURLFORM_COPYNAME, "output_format",
                CURLFORM_COPYCONTENTS, ext,
                CURLFORM_END);

        /* Fill in the filename field */
        curl_formadd(&formpost,
                &lastptr,
                CURLFORM_COPYNAME, "file",
                CURLFORM_FILENAME, "y18.gif", //This needs to be the filename of the upload
                CURLFORM_STREAM, &readData,
                CURLFORM_CONTENTSLENGTH, 100,  //This needs to be the size of the upload
                CURLFORM_CONTENTTYPE, "application/octet-stream",
                CURLFORM_END);

        // Zero fill openedDataObjInp
        memset( &openedDataObjInp, 0, sizeof( openedDataObjInp_t ) );

        // Set up writeDataInp
        snprintf( writeDataInp.objPath, MAX_NAME_LEN, "%s", destPath );
        writeDataInp.l1descInx = 0;	// the object is yet to be created
        writeDataInp.rsComm = rsComm;

        // Set up writeDataInp
        snprintf(readData.sourcePath, MAX_NAME_LEN, "%s", sourcePath);
        readData.fd = 0;	// the object is yet to be created

        // Set up easy handler
 	curl = curl_easy_init();

	/* what URL that receives this POST */
        curl_easy_setopt(curl, CURLOPT_URL, url);

        curl_easy_setopt(curl, CURLOPT_READFUNCTION, &irodsCurl::my_read_obj);
        curl_easy_setopt(curl, CURLOPT_READDATA, &readData);
        curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);

        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &irodsCurl::my_write_obj);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &writeDataInp );

        // CURL call
        res = curl_easy_perform( curl );

        // Some error logging
        if ( res != CURLE_OK ) {
            rodsLog( LOG_ERROR, "irodsCurl::get: cURL error: %s", curl_easy_strerror( res ) );
        }

        // close iRODS object
        if ( writeDataInp.l1descInx ) {
            openedDataObjInp.l1descInx = writeDataInp.l1descInx;
            status = rsDataObjClose( rsComm, &openedDataObjInp );
            if ( status < 0 ) {
                rodsLog( LOG_ERROR, "irodsCurl::get: rsDataObjClose failed for %s, status = %d",
                         writeDataInp.objPath, status );
            }
        }

        /* then cleanup the formpost chain */
        curl_formfree(formpost);

        return res;
    }

    static size_t my_read_obj(void *buffer, size_t size, size_t nmemb, void* userp) {
        struct readData_t *readData = (struct readData_t *) userp;

        if (!readData) {
            return -11;
        }

        if (!readData->fd) {
            readData->fd = fopen(readData->sourcePath, "r");
        }

        return fread(buffer, size, nmemb, readData->fd);
    }

    // Custom callback function for the curl handler, to write to an iRODS object
    static size_t my_write_obj( void *buffer, size_t size, size_t nmemb, writeDataInp_t *writeDataInp ) {
        dataObjInp_t dataObjInp;	// input struct for rsDataObjCreate
        openedDataObjInp_t openedDataObjInp;	// input struct for rsDataObjWrite
        bytesBuf_t bytesBuf;	// input buffer for rsDataObjWrite
        size_t written;	// return value

        int l1descInx;

        // Make sure we have something to write to
        if ( !writeDataInp ) {
            rodsLog( LOG_ERROR, "my_write_obj: writeDataInp is NULL, status = %d", SYS_INTERNAL_NULL_INPUT_ERR );
            return SYS_INTERNAL_NULL_INPUT_ERR;
        }

        // Zero fill input structs
        memset( &dataObjInp, 0, sizeof( dataObjInp_t ) );
        memset( &openedDataObjInp, 0, sizeof( openedDataObjInp_t ) );

        // If this is the first call we need to create our data object before writing to it
        if ( !writeDataInp->l1descInx ) {
            strncpy( dataObjInp.objPath, writeDataInp->objPath, MAX_NAME_LEN );

            // Overwrite existing file (for this tutorial only, in case the example has been run before)
            addKeyVal( &dataObjInp.condInput, FORCE_FLAG_KW, "" );

            writeDataInp->l1descInx = rsDataObjCreate( writeDataInp->rsComm, &dataObjInp );

            // No create?
            if ( writeDataInp->l1descInx <= 2 ) {
                rodsLog( LOG_ERROR, "my_write_obj: rsDataObjCreate failed for %s, status = %d", dataObjInp.objPath, writeDataInp->l1descInx );
                return ( writeDataInp->l1descInx );
            }
        }

        // Set up input buffer for rsDataObjWrite
        bytesBuf.len = ( int )( size * nmemb );
        bytesBuf.buf = buffer;

        // Set up input struct for rsDataObjWrite
        openedDataObjInp.l1descInx = writeDataInp->l1descInx;;
        openedDataObjInp.len = bytesBuf.len;

        // Write to data object
        written = rsDataObjWrite( writeDataInp->rsComm, &openedDataObjInp, &bytesBuf );

        return ( written );
    }

}; // class irodsCurl

extern "C" {

// =-=-=-=-=-=-=-
// 1. Write a standard issue microservice
    int irods_curl_get( msParam_t* url, msParam_t* source_obj, msParam_t* ext_obj,
                                        msParam_t* dest_obj, ruleExecInfo_t* rei ) {
        dataObjInp_t destObjInp, *myDestObjInp;	/* for parsing input object */

        // Sanity checks
        if ( !rei || !rei->rsComm ) {
            rodsLog( LOG_ERROR, "irods_curl_get: Input rei or rsComm is NULL." );
            return ( SYS_INTERNAL_NULL_INPUT_ERR );
        }

	// get destination path from sourcePath and exten.
	char *sourceStr = parseMspForStr(source_obj);
	char *extStr = parseMspForStr(ext_obj);

	char *source = "/tempZone/home/public/new.png";

	char tmpSource[strlen(source) + 10];

	strcpy(tmpSource, source);

    	char *lastdot = strrchr (tmpSource, '.');
	char *lastsep = ('/' == 0) ? NULL : strrchr (tmpSource, '/');

	if (lastdot != NULL)
	{
        // and it's before the extenstion separator.

        	if (lastsep != NULL)
		{
            		if (lastsep < lastdot)
			{
                	// then remove it.

                	*lastdot = '\0';
            		}
        	}
		else
		{
            	// Has extension separator with no path separator.

            	*lastdot = '\0';
        	}
    	}
        char destStr[strlen(source)+10];

	snprintf(destStr, strlen(source) + 10, "%s%s%s", tmpSource, ".", extStr);

	fillStrInMsParam(dest_obj, destStr);

        // Get path of destination object
        rei->status = parseMspForDataObjInp( dest_obj, &destObjInp, &myDestObjInp, 0 );
        if ( rei->status < 0 ) {
            rodsLog( LOG_ERROR, "irods_curl_get: Input object error. status = %d", rei->status );
            return ( rei->status );
        }

        // Create irodsCurl instance
        irodsCurl myCurl( rei->rsComm );

        // Call irodsCurl::get

        rei->status = myCurl.get( parseMspForStr( url ), sourceStr,  destObjInp.objPath, extStr);

        // Done
        return rei->status;

    }

// =-=-=-=-=-=-=-
// 2. Create the plugin factory function which will return a microservice
// table entry
    irods::ms_table_entry* plugin_factory() {
        // =-=-=-=-=-=-=-
        // 3. allocate a microservice plugin which takes the number of function
        // params as a parameter to the constructor
        irods::ms_table_entry* msvc = new irods::ms_table_entry( 4 );

        // =-=-=-=-=-=-=-
        // 4. add the microservice function as an operation to the plugin
        // the first param is the name / key of the operation, the second
        // is the name of the function which will be the microservice
        msvc->add_operation( "irods_curl_get", "irods_curl_get" );

        // =-=-=-=-=-=-=-
        // 5. return the newly created microservice plugin
        return msvc;
    }

}	// extern "C"

<commit_msg>Get rid of unused file descriptor<commit_after>// =-=-=-=-=-=-=-
#include "apiHeaderAll.hpp"
#include "msParam.hpp"
#include "reGlobalsExtern.hpp"
#include "irods_ms_plugin.hpp"

// =-=-=-=-=-=-=-
// STL Includes
#include <string>
#include <iostream>

// =-=-=-=-=-=-=-
// cURL Includes
#include <curl/curl.h>
#include <curl/easy.h>

typedef struct writeDataInp_t {
    char objPath[MAX_NAME_LEN];
    int l1descInx;
    rsComm_t *rsComm;
} writeDataInp_t;

typedef struct readData_t {
  char sourcePath[MAX_NAME_LEN];
  FILE *fd;
} readData_t;

class irodsCurl {
private:
    // iRODS serv, char *destPath er handle
    rsComm_t *rsComm;

    // cURL handle
    CURL *curl;

public:
    irodsCurl( rsComm_t *comm ) {
        rsComm = comm;

        curl = curl_easy_init();
        if ( !curl ) {
            rodsLog( LOG_ERROR, "irodsCurl: %s", curl_easy_strerror( CURLE_FAILED_INIT ) );
        }
    }

    ~irodsCurl() {
        if ( curl ) {
            curl_easy_cleanup( curl );
        }
    }

    int get( char *url, char *sourcePath, char *destPath, char *ext) {

	CURL *curl;
	CURLcode res = CURLE_OK;
        writeDataInp_t writeDataInp;	// the "file descriptor" for our destination object
        openedDataObjInp_t openedDataObjInp;	// for closing iRODS object after writing

        readData_t readData;

        int status;

	struct curl_httppost *formpost=NULL;
	struct curl_httppost *lastptr=NULL;

	curl_global_init(CURL_GLOBAL_ALL);

        /* Fill in the file upload field */
        curl_formadd(&formpost,
                &lastptr,
                CURLFORM_COPYNAME, "output_format",
                CURLFORM_COPYCONTENTS, ext,
                CURLFORM_END);

        /* Fill in the filename field */
        curl_formadd(&formpost,
                &lastptr,
                CURLFORM_COPYNAME, "file",
                CURLFORM_FILENAME, "y18.gif", //This needs to be the filename of the upload
                CURLFORM_STREAM, &readData,
                CURLFORM_CONTENTSLENGTH, 100,  //This needs to be the size of the upload
                CURLFORM_CONTENTTYPE, "application/octet-stream",
                CURLFORM_END);

        // Zero fill openedDataObjInp
        memset( &openedDataObjInp, 0, sizeof( openedDataObjInp_t ) );

        // Set up writeDataInp
        snprintf( writeDataInp.objPath, MAX_NAME_LEN, "%s", destPath );
        writeDataInp.l1descInx = 0;	// the object is yet to be created
        writeDataInp.rsComm = rsComm;

        // Set up writeDataInp
        snprintf(readData.sourcePath, MAX_NAME_LEN, "%s", sourcePath);
        readData.fd = 0;	// the object is yet to be created

        // Set up easy handler
 	curl = curl_easy_init();

	/* what URL that receives this POST */
        curl_easy_setopt(curl, CURLOPT_URL, url);

        curl_easy_setopt(curl, CURLOPT_READFUNCTION, &irodsCurl::my_read_obj);
        curl_easy_setopt(curl, CURLOPT_READDATA, &readData);
        curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);

        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &irodsCurl::my_write_obj);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &writeDataInp );

        // CURL call
        res = curl_easy_perform( curl );

        // Some error logging
        if ( res != CURLE_OK ) {
            rodsLog( LOG_ERROR, "irodsCurl::get: cURL error: %s", curl_easy_strerror( res ) );
        }

        // close iRODS object
        if ( writeDataInp.l1descInx ) {
            openedDataObjInp.l1descInx = writeDataInp.l1descInx;
            status = rsDataObjClose( rsComm, &openedDataObjInp );
            if ( status < 0 ) {
                rodsLog( LOG_ERROR, "irodsCurl::get: rsDataObjClose failed for %s, status = %d",
                         writeDataInp.objPath, status );
            }
        }

        /* then cleanup the formpost chain */
        curl_formfree(formpost);

        return res;
    }

    static size_t my_read_obj(void *buffer, size_t size, size_t nmemb, void* userp) {
        struct readData_t *readData = (struct readData_t *) userp;

        if (!readData) {
            return -11;
        }

        if (!readData->fd) {
            readData->fd = fopen(readData->sourcePath, "r");
        }

        return fread(buffer, size, nmemb, readData->fd);
    }

    // Custom callback function for the curl handler, to write to an iRODS object
    static size_t my_write_obj( void *buffer, size_t size, size_t nmemb, writeDataInp_t *writeDataInp ) {
        dataObjInp_t dataObjInp;	// input struct for rsDataObjCreate
        openedDataObjInp_t openedDataObjInp;	// input struct for rsDataObjWrite
        bytesBuf_t bytesBuf;	// input buffer for rsDataObjWrite
        size_t written;	// return value

        int l1descInx;

        // Make sure we have something to write to
        if ( !writeDataInp ) {
            rodsLog( LOG_ERROR, "my_write_obj: writeDataInp is NULL, status = %d", SYS_INTERNAL_NULL_INPUT_ERR );
            return SYS_INTERNAL_NULL_INPUT_ERR;
        }

        // Zero fill input structs
        memset( &dataObjInp, 0, sizeof( dataObjInp_t ) );
        memset( &openedDataObjInp, 0, sizeof( openedDataObjInp_t ) );

        // If this is the first call we need to create our data object before writing to it
        if ( !writeDataInp->l1descInx ) {
            strncpy( dataObjInp.objPath, writeDataInp->objPath, MAX_NAME_LEN );

            // Overwrite existing file (for this tutorial only, in case the example has been run before)
            addKeyVal( &dataObjInp.condInput, FORCE_FLAG_KW, "" );

            writeDataInp->l1descInx = rsDataObjCreate( writeDataInp->rsComm, &dataObjInp );

            // No create?
            if ( writeDataInp->l1descInx <= 2 ) {
                rodsLog( LOG_ERROR, "my_write_obj: rsDataObjCreate failed for %s, status = %d", dataObjInp.objPath, writeDataInp->l1descInx );
                return ( writeDataInp->l1descInx );
            }
        }

        // Set up input buffer for rsDataObjWrite
        bytesBuf.len = ( int )( size * nmemb );
        bytesBuf.buf = buffer;

        // Set up input struct for rsDataObjWrite
        openedDataObjInp.l1descInx = writeDataInp->l1descInx;;
        openedDataObjInp.len = bytesBuf.len;

        // Write to data object
        written = rsDataObjWrite( writeDataInp->rsComm, &openedDataObjInp, &bytesBuf );

        return ( written );
    }

}; // class irodsCurl

extern "C" {

// =-=-=-=-=-=-=-
// 1. Write a standard issue microservice
    int irods_curl_get( msParam_t* url, msParam_t* source_obj, msParam_t* ext_obj,
                                        msParam_t* dest_obj, ruleExecInfo_t* rei ) {
        dataObjInp_t destObjInp, *myDestObjInp;	/* for parsing input object */

        // Sanity checks
        if ( !rei || !rei->rsComm ) {
            rodsLog( LOG_ERROR, "irods_curl_get: Input rei or rsComm is NULL." );
            return ( SYS_INTERNAL_NULL_INPUT_ERR );
        }

	// get destination path from sourcePath and exten.
	char *sourceStr = parseMspForStr(source_obj);
	char *extStr = parseMspForStr(ext_obj);

	char *source = "/tempZone/home/public/new.png";

	char tmpSource[strlen(source) + 10];

	strcpy(tmpSource, source);

    	char *lastdot = strrchr (tmpSource, '.');
	char *lastsep = ('/' == 0) ? NULL : strrchr (tmpSource, '/');

	if (lastdot != NULL)
	{
        // and it's before the extenstion separator.

        	if (lastsep != NULL)
		{
            		if (lastsep < lastdot)
			{
                	// then remove it.

                	*lastdot = '\0';
            		}
        	}
		else
		{
            	// Has extension separator with no path separator.

            	*lastdot = '\0';
        	}
    	}
        char destStr[strlen(source)+10];

	snprintf(destStr, strlen(source) + 10, "%s%s%s", tmpSource, ".", extStr);

	fillStrInMsParam(dest_obj, destStr);

        // Get path of destination object
        rei->status = parseMspForDataObjInp( dest_obj, &destObjInp, &myDestObjInp, 0 );
        if ( rei->status < 0 ) {
            rodsLog( LOG_ERROR, "irods_curl_get: Input object error. status = %d", rei->status );
            return ( rei->status );
        }

        // Create irodsCurl instance
        irodsCurl myCurl( rei->rsComm );

        // Call irodsCurl::get

        rei->status = myCurl.get( parseMspForStr( url ), sourceStr,  destObjInp.objPath, extStr);

        // Done
        return rei->status;

    }

// =-=-=-=-=-=-=-
// 2. Create the plugin factory function which will return a microservice
// table entry
    irods::ms_table_entry* plugin_factory() {
        // =-=-=-=-=-=-=-
        // 3. allocate a microservice plugin which takes the number of function
        // params as a parameter to the constructor
        irods::ms_table_entry* msvc = new irods::ms_table_entry( 4 );

        // =-=-=-=-=-=-=-
        // 4. add the microservice function as an operation to the plugin
        // the first param is the name / key of the operation, the second
        // is the name of the function which will be the microservice
        msvc->add_operation( "irods_curl_get", "irods_curl_get" );

        // =-=-=-=-=-=-=-
        // 5. return the newly created microservice plugin
        return msvc;
    }

}	// extern "C"

<|endoftext|>


<commit_before>/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */

/* -------------------------------------------------------------------------
   ATS

   License: see $ATS_DIR/COPYRIGHT
   Author: Ethan Coon

   Default base with default implementations of methods for a physical PK.
   ------------------------------------------------------------------------- */
#include "pk_physical_base.hh"

namespace Amanzi {

PKPhysicalBase::PKPhysicalBase(const Teuchos::RCP<Teuchos::ParameterList>& plist,
        Teuchos::ParameterList& FElist,
        const Teuchos::RCP<TreeVector>& solution) :
    PKDefaultBase(plist,FElist,solution) {
  // process the PList
  // domain
  if (domain_ == std::string("")) {
    domain_ = plist_->get<std::string>("domain name", std::string("domain"));
  }
  if (key_ == std::string("")) {
    key_ = plist_->get<std::string>("primary variable");
  }

  // derive the prefix
  if (domain_ == std::string("domain")) {
    domain_prefix_ = std::string("");
  } else {
    domain_prefix_ = domain_ + std::string("_");
  }

  // set up the primary variable solution, and its evaluator
  Teuchos::ParameterList& pv_sublist = FElist.sublist(key_);
  pv_sublist.set("evaluator name", key_);
  pv_sublist.set("field evaluator type", "primary variable");
}

// -----------------------------------------------------------------------------
// Construction of data.
// -----------------------------------------------------------------------------
void PKPhysicalBase::setup(const Teuchos::Ptr<State>& S) {
  PKDefaultBase::setup(S);

  // get the mesh
  mesh_ = S->GetMesh(domain_);

  // set up the debugger
  db_ = Teuchos::rcp(new Debugger(mesh_, name_, *plist_));

  // require primary variable evaluator
  S->RequireFieldEvaluator(key_);
  Teuchos::RCP<FieldEvaluator> fm = S->GetFieldEvaluator(key_);
#if ENABLE_DBC
  solution_evaluator_ = Teuchos::rcp_dynamic_cast<PrimaryVariableFieldEvaluator>(fm);
  ASSERT(solution_evaluator_ != Teuchos::null);
#else
  solution_evaluator_ = Teuchos::rcp_static_cast<PrimaryVariableFieldEvaluator>(fm);
#endif
};

// -----------------------------------------------------------------------------
// Transfer operators -- ONLY COPIES POINTERS
// -----------------------------------------------------------------------------
void PKPhysicalBase::state_to_solution(const Teuchos::RCP<State>& S,
        const Teuchos::RCP<TreeVector>& solution) {
  solution->SetData(S->GetFieldData(key_, name_));
};

// -----------------------------------------------------------------------------
// Transfer operators -- ONLY COPIES POINTERS
// -----------------------------------------------------------------------------
void PKPhysicalBase::solution_to_state(const Teuchos::RCP<TreeVector>& solution,
        const Teuchos::RCP<State>& S) {
  ASSERT(solution->Data() == S->GetFieldData(key_));
  //  S->SetData(key_, name_, solution->Data());
  //  solution_evaluator_->SetFieldAsChanged();
};

// -----------------------------------------------------------------------------
// Experimental approach -- we must pull out S_next_'s solution_evaluator_ to
// stay current for changed_solution()
// -----------------------------------------------------------------------------
void PKPhysicalBase::set_states(const Teuchos::RCP<const State>& S,
        const Teuchos::RCP<State>& S_inter,
        const Teuchos::RCP<State>& S_next) {
  PKDefaultBase::set_states(S, S_inter, S_next);

  // Get the FE and mark it as changed.
  // Note that this is necessary because we need this to point at the
  // FE in S_next_, not the one which we created in S_.
  Teuchos::RCP<FieldEvaluator> fm = S_next->GetFieldEvaluator(key_);
#if ENABLE_DBC
  solution_evaluator_ = Teuchos::rcp_dynamic_cast<PrimaryVariableFieldEvaluator>(fm);
  ASSERT(solution_evaluator_ != Teuchos::null);
#else
  solution_evaluator_ = Teuchos::rcp_static_cast<PrimaryVariableFieldEvaluator>(fm);
#endif

  solution_evaluator_->SetFieldAsChanged(S_next_.ptr());
};

// -----------------------------------------------------------------------------
// Initialization of the PK data.
// -----------------------------------------------------------------------------
void PKPhysicalBase::initialize(const Teuchos::Ptr<State>& S) {
  Teuchos::RCP<Field> field = S->GetField(key_, name_);

  if (!field->initialized()) {
    // initial conditions
    // -- Get the IC function plist.
    if (!plist_->isSublist("initial condition")) {
      std::stringstream messagestream;
      messagestream << name_ << " has no initial condition parameter list.";
      Errors::Message message(messagestream.str());
      Exceptions::amanzi_throw(message);
    }

    // -- Calculate the IC.
    Teuchos::ParameterList ic_plist = plist_->sublist("initial condition");
    field->Initialize(ic_plist);

    // -- Update faces from cells if needed.
    if (ic_plist.get<bool>("initialize faces from cells", false)) {
      DeriveFaceValuesFromCellValues_(field->GetFieldData().ptr());
    }

    // communicate just to make sure values are initialized for valgrind's sake
    field->GetFieldData()->ScatterMasterToGhosted();
    solution_evaluator_->SetFieldAsChanged(S);
  }

  // -- Push the data into the solution.
  solution_->SetData(field->GetFieldData());
};

// -----------------------------------------------------------------------------
// Interpolate pressure ICs on cells to ICs for lambda (faces).
// -----------------------------------------------------------------------------
void PKPhysicalBase::DeriveFaceValuesFromCellValues_(const Teuchos::Ptr<CompositeVector>& cv) {
  cv->ScatterMasterToGhosted("cell");
  Teuchos::Ptr<const CompositeVector> cv_const(cv);
  const Epetra_MultiVector& cv_c = *cv_const->ViewComponent("cell",true);
  Epetra_MultiVector& cv_f = *cv->ViewComponent("face",false);

  int f_owned = cv_f.MyLength();
  for (int f=0; f!=f_owned; ++f) {
    AmanziMesh::Entity_ID_List cells;
    cv->Mesh()->face_get_cells(f, AmanziMesh::USED, &cells);
    int ncells = cells.size();

    double face_value = 0.0;
    for (int n=0; n!=ncells; ++n) {
      face_value += cv_c[0][cells[n]];
    }
    cv_f[0][f] = face_value / ncells;
  }
};

} // namespace
<commit_msg>remove deriving face values from cell values as that should now be handled by Amanzi Field_CV<commit_after>/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */

/* -------------------------------------------------------------------------
   ATS

   License: see $ATS_DIR/COPYRIGHT
   Author: Ethan Coon

   Default base with default implementations of methods for a physical PK.
   ------------------------------------------------------------------------- */
#include "pk_physical_base.hh"

namespace Amanzi {

PKPhysicalBase::PKPhysicalBase(const Teuchos::RCP<Teuchos::ParameterList>& plist,
        Teuchos::ParameterList& FElist,
        const Teuchos::RCP<TreeVector>& solution) :
    PKDefaultBase(plist,FElist,solution) {
  // process the PList
  // domain
  if (domain_ == std::string("")) {
    domain_ = plist_->get<std::string>("domain name", std::string("domain"));
  }
  if (key_ == std::string("")) {
    key_ = plist_->get<std::string>("primary variable");
  }

  // derive the prefix
  if (domain_ == std::string("domain")) {
    domain_prefix_ = std::string("");
  } else {
    domain_prefix_ = domain_ + std::string("_");
  }

  // set up the primary variable solution, and its evaluator
  Teuchos::ParameterList& pv_sublist = FElist.sublist(key_);
  pv_sublist.set("evaluator name", key_);
  pv_sublist.set("field evaluator type", "primary variable");
}

// -----------------------------------------------------------------------------
// Construction of data.
// -----------------------------------------------------------------------------
void PKPhysicalBase::setup(const Teuchos::Ptr<State>& S) {
  PKDefaultBase::setup(S);

  // get the mesh
  mesh_ = S->GetMesh(domain_);

  // set up the debugger
  db_ = Teuchos::rcp(new Debugger(mesh_, name_, *plist_));

  // require primary variable evaluator
  S->RequireFieldEvaluator(key_);
  Teuchos::RCP<FieldEvaluator> fm = S->GetFieldEvaluator(key_);
#if ENABLE_DBC
  solution_evaluator_ = Teuchos::rcp_dynamic_cast<PrimaryVariableFieldEvaluator>(fm);
  ASSERT(solution_evaluator_ != Teuchos::null);
#else
  solution_evaluator_ = Teuchos::rcp_static_cast<PrimaryVariableFieldEvaluator>(fm);
#endif
};

// -----------------------------------------------------------------------------
// Transfer operators -- ONLY COPIES POINTERS
// -----------------------------------------------------------------------------
void PKPhysicalBase::state_to_solution(const Teuchos::RCP<State>& S,
        const Teuchos::RCP<TreeVector>& solution) {
  solution->SetData(S->GetFieldData(key_, name_));
};

// -----------------------------------------------------------------------------
// Transfer operators -- ONLY COPIES POINTERS
// -----------------------------------------------------------------------------
void PKPhysicalBase::solution_to_state(const Teuchos::RCP<TreeVector>& solution,
        const Teuchos::RCP<State>& S) {
  ASSERT(solution->Data() == S->GetFieldData(key_));
  //  S->SetData(key_, name_, solution->Data());
  //  solution_evaluator_->SetFieldAsChanged();
};

// -----------------------------------------------------------------------------
// Experimental approach -- we must pull out S_next_'s solution_evaluator_ to
// stay current for changed_solution()
// -----------------------------------------------------------------------------
void PKPhysicalBase::set_states(const Teuchos::RCP<const State>& S,
        const Teuchos::RCP<State>& S_inter,
        const Teuchos::RCP<State>& S_next) {
  PKDefaultBase::set_states(S, S_inter, S_next);

  // Get the FE and mark it as changed.
  // Note that this is necessary because we need this to point at the
  // FE in S_next_, not the one which we created in S_.
  Teuchos::RCP<FieldEvaluator> fm = S_next->GetFieldEvaluator(key_);
#if ENABLE_DBC
  solution_evaluator_ = Teuchos::rcp_dynamic_cast<PrimaryVariableFieldEvaluator>(fm);
  ASSERT(solution_evaluator_ != Teuchos::null);
#else
  solution_evaluator_ = Teuchos::rcp_static_cast<PrimaryVariableFieldEvaluator>(fm);
#endif

  solution_evaluator_->SetFieldAsChanged(S_next_.ptr());
};

// -----------------------------------------------------------------------------
// Initialization of the PK data.
// -----------------------------------------------------------------------------
void PKPhysicalBase::initialize(const Teuchos::Ptr<State>& S) {
  Teuchos::RCP<Field> field = S->GetField(key_, name_);

  if (!field->initialized()) {
    // initial conditions
    // -- Get the IC function plist.
    if (!plist_->isSublist("initial condition")) {
      std::stringstream messagestream;
      messagestream << name_ << " has no initial condition parameter list.";
      Errors::Message message(messagestream.str());
      Exceptions::amanzi_throw(message);
    }

    // -- Calculate the IC.
    Teuchos::ParameterList ic_plist = plist_->sublist("initial condition");
    field->Initialize(ic_plist);

    // -- Update faces from cells if needed.
    // if (ic_plist.get<bool>("initialize faces from cells", false)) {
    //   DeriveFaceValuesFromCellValues_(field->GetFieldData().ptr());
    // }

    // communicate just to make sure values are initialized for valgrind's sake
    field->GetFieldData()->ScatterMasterToGhosted();
    solution_evaluator_->SetFieldAsChanged(S);
  }

  // -- Push the data into the solution.
  solution_->SetData(field->GetFieldData());
};

// -----------------------------------------------------------------------------
// Interpolate pressure ICs on cells to ICs for lambda (faces).
// -----------------------------------------------------------------------------
void PKPhysicalBase::DeriveFaceValuesFromCellValues_(const Teuchos::Ptr<CompositeVector>& cv) {
  cv->ScatterMasterToGhosted("cell");
  Teuchos::Ptr<const CompositeVector> cv_const(cv);
  const Epetra_MultiVector& cv_c = *cv_const->ViewComponent("cell",true);
  Epetra_MultiVector& cv_f = *cv->ViewComponent("face",false);

  int f_owned = cv_f.MyLength();
  for (int f=0; f!=f_owned; ++f) {
    AmanziMesh::Entity_ID_List cells;
    cv->Mesh()->face_get_cells(f, AmanziMesh::USED, &cells);
    int ncells = cells.size();

    double face_value = 0.0;
    for (int n=0; n!=ncells; ++n) {
      face_value += cv_c[0][cells[n]];
    }
    cv_f[0][f] = face_value / ncells;
  }
};

} // namespace
<|endoftext|>


<commit_before>#ifndef INCLUDE_ACKWARD_CORE_EXCEPTIONS_HPP
#define INCLUDE_ACKWARD_CORE_EXCEPTIONS_HPP

/** C++ counterparts to the standard Python exceptions.
 */

#include <Python.h>

#include <exception>

#include <boost/exception/all.hpp>

namespace boost { namespace python { class tuple; } }

namespace ackward {
namespace core {

/** The base for all ackward exceptions. */
class Exception : public virtual boost::exception,
                  public virtual std::exception
{};

/** A collection of C++ analogues for the standard Python exceptions.
 */
class AttributeError : public Exception {};
class ImportError : public Exception {};
class IndexError : public Exception {};
class IOError : public Exception {};
class KeyError : public Exception {};
class TypeError : public Exception {};
class ReferenceError : public Exception {};
class ValueError : public Exception {};
class StopIteration : public Exception {};

}}

#endif
<commit_msg>de-doxygened some commentary in core/exceptions<commit_after>#ifndef INCLUDE_ACKWARD_CORE_EXCEPTIONS_HPP
#define INCLUDE_ACKWARD_CORE_EXCEPTIONS_HPP

/** C++ counterparts to the standard Python exceptions.
 */

#include <Python.h>

#include <exception>

#include <boost/exception/all.hpp>

namespace boost { namespace python { class tuple; } }

namespace ackward {
namespace core {

/** The base for all ackward exceptions. */
class Exception : public virtual boost::exception,
                  public virtual std::exception
{};

/* A collection of C++ analogues for the standard Python exceptions.
 */

class AttributeError : public Exception {};
class ImportError : public Exception {};
class IndexError : public Exception {};
class IOError : public Exception {};
class KeyError : public Exception {};
class TypeError : public Exception {};
class ReferenceError : public Exception {};
class ValueError : public Exception {};
class StopIteration : public Exception {};

}}

#endif
<|endoftext|>


<commit_before>#ifndef ___INANITY_GRAPHICS_GRAPHICS_HPP___
#define ___INANITY_GRAPHICS_GRAPHICS_HPP___

/*
 * Общий файл для подсистемы графики.
 * Подсистема графики является сборной. Основная часть подсистемы - заменяемая,
 * подменяется конкретными подсистемами (пока только DX).
 * А некоторые компоненты являются общими для всех реализаций.
 */

#include "../Object.hpp"

#define BEGIN_INANITY_GRAPHICS BEGIN_INANITY namespace Graphics {
#define END_INANITY_GRAPHICS } END_INANITY

// Конфигурация графики.

#ifdef ___INANITY_WINDOWS
#define ___INANITY_GRAPHICS_DX
#endif
#ifdef INANITY_LIB
BEGIN_INANITY_GRAPHICS
END_INANITY_GRAPHICS
using namespace Graphics;
#endif

#endif
<commit_msg>fixed including mathematics in graphics<commit_after>#ifndef ___INANITY_GRAPHICS_GRAPHICS_HPP___
#define ___INANITY_GRAPHICS_GRAPHICS_HPP___

/*
 * Общий файл для подсистемы графики.
 * Подсистема графики является сборной. Основная часть подсистемы - заменяемая,
 * подменяется конкретными подсистемами (пока только DX).
 * А некоторые компоненты являются общими для всех реализаций.
 */

#include "../Object.hpp"
// Решено просто включать математику во всю графику.
#include "../inanity-math.hpp"

#define BEGIN_INANITY_GRAPHICS BEGIN_INANITY namespace Graphics {
#define END_INANITY_GRAPHICS } END_INANITY

#ifdef ___INANITY_WINDOWS
#define ___INANITY_GRAPHICS_DX
#endif
BEGIN_INANITY_GRAPHICS
using namespace Inanity::Math;
END_INANITY_GRAPHICS
#ifdef INANITY_LIB
using namespace Graphics;
#endif

#endif
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <aikido/statespace/dart/MetaSkeletonStateSpace.hpp>
#include <aikido/constraint/CollisionConstraint.hpp>
#include <aikido/constraint/dart.hpp>
#include <aikido/distance/DistanceMetricDefaults.hpp>
#include <aikido/ompl/OMPLPlanner.hpp>
#include <ompl/geometric/planners/rrt/RRTConnect.h>
#include <dart/dart.h>
#include <tuple>

using std::shared_ptr;
using std::make_shared;
using aikido::util::RNGWrapper;
using aikido::util::RNG;
using dart::common::make_unique;

using DefaultRNG = RNGWrapper<std::default_random_engine>;

static std::unique_ptr<DefaultRNG> make_rng()
{
  return make_unique<RNGWrapper<std::default_random_engine>>(0);
}

TEST(OMPLPlannerTest, Plan)
{
  auto skel = dart::dynamics::Skeleton::create("robot");

  auto jn_bn =
      skel->createJointAndBodyNodePair<dart::dynamics::TranslationalJoint>();

  // TODO: Set bounds on the skeleton
  skel->setPositionLowerLimit(0, -5);
  skel->setPositionUpperLimit(0, 5);
  skel->setPositionLowerLimit(1, -5);
  skel->setPositionUpperLimit(1, 5);
  skel->setPositionLowerLimit(2, 0);
  skel->setPositionUpperLimit(2, 0);

  // State space for this robot
  using StateSpace = aikido::statespace::MetaSkeletonStateSpace;
  auto stateSpace = make_shared<StateSpace>(skel);

  // Start state - 3 dof real vector
  using RealVectorStateSpace = aikido::statespace::RealVectorStateSpace;
  StateSpace::ScopedState startState = stateSpace->createState();
  auto subState = startState.getSubStateHandle<RealVectorStateSpace>(0);
  Eigen::Vector3d start_pose(-5, -5, 0);
  subState.setValue(start_pose);

  stateSpace->setStateOnMetaSkeleton(startState);

  // Goal state
  StateSpace::ScopedState goalState = stateSpace->createState();
  Eigen::Vector3d goal_pose(5, 5, 0);
  subState = goalState.getSubStateHandle<RealVectorStateSpace>(0);
  subState.setValue(goal_pose);

  // Collision constraint
  auto cd = dart::collision::FCLCollisionDetector::create();
  auto collConstraint =
      std::make_shared<aikido::constraint::CollisionConstraint>(stateSpace, cd);

  // Distance metric
  auto dmetric = aikido::distance::createDistanceMetricFor(stateSpace);

  // Sampler
  auto sampler =
      aikido::constraint::createSampleableBounds(stateSpace, make_rng());

  // Projectable constraint
  auto projConstraint =
      aikido::constraint::createProjectableBounds(stateSpace);

  // Joint limits
  auto jlimit =
      aikido::constraint::createTestableBounds(stateSpace);

  // Plan
  auto traj =
      aikido::ompl::planOMPL<ompl::geometric::RRTConnect>(
          startState, goalState, stateSpace, std::move(collConstraint), std::move(jlimit),
          std::move(dmetric), std::move(sampler), std::move(projConstraint), 5.0);

  // Check the first waypoint
  auto s0 = stateSpace->createState();
  traj->evaluate(0, s0);
  auto r0 = s0.getSubStateHandle<RealVectorStateSpace>(0);
  ASSERT_TRUE(r0.getValue().isApprox(start_pose));

  // Check the last waypoint
  traj->evaluate(traj->getDuration(), s0);
  r0 = s0.getSubStateHandle<RealVectorStateSpace>(0);
  ASSERT_TRUE(r0.getValue().isApprox(goal_pose));
}
<commit_msg>Updating planner test structure<commit_after>#include <gtest/gtest.h>
#include <aikido/statespace/dart/MetaSkeletonStateSpace.hpp>
#include <aikido/constraint/CollisionConstraint.hpp>
#include <aikido/constraint/dart.hpp>
#include <aikido/distance/DistanceMetricDefaults.hpp>
#include <aikido/ompl/OMPLPlanner.hpp>
#include <ompl/geometric/planners/rrt/RRTConnect.h>
#include <dart/dart.h>
#include <tuple>

using std::shared_ptr;
using std::make_shared;
using aikido::util::RNGWrapper;
using aikido::util::RNG;
using dart::common::make_unique;
using DefaultRNG = RNGWrapper<std::default_random_engine>;
using RealVectorStateSpace = aikido::statespace::RealVectorStateSpace;

static std::unique_ptr<DefaultRNG> make_rng()
{
  return make_unique<RNGWrapper<std::default_random_engine>>(0);
}

class OMPLPlannerTest : public ::testing::Test
{
public:
  using StateSpace = aikido::statespace::MetaSkeletonStateSpace;

  OMPLPlannerTest()
      : skel{dart::dynamics::Skeleton::create("robot")}
      , stateSpace{make_shared<StateSpace>(skel)}
      , startState{stateSpace->createState()}
      , goalState{stateSpace->createState()}
      , startPose{Eigen::Vector3d(-5, -5, 0)}
      , goalPose{Eigen::Vector3d(5, 5, 0)}
  {
    skel = dart::dynamics::Skeleton::create("robot");

    auto jn_bn =
        skel->createJointAndBodyNodePair<dart::dynamics::TranslationalJoint>();

    // TODO: Set bounds on the skeleton
    skel->setPositionLowerLimit(0, -5);
    skel->setPositionUpperLimit(0, 5);
    skel->setPositionLowerLimit(1, -5);
    skel->setPositionUpperLimit(1, 5);
    skel->setPositionLowerLimit(2, 0);
    skel->setPositionUpperLimit(2, 0);

    // Start state - 3 dof real vector
    auto subState = startState.getSubStateHandle<RealVectorStateSpace>(0);
    subState.setValue(startPose);

    stateSpace->setStateOnMetaSkeleton(startState);

    // Goal state
    subState = goalState.getSubStateHandle<RealVectorStateSpace>(0);
    subState.setValue(goalPose);

    // Collision constraint
    auto cd = dart::collision::FCLCollisionDetector::create();
    collConstraint = std::make_shared<aikido::constraint::CollisionConstraint>(
        stateSpace, cd);

    // Distance metric
    dmetric = aikido::distance::createDistanceMetricFor(stateSpace);

    // Sampler
    sampler =
        aikido::constraint::createSampleableBounds(stateSpace, make_rng());

    // Projectable constraint
    projConstraint = aikido::constraint::createProjectableBounds(stateSpace);

    // Joint limits
    jlimit = aikido::constraint::createTestableBounds(stateSpace);
  }

  dart::dynamics::SkeletonPtr skel;
  aikido::statespace::MetaSkeletonStateSpacePtr stateSpace;
  StateSpace::ScopedState startState;
  StateSpace::ScopedState goalState;
  aikido::distance::DistanceMetricPtr dmetric;
  aikido::constraint::SampleableConstraintPtr sampler;
  aikido::constraint::ProjectablePtr projConstraint;
  aikido::constraint::TestableConstraintPtr jlimit;
  aikido::constraint::TestableConstraintPtr collConstraint;
  Eigen::Vector3d startPose;
  Eigen::Vector3d goalPose;
};

TEST_F(OMPLPlannerTest, Plan)
{
  // Plan
  auto traj = aikido::ompl::planOMPL<ompl::geometric::RRTConnect>(
      startState, goalState, stateSpace, std::move(collConstraint),
      std::move(jlimit), std::move(dmetric), std::move(sampler),
      std::move(projConstraint), 5.0);

  // Check the first waypoint
  auto s0 = stateSpace->createState();
  traj->evaluate(0, s0);
  auto r0 = s0.getSubStateHandle<RealVectorStateSpace>(0);
  ASSERT_TRUE(r0.getValue().isApprox(startPose));

  // Check the last waypoint
  traj->evaluate(traj->getDuration(), s0);
  r0 = s0.getSubStateHandle<RealVectorStateSpace>(0);
  ASSERT_TRUE(r0.getValue().isApprox(goalPose));
}
<|endoftext|>


<commit_before>#ifndef MATCHES_DHT_HPP
#define MATCHES_DHT_HPP

#include <Grappa.hpp>
#include <GlobalAllocator.hpp>
#include <GlobalCompletionEvent.hpp>
#include <ParallelLoop.hpp>
#include <BufferVector.hpp>
#include <Metrics.hpp>

#include <list>
#include <cmath>

//GRAPPA_DECLARE_METRIC(MaxMetric<uint64_t>, max_cell_length);
GRAPPA_DECLARE_METRIC(SimpleMetric<uint64_t>, hash_tables_size);
GRAPPA_DECLARE_METRIC(SummarizingMetric<uint64_t>, hash_tables_lookup_steps);

GRAPPA_DECLARE_METRIC(SimpleMetric<uint64_t>, hash_remote_lookups);
GRAPPA_DECLARE_METRIC(SimpleMetric<uint64_t>, hash_remote_inserts);
GRAPPA_DECLARE_METRIC(SimpleMetric<uint64_t>, hash_local_lookups);
GRAPPA_DECLARE_METRIC(SimpleMetric<uint64_t>, hash_local_inserts);
GRAPPA_DECLARE_METRIC(SimpleMetric<uint64_t>, hash_called_lookups);
GRAPPA_DECLARE_METRIC(SimpleMetric<uint64_t>, hash_called_inserts);

// for naming the types scoped in MatchesDHT
#define MDHT_TYPE(type) typename MatchesDHT<K,V,HF>::type

// Hash table for joins
// * allows multiple copies of a Key
// * lookups return all Key matches
template <typename K, typename V, uint64_t (*HF)(K)>
class MatchesDHT {

  private:
    struct Entry {
      K key;
      std::vector<V> * vs;
      //BufferVector<V> * vs;
      Entry( K key ) : key(key), vs(new std::vector<V>()) {}
      //Entry( K key ) : key(key), vs(new BufferVector<V>( 16 )) {}
      Entry ( ) {}
    };

    struct Cell {
      std::list<Entry> * entries;

      Cell() : entries( NULL ) {}
    };

    struct lookup_result {
      GlobalAddress<V> matches;
      size_t num;
    };

    // private members
    GlobalAddress< Cell > base;
    size_t capacity;

    uint64_t computeIndex( K key ) {
      return HF(key) & (capacity - 1);
    }

    // for creating local MatchesDHT
    MatchesDHT( GlobalAddress<Cell> base, uint32_t capacity_pow2 ) {
      this->base = base;
      this->capacity = capacity_pow2;
    }

    static bool lookup_local( K key, Cell * target, Entry * result ) {
        std::list<MDHT_TYPE(Entry)> * entries = target->entries;

        // first check if the cell has any entries;
        // if not then the lookup returns nothing
        if ( entries == NULL ) return false;

        typename std::list<MDHT_TYPE(Entry)>::iterator i;
        uint64_t steps = 1;
        for (i = entries->begin(); i!=entries->end(); ++i) {
          const Entry e = *i;
          if ( e.key == key ) {  // typename K must implement operator==
            *result = e;
            hash_tables_lookup_steps += steps;
            return true;
          }
          ++steps;
        }
        hash_tables_lookup_steps += steps;
        return false;
    }

  public:
    // for static construction
    MatchesDHT( ) {}

    static void init_global_DHT( MatchesDHT<K,V,HF> * globally_valid_local_pointer, size_t capacity ) {

      uint32_t capacity_exp = log2(capacity);
      size_t capacity_powerof2 = pow(2, capacity_exp);
      GlobalAddress<Cell> base = Grappa::global_alloc<Cell>( capacity_powerof2 );

      Grappa::on_all_cores( [globally_valid_local_pointer,base,capacity_powerof2] {
        *globally_valid_local_pointer = MatchesDHT<K,V,HF>( base, capacity_powerof2 );
      });

      Grappa::forall( base, capacity_powerof2, []( int64_t i, Cell& c ) {
        Cell empty;
        c = empty;
      });
    }

    struct size_aligned {
      size_t s;

      size_aligned operator+(const size_aligned& o) const {
        size_aligned v;
        v.s = this->s + o.s;
        return v;
      }
    } GRAPPA_BLOCK_ALIGNED;

   size_t size() {
     auto l_size = Grappa::symmetric_global_alloc<size_aligned>();
     Grappa::forall( base, capacity, [l_size](int64_t i, Cell& c) {
       if (c.entries != NULL) {
         for (auto eiter = c.entries->begin(); eiter != c.entries->end(); ++eiter) {
           l_size->s += eiter->vs->size();
         }
       }
     });
    return Grappa::reduce<size_aligned, COLL_ADD>(l_size ).s;
        //FIXME: mem leak l_size
   }

    static void set_RO_global( MatchesDHT<K,V,HF> * globally_valid_local_pointer ) {
      Grappa::forall( globally_valid_local_pointer->base, globally_valid_local_pointer->capacity, []( int64_t i, Cell& c ) {
        // list of entries in this cell
        std::list<MDHT_TYPE(Entry)> * entries = c.entries;

        // if cell is not hit then no action
        if ( entries == NULL ) {
          return;
        }

        uint64_t sum_size = 0;
        // for all keys, set match vector to RO
        typename std::list<MDHT_TYPE(Entry)>::iterator it;
        for (it = entries->begin(); it!=entries->end(); ++it) {
          Entry e = *it;
          //e.vs->setReadMode();
          sum_size+=e.vs->size();
        }
        //max_cell_length.add(sum_size);
      });
    }

    uint64_t lookup ( K key, GlobalAddress<V> * vals ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      // FIXME: remove 'this' capture when using gcc4.8, this is just a bug in 4.7
      lookup_result result = Grappa::delegate::call( target.core(), [key,target,this]() {
        hash_called_lookups++;

        MDHT_TYPE(lookup_result) lr;
        lr.num = 0;

        Entry e;
        if (lookup_local( key, target.pointer(), &e)) {
         // lr.matches = static_cast<GlobalAddress<V>>(e.vs->getReadBuffer());
          lr.num = e.vs->size();
        }

        return lr;
      });

      *vals = result.matches;
      return result.num;
    }

    // version of lookup that takes a continuation instead of returning results back
    template< typename CF, Grappa::GlobalCompletionEvent * GCE = &Grappa::impl::local_gce >
    void lookup_iter ( K key, CF f ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      // FIXME: remove 'this' capture when using gcc4.8, this is just a bug in 4.7
      //TODO optimization where only need to do remotePrivateTask instead of call_async
      //if you are going to do more suspending ops (comms) inside the loop
      if (target.core() == Grappa::mycore()) {
        hash_local_lookups++;
      } else {
        hash_remote_lookups++;
      }
      Grappa::spawnRemote<GCE>( target.core(), [key, target, f, this]() {
        hash_called_lookups++;
        Entry e;
        if (lookup_local( key, target.pointer(), &e)) {
          auto resultsptr = e.vs;
          Grappa::forall_here<async,GCE>(0, e.vs->size(), [f,resultsptr](int64_t start, int64_t iters) {
            for  (int64_t i=start; i<start+iters; i++) {
              auto results = *resultsptr;
              // call the continuation with the lookup result
              f(results[i]);
            }
          });
        }
      });
    }
    template< Grappa::GlobalCompletionEvent * GCE, typename CF >
    void lookup_iter ( K key, CF f ) {
      lookup_iter<CF, GCE>(key, f);
    }

    // version of lookup that takes a continuation instead of returning results back
    template< typename CF, Grappa::GlobalCompletionEvent * GCE = &Grappa::impl::local_gce >
    void lookup ( K key, CF f ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      Grappa::delegate::call<async>( target.core(), [key, target, f]() {
        hash_called_lookups++;
        Entry e;
        if (lookup_local( key, target.pointer(), &e)) {
          uint64_t len = e.vs->size();
          f(e.vs, len);
        }
      });
    }

    // Inserts the key if not already in the set
    // Shouldn't be used with `insert`.
    //
    // returns true if the set already contains the key
    void insert_unique( K key, V val ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;
      Grappa::delegate::call( target.core(), [key,val,target]() {   // TODO: have an additional version that returns void
                                                                 // to upgrade to call_async
        hash_called_inserts++;

        // list of entries in this cell
        std::list<MDHT_TYPE(Entry)> * entries = target.pointer()->entries;

        // if first time the cell is hit then initialize
        if ( entries == NULL ) {
          entries = new std::list<Entry>();
          target.pointer()->entries = entries;
        }

        // find matching key in the list
        typename std::list<MDHT_TYPE(Entry)>::iterator i;
        for (i = entries->begin(); i!=entries->end(); ++i) {
          Entry e = *i;
          if ( e.key == key ) {
            // key found so no insert
            return;
          }
        }

        // this is the first time the key has been seen
        // so add it to the list
        Entry newe( key );        // TODO: cleanup since sharing insert* code here, we are just going to store an empty vector
        newe.vs->push_back( val );
                                  // perhaps a different module
        entries->push_back( newe );

        return;
     });
    }

    void insert( K key, V val ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      if (target.core() == Grappa::mycore()) {
        hash_local_inserts++;
      } else {
        hash_remote_inserts++;
      }
      Grappa::delegate::call( target.core(), [key, val, target]() {   // TODO: upgrade to call_async; using GCE
        hash_called_inserts++;

        // list of entries in this cell
        std::list<MDHT_TYPE(Entry)> * entries = target.pointer()->entries;

        // if first time the cell is hit then initialize
        if ( entries == NULL ) {
          entries = new std::list<Entry>();
          target.pointer()->entries = entries;
        }

        // find matching key in the list
        typename std::list<MDHT_TYPE(Entry)>::iterator i;
        for (i = entries->begin(); i!=entries->end(); ++i) {
          Entry e = *i;
          if ( e.key == key ) {
            // key found so add to matches
            e.vs->push_back( val );
            hash_tables_size+=1;
            return 0;
          }
        }

        // this is the first time the key has been seen
        // so add it to the list
        Entry newe( key );
        newe.vs->push_back( val );
        entries->push_back( newe );

        return 0;
      });
    }

};

#endif // MATCHES_DHT_HPP
<commit_msg>insert_async...again<commit_after>#ifndef MATCHES_DHT_HPP
#define MATCHES_DHT_HPP

#include <Grappa.hpp>
#include <GlobalAllocator.hpp>
#include <GlobalCompletionEvent.hpp>
#include <ParallelLoop.hpp>
#include <BufferVector.hpp>
#include <Metrics.hpp>

#include <list>
#include <cmath>

//GRAPPA_DECLARE_METRIC(MaxMetric<uint64_t>, max_cell_length);
GRAPPA_DECLARE_METRIC(SimpleMetric<uint64_t>, hash_tables_size);
GRAPPA_DECLARE_METRIC(SummarizingMetric<uint64_t>, hash_tables_lookup_steps);

GRAPPA_DECLARE_METRIC(SimpleMetric<uint64_t>, hash_remote_lookups);
GRAPPA_DECLARE_METRIC(SimpleMetric<uint64_t>, hash_remote_inserts);
GRAPPA_DECLARE_METRIC(SimpleMetric<uint64_t>, hash_local_lookups);
GRAPPA_DECLARE_METRIC(SimpleMetric<uint64_t>, hash_local_inserts);
GRAPPA_DECLARE_METRIC(SimpleMetric<uint64_t>, hash_called_lookups);
GRAPPA_DECLARE_METRIC(SimpleMetric<uint64_t>, hash_called_inserts);

// for naming the types scoped in MatchesDHT
#define MDHT_TYPE(type) typename MatchesDHT<K,V,HF>::type

// Hash table for joins
// * allows multiple copies of a Key
// * lookups return all Key matches
template <typename K, typename V, uint64_t (*HF)(K)>
class MatchesDHT {

  private:
    struct Entry {
      K key;
      std::vector<V> * vs;
      //BufferVector<V> * vs;
      Entry( K key ) : key(key), vs(new std::vector<V>()) {}
      //Entry( K key ) : key(key), vs(new BufferVector<V>( 16 )) {}
      Entry ( ) {}
    };

    struct Cell {
      std::list<Entry> * entries;

      Cell() : entries( NULL ) {}
    };

    struct lookup_result {
      GlobalAddress<V> matches;
      size_t num;
    };

    // private members
    GlobalAddress< Cell > base;
    size_t capacity;

    uint64_t computeIndex( K key ) {
      return HF(key) & (capacity - 1);
    }

    // for creating local MatchesDHT
    MatchesDHT( GlobalAddress<Cell> base, uint32_t capacity_pow2 ) {
      this->base = base;
      this->capacity = capacity_pow2;
    }

    static bool lookup_local( K key, Cell * target, Entry * result ) {
        std::list<MDHT_TYPE(Entry)> * entries = target->entries;

        // first check if the cell has any entries;
        // if not then the lookup returns nothing
        if ( entries == NULL ) return false;

        typename std::list<MDHT_TYPE(Entry)>::iterator i;
        uint64_t steps = 1;
        for (i = entries->begin(); i!=entries->end(); ++i) {
          const Entry e = *i;
          if ( e.key == key ) {  // typename K must implement operator==
            *result = e;
            hash_tables_lookup_steps += steps;
            return true;
          }
          ++steps;
        }
        hash_tables_lookup_steps += steps;
        return false;
    }

  public:
    // for static construction
    MatchesDHT( ) {}

    static void init_global_DHT( MatchesDHT<K,V,HF> * globally_valid_local_pointer, size_t capacity ) {

      uint32_t capacity_exp = log2(capacity);
      size_t capacity_powerof2 = pow(2, capacity_exp);
      GlobalAddress<Cell> base = Grappa::global_alloc<Cell>( capacity_powerof2 );

      Grappa::on_all_cores( [globally_valid_local_pointer,base,capacity_powerof2] {
        *globally_valid_local_pointer = MatchesDHT<K,V,HF>( base, capacity_powerof2 );
      });

      Grappa::forall( base, capacity_powerof2, []( int64_t i, Cell& c ) {
        Cell empty;
        c = empty;
      });
    }

    struct size_aligned {
      size_t s;

      size_aligned operator+(const size_aligned& o) const {
        size_aligned v;
        v.s = this->s + o.s;
        return v;
      }
    } GRAPPA_BLOCK_ALIGNED;

   size_t size() {
     auto l_size = Grappa::symmetric_global_alloc<size_aligned>();
     Grappa::forall( base, capacity, [l_size](int64_t i, Cell& c) {
       if (c.entries != NULL) {
         for (auto eiter = c.entries->begin(); eiter != c.entries->end(); ++eiter) {
           l_size->s += eiter->vs->size();
         }
       }
     });
    return Grappa::reduce<size_aligned, COLL_ADD>(l_size ).s;
        //FIXME: mem leak l_size
   }

    static void set_RO_global( MatchesDHT<K,V,HF> * globally_valid_local_pointer ) {
      Grappa::forall( globally_valid_local_pointer->base, globally_valid_local_pointer->capacity, []( int64_t i, Cell& c ) {
        // list of entries in this cell
        std::list<MDHT_TYPE(Entry)> * entries = c.entries;

        // if cell is not hit then no action
        if ( entries == NULL ) {
          return;
        }

        uint64_t sum_size = 0;
        // for all keys, set match vector to RO
        typename std::list<MDHT_TYPE(Entry)>::iterator it;
        for (it = entries->begin(); it!=entries->end(); ++it) {
          Entry e = *it;
          //e.vs->setReadMode();
          sum_size+=e.vs->size();
        }
        //max_cell_length.add(sum_size);
      });
    }

    uint64_t lookup ( K key, GlobalAddress<V> * vals ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      // FIXME: remove 'this' capture when using gcc4.8, this is just a bug in 4.7
      lookup_result result = Grappa::delegate::call( target.core(), [key,target,this]() {
        hash_called_lookups++;

        MDHT_TYPE(lookup_result) lr;
        lr.num = 0;

        Entry e;
        if (lookup_local( key, target.pointer(), &e)) {
         // lr.matches = static_cast<GlobalAddress<V>>(e.vs->getReadBuffer());
          lr.num = e.vs->size();
        }

        return lr;
      });

      *vals = result.matches;
      return result.num;
    }

    // version of lookup that takes a continuation instead of returning results back
    template< typename CF, Grappa::GlobalCompletionEvent * GCE = &Grappa::impl::local_gce >
    void lookup_iter ( K key, CF f ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      // FIXME: remove 'this' capture when using gcc4.8, this is just a bug in 4.7
      //TODO optimization where only need to do remotePrivateTask instead of call_async
      //if you are going to do more suspending ops (comms) inside the loop
      if (target.core() == Grappa::mycore()) {
        hash_local_lookups++;
      } else {
        hash_remote_lookups++;
      }
      Grappa::spawnRemote<GCE>( target.core(), [key, target, f, this]() {
        hash_called_lookups++;
        Entry e;
        if (lookup_local( key, target.pointer(), &e)) {
          auto resultsptr = e.vs;
          Grappa::forall_here<async,GCE>(0, e.vs->size(), [f,resultsptr](int64_t start, int64_t iters) {
            for  (int64_t i=start; i<start+iters; i++) {
              auto results = *resultsptr;
              // call the continuation with the lookup result
              f(results[i]);
            }
          });
        }
      });
    }
    template< Grappa::GlobalCompletionEvent * GCE, typename CF >
    void lookup_iter ( K key, CF f ) {
      lookup_iter<CF, GCE>(key, f);
    }

    // version of lookup that takes a continuation instead of returning results back
    template< typename CF, Grappa::GlobalCompletionEvent * GCE = &Grappa::impl::local_gce >
    void lookup ( K key, CF f ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      Grappa::delegate::call<async>( target.core(), [key, target, f]() {
        hash_called_lookups++;
        Entry e;
        if (lookup_local( key, target.pointer(), &e)) {
          uint64_t len = e.vs->size();
          f(e.vs, len);
        }
      });
    }

    // Inserts the key if not already in the set
    // Shouldn't be used with `insert`.
    //
    // returns true if the set already contains the key
    void insert_unique( K key, V val ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;
      Grappa::delegate::call( target.core(), [key,val,target]() {   // TODO: have an additional version that returns void
                                                                 // to upgrade to call_async
        hash_called_inserts++;

        // list of entries in this cell
        std::list<MDHT_TYPE(Entry)> * entries = target.pointer()->entries;

        // if first time the cell is hit then initialize
        if ( entries == NULL ) {
          entries = new std::list<Entry>();
          target.pointer()->entries = entries;
        }

        // find matching key in the list
        typename std::list<MDHT_TYPE(Entry)>::iterator i;
        for (i = entries->begin(); i!=entries->end(); ++i) {
          Entry e = *i;
          if ( e.key == key ) {
            // key found so no insert
            return;
          }
        }

        // this is the first time the key has been seen
        // so add it to the list
        Entry newe( key );        // TODO: cleanup since sharing insert* code here, we are just going to store an empty vector
        newe.vs->push_back( val );
                                  // perhaps a different module
        entries->push_back( newe );

        return;
     });
    }

    template< Grappa::GlobalCompletionEvent * GCE = &Grappa::impl::local_gce >
    void insert_async( K key, V val ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      if (target.core() == Grappa::mycore()) {
        hash_local_inserts++;
      } else {
        hash_remote_inserts++;
      }
      Grappa::delegate::call<async, GCE>( target.core(), [key, val, target]() {   // TODO: upgrade to call_async; using GCE
        hash_called_inserts++;

        // list of entries in this cell
        std::list<MDHT_TYPE(Entry)> * entries = target.pointer()->entries;

        // if first time the cell is hit then initialize
        if ( entries == NULL ) {
          entries = new std::list<Entry>();
          target.pointer()->entries = entries;
        }

        // find matching key in the list
        typename std::list<MDHT_TYPE(Entry)>::iterator i;
        for (i = entries->begin(); i!=entries->end(); ++i) {
          Entry e = *i;
          if ( e.key == key ) {
            // key found so add to matches
            e.vs->push_back( val );
            hash_tables_size+=1;
            return;
          }
        }

        // this is the first time the key has been seen
        // so add it to the list
        Entry newe( key );
        newe.vs->push_back( val );
        entries->push_back( newe );

        return;
      });
    }

};

#endif // MATCHES_DHT_HPP
<|endoftext|>


<commit_before>// Source : https://leetcode.com/problems/happy-number/
// Author : Hao Chen
// Date   : 2015-06-08

/**********************************************************************************
 *
 * Write an algorithm to determine if a number is "happy".
 *
 * A happy number is a number defined by the following process: Starting with any positive integer,
 * replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1
 * (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this
 * process ends in 1 are happy numbers.
 *
 * Example: 19 is a happy number
 *
 * 12 + 92 = 82
 * 82 + 22 = 68
 * 62 + 82 = 100
 * 12 + 02 + 02 = 1
 *
 * Credits:Special thanks to @mithmatt and @ts for adding this problem and creating all test cases.
 *
 **********************************************************************************/
#include <stdlib.h>
#include <iostream>
#include <map>
using namespace std;

int squares(int n) {
    int result = 0;
    int sq = 0;
    for (; n>0; n/=10) {
        sq = n%10;
        result += (sq * sq);
    }
    return result;
}

bool isHappy(int n) {

    if (n==1) return true;

    map<int, bool> m;
    m[n]=true;

    while (n!=1) {
        n = squares(n);
cout << n << endl;
        if (m.find(n) != m.end()){
            return false;
        }
        m[n] = true;
    }

    return true;
}

int main(int argc, char** argv)
{
    int n = 2;
    if (argc > 1){
        n = atoi(argv[1]);
    }
    cout << n << (isHappy(n) ? " is " : " isn't ") << "a happy number" << endl;
    return 0;
}
<commit_msg>remove debug information<commit_after>// Source : https://leetcode.com/problems/happy-number/
// Author : Hao Chen
// Date   : 2015-06-08

/**********************************************************************************
 *
 * Write an algorithm to determine if a number is "happy".
 *
 * A happy number is a number defined by the following process: Starting with any positive integer,
 * replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1
 * (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this
 * process ends in 1 are happy numbers.
 *
 * Example: 19 is a happy number
 *
 * 12 + 92 = 82
 * 82 + 22 = 68
 * 62 + 82 = 100
 * 12 + 02 + 02 = 1
 *
 * Credits:Special thanks to @mithmatt and @ts for adding this problem and creating all test cases.
 *
 **********************************************************************************/
#include <stdlib.h>
#include <iostream>
#include <map>
using namespace std;

int squares(int n) {
    int result = 0;
    int sq = 0;
    for (; n>0; n/=10) {
        sq = n%10;
        result += (sq * sq);
    }
    return result;
}

bool isHappy(int n) {

    if (n==1) return true;

    map<int, bool> m;
    m[n]=true;

    while (n!=1) {
        n = squares(n);
        //cout << n << endl;
        if (m.find(n) != m.end()){
            return false;
        }
        m[n] = true;
    }

    return true;
}

int main(int argc, char** argv)
{
    int n = 2;
    if (argc > 1){
        n = atoi(argv[1]);
    }
    cout << n << (isHappy(n) ? " is " : " isn't ") << "a happy number" << endl;
    return 0;
}
<|endoftext|>


<commit_before>//
// Copyright (C) 2017 by the linalgwrap authors
//
/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

Bohrium is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3
of the License, or (at your option) any later version.

Bohrium is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once

#include <bhxx/BhArray.hpp>
#include <bhxx/Runtime.hpp>
#include <bhxx/array_operations.hpp>
#include <bhxx/util.hpp>
<commit_msg>bhxx: including random and array_creation in bhxx.hpp<commit_after>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

Bohrium is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3
of the License, or (at your option) any later version.

Bohrium is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once

#include <bhxx/BhArray.hpp>
#include <bhxx/Runtime.hpp>
#include <bhxx/array_operations.hpp>
#include <bhxx/util.hpp>
#include <bhxx/random.hpp>
#include <bhxx/array_create.hpp>
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include "ccode.hpp"

#include <kdblogger.h>

namespace
{

/**
 * @brief Cast a character to an unsigned character.
 *
 * @param character This parameter specifies the character this function casts to an unsigned value.
 *
 * @return A unsigned character corresponding to the given argument
 */
inline constexpr unsigned char operator"" _uc (char character) noexcept
{
	return static_cast<unsigned char> (character);
}

/**
 * @brief This function maps hex characters to integer numbers.
 *
 * @pre The specified character has to be between
 *
 *      - `'0'`–`'9'`,
 *      - `'a'`-`'f'`, or
 *      - `'A'`-`'F'`
 *
 *     .
 *
 * @param character This argument specifies the (hexadecimal) character this function converts.
 *
 * @return An integer number between `0` and `15` if the precondition is valid or `0` otherwise
 */
inline int elektraHexcodeConvFromHex (char character)
{
	if (character >= '0' && character <= '9') return character - '0';
	if (character >= 'a' && character <= 'f') return character - 'a' + 10;
	if (character >= 'A' && character <= 'F') return character - 'A' + 10;

	return 0; /* Unknown escape char */
}

} // end namespace

using namespace ckdb;
extern "C" {

/**
 * @brief This function sets default values for the encoding and decoding character mapping.
 *
 * @param mapping This parameter stores the encoding and decoding table this function fills with default values.
 */
void setDefaultConfig (CCodeData * const mapping)
{
	unsigned char pairs[][2] = { { '\b'_uc, 'b'_uc }, { '\t'_uc, 't'_uc }, { '\n'_uc, 'n'_uc },  { '\v'_uc, 'v'_uc },
				     { '\f'_uc, 'f'_uc }, { '\r'_uc, 'r'_uc }, { '\\'_uc, '\\'_uc }, { '\''_uc, '\''_uc },
				     { '\"'_uc, '"'_uc }, { '\0'_uc, '0'_uc } };

	for (size_t pair = 0; pair < sizeof (pairs) / sizeof (pairs[0]); pair++)
	{
		unsigned char character = pairs[pair][0];
		unsigned char replacement = pairs[pair][1];

		mapping->encode[character] = replacement;
		mapping->decode[replacement] = character;
	}
}

/**
 * @brief This function sets values for the encoding and decoding character mapping.
 *
 * @param mapping This parameter stores the encoding and decoding table this function fills with the values specified in `config`.
 * @param config This key set stores the character mappings this function stores inside `mappings`.
 * @param root This key stores the root key for the character mapping stored in `config`.
 */
void readConfig (CCodeData * const mapping, KeySet * const config, Key const * const root)
{
	Key const * key = 0;
	while ((key = ksNext (config)) != 0)
	{
		/* Ignore keys that are not directly below the config root key or have an incorrect size */
		if (keyRel (root, key) != 1 || keyGetBaseNameSize (key) != 3 || keyGetValueSize (key) != 3) continue;

		int character = elektraHexcodeConvFromHex (keyBaseName (key)[1]);
		character += elektraHexcodeConvFromHex (keyBaseName (key)[0]) * 16;

		int replacement = elektraHexcodeConvFromHex (keyString (key)[1]);
		replacement += elektraHexcodeConvFromHex (keyString (key)[0]) * 16;

		/* Hexencode this character! */
		mapping->encode[character & 255] = replacement;
		mapping->decode[replacement & 255] = character;
	}
}

int elektraCcodeOpen (Plugin * handle, Key * key ELEKTRA_UNUSED)
{
	CCodeData * mapping = new CCodeData ();

	/* Store for later use...*/
	elektraPluginSetData (handle, mapping);

	KeySet * config = elektraPluginGetConfig (handle);

	Key * escape = ksLookupByName (config, "/escape", 0);
	mapping->escape = '\\';
	if (escape && keyGetBaseNameSize (escape) && keyGetValueSize (escape) == 3)
	{
		int res;
		res = elektraHexcodeConvFromHex (keyString (escape)[1]);
		res += elektraHexcodeConvFromHex (keyString (escape)[0]) * 16;

		mapping->escape = res & 255;
	}
	ELEKTRA_LOG_DEBUG ("Use “%c” as escape character", mapping->escape);

	Key * root = ksLookupByName (config, "/chars", 0);

	if (root)
	{
		readConfig (mapping, config, root);
	}
	else
	{
		setDefaultConfig (mapping);
	}

	return 0;
}

int elektraCcodeClose (Plugin * handle, Key * key ELEKTRA_UNUSED)
{
	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));

	delete[](mapping->buf);
	delete (mapping);

	return 0;
}

/** Reads the value of the key and decodes all escaping
 * codes into the buffer.
 * @pre the buffer needs to be as large as value's size.
 * @param cur the key holding the value to decode
 * @param mapping the buffer to write to
 */
void elektraCcodeDecode (Key * cur, CCodeData * mapping)
{
	size_t valsize = keyGetValueSize (cur);
	const char * val = static_cast<const char *> (keyValue (cur));

	if (!val) return;

	size_t out = 0;
	for (size_t in = 0; in < valsize - 1; ++in)
	{
		unsigned char character = val[in];

		if (character == mapping->escape)
		{
			++in; /* Advance twice */
			character = val[in];

			mapping->buf[out] = mapping->decode[character & 255];
		}
		else
		{
			mapping->buf[out] = character;
		}
		++out; /* Only one char is written */
	}

	mapping->buf[out] = 0; // null termination for keyString()

	keySetRaw (cur, mapping->buf, out + 1);
}

int elektraCcodeGet (Plugin * handle, KeySet * returned, Key * parentKey)
{
	/* get all keys */

	if (!strcmp (keyName (parentKey), "system/elektra/modules/ccode"))
	{
		KeySet * pluginConfig =
			ksNew (30, keyNew ("system/elektra/modules/ccode", KEY_VALUE, "ccode plugin waits for your orders", KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports", KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/open", KEY_FUNC, elektraCcodeOpen, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/close", KEY_FUNC, elektraCcodeClose, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/get", KEY_FUNC, elektraCcodeGet, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/set", KEY_FUNC, elektraCcodeSet, KEY_END),
#include "readme_ccode.c"
			       keyNew ("system/elektra/modules/ccode/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
		ksAppend (returned, pluginConfig);
		ksDel (pluginConfig);
		return 1;
	}

	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));
	if (!mapping->buf)
	{
		mapping->bufalloc = 1000;
		mapping->buf = new unsigned char[mapping->bufalloc];
	}

	Key * cur;
	ksRewind (returned);
	while ((cur = ksNext (returned)) != 0)
	{
		size_t valsize = keyGetValueSize (cur);
		if (valsize > mapping->bufalloc)
		{
			mapping->bufalloc = valsize;
			mapping->buf = new unsigned char[mapping->bufalloc];
		}

		elektraCcodeDecode (cur, mapping);
	}

	return 1; /* success */
}

/** Reads the value of the key and encodes it in
 * c-style in the buffer.
 *
 * @param cur the key which value is to encode
 * @param mapping the buffer
 * @pre the buffer needs to have twice as much space as the value's size
 */
void elektraCcodeEncode (Key * cur, CCodeData * mapping)
{
	size_t valsize = keyGetValueSize (cur);
	const char * val = static_cast<const char *> (keyValue (cur));

	if (!val) return;

	size_t out = 0;
	for (size_t in = 0; in < valsize - 1; ++in)
	{
		unsigned char character = val[in];

		if (mapping->encode[character])
		{
			mapping->buf[out + 1] = mapping->encode[character];
			// Escape char
			mapping->buf[out] = mapping->escape;
			out += 2;
		}
		else
		{
			// just copy one character
			mapping->buf[out] = val[in];
			// advance out cursor
			out++;
			// go to next char
		}
	}

	mapping->buf[out] = 0; // null termination for keyString()

	keySetRaw (cur, mapping->buf, out + 1);
}

int elektraCcodeSet (Plugin * handle, KeySet * returned, Key * parentKey ELEKTRA_UNUSED)
{
	/* set all keys */
	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));
	if (!mapping->buf)
	{
		mapping->bufalloc = 1000;
		mapping->buf = new unsigned char[mapping->bufalloc];
	}

	Key * cur;
	ksRewind (returned);
	while ((cur = ksNext (returned)) != 0)
	{
		size_t valsize = keyGetValueSize (cur);
		if (valsize * 2 > mapping->bufalloc)
		{
			mapping->bufalloc = valsize * 2;
			mapping->buf = new unsigned char[mapping->bufalloc];
		}

		elektraCcodeEncode (cur, mapping);
	}

	return 1; /* success */
}

Plugin * ELEKTRA_PLUGIN_EXPORT (ccode)
{
	// clang-format off
	return elektraPluginExport("ccode",
		ELEKTRA_PLUGIN_OPEN,	&elektraCcodeOpen,
		ELEKTRA_PLUGIN_CLOSE,	&elektraCcodeClose,
		ELEKTRA_PLUGIN_GET,	&elektraCcodeGet,
		ELEKTRA_PLUGIN_SET,	&elektraCcodeSet,
		ELEKTRA_PLUGIN_END);
}

} // end extern "C"
<commit_msg>CCode: Group plugin interface functions<commit_after>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include "ccode.hpp"

#include <kdblogger.h>

namespace
{

/**
 * @brief Cast a character to an unsigned character.
 *
 * @param character This parameter specifies the character this function casts to an unsigned value.
 *
 * @return A unsigned character corresponding to the given argument
 */
inline constexpr unsigned char operator"" _uc (char character) noexcept
{
	return static_cast<unsigned char> (character);
}

/**
 * @brief This function maps hex characters to integer numbers.
 *
 * @pre The specified character has to be between
 *
 *      - `'0'`–`'9'`,
 *      - `'a'`-`'f'`, or
 *      - `'A'`-`'F'`
 *
 *     .
 *
 * @param character This argument specifies the (hexadecimal) character this function converts.
 *
 * @return An integer number between `0` and `15` if the precondition is valid or `0` otherwise
 */
inline int elektraHexcodeConvFromHex (char character)
{
	if (character >= '0' && character <= '9') return character - '0';
	if (character >= 'a' && character <= 'f') return character - 'a' + 10;
	if (character >= 'A' && character <= 'F') return character - 'A' + 10;

	return 0; /* Unknown escape char */
}

} // end namespace

using namespace ckdb;
extern "C" {

/**
 * @brief This function sets default values for the encoding and decoding character mapping.
 *
 * @param mapping This parameter stores the encoding and decoding table this function fills with default values.
 */
void setDefaultConfig (CCodeData * const mapping)
{
	unsigned char pairs[][2] = { { '\b'_uc, 'b'_uc }, { '\t'_uc, 't'_uc }, { '\n'_uc, 'n'_uc },  { '\v'_uc, 'v'_uc },
				     { '\f'_uc, 'f'_uc }, { '\r'_uc, 'r'_uc }, { '\\'_uc, '\\'_uc }, { '\''_uc, '\''_uc },
				     { '\"'_uc, '"'_uc }, { '\0'_uc, '0'_uc } };

	for (size_t pair = 0; pair < sizeof (pairs) / sizeof (pairs[0]); pair++)
	{
		unsigned char character = pairs[pair][0];
		unsigned char replacement = pairs[pair][1];

		mapping->encode[character] = replacement;
		mapping->decode[replacement] = character;
	}
}

/**
 * @brief This function sets values for the encoding and decoding character mapping.
 *
 * @param mapping This parameter stores the encoding and decoding table this function fills with the values specified in `config`.
 * @param config This key set stores the character mappings this function stores inside `mappings`.
 * @param root This key stores the root key for the character mapping stored in `config`.
 */
void readConfig (CCodeData * const mapping, KeySet * const config, Key const * const root)
{
	Key const * key = 0;
	while ((key = ksNext (config)) != 0)
	{
		/* Ignore keys that are not directly below the config root key or have an incorrect size */
		if (keyRel (root, key) != 1 || keyGetBaseNameSize (key) != 3 || keyGetValueSize (key) != 3) continue;

		int character = elektraHexcodeConvFromHex (keyBaseName (key)[1]);
		character += elektraHexcodeConvFromHex (keyBaseName (key)[0]) * 16;

		int replacement = elektraHexcodeConvFromHex (keyString (key)[1]);
		replacement += elektraHexcodeConvFromHex (keyString (key)[0]) * 16;

		/* Hexencode this character! */
		mapping->encode[character & 255] = replacement;
		mapping->decode[replacement & 255] = character;
	}
}

/** Reads the value of the key and decodes all escaping
 * codes into the buffer.
 * @pre the buffer needs to be as large as value's size.
 * @param cur the key holding the value to decode
 * @param mapping the buffer to write to
 */
void elektraCcodeDecode (Key * cur, CCodeData * mapping)
{
	size_t valsize = keyGetValueSize (cur);
	const char * val = static_cast<const char *> (keyValue (cur));

	if (!val) return;

	size_t out = 0;
	for (size_t in = 0; in < valsize - 1; ++in)
	{
		unsigned char character = val[in];

		if (character == mapping->escape)
		{
			++in; /* Advance twice */
			character = val[in];

			mapping->buf[out] = mapping->decode[character & 255];
		}
		else
		{
			mapping->buf[out] = character;
		}
		++out; /* Only one char is written */
	}

	mapping->buf[out] = 0; // null termination for keyString()

	keySetRaw (cur, mapping->buf, out + 1);
}

/** Reads the value of the key and encodes it in
 * c-style in the buffer.
 *
 * @param cur the key which value is to encode
 * @param mapping the buffer
 * @pre the buffer needs to have twice as much space as the value's size
 */
void elektraCcodeEncode (Key * cur, CCodeData * mapping)
{
	size_t valsize = keyGetValueSize (cur);
	const char * val = static_cast<const char *> (keyValue (cur));

	if (!val) return;

	size_t out = 0;
	for (size_t in = 0; in < valsize - 1; ++in)
	{
		unsigned char character = val[in];

		if (mapping->encode[character])
		{
			mapping->buf[out + 1] = mapping->encode[character];
			// Escape char
			mapping->buf[out] = mapping->escape;
			out += 2;
		}
		else
		{
			// just copy one character
			mapping->buf[out] = val[in];
			// advance out cursor
			out++;
			// go to next char
		}
	}

	mapping->buf[out] = 0; // null termination for keyString()

	keySetRaw (cur, mapping->buf, out + 1);
}

// ====================
// = Plugin Interface =
// ====================

int elektraCcodeOpen (Plugin * handle, Key * key ELEKTRA_UNUSED)
{
	CCodeData * mapping = new CCodeData ();

	/* Store for later use...*/
	elektraPluginSetData (handle, mapping);

	KeySet * config = elektraPluginGetConfig (handle);

	Key * escape = ksLookupByName (config, "/escape", 0);
	mapping->escape = '\\';
	if (escape && keyGetBaseNameSize (escape) && keyGetValueSize (escape) == 3)
	{
		int res;
		res = elektraHexcodeConvFromHex (keyString (escape)[1]);
		res += elektraHexcodeConvFromHex (keyString (escape)[0]) * 16;

		mapping->escape = res & 255;
	}
	ELEKTRA_LOG_DEBUG ("Use “%c” as escape character", mapping->escape);

	Key * root = ksLookupByName (config, "/chars", 0);

	if (root)
	{
		readConfig (mapping, config, root);
	}
	else
	{
		setDefaultConfig (mapping);
	}

	return 0;
}

int elektraCcodeClose (Plugin * handle, Key * key ELEKTRA_UNUSED)
{
	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));

	delete[](mapping->buf);
	delete (mapping);

	return 0;
}

int elektraCcodeGet (Plugin * handle, KeySet * returned, Key * parentKey)
{
	/* get all keys */

	if (!strcmp (keyName (parentKey), "system/elektra/modules/ccode"))
	{
		KeySet * pluginConfig =
			ksNew (30, keyNew ("system/elektra/modules/ccode", KEY_VALUE, "ccode plugin waits for your orders", KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports", KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/open", KEY_FUNC, elektraCcodeOpen, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/close", KEY_FUNC, elektraCcodeClose, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/get", KEY_FUNC, elektraCcodeGet, KEY_END),
			       keyNew ("system/elektra/modules/ccode/exports/set", KEY_FUNC, elektraCcodeSet, KEY_END),
#include "readme_ccode.c"
			       keyNew ("system/elektra/modules/ccode/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
		ksAppend (returned, pluginConfig);
		ksDel (pluginConfig);
		return 1;
	}

	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));
	if (!mapping->buf)
	{
		mapping->bufalloc = 1000;
		mapping->buf = new unsigned char[mapping->bufalloc];
	}

	Key * cur;
	ksRewind (returned);
	while ((cur = ksNext (returned)) != 0)
	{
		size_t valsize = keyGetValueSize (cur);
		if (valsize > mapping->bufalloc)
		{
			mapping->bufalloc = valsize;
			mapping->buf = new unsigned char[mapping->bufalloc];
		}

		elektraCcodeDecode (cur, mapping);
	}

	return 1; /* success */
}

int elektraCcodeSet (Plugin * handle, KeySet * returned, Key * parentKey ELEKTRA_UNUSED)
{
	/* set all keys */
	CCodeData * mapping = static_cast<CCodeData *> (elektraPluginGetData (handle));
	if (!mapping->buf)
	{
		mapping->bufalloc = 1000;
		mapping->buf = new unsigned char[mapping->bufalloc];
	}

	Key * cur;
	ksRewind (returned);
	while ((cur = ksNext (returned)) != 0)
	{
		size_t valsize = keyGetValueSize (cur);
		if (valsize * 2 > mapping->bufalloc)
		{
			mapping->bufalloc = valsize * 2;
			mapping->buf = new unsigned char[mapping->bufalloc];
		}

		elektraCcodeEncode (cur, mapping);
	}

	return 1; /* success */
}

Plugin * ELEKTRA_PLUGIN_EXPORT (ccode)
{
	// clang-format off
	return elektraPluginExport("ccode",
		ELEKTRA_PLUGIN_OPEN,	&elektraCcodeOpen,
		ELEKTRA_PLUGIN_CLOSE,	&elektraCcodeClose,
		ELEKTRA_PLUGIN_GET,	&elektraCcodeGet,
		ELEKTRA_PLUGIN_SET,	&elektraCcodeSet,
		ELEKTRA_PLUGIN_END);
}

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


<commit_before>#include <process/timer.hpp>

namespace process {

class TimerProcess : public Process<TimerProcess>
{
public:
  TimerProcess(double _secs,
               const UPID& _pid,
               std::tr1::function<void(ProcessBase*)>* _dispatcher)
    : secs(_secs), pid(_pid), dispatcher(_dispatcher) {}

protected:
  virtual void operator () ()
  {
    if (receive(secs) == TIMEOUT) {
      internal::dispatch(pid, dispatcher);
    } else {
      delete dispatcher;
    }
  }

private:
  const double secs;
  const UPID pid;
  std::tr1::function<void(ProcessBase*)>* dispatcher;
};

Timer::Timer(double secs,
             const UPID& pid,
             std::tr1::function<void(ProcessBase*)>* dispatcher)
{
  timer = spawn(new TimerProcess(secs, pid, dispatcher), true);
}

Timer::~Timer() {}

void Timer::cancel()
{
  terminate(timer);
}

} // namespace process {
<commit_msg>Added a comment.<commit_after>#include <process/timer.hpp>

namespace process {

class TimerProcess : public Process<TimerProcess>
{
public:
  TimerProcess(double _secs,
               const UPID& _pid,
               std::tr1::function<void(ProcessBase*)>* _dispatcher)
    : secs(_secs), pid(_pid), dispatcher(_dispatcher) {}

protected:
  virtual void operator () ()
  {
    if (receive(secs) == TIMEOUT) {
      internal::dispatch(pid, dispatcher);
    } else {
      delete dispatcher;
    }
  }

private:
  const double secs;
  const UPID pid;
  std::tr1::function<void(ProcessBase*)>* dispatcher;
};

Timer::Timer(double secs,
             const UPID& pid,
             std::tr1::function<void(ProcessBase*)>* dispatcher)
{
  timer = spawn(new TimerProcess(secs, pid, dispatcher), true);
}

Timer::~Timer()
{
  // NOTE: Do not terminate the timer! Some users will simply ignore
  // saving the timer because they never want to cancel, thus
  // we can not terminate it here!
}

void Timer::cancel()
{
  terminate(timer);
}

} // namespace process {
<|endoftext|>


<commit_before>#include "model.h"

#include <algorithm>
#include <functional>
#include <locale>

using namespace std;

TypeUsage::TypeUsage(const ObjectSchema& schema)
    : scope(schema.scope), name(schema.name), baseName(schema.name)
{ }

TypeUsage TypeUsage::instantiate(vector<TypeUsage>&& innerTypes) const
{
    TypeUsage tu = *this;
    for (auto&& innerType: innerTypes)
    {
        tu.innerTypes.emplace_back(innerType);

        auto& tuImports = tu.lists["imports"];
        const auto singleInnerImport = innerType.attributes.find("imports");
        if (singleInnerImport != innerType.attributes.end())
            tuImports.push_back(singleInnerImport->second);
        const auto innerImports = innerType.lists.find("imports");
        if (innerImports != innerType.lists.end())
            tuImports.insert(tuImports.end(),
                             innerImports->second.begin(),
                             innerImports->second.end());
    }

    return tu;
}

void capitalize(string& s, string::size_type pos = 0)
{
    if (pos < s.size())
        s[pos] = toupper(s[pos], locale::classic());
}

string capitalizedCopy(string s)
{
    capitalize(s);
    return s;
}

string camelCase(string s)
{
    string::size_type pos = 0;
    while (pos < s.size())
    {
        capitalize(s, pos);
        pos = s.find_first_of("/_ .-:", pos);
        if (pos == string::npos)
            break;
        // Do not erase '_' at the beginning or the end of an identifier
        if (s[pos] != '_' || (pos != 0 && pos != s.size() - 1))
            s.erase(pos, 1);
        else
            ++pos;
    }
    // Remove all remaining non-identifier characters
    s.erase(remove_if(s.begin(), s.end(),
                      [] (auto c) { return !isalnum(c) && c != '_'; }),
            s.end());
    return s;
}

void eraseSuffix(string* path, const string& suffix)
{
    auto trimAt = path->size() - suffix.size();
    if (path->find(suffix, trimAt) != string::npos)
        path->erase(trimAt);
}

string withoutSuffix(const string& path, const string& suffix)
{
    return path.substr(0, path.find(suffix, path.size() - suffix.size()));
}

string VarDecl::toString(bool withDefault) const
{
    auto result = type.name + " " + name;
    if (withDefault && !required)
        result += " = " + (defaultValue.empty() ? "(empty)" : defaultValue);
    return result;
}

Path::Path(string path)
    : string(move(path))
{
    if (empty())
        throw ModelException("Path cannot be empty");

    // Working around quirks in the current Matrix CS API definition
    // (still applies to any other spec as well)
    while (back() == ' ' || back() == '/')
        pop_back();

    for (size_type i = 0; i < size();)
    {
        const auto i1 = find('{', i);
        if (i1 == npos)
        {
            parts.emplace_back(i, npos, Literal);
            break;
        }
        const auto i2 = find('}', i1);
        if (i2 == npos)
            throw ModelException("Unbalanced braces in the path: " + *this);

        parts.emplace_back(i, i1 - i, Literal);
        parts.emplace_back(i1 + 1, i2 - i1 - 1, Variable);
        i = i2 + 1;
    }
}

const array<string, 4> Call::paramsBlockNames
    { { "path", "query", "header", "body" } };

size_t getParamsBlockIndex(const string& name)
{
    for (Call::params_type::size_type i = 0; i < 4; ++i)
        if (Call::paramsBlockNames[i] == name)
            return i;

    throw ModelException("Unknown params block name: " + name);
}

const Call::params_type& Call::getParamsBlock(const string& blockName) const
{
    return allParams[getParamsBlockIndex(blockName)];
}

Call::params_type& Call::getParamsBlock(const string& blockName)
{
    return allParams[getParamsBlockIndex(blockName)];
}

Call::params_type Call::collateParams() const
{
    params_type allCollated;
    for (auto c: allParams)
        allCollated.insert(allCollated.end(), c.begin(), c.end());

    stable_partition(allCollated.begin(), allCollated.end(),
                     [] (const VarDecl& v) { return v.required; });
    return allCollated;
}

Call& Model::addCall(Path path, string verb, string operationId, bool needsToken)
{
    if (callClasses.empty())
        callClasses.emplace_back();
    auto& cc = callClasses.back();
    cc.calls.emplace_back(move(path), move(verb), move(operationId), needsToken);
    return cc.calls.back();
}

void Model::addVarDecl(VarDecls& varList, VarDecl var)
{
    addImports(var.type);
    varList.emplace_back(move(var));
}

void Model::addSchema(const ObjectSchema& schema)
{
    auto dupIt = find_if(types.begin(), types.end(),
            [&](const ObjectSchema& s)
            {
                return s.scope == schema.scope &&
                        s.name == schema.name;
            });
    if (dupIt != types.end())
        return;

    types.emplace_back(schema);
    for (const auto& pt: schema.parentTypes)
        addImports(pt);
}

void Model::addImports(const TypeUsage& type)
{
    const auto singleTypeImport = type.attributes.find("imports");
    if (singleTypeImport != type.attributes.end())
        imports.insert(singleTypeImport->second);
    const auto typeImportsIt = type.lists.find("imports");
    if (typeImportsIt != type.lists.end())
    {
        const auto& typeImports = typeImportsIt->second;
        imports.insert(typeImports.begin(), typeImports.end());
    }
}
<commit_msg>Model::addSchema: add imports from additionalProperties if not empty<commit_after>#include "model.h"

#include <algorithm>
#include <functional>
#include <locale>

using namespace std;

TypeUsage::TypeUsage(const ObjectSchema& schema)
    : scope(schema.scope), name(schema.name), baseName(schema.name)
{ }

TypeUsage TypeUsage::instantiate(vector<TypeUsage>&& innerTypes) const
{
    TypeUsage tu = *this;
    for (auto&& innerType: innerTypes)
    {
        tu.innerTypes.emplace_back(innerType);

        auto& tuImports = tu.lists["imports"];
        const auto singleInnerImport = innerType.attributes.find("imports");
        if (singleInnerImport != innerType.attributes.end())
            tuImports.push_back(singleInnerImport->second);
        const auto innerImports = innerType.lists.find("imports");
        if (innerImports != innerType.lists.end())
            tuImports.insert(tuImports.end(),
                             innerImports->second.begin(),
                             innerImports->second.end());
    }

    return tu;
}

void capitalize(string& s, string::size_type pos = 0)
{
    if (pos < s.size())
        s[pos] = toupper(s[pos], locale::classic());
}

string capitalizedCopy(string s)
{
    capitalize(s);
    return s;
}

string camelCase(string s)
{
    string::size_type pos = 0;
    while (pos < s.size())
    {
        capitalize(s, pos);
        pos = s.find_first_of("/_ .-:", pos);
        if (pos == string::npos)
            break;
        // Do not erase '_' at the beginning or the end of an identifier
        if (s[pos] != '_' || (pos != 0 && pos != s.size() - 1))
            s.erase(pos, 1);
        else
            ++pos;
    }
    // Remove all remaining non-identifier characters
    s.erase(remove_if(s.begin(), s.end(),
                      [] (auto c) { return !isalnum(c) && c != '_'; }),
            s.end());
    return s;
}

void eraseSuffix(string* path, const string& suffix)
{
    auto trimAt = path->size() - suffix.size();
    if (path->find(suffix, trimAt) != string::npos)
        path->erase(trimAt);
}

string withoutSuffix(const string& path, const string& suffix)
{
    return path.substr(0, path.find(suffix, path.size() - suffix.size()));
}

string VarDecl::toString(bool withDefault) const
{
    auto result = type.name + " " + name;
    if (withDefault && !required)
        result += " = " + (defaultValue.empty() ? "(empty)" : defaultValue);
    return result;
}

Path::Path(string path)
    : string(move(path))
{
    if (empty())
        throw ModelException("Path cannot be empty");

    // Working around quirks in the current Matrix CS API definition
    // (still applies to any other spec as well)
    while (back() == ' ' || back() == '/')
        pop_back();

    for (size_type i = 0; i < size();)
    {
        const auto i1 = find('{', i);
        if (i1 == npos)
        {
            parts.emplace_back(i, npos, Literal);
            break;
        }
        const auto i2 = find('}', i1);
        if (i2 == npos)
            throw ModelException("Unbalanced braces in the path: " + *this);

        parts.emplace_back(i, i1 - i, Literal);
        parts.emplace_back(i1 + 1, i2 - i1 - 1, Variable);
        i = i2 + 1;
    }
}

const array<string, 4> Call::paramsBlockNames
    { { "path", "query", "header", "body" } };

size_t getParamsBlockIndex(const string& name)
{
    for (Call::params_type::size_type i = 0; i < 4; ++i)
        if (Call::paramsBlockNames[i] == name)
            return i;

    throw ModelException("Unknown params block name: " + name);
}

const Call::params_type& Call::getParamsBlock(const string& blockName) const
{
    return allParams[getParamsBlockIndex(blockName)];
}

Call::params_type& Call::getParamsBlock(const string& blockName)
{
    return allParams[getParamsBlockIndex(blockName)];
}

Call::params_type Call::collateParams() const
{
    params_type allCollated;
    for (auto c: allParams)
        allCollated.insert(allCollated.end(), c.begin(), c.end());

    stable_partition(allCollated.begin(), allCollated.end(),
                     [] (const VarDecl& v) { return v.required; });
    return allCollated;
}

Call& Model::addCall(Path path, string verb, string operationId, bool needsToken)
{
    if (callClasses.empty())
        callClasses.emplace_back();
    auto& cc = callClasses.back();
    cc.calls.emplace_back(move(path), move(verb), move(operationId), needsToken);
    return cc.calls.back();
}

void Model::addVarDecl(VarDecls& varList, VarDecl var)
{
    addImports(var.type);
    varList.emplace_back(move(var));
}

void Model::addSchema(const ObjectSchema& schema)
{
    auto dupIt = find_if(types.begin(), types.end(),
            [&](const ObjectSchema& s)
            {
                return s.scope == schema.scope &&
                        s.name == schema.name;
            });
    if (dupIt != types.end())
        return;

    types.emplace_back(schema);
    for (const auto& pt: schema.parentTypes)
        addImports(pt);
    if (!schema.propertyMap.type.empty())
        addImports(schema.propertyMap.type);
}

void Model::addImports(const TypeUsage& type)
{
    const auto singleTypeImport = type.attributes.find("imports");
    if (singleTypeImport != type.attributes.end())
        imports.insert(singleTypeImport->second);
    const auto typeImportsIt = type.lists.find("imports");
    if (typeImportsIt != type.lists.end())
    {
        const auto& typeImports = typeImportsIt->second;
        imports.insert(typeImports.begin(), typeImports.end());
    }
}
<|endoftext|>