<commit_before>/*BEGIN_LEGAL
Intel Open Source License

Copyright (c) 2002-2013 Intel Corporation. All rights reserved.

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

Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.  Redistributions
in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.  Neither the name of
the Intel Corporation nor the names of its contributors may be used to
endorse or promote products derived from this software without
specific prior written permission.

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

#include "pin.H"
#include <iostream>
#include <cstdio>
#include <set>
#include "whitelist.h"
using namespace std;

// Prototypes ; TODO: Move to Seperate Header file?
void HookFree(IMG img);
void HookMalloc(IMG img);

typedef VOID* (*FP_MALLOC)(size_t);
typedef void (*FP_FREE)(void*);

bool inMain = false;
FILE * trace;
WhiteList wl;
int freeWasCalled = 0;
// Malloc
int mallocNumber = -1;
int freeNumber = -1;

// Print a memory read record
VOID RecordHeapMemRead(VOID * ip, VOID * addr) {
    int rtn = wl.containsAddress(addr);
    if(rtn != ERR_NOT_FOUND) {
        fprintf(trace,"##########BAD WRITE: %p \n", addr);
        cout << "BAD WRITE" << endl;
    }
    //printf("heap: %p\n", addr);
}

// Print a memory write record
VOID RecordHeapMemWrite(VOID * ip, VOID * addr) {
    int rtn = wl.containsAddress(addr);
    if(rtn != ERR_NOT_FOUND) {
        fprintf(trace,"##########BAD WRITE: %p \n", addr);
        cout << "BAD WRITE" << endl;

    }
    //printf("heap: %p\n", addr);
}

VOID RecordStackMemRead(VOID * ip, VOID * addr) {
    //printf("stack: %p\n", addr);
}

// Print a memory write record
VOID RecordStackMemWrite(VOID * ip, VOID * addr) {
    //printf("stack: %p\n", addr);
}

// Is called for every instruction and instruments reads and writes
VOID Instruction(INS ins, VOID *v) {
    if(!inMain || (mallocNumber <= 0 && freeNumber <=0))
        return;
    // Instruments memory accesses using a predicated call, i.e.
    // the instrumentation is called iff the instruction will actually be executed.
    //
    // On the IA-32 and Intel(R) 64 architectures conditional moves and REP
    // prefixed instructions appear as predicated instructions in Pin.
    UINT32 memOperands = INS_MemoryOperandCount(ins);

    // Iterate over each memory operand of the instruction.
    for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
        //if (INS_MemoryOperandIsRead(ins, memOp)) {
        if (INS_MemoryOperandIsRead(ins, memOp) && !INS_IsStackRead(ins)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordHeapMemRead,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        } else if (INS_MemoryOperandIsRead(ins, memOp)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordStackMemRead,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        }
        // Note that in some architectures a single memory operand can be
        // both read and written (for instance incl (%eax) on IA-32)
        // In that case we instrument it once for read and once for write.
        //if (INS_MemoryOperandIsWritten(ins, memOp)) {
        if (INS_MemoryOperandIsWritten(ins, memOp) && !INS_IsStackWrite(ins)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordHeapMemWrite,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        } else if (INS_MemoryOperandIsWritten(ins, memOp)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordStackMemWrite,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        }
    }
}

VOID Fini(INT32 code, VOID *v) {
    fprintf(trace, "#eof \n");
    fclose(trace);
}

// This is the replacement routine.
VOID* NewMalloc(FP_MALLOC orgFuncptr, UINT32 arg0, ADDRINT returnIp) {
    // Call the relocated entry point of the original (replaced) routine.
    void* v = orgFuncptr(arg0 + 16);
    char *cp = (char*)v;
    wl.add(cp, 8);
    fprintf(trace, "ADDED: %p %d \n", cp, 8);
    cp += (8 + arg0);
    wl.add(cp, 8);
    fprintf(trace, "ADDED: %p %d \n", cp, 8);
    return (void*)(((char*)v)+8);
}

void NewFree(FP_FREE orgFuncptr, void* ptr, ADDRINT returnIp) {
    printf("address free %p\n", ptr);
    if(ptr != NULL) {
        // TODO: -8 is the fence size; Make it a constant
        // Set the pointer to the actual start of memory
        void* realPtr = (char*)ptr - 8;
        // Check the WhiteList
        int index  = wl.containsAddress(ptr);
        if(index > 0) {
            // Remove the space
            orgFuncptr(realPtr);
        } else if(index == ERR_NOT_FOUND) {
            // This currently gets hit since a blacklist is being used
            fprintf(trace, "Address = %p not found. Bad address or stack address used.\n", ptr);
        } else if(index == ERR_MID_CHUNK) {
            fprintf(trace, "Mid-chunk memory deallocation @ %p\n", ptr);
        } else {
            fprintf(trace, "Unable to deallocate the memory @ %p\n", ptr);
        }
    } else {
        fprintf(trace, "Attempted to free NULL\n");
    }
}

// Pin calls this function every time a new img is loaded.
// It is best to do probe replacement when the image is loaded,
// because only one thread knows about the image at this time.
VOID ImageLoad(IMG img, VOID *v) {
    if(!inMain) {
        inMain = IMG_IsMainExecutable(img);
        return;
    }
    // Hook Functions
    HookMalloc(img);
    HookFree(img);
}

void HookFree(IMG img) {
    RTN rtn = RTN_FindByName(img, "free");
    // TODO: Hack for skipping hooks to /lib64/ld-linux-x86-64.so.2
    if(RTN_Valid(rtn)) {
        freeNumber++;
    }
    if(RTN_Valid(rtn) && freeNumber > 0) {
        cout << "Replacing free in " << IMG_Name(img) << endl;
        // Return type, cstype, function name, arguments...
        PROTO proto = PROTO_Allocate(PIN_PARG(void), CALLINGSTD_DEFAULT, "free", PIN_PARG(void*), PIN_PARG_END());
        // Replace free
        RTN_ReplaceSignature(rtn, AFUNPTR(NewFree),
            IARG_PROTOTYPE,
            proto,
            IARG_ORIG_FUNCPTR,
            IARG_FUNCARG_ENTRYPOINT_VALUE,
            0,
            IARG_RETURN_IP,
            IARG_END);
        // Free the function prototype
        PROTO_Free(proto);
    }
}

void HookMalloc(IMG img) {
    // See if malloc() is present in the image.  If so, replace it.
    RTN rtnMalloc = RTN_FindByName(img, "malloc");
    if(RTN_Valid(rtnMalloc)) {
        mallocNumber++;
    }
    if(RTN_Valid(rtnMalloc) && mallocNumber > 0) {
        cout << "Replacing malloc in " << IMG_Name(img) << endl;
        PROTO proto_malloc = PROTO_Allocate(PIN_PARG(void *), CALLINGSTD_DEFAULT,
            "malloc", PIN_PARG(int), PIN_PARG_END());
        RTN_ReplaceSignature(rtnMalloc, AFUNPTR(NewMalloc),
            IARG_PROTOTYPE, proto_malloc,
            IARG_ORIG_FUNCPTR,
            IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
            IARG_RETURN_IP,
            IARG_END);
        // Free the function prototype.
        PROTO_Free(proto_malloc);
    }
}

/* ===================================================================== */
/* Print Help Message                                                    */
/* ===================================================================== */

INT32 Usage() {
    cerr << "This tool demonstrates how to replace an original" << endl;
    cerr << " function with a custom function defined in the tool " << endl;
    cerr << " using probes.  The replacement function has a different " << endl;
    cerr << " signature from that of the original replaced function." << endl;
    cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
    return -1;
}

/* ===================================================================== */
/* Main: Initialize and start Pin in Probe mode.                         */
/* ===================================================================== */

int main(INT32 argc, CHAR *argv[]) {
    // Initialize symbol processing
    PIN_InitSymbols();
    // Initialize pin
    if (PIN_Init(argc, argv))
        return Usage();
    // Open up the trace file
    trace = fopen("zzz.out", "w");
    // Register ImageLoad to be called when an image is loaded
    IMG_AddInstrumentFunction(ImageLoad, 0);
    INS_AddInstrumentFunction(Instruction, 0);
    PIN_AddFiniFunction(Fini, 0);
    PIN_StartProgram();
    return 0;
}
<commit_msg>added pauls changes back<commit_after>/*BEGIN_LEGAL
Intel Open Source License

Copyright (c) 2002-2013 Intel Corporation. All rights reserved.

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

Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.  Redistributions
in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.  Neither the name of
the Intel Corporation nor the names of its contributors may be used to
endorse or promote products derived from this software without
specific prior written permission.

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

#include "pin.H"
#include <iostream>
#include <cstdio>
#include <set>
#include "whitelist.h"
using namespace std;

// Prototypes ; TODO: Move to Seperate Header file?
void HookFree(IMG img);
void HookMalloc(IMG img);

typedef VOID* (*FP_MALLOC)(size_t);
typedef void (*FP_FREE)(void*);

bool inMain = false;
FILE * trace;
WhiteList wl;
int freeWasCalled = 0;
// Malloc
int mallocNumber = -1;
int freeNumber = -1;

// Print a memory read record
VOID RecordHeapMemRead(VOID * ip, VOID * addr) {
    int rtn = wl.containsAddress(addr);
    if(rtn != ERR_NOT_FOUND) {
        fprintf(trace,"##########BAD WRITE: %p \n", addr);
        cout << "BAD WRITE" << endl;
    }
    //printf("heap read: %p\n", addr);
}

// Print a memory write record
VOID RecordHeapMemWrite(VOID * ip, VOID * addr) {
    int rtn = wl.containsAddress(addr);
    if(rtn != ERR_NOT_FOUND) {
        fprintf(trace,"##########BAD WRITE: %p \n", addr);
        cout << "BAD WRITE" << endl;

    }
    //printf("heap write: %p\n", addr);
}

VOID RecordStackMemRead(VOID * ip, VOID * addr) {
    //printf("stack read: %p\n", addr);
}

// Print a memory write record
VOID RecordStackMemWrite(VOID * ip, VOID * addr) {
    //printf("stack write: %p\n", addr);
}

// Is called for every instruction and instruments reads and writes
VOID Instruction(INS ins, VOID *v) {
    if(!inMain || (mallocNumber <= 0 && freeNumber <=0))
        return;
    // Instruments memory accesses using a predicated call, i.e.
    // the instrumentation is called iff the instruction will actually be executed.
    //
    // On the IA-32 and Intel(R) 64 architectures conditional moves and REP
    // prefixed instructions appear as predicated instructions in Pin.
    UINT32 memOperands = INS_MemoryOperandCount(ins);

    // Iterate over each memory operand of the instruction.
    for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
        //if (INS_MemoryOperandIsRead(ins, memOp)) {
        if (INS_MemoryOperandIsRead(ins, memOp) && !INS_IsStackRead(ins)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordHeapMemRead,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        } else if (INS_MemoryOperandIsRead(ins, memOp)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordStackMemRead,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        }
        // Note that in some architectures a single memory operand can be
        // both read and written (for instance incl (%eax) on IA-32)
        // In that case we instrument it once for read and once for write.
        //if (INS_MemoryOperandIsWritten(ins, memOp)) {
        if (INS_MemoryOperandIsWritten(ins, memOp) && !INS_IsStackWrite(ins)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordHeapMemWrite,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        } else if (INS_MemoryOperandIsWritten(ins, memOp)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordStackMemWrite,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        }
    }
}

VOID Fini(INT32 code, VOID *v) {
    fprintf(trace, "#eof \n");
    fclose(trace);
}

// This is the replacement routine.
VOID* NewMalloc(FP_MALLOC orgFuncptr, UINT32 arg0, ADDRINT returnIp) {
    // Call the relocated entry point of the original (replaced) routine.
    void* v = orgFuncptr(arg0 + 16);
    char *cp = (char*)v;
    wl.add(cp, 8);
    fprintf(trace, "ADDED: %p %d \n", cp, 8);
    cp += (8 + arg0);
    wl.add(cp, 8);
    fprintf(trace, "ADDED: %p %d \n", cp, 8);
    return (void*)(((char*)v)+8);
}

void NewFree(FP_FREE orgFuncptr, void* ptr, ADDRINT returnIp) {
    printf("address free %p\n", ptr);
    if(ptr != NULL) {
        // TODO: -8 is the fence size; Make it a constant
        // Set the pointer to the actual start of memory
        void* realPtr = (char*)ptr - 8;
        // Check the WhiteList
        int index  = wl.containsAddress(ptr);
        if(index > 0) {
            // Remove the space
            orgFuncptr(realPtr);
        } else if(index == ERR_NOT_FOUND) {
            // This currently gets hit since a blacklist is being used
            fprintf(trace, "Address = %p not found. Bad address or stack address used.\n", ptr);
        } else if(index == ERR_MID_CHUNK) {
            fprintf(trace, "Mid-chunk memory deallocation @ %p\n", ptr);
        } else {
            fprintf(trace, "Unable to deallocate the memory @ %p\n", ptr);
        }
    } else {
        fprintf(trace, "Attempted to free NULL\n");
    }
}

// Pin calls this function every time a new img is loaded.
// It is best to do probe replacement when the image is loaded,
// because only one thread knows about the image at this time.
VOID ImageLoad(IMG img, VOID *v) {
    if(!inMain) {
        inMain = IMG_IsMainExecutable(img);
        return;
    }
    // Hook Functions
    HookMalloc(img);
    HookFree(img);
}

void HookFree(IMG img) {
    RTN rtn = RTN_FindByName(img, "free");
    // TODO: Hack for skipping hooks to /lib64/ld-linux-x86-64.so.2
    if(RTN_Valid(rtn)) {
        freeNumber++;
    }
    if(RTN_Valid(rtn) && freeNumber > 0) {
        cout << "Replacing free in " << IMG_Name(img) << endl;
        // Return type, cstype, function name, arguments...
        PROTO proto = PROTO_Allocate(PIN_PARG(void), CALLINGSTD_DEFAULT, "free", PIN_PARG(void*), PIN_PARG_END());
        // Replace free
        RTN_ReplaceSignature(rtn, AFUNPTR(NewFree),
            IARG_PROTOTYPE,
            proto,
            IARG_ORIG_FUNCPTR,
            IARG_FUNCARG_ENTRYPOINT_VALUE,
            0,
            IARG_RETURN_IP,
            IARG_END);
        // Free the function prototype
        PROTO_Free(proto);
    }
}

void HookMalloc(IMG img) {
    // See if malloc() is present in the image.  If so, replace it.
    RTN rtnMalloc = RTN_FindByName(img, "malloc");
    if(RTN_Valid(rtnMalloc)) {
        mallocNumber++;
    }
    if(RTN_Valid(rtnMalloc) && mallocNumber > 0) {
        cout << "Replacing malloc in " << IMG_Name(img) << endl;
        PROTO proto_malloc = PROTO_Allocate(PIN_PARG(void *), CALLINGSTD_DEFAULT,
            "malloc", PIN_PARG(int), PIN_PARG_END());
        RTN_ReplaceSignature(rtnMalloc, AFUNPTR(NewMalloc),
            IARG_PROTOTYPE, proto_malloc,
            IARG_ORIG_FUNCPTR,
            IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
            IARG_RETURN_IP,
            IARG_END);
        // Free the function prototype.
        PROTO_Free(proto_malloc);
    }
}

/* ===================================================================== */
/* Print Help Message                                                    */
/* ===================================================================== */

INT32 Usage() {
    cerr << "This tool demonstrates how to replace an original" << endl;
    cerr << " function with a custom function defined in the tool " << endl;
    cerr << " using probes.  The replacement function has a different " << endl;
    cerr << " signature from that of the original replaced function." << endl;
    cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
    return -1;
}

/* ===================================================================== */
/* Main: Initialize and start Pin in Probe mode.                         */
/* ===================================================================== */

int main(INT32 argc, CHAR *argv[]) {
    // Initialize symbol processing
    PIN_InitSymbols();
    // Initialize pin
    if (PIN_Init(argc, argv))
        return Usage();
    // Open up the trace file
    trace = fopen("zzz.out", "w");
    // Register ImageLoad to be called when an image is loaded
    IMG_AddInstrumentFunction(ImageLoad, 0);
    INS_AddInstrumentFunction(Instruction, 0);
    PIN_AddFiniFunction(Fini, 0);
    PIN_StartProgram();
    return 0;
}
<|endoftext|>


<commit_before>// @(#)root/mathmore:$Name:  $:$Id: GSLRootFinderDeriv.h,v 1.1 2005/09/18 17:33:47 brun Exp $
// Authors: L. Moneta, A. Zsenei   08/2005

 /**********************************************************************
  *                                                                    *
  * Copyright (c) 2004 ROOT Foundation,  CERN/PH-SFT                   *
  *                                                                    *
  * This library is free software; you can redistribute it and/or      *
  * modify it under the terms of the GNU General Public License        *
  * as published by the Free Software Foundation; either version 2     *
  * of the License, or (at your option) any later version.             *
  *                                                                    *
  * This library 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 General Public License  *
  * along with this library (see file COPYING); if not, write          *
  * to the Free Software Foundation, Inc., 59 Temple Place, Suite      *
  * 330, Boston, MA 02111-1307 USA, or contact the author.             *
  *                                                                    *
  **********************************************************************/

// Header file for class GSLRandom
//
// Created by: moneta  at Sun Nov 21 16:26:03 2004
//
// Last update: Sun Nov 21 16:26:03 2004
//

// need to be included later
#include <time.h>

#include "gsl/gsl_rng.h"
#include "gsl/gsl_randist.h"

#include "Math/GSLRndmEngines.h"

//#include <iostream>

namespace ROOT {
namespace Math {

  /**
     wrapper to gsl_rng and gsl_rng_type
  */
  class GSLRng {
    public:

    GSLRng() :
      fRng(0),
      fRngType(0)
    {
    }

    GSLRng(const gsl_rng_type * type) :
      fRng(0),
      fRngType(type)
    {
    }

    ~GSLRng() { /** no op */  }

    void Allocate() {
      if (fRngType == 0) SetDefaultType();
      fRng = gsl_rng_alloc( fRngType );
      //std::cout << " allocate   " << fRng <<  std::endl;
    }

    void Free() {
      //std::cout << "free gslrng " << fRngType <<  "  " << fRng <<  std::endl;
      if (fRng != 0) gsl_rng_free(fRng);
      fRng = 0;
    }

    void SetType(const gsl_rng_type * type) {
      fRngType = type;
    }

    void SetDefaultType() {
      // construct default engine
      gsl_rng_env_setup();
      fRngType =  gsl_rng_default;
    }

    inline gsl_rng * Rng() const { return fRng; }

  private:

    gsl_rng * fRng;
    const gsl_rng_type * fRngType;
  };

  // default constructor
  GSLRandomEngine::GSLRandomEngine() :
    fCurTime(0)
  {
    fRng = new GSLRng();
  }

  GSLRandomEngine::~GSLRandomEngine() {
    /* no op , fRng is delete in terminate to avoid problem when copying the instances*/
  }

  void GSLRandomEngine::Initialize() {
  //----------------------------------------------------
    assert(fRng);
    fRng->Allocate();
  }

  void GSLRandomEngine::Terminate() {
  //----------------------------------------------------
    assert(fRng);
    fRng->Free();
    delete fRng;
    fRng = 0;
  }

  double GSLRandomEngine::operator() () {
    // generate random between 0 and 1.
    // 0 is excluded
    assert(fRng);
    return gsl_rng_uniform_pos(fRng->Rng() );
  }

  void GSLRandomEngine::RandomArray(double * begin, double * end )  {
    // generate array of randoms betweeen 0 and 1. 0 is excluded
    // specialization for double * (to be faster)
      assert(fRng);
      for ( double * itr = begin; itr != end; ++itr ) {
	*itr = gsl_rng_uniform_pos(fRng->Rng() );
      }
  }

  void GSLRandomEngine::SetSeed(unsigned int seed) {
  // set the seed, if = 0then the seed is set randomly using an std::rand()
  // seeded with the current time. Be carefuk in case the current time is
  // the same in consecutive calls
    if (seed == 0) {
      // use like in root (use time)
      time_t curtime;
      time(&curtime);
      unsigned int ct = static_cast<unsigned int>(curtime);
      if (ct != fCurTime) {
	fCurTime = ct;
	// set the seed for rand
	std::srand(ct);
      }
      seed = std::rand();
    }

    assert(fRng);
    gsl_rng_set(fRng->Rng(), seed );
  }

  std::string GSLRandomEngine::Name() const {
  //----------------------------------------------------
    assert ( fRng != 0);
    assert ( fRng->Rng() != 0 );
    return std::string( gsl_rng_name( fRng->Rng() ) );
  }

  unsigned int GSLRandomEngine::Size() const {
  //----------------------------------------------------
    return gsl_rng_size( fRng->Rng() );
  }

  // Random distributions

  double GSLRandomEngine::Gaussian(double sigma)
  {
    // Gaussian distribution
    //#define HAVE_GSL18
#ifdef HAVE_GSL18
    return gsl_ran_gaussian_ziggurat(  fRng->Rng(), sigma);
#else
    return gsl_ran_gaussian(  fRng->Rng(), sigma);
#endif
  }

  double GSLRandomEngine::GaussianTail(double a , double sigma)
  {
    // Gaussian Tail distribution: eeturn values larger than a distributed
    // according to the gaussian
    return gsl_ran_gaussian_tail(  fRng->Rng(), a, sigma);
  }

  void GSLRandomEngine::Gaussian2D(double sigmaX, double sigmaY, double rho, double &x, double &y)
  {
    // Gaussian Bivariate distribution, with correlation coefficient rho
    gsl_ran_bivariate_gaussian(  fRng->Rng(), sigmaX, sigmaY, rho, &x, &y);
  }

  double GSLRandomEngine::Exponential(double mu)
  {
    // Exponential distribution
    return gsl_ran_exponential(  fRng->Rng(), mu);
  }

  double GSLRandomEngine::Cauchy(double a)
  {
    // Cauchy distribution
    return gsl_ran_cauchy(  fRng->Rng(), a);
  }

  double GSLRandomEngine::Landau()
  {
    // Landau distribution
    return gsl_ran_landau(  fRng->Rng());
  }

  double GSLRandomEngine::Gamma(double a, double b)
  {
    // Gamma distribution
    return gsl_ran_gamma(  fRng->Rng(), a, b);
  }

  double GSLRandomEngine::LogNormal(double zeta, double sigma)
  {
    // Log normal distribution
    return gsl_ran_lognormal(  fRng->Rng(), zeta, sigma);
  }

  double GSLRandomEngine::ChiSquare(double nu)
  {
    // Chi square distribution
    return gsl_ran_chisq(  fRng->Rng(), nu);
  }

  double GSLRandomEngine::FDist(double nu1, double nu2)
  {
    // F distribution
    return gsl_ran_fdist(  fRng->Rng(), nu1, nu2);
  }

  double GSLRandomEngine::tDist(double nu)
  {
    // t distribution
    return gsl_ran_tdist(  fRng->Rng(), nu);
  }

  void GSLRandomEngine::Dir2D(double &x, double &y)
  {
    // generate random numbers in a 2D circle of radious 1
    gsl_ran_dir_2d(  fRng->Rng(), &x, &y);
  }

  void GSLRandomEngine::Dir3D(double &x, double &y, double &z)
  {
    // generate random numbers in a 3D sphere of radious 1
    gsl_ran_dir_3d(  fRng->Rng(), &x, &y, &z);
  }

  unsigned int GSLRandomEngine::Poisson(double mu)
  {
    // Poisson distribution
    return gsl_ran_poisson(  fRng->Rng(), mu);
  }

  unsigned int GSLRandomEngine::Binomial(double p, unsigned int n)
  {
    // Binomial distribution
    return gsl_ran_binomial(  fRng->Rng(), p, n);
  }

  std::vector<unsigned int>  GSLRandomEngine::Multinomial( unsigned int ntot, const std::vector<double> & p )
  {
    // Multinomial distribution  return vector of integers which sum is ntot
    unsigned int * narray = new unsigned int(p.size() );
    gsl_ran_multinomial(  fRng->Rng(), p.size(), ntot, &p.front(), narray);
    std::vector<unsigned int> ival( narray, narray+p.size());
    return ival;
  }

  //----------------------------------------------------
  // generators
  //----------------------------------------------------

  //----------------------------------------------------
  GSLRngMT::GSLRngMT() :
    GSLRandomEngine(new GSLRng(gsl_rng_mt19937) )
  {}

  GSLRngRanLux::GSLRngRanLux() :
    GSLRandomEngine(new GSLRng(gsl_rng_ranlux) )
  {}

  //----------------------------------------------------
  GSLRngTaus::GSLRngTaus() :
    GSLRandomEngine(new GSLRng(gsl_rng_taus2) )
  {}

  //----------------------------------------------------
  GSLRngGFSR4::GSLRngGFSR4() :
    GSLRandomEngine(new GSLRng(gsl_rng_gfsr4) )
  {}

  //----------------------------------------------------
  GSLRngCMRG::GSLRngCMRG() :
    GSLRandomEngine(new GSLRng(gsl_rng_cmrg) )
  {}

  //----------------------------------------------------
  GSLRngMRG::GSLRngMRG() :
    GSLRandomEngine(new GSLRng(gsl_rng_mrg) )
  {}

  //----------------------------------------------------
  GSLRngRand::GSLRngRand() :
    GSLRandomEngine(new GSLRng(gsl_rng_rand) )
  {}

  //----------------------------------------------------
  GSLRngRanMar::GSLRngRanMar() :
    GSLRandomEngine(new GSLRng(gsl_rng_ranmar) )
  {}

  //----------------------------------------------------
  GSLRngMinStd::GSLRngMinStd() :
    GSLRandomEngine(new GSLRng(gsl_rng_minstd) )
  {}

} // namespace Math
} // namespace ROOT

<commit_msg>add a missing include <cassert><commit_after>// @(#)root/mathmore:$Name:  $:$Id: GSLRndmEngines.cxx,v 1.1 2006/05/26 14:26:08 moneta Exp $
// Authors: L. Moneta, A. Zsenei   08/2005

 /**********************************************************************
  *                                                                    *
  * Copyright (c) 2004 ROOT Foundation,  CERN/PH-SFT                   *
  *                                                                    *
  * This library is free software; you can redistribute it and/or      *
  * modify it under the terms of the GNU General Public License        *
  * as published by the Free Software Foundation; either version 2     *
  * of the License, or (at your option) any later version.             *
  *                                                                    *
  * This library 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 General Public License  *
  * along with this library (see file COPYING); if not, write          *
  * to the Free Software Foundation, Inc., 59 Temple Place, Suite      *
  * 330, Boston, MA 02111-1307 USA, or contact the author.             *
  *                                                                    *
  **********************************************************************/

// Header file for class GSLRandom
//
// Created by: moneta  at Sun Nov 21 16:26:03 2004
//
// Last update: Sun Nov 21 16:26:03 2004
//

// need to be included later
#include <time.h>
#include <cassert>

#include "gsl/gsl_rng.h"
#include "gsl/gsl_randist.h"

#include "Math/GSLRndmEngines.h"

//#include <iostream>

namespace ROOT {
namespace Math {

  /**
     wrapper to gsl_rng and gsl_rng_type
  */
  class GSLRng {
    public:

    GSLRng() :
      fRng(0),
      fRngType(0)
    {
    }

    GSLRng(const gsl_rng_type * type) :
      fRng(0),
      fRngType(type)
    {
    }

    ~GSLRng() { /** no op */  }

    void Allocate() {
      if (fRngType == 0) SetDefaultType();
      fRng = gsl_rng_alloc( fRngType );
      //std::cout << " allocate   " << fRng <<  std::endl;
    }

    void Free() {
      //std::cout << "free gslrng " << fRngType <<  "  " << fRng <<  std::endl;
      if (fRng != 0) gsl_rng_free(fRng);
      fRng = 0;
    }

    void SetType(const gsl_rng_type * type) {
      fRngType = type;
    }

    void SetDefaultType() {
      // construct default engine
      gsl_rng_env_setup();
      fRngType =  gsl_rng_default;
    }

    inline gsl_rng * Rng() const { return fRng; }

  private:

    gsl_rng * fRng;
    const gsl_rng_type * fRngType;
  };

  // default constructor
  GSLRandomEngine::GSLRandomEngine() :
    fCurTime(0)
  {
    fRng = new GSLRng();
  }

  GSLRandomEngine::~GSLRandomEngine() {
    /* no op , fRng is delete in terminate to avoid problem when copying the instances*/
  }

  void GSLRandomEngine::Initialize() {
  //----------------------------------------------------
    assert(fRng);
    fRng->Allocate();
  }

  void GSLRandomEngine::Terminate() {
  //----------------------------------------------------
    assert(fRng);
    fRng->Free();
    delete fRng;
    fRng = 0;
  }

  double GSLRandomEngine::operator() () {
    // generate random between 0 and 1.
    // 0 is excluded
    assert(fRng);
    return gsl_rng_uniform_pos(fRng->Rng() );
  }

  void GSLRandomEngine::RandomArray(double * begin, double * end )  {
    // generate array of randoms betweeen 0 and 1. 0 is excluded
    // specialization for double * (to be faster)
      assert(fRng);
      for ( double * itr = begin; itr != end; ++itr ) {
	*itr = gsl_rng_uniform_pos(fRng->Rng() );
      }
  }

  void GSLRandomEngine::SetSeed(unsigned int seed) {
  // set the seed, if = 0then the seed is set randomly using an std::rand()
  // seeded with the current time. Be carefuk in case the current time is
  // the same in consecutive calls
    if (seed == 0) {
      // use like in root (use time)
      time_t curtime;
      time(&curtime);
      unsigned int ct = static_cast<unsigned int>(curtime);
      if (ct != fCurTime) {
	fCurTime = ct;
	// set the seed for rand
	std::srand(ct);
      }
      seed = std::rand();
    }

    assert(fRng);
    gsl_rng_set(fRng->Rng(), seed );
  }

  std::string GSLRandomEngine::Name() const {
  //----------------------------------------------------
    assert ( fRng != 0);
    assert ( fRng->Rng() != 0 );
    return std::string( gsl_rng_name( fRng->Rng() ) );
  }

  unsigned int GSLRandomEngine::Size() const {
  //----------------------------------------------------
    return gsl_rng_size( fRng->Rng() );
  }

  // Random distributions

  double GSLRandomEngine::Gaussian(double sigma)
  {
    // Gaussian distribution
    //#define HAVE_GSL18
#ifdef HAVE_GSL18
    return gsl_ran_gaussian_ziggurat(  fRng->Rng(), sigma);
#else
    return gsl_ran_gaussian(  fRng->Rng(), sigma);
#endif
  }

  double GSLRandomEngine::GaussianTail(double a , double sigma)
  {
    // Gaussian Tail distribution: eeturn values larger than a distributed
    // according to the gaussian
    return gsl_ran_gaussian_tail(  fRng->Rng(), a, sigma);
  }

  void GSLRandomEngine::Gaussian2D(double sigmaX, double sigmaY, double rho, double &x, double &y)
  {
    // Gaussian Bivariate distribution, with correlation coefficient rho
    gsl_ran_bivariate_gaussian(  fRng->Rng(), sigmaX, sigmaY, rho, &x, &y);
  }

  double GSLRandomEngine::Exponential(double mu)
  {
    // Exponential distribution
    return gsl_ran_exponential(  fRng->Rng(), mu);
  }

  double GSLRandomEngine::Cauchy(double a)
  {
    // Cauchy distribution
    return gsl_ran_cauchy(  fRng->Rng(), a);
  }

  double GSLRandomEngine::Landau()
  {
    // Landau distribution
    return gsl_ran_landau(  fRng->Rng());
  }

  double GSLRandomEngine::Gamma(double a, double b)
  {
    // Gamma distribution
    return gsl_ran_gamma(  fRng->Rng(), a, b);
  }

  double GSLRandomEngine::LogNormal(double zeta, double sigma)
  {
    // Log normal distribution
    return gsl_ran_lognormal(  fRng->Rng(), zeta, sigma);
  }

  double GSLRandomEngine::ChiSquare(double nu)
  {
    // Chi square distribution
    return gsl_ran_chisq(  fRng->Rng(), nu);
  }

  double GSLRandomEngine::FDist(double nu1, double nu2)
  {
    // F distribution
    return gsl_ran_fdist(  fRng->Rng(), nu1, nu2);
  }

  double GSLRandomEngine::tDist(double nu)
  {
    // t distribution
    return gsl_ran_tdist(  fRng->Rng(), nu);
  }

  void GSLRandomEngine::Dir2D(double &x, double &y)
  {
    // generate random numbers in a 2D circle of radious 1
    gsl_ran_dir_2d(  fRng->Rng(), &x, &y);
  }

  void GSLRandomEngine::Dir3D(double &x, double &y, double &z)
  {
    // generate random numbers in a 3D sphere of radious 1
    gsl_ran_dir_3d(  fRng->Rng(), &x, &y, &z);
  }

  unsigned int GSLRandomEngine::Poisson(double mu)
  {
    // Poisson distribution
    return gsl_ran_poisson(  fRng->Rng(), mu);
  }

  unsigned int GSLRandomEngine::Binomial(double p, unsigned int n)
  {
    // Binomial distribution
    return gsl_ran_binomial(  fRng->Rng(), p, n);
  }

  std::vector<unsigned int>  GSLRandomEngine::Multinomial( unsigned int ntot, const std::vector<double> & p )
  {
    // Multinomial distribution  return vector of integers which sum is ntot
    unsigned int * narray = new unsigned int(p.size() );
    gsl_ran_multinomial(  fRng->Rng(), p.size(), ntot, &p.front(), narray);
    std::vector<unsigned int> ival( narray, narray+p.size());
    return ival;
  }

  //----------------------------------------------------
  // generators
  //----------------------------------------------------

  //----------------------------------------------------
  GSLRngMT::GSLRngMT() :
    GSLRandomEngine(new GSLRng(gsl_rng_mt19937) )
  {}

  GSLRngRanLux::GSLRngRanLux() :
    GSLRandomEngine(new GSLRng(gsl_rng_ranlux) )
  {}

  //----------------------------------------------------
  GSLRngTaus::GSLRngTaus() :
    GSLRandomEngine(new GSLRng(gsl_rng_taus2) )
  {}

  //----------------------------------------------------
  GSLRngGFSR4::GSLRngGFSR4() :
    GSLRandomEngine(new GSLRng(gsl_rng_gfsr4) )
  {}

  //----------------------------------------------------
  GSLRngCMRG::GSLRngCMRG() :
    GSLRandomEngine(new GSLRng(gsl_rng_cmrg) )
  {}

  //----------------------------------------------------
  GSLRngMRG::GSLRngMRG() :
    GSLRandomEngine(new GSLRng(gsl_rng_mrg) )
  {}

  //----------------------------------------------------
  GSLRngRand::GSLRngRand() :
    GSLRandomEngine(new GSLRng(gsl_rng_rand) )
  {}

  //----------------------------------------------------
  GSLRngRanMar::GSLRngRanMar() :
    GSLRandomEngine(new GSLRng(gsl_rng_ranmar) )
  {}

  //----------------------------------------------------
  GSLRngMinStd::GSLRngMinStd() :
    GSLRandomEngine(new GSLRng(gsl_rng_minstd) )
  {}

} // namespace Math
} // namespace ROOT

<|endoftext|>


<commit_before>#ifndef STAN_MATH_OPENCL_OPENCL
#define STAN_MATH_OPENCL_OPENCL
#ifdef STAN_OPENCL

/**
 * \defgroup opencl OpenCL
 * Stan's OpenCL backend allows for computation to executed in parallel
 *  on a GPU or in multithreaded CPUs. It is meant to easily conform with Eigen
 * such that you can create and read from a `matrix_cl` by doing
 *
 *```cpp
 * Eigen::MatrixXd A_eig = Eigen::MatrixXd::Random(10, 10);
 * matrix_cl<double> A(A_eig);
 * matrix_cl<double> B = to_matrix_cl(A_eig);
 * matrix_cl<double> C = cholesky_decompose(A * B);
 * // Read back to eigen matrix.
 * Eigen::MatrixXd C_eig = from_matrix_cl(C);
 *```
 *
 * Execution is performed in async and Kernel operations are compounded and
 *compiled Just In Time. This allows for a low amount of overhead when passing
 *data to and from the device and executing computations.
 *
 * For more details see the paper on Arvix.
 * https://arxiv.org/pdf/1907.01063.pdf
 */

/**
 * \ingroup opencl
 * \defgroup error_checks_opencl Error Checks
 */

/**
 * \ingroup opencl
 * \defgroup kernel_executor_opencl Kernel Executor
 * The kernel executor allows OpenCL kernels to be executed in async. GPUs
 * have the capability to perform reads, writes, and computation at the same
 * time. In order to maximize the throughput to the device the Kernel
 * Executor assigns matrices read and write events. Write events are blocking
 * in that no further operations can be completed until the write event
 * is finished. However, read events can happen in async together.
 * Take the following for example
 *
 *```cpp
 * matrix_cl<double> A = from_eigen_cl(A_eig);
 * matrix_cl<double> B = from_eigen_cl(B_eig);
 * matrix_cl<double> C = A * B;
 * matrix_cl<double> D = A + B;
 * matrix_cl<double> E = C + D;
 *```
 * In the above, When `A` and `B` are created from the Eigen matrices `A_eig`
 *and `B_eig`. they are both assigned write events to their write event stack.
 * `C` and `D` depend on `A` and `B` while `E` depends on
 * `C` and `D`. When executing `C`'s operation, `A` and `B` are assigned
 * events to their read event stack while `C` is assigned an event to it's write
 *event stack. Once `A` and `B` have finished their write event the kernel to
 *compute `C` can begin. The excution to create `D` also waits for the write
 *events of `A` and `B`, but does not have to wait for the execution of `C` to
 *finish. Executing `E` requires waiting for for the write events of both `C`
 *and `D`.
 *
 */

/**
 * \ingroup opencl
 * \defgroup opencl_kernels Custom OpenCL kernels
 */
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/opencl/kernel_generator.hpp>
#include <stan/math/opencl/opencl_context.hpp>
#include <stan/math/opencl/matrix_cl.hpp>
#include <stan/math/opencl/copy.hpp>
#include <stan/math/opencl/copy_triangular.hpp>
#include <stan/math/opencl/cholesky_decompose.hpp>
#include <stan/math/opencl/diagonal_multiply.hpp>
#include <stan/math/opencl/identity.hpp>
#include <stan/math/opencl/is_matrix_cl.hpp>
#include <stan/math/opencl/tri_inverse.hpp>
#include <stan/math/opencl/multiply_transpose.hpp>
#include <stan/math/opencl/matrix_cl_view.hpp>
#include <stan/math/opencl/prim/rep_matrix.hpp>
#include <stan/math/opencl/prim/rep_row_vector.hpp>
#include <stan/math/opencl/prim/rep_vector.hpp>
#include <stan/math/opencl/scalar_type.hpp>
#include <stan/math/opencl/sub_block.hpp>
#include <stan/math/opencl/triangular_transpose.hpp>
#include <stan/math/opencl/value_type.hpp>
#include <stan/math/opencl/zeros.hpp>

#include <stan/math/opencl/prim/bernoulli_logit_glm_lpmf.hpp>
#include <stan/math/opencl/prim/categorical_logit_glm_lpmf.hpp>
#include <stan/math/opencl/prim/cholesky_decompose.hpp>
#include <stan/math/opencl/prim/divide_columns.hpp>
#include <stan/math/opencl/prim/gp_exp_quad_cov.hpp>
#include <stan/math/opencl/prim/mdivide_left_tri_low.hpp>
#include <stan/math/opencl/prim/mdivide_right_tri_low.hpp>
#include <stan/math/opencl/prim/neg_binomial_2_log_glm_lpmf.hpp>
#include <stan/math/opencl/prim/normal_id_glm_lpdf.hpp>
#include <stan/math/opencl/prim/ordered_logistic_glm_lpmf.hpp>
#include <stan/math/opencl/prim/poisson_log_glm_lpmf.hpp>

#include <stan/math/opencl/err.hpp>

#endif
#endif
<commit_msg>fix typos in opencl docs<commit_after>#ifndef STAN_MATH_OPENCL_OPENCL
#define STAN_MATH_OPENCL_OPENCL
#ifdef STAN_OPENCL

/**
 * \defgroup opencl OpenCL
 * Stan's OpenCL backend allows for computation to be executed in parallel
 *  on a GPU or in multithreaded CPUs. It is meant to easily conform with Eigen
 * such that you can create and read from a `matrix_cl` by doing
 *
 *```cpp
 * Eigen::MatrixXd A_eig = Eigen::MatrixXd::Random(10, 10);
 * matrix_cl<double> A(A_eig);
 * matrix_cl<double> B = to_matrix_cl(A_eig);
 * matrix_cl<double> C = cholesky_decompose(A * B);
 * // Read back to eigen matrix.
 * Eigen::MatrixXd C_eig = from_matrix_cl(C);
 *
 * // Also for vectors and raw pointers of pointers
 * std::vector<var> A_vec(10, 0);
 * matrix_cl<var> B_var(A_vec, 10, 1);
 *
 * vari** A_vari= // fill
 * matrix_cl<var> B_vari(A_vari, 10, 1);
 *
 *```
 *
 * Execution is performed in async and Kernel operations are compounded and
 * compiled Just In Time. This allows for a low amount of overhead when passing
 * data to and from the device and executing computations.
 *
 * For more details see the paper on Arvix.
 * https://arxiv.org/pdf/1907.01063.pdf
 */

/**
 * \ingroup opencl
 * \defgroup error_checks_opencl Error Checks
 */

/**
 * \ingroup opencl
 * \defgroup kernel_executor_opencl Kernel Executor
 * The kernel executor allows OpenCL kernels to be executed in async. GPUs
 * have the capability to perform reads, writes, and computation at the same
 * time. In order to maximize the throughput to the device the Kernel
 * Executor assigns matrices read and write events. Write events are blocking
 * in that no further operations can be completed until the write event
 * is finished. However, read events can happen in async together.
 * Take the following for example
 *
 *```cpp
 * matrix_cl<double> A = from_eigen_cl(A_eig);
 * matrix_cl<double> B = from_eigen_cl(B_eig);
 * matrix_cl<double> C = A * B;
 * matrix_cl<double> D = A + B;
 * matrix_cl<double> E = C + D;
 *```
 * In the above, When `A` and `B` are created from the Eigen matrices `A_eig`
 *and `B_eig`. they are both assigned write events to their write event stack.
 * `C` and `D` depend on `A` and `B` while `E` depends on
 * `C` and `D`. When executing `C`'s operation, `A` and `B` are assigned
 * events to their read event stack while `C` is assigned an event to it's write
 *event stack. Once `A` and `B` have finished their write event the kernel to
 *compute `C` can begin. The excution to create `D` also waits for the write
 *events of `A` and `B`, but does not have to wait for the execution of `C` to
 *finish. Executing `E` requires waiting for for the write events of both `C`
 *and `D`.
 *
 */

/**
 * \ingroup opencl
 * \defgroup opencl_kernels Custom OpenCL kernels
 */
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/opencl/kernel_generator.hpp>
#include <stan/math/opencl/opencl_context.hpp>
#include <stan/math/opencl/matrix_cl.hpp>
#include <stan/math/opencl/copy.hpp>
#include <stan/math/opencl/copy_triangular.hpp>
#include <stan/math/opencl/cholesky_decompose.hpp>
#include <stan/math/opencl/diagonal_multiply.hpp>
#include <stan/math/opencl/identity.hpp>
#include <stan/math/opencl/is_matrix_cl.hpp>
#include <stan/math/opencl/tri_inverse.hpp>
#include <stan/math/opencl/multiply_transpose.hpp>
#include <stan/math/opencl/matrix_cl_view.hpp>
#include <stan/math/opencl/prim/rep_matrix.hpp>
#include <stan/math/opencl/prim/rep_row_vector.hpp>
#include <stan/math/opencl/prim/rep_vector.hpp>
#include <stan/math/opencl/scalar_type.hpp>
#include <stan/math/opencl/sub_block.hpp>
#include <stan/math/opencl/triangular_transpose.hpp>
#include <stan/math/opencl/value_type.hpp>
#include <stan/math/opencl/zeros.hpp>

#include <stan/math/opencl/prim/bernoulli_logit_glm_lpmf.hpp>
#include <stan/math/opencl/prim/categorical_logit_glm_lpmf.hpp>
#include <stan/math/opencl/prim/cholesky_decompose.hpp>
#include <stan/math/opencl/prim/divide_columns.hpp>
#include <stan/math/opencl/prim/gp_exp_quad_cov.hpp>
#include <stan/math/opencl/prim/mdivide_left_tri_low.hpp>
#include <stan/math/opencl/prim/mdivide_right_tri_low.hpp>
#include <stan/math/opencl/prim/neg_binomial_2_log_glm_lpmf.hpp>
#include <stan/math/opencl/prim/normal_id_glm_lpdf.hpp>
#include <stan/math/opencl/prim/ordered_logistic_glm_lpmf.hpp>
#include <stan/math/opencl/prim/poisson_log_glm_lpmf.hpp>

#include <stan/math/opencl/err.hpp>

#endif
#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * (C) Copyright Ion Gaztanaga 2013-2014
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 */

#pragma once

#include <boost/intrusive/set.hpp>

namespace bi = boost::intrusive;

typedef bi::rbtree_algorithms<bi::rbtree_node_traits<void*, true>> algo;

class intrusive_set_external_comparator_member_hook : public bi::set_member_hook<bi::optimize_size<true>> {
public:
    intrusive_set_external_comparator_member_hook() = default;
    intrusive_set_external_comparator_member_hook(intrusive_set_external_comparator_member_hook&& o) noexcept {
        algo::replace_node(o.this_ptr(), this_ptr());
        algo::init(o.this_ptr());
    }
};

template<typename Elem,
         intrusive_set_external_comparator_member_hook Elem::* PtrToMember>
class intrusive_set_external_comparator final {
    typedef boost::intrusive::mhtraits<Elem, intrusive_set_external_comparator_member_hook, PtrToMember> value_traits;
    typedef typename value_traits::node_traits node_traits;
    typedef typename node_traits::node_ptr node_ptr;
public:
    typedef Elem value_type;
    typedef typename bi::tree_iterator<value_traits, false> iterator;
    typedef typename bi::tree_iterator<value_traits, true> const_iterator;
    typedef typename bi::reverse_iterator<iterator> reverse_iterator;
    typedef typename bi::reverse_iterator<const_iterator> const_reverse_iterator;

private:
    intrusive_set_external_comparator_member_hook _header;
    static const value_traits _value_traits;

    struct key_of_value {
        typedef Elem type;
        Elem& operator()(Elem& t) { return t; }
    };

    template <typename Comparator>
    struct key_node_comparator {
        Comparator _cmp;
        const value_traits& _value_traits;
        key_node_comparator(Comparator cmp, const value_traits& value_traits) : _cmp(cmp), _value_traits(value_traits) { }
        bool operator()(const node_ptr& a, const node_ptr& b) {
            return _cmp(*_value_traits.to_value_ptr(a), *_value_traits.to_value_ptr(b));
        }
        template <typename T1>
        bool operator()(const node_ptr& a, const T1& b) {
            return _cmp(*_value_traits.to_value_ptr(a), b);
        }
        template <typename T1>
        bool operator()(const T1& a, const node_ptr& b) {
            return _cmp(a, *_value_traits.to_value_ptr(b));
        }
        template <typename T1, typename T2>
        bool operator()(const T1& a, const T2& b) {
            return _cmp(a, b);
        }
    };

    typedef typename bi::value_traits_pointers<value_traits>::const_value_traits_ptr const_value_traits_ptr;

    const_value_traits_ptr priv_value_traits_ptr() const {
        return bi::pointer_traits<const_value_traits_ptr>::pointer_to(_value_traits);
    }
    template <typename Comparator>
    key_node_comparator<Comparator> key_node_comp(Comparator comp) const {
        return key_node_comparator<Comparator>(comp, _value_traits);
    }
    iterator insert_unique_commit(Elem& value, const algo::insert_commit_data &commit_data) {
        node_ptr to_insert(_value_traits.to_node_ptr(value));
        algo::insert_unique_commit(_header.this_ptr(), to_insert, commit_data);
        return iterator(to_insert, priv_value_traits_ptr());
    }
public:
    intrusive_set_external_comparator() { algo::init_header(_header.this_ptr()); }
    intrusive_set_external_comparator(intrusive_set_external_comparator&& o) {
        algo::swap_tree(_header.this_ptr(), node_ptr(o._header.this_ptr()));
    }
    iterator begin() { return iterator(algo::begin_node(_header.this_ptr()), priv_value_traits_ptr()); }
    const_iterator begin() const { return const_iterator(algo::begin_node(_header.this_ptr()), priv_value_traits_ptr()); }
    iterator end() { return iterator(algo::end_node(_header.this_ptr()), priv_value_traits_ptr()); }
    const_iterator end() const { return const_iterator(algo::end_node(_header.this_ptr()), priv_value_traits_ptr()); }
    reverse_iterator rbegin() { return reverse_iterator(end()); }
    const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
    reverse_iterator rend() { return reverse_iterator(begin()); }
    const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
    template<class Disposer>
    void clear_and_dispose(Disposer disposer) {
        algo::clear_and_dispose(_header.this_ptr(),
                                [&disposer] (const node_ptr& p) {
                                    disposer(_value_traits.to_value_ptr(p));
                                });
        algo::init_header(_header.this_ptr());
    }
    bool empty() const { return algo::unique(_header.this_ptr()); }

    // WARNING: this method has O(N) time complexity, use with care
    auto calculate_size() const { return algo::size(_header.this_ptr()); }
    iterator erase(const_iterator i) {
        const_iterator ret(i);
        ++ret;
        node_ptr to_erase(i.pointed_node());
        algo::erase(_header.this_ptr(), to_erase);
        algo::init(to_erase);
        return ret.unconst();
    }
    iterator erase(const_iterator b, const_iterator e) {
        while (b != e) {
            erase(b++);
        }
        return b.unconst();
    }
    template<class Disposer>
    iterator erase_and_dispose(const_iterator i, Disposer disposer) {
        node_ptr to_erase(i.pointed_node());
        iterator ret(erase(i));
        disposer(_value_traits.to_value_ptr(to_erase));
        return ret;
    }
    template<class Disposer>
    iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) {
        while (b != e) {
            erase_and_dispose(b++, disposer);
        }
        return b.unconst();
    }
    template <class Cloner, class Disposer>
    void clone_from(const intrusive_set_external_comparator &src, Cloner cloner, Disposer disposer) {
        clear_and_dispose(disposer);
        if (!src.empty()) {
            auto rollback = defer([this, &disposer] { this->clear_and_dispose(disposer); });
            algo::clone(src._header.this_ptr(),
                        _header.this_ptr(),
                        [&cloner] (const node_ptr& p) {
                            return _value_traits.to_node_ptr(*cloner(*_value_traits.to_value_ptr(p)));
                        },
                        [&disposer] (const node_ptr& p) {
                            disposer(_value_traits.to_value_ptr(p));
                        });
            rollback.cancel();
        }
    }
    Elem* unlink_leftmost_without_rebalance() {
        node_ptr to_be_disposed(algo::unlink_leftmost_without_rebalance(_header.this_ptr()));
        if(!to_be_disposed)
            return 0;
        algo::init(to_be_disposed);
        return _value_traits.to_value_ptr(to_be_disposed);
    }
    iterator insert_before(const_iterator pos, Elem& value) {
        node_ptr to_insert(_value_traits.to_node_ptr(value));
        return iterator(algo::insert_before(_header.this_ptr(), pos.pointed_node(), to_insert), priv_value_traits_ptr());
    }
    template<class KeyType, class KeyTypeKeyCompare>
    iterator upper_bound(const KeyType& key, KeyTypeKeyCompare comp) {
        return iterator(algo::upper_bound(_header.this_ptr(), key, key_node_comp(comp)), priv_value_traits_ptr());
    }
    template<class KeyType, class KeyTypeKeyCompare>
    const_iterator upper_bound(const KeyType& key, KeyTypeKeyCompare comp) const {
        return const_iterator(algo::upper_bound(_header.this_ptr(), key, key_node_comp(comp)), priv_value_traits_ptr());
    }
    template<class KeyType, class KeyTypeKeyCompare>
    iterator lower_bound(const KeyType &key, KeyTypeKeyCompare comp) {
        return iterator(algo::lower_bound(_header.this_ptr(), key, key_node_comp(comp)), priv_value_traits_ptr());
    }
    template<class KeyType, class KeyTypeKeyCompare>
    const_iterator lower_bound(const KeyType &key, KeyTypeKeyCompare comp) const {
        return const_iterator(algo::lower_bound(_header.this_ptr(), key, key_node_comp(comp)), priv_value_traits_ptr());
    }
    template<class KeyType, class KeyTypeKeyCompare>
    iterator find(const KeyType &key, KeyTypeKeyCompare comp) {
        return iterator(algo::find(_header.this_ptr(), key, key_node_comp(comp)), priv_value_traits_ptr());
    }
    template<class KeyType, class KeyTypeKeyCompare>
    const_iterator find(const KeyType &key, KeyTypeKeyCompare comp) const {
        return const_iterator(algo::find(_header.this_ptr(), key, key_node_comp(comp)), priv_value_traits_ptr());
    }
    template<class ElemCompare>
    iterator insert(const_iterator hint, Elem& value, ElemCompare cmp) {
        algo::insert_commit_data commit_data;
        std::pair<node_ptr, bool> ret =
            algo::insert_unique_check(_header.this_ptr(),
                                      hint.pointed_node(),
                                      key_of_value()(value),
                                      key_node_comp(cmp),
                                      commit_data);
        return ret.second ? insert_unique_commit(value, commit_data)
                          : iterator(ret.first, priv_value_traits_ptr());
    }
};

template<typename Elem,
         intrusive_set_external_comparator_member_hook Elem::* PtrToMember>
const typename intrusive_set_external_comparator<Elem, PtrToMember>::value_traits intrusive_set_external_comparator<Elem, PtrToMember>::_value_traits;
<commit_msg>intrusive_set_external_comparator: avoid using boost::intrusive::value_traits_pointers<commit_after>/*
 * Copyright (C) 2016 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * (C) Copyright Ion Gaztanaga 2013-2014
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 */

#pragma once

#include <boost/intrusive/set.hpp>
#include <iterator>

namespace bi = boost::intrusive;

typedef bi::rbtree_algorithms<bi::rbtree_node_traits<void*, true>> algo;

class intrusive_set_external_comparator_member_hook : public bi::set_member_hook<bi::optimize_size<true>> {
public:
    intrusive_set_external_comparator_member_hook() = default;
    intrusive_set_external_comparator_member_hook(intrusive_set_external_comparator_member_hook&& o) noexcept {
        algo::replace_node(o.this_ptr(), this_ptr());
        algo::init(o.this_ptr());
    }
};

template<typename Elem,
         intrusive_set_external_comparator_member_hook Elem::* PtrToMember>
class intrusive_set_external_comparator final {
    typedef boost::intrusive::mhtraits<Elem, intrusive_set_external_comparator_member_hook, PtrToMember> value_traits;
    typedef typename value_traits::node_traits node_traits;
    typedef typename node_traits::node_ptr node_ptr;
public:
    typedef Elem value_type;
    typedef typename bi::tree_iterator<value_traits, false> iterator;
    typedef typename bi::tree_iterator<value_traits, true> const_iterator;
    typedef typename std::reverse_iterator<iterator> reverse_iterator;
    typedef typename std::reverse_iterator<const_iterator> const_reverse_iterator;

private:
    intrusive_set_external_comparator_member_hook _header;
    static const value_traits _value_traits;

    struct key_of_value {
        typedef Elem type;
        Elem& operator()(Elem& t) { return t; }
    };

    template <typename Comparator>
    struct key_node_comparator {
        Comparator _cmp;
        const value_traits& _value_traits;
        key_node_comparator(Comparator cmp, const value_traits& value_traits) : _cmp(cmp), _value_traits(value_traits) { }
        bool operator()(const node_ptr& a, const node_ptr& b) {
            return _cmp(*_value_traits.to_value_ptr(a), *_value_traits.to_value_ptr(b));
        }
        template <typename T1>
        bool operator()(const node_ptr& a, const T1& b) {
            return _cmp(*_value_traits.to_value_ptr(a), b);
        }
        template <typename T1>
        bool operator()(const T1& a, const node_ptr& b) {
            return _cmp(a, *_value_traits.to_value_ptr(b));
        }
        template <typename T1, typename T2>
        bool operator()(const T1& a, const T2& b) {
            return _cmp(a, b);
        }
    };

    using const_value_traits_ptr = typename std::pointer_traits<typename value_traits::node_ptr>::template rebind<const value_traits>;

    const_value_traits_ptr priv_value_traits_ptr() const {
        return bi::pointer_traits<const_value_traits_ptr>::pointer_to(_value_traits);
    }
    template <typename Comparator>
    key_node_comparator<Comparator> key_node_comp(Comparator comp) const {
        return key_node_comparator<Comparator>(comp, _value_traits);
    }
    iterator insert_unique_commit(Elem& value, const algo::insert_commit_data &commit_data) {
        node_ptr to_insert(_value_traits.to_node_ptr(value));
        algo::insert_unique_commit(_header.this_ptr(), to_insert, commit_data);
        return iterator(to_insert, priv_value_traits_ptr());
    }
public:
    intrusive_set_external_comparator() { algo::init_header(_header.this_ptr()); }
    intrusive_set_external_comparator(intrusive_set_external_comparator&& o) {
        algo::swap_tree(_header.this_ptr(), node_ptr(o._header.this_ptr()));
    }
    iterator begin() { return iterator(algo::begin_node(_header.this_ptr()), priv_value_traits_ptr()); }
    const_iterator begin() const { return const_iterator(algo::begin_node(_header.this_ptr()), priv_value_traits_ptr()); }
    iterator end() { return iterator(algo::end_node(_header.this_ptr()), priv_value_traits_ptr()); }
    const_iterator end() const { return const_iterator(algo::end_node(_header.this_ptr()), priv_value_traits_ptr()); }
    reverse_iterator rbegin() { return reverse_iterator(end()); }
    const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
    reverse_iterator rend() { return reverse_iterator(begin()); }
    const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
    template<class Disposer>
    void clear_and_dispose(Disposer disposer) {
        algo::clear_and_dispose(_header.this_ptr(),
                                [&disposer] (const node_ptr& p) {
                                    disposer(_value_traits.to_value_ptr(p));
                                });
        algo::init_header(_header.this_ptr());
    }
    bool empty() const { return algo::unique(_header.this_ptr()); }

    // WARNING: this method has O(N) time complexity, use with care
    auto calculate_size() const { return algo::size(_header.this_ptr()); }
    iterator erase(const_iterator i) {
        const_iterator ret(i);
        ++ret;
        node_ptr to_erase(i.pointed_node());
        algo::erase(_header.this_ptr(), to_erase);
        algo::init(to_erase);
        return ret.unconst();
    }
    iterator erase(const_iterator b, const_iterator e) {
        while (b != e) {
            erase(b++);
        }
        return b.unconst();
    }
    template<class Disposer>
    iterator erase_and_dispose(const_iterator i, Disposer disposer) {
        node_ptr to_erase(i.pointed_node());
        iterator ret(erase(i));
        disposer(_value_traits.to_value_ptr(to_erase));
        return ret;
    }
    template<class Disposer>
    iterator erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer) {
        while (b != e) {
            erase_and_dispose(b++, disposer);
        }
        return b.unconst();
    }
    template <class Cloner, class Disposer>
    void clone_from(const intrusive_set_external_comparator &src, Cloner cloner, Disposer disposer) {
        clear_and_dispose(disposer);
        if (!src.empty()) {
            auto rollback = defer([this, &disposer] { this->clear_and_dispose(disposer); });
            algo::clone(src._header.this_ptr(),
                        _header.this_ptr(),
                        [&cloner] (const node_ptr& p) {
                            return _value_traits.to_node_ptr(*cloner(*_value_traits.to_value_ptr(p)));
                        },
                        [&disposer] (const node_ptr& p) {
                            disposer(_value_traits.to_value_ptr(p));
                        });
            rollback.cancel();
        }
    }
    Elem* unlink_leftmost_without_rebalance() {
        node_ptr to_be_disposed(algo::unlink_leftmost_without_rebalance(_header.this_ptr()));
        if(!to_be_disposed)
            return 0;
        algo::init(to_be_disposed);
        return _value_traits.to_value_ptr(to_be_disposed);
    }
    iterator insert_before(const_iterator pos, Elem& value) {
        node_ptr to_insert(_value_traits.to_node_ptr(value));
        return iterator(algo::insert_before(_header.this_ptr(), pos.pointed_node(), to_insert), priv_value_traits_ptr());
    }
    template<class KeyType, class KeyTypeKeyCompare>
    iterator upper_bound(const KeyType& key, KeyTypeKeyCompare comp) {
        return iterator(algo::upper_bound(_header.this_ptr(), key, key_node_comp(comp)), priv_value_traits_ptr());
    }
    template<class KeyType, class KeyTypeKeyCompare>
    const_iterator upper_bound(const KeyType& key, KeyTypeKeyCompare comp) const {
        return const_iterator(algo::upper_bound(_header.this_ptr(), key, key_node_comp(comp)), priv_value_traits_ptr());
    }
    template<class KeyType, class KeyTypeKeyCompare>
    iterator lower_bound(const KeyType &key, KeyTypeKeyCompare comp) {
        return iterator(algo::lower_bound(_header.this_ptr(), key, key_node_comp(comp)), priv_value_traits_ptr());
    }
    template<class KeyType, class KeyTypeKeyCompare>
    const_iterator lower_bound(const KeyType &key, KeyTypeKeyCompare comp) const {
        return const_iterator(algo::lower_bound(_header.this_ptr(), key, key_node_comp(comp)), priv_value_traits_ptr());
    }
    template<class KeyType, class KeyTypeKeyCompare>
    iterator find(const KeyType &key, KeyTypeKeyCompare comp) {
        return iterator(algo::find(_header.this_ptr(), key, key_node_comp(comp)), priv_value_traits_ptr());
    }
    template<class KeyType, class KeyTypeKeyCompare>
    const_iterator find(const KeyType &key, KeyTypeKeyCompare comp) const {
        return const_iterator(algo::find(_header.this_ptr(), key, key_node_comp(comp)), priv_value_traits_ptr());
    }
    template<class ElemCompare>
    iterator insert(const_iterator hint, Elem& value, ElemCompare cmp) {
        algo::insert_commit_data commit_data;
        std::pair<node_ptr, bool> ret =
            algo::insert_unique_check(_header.this_ptr(),
                                      hint.pointed_node(),
                                      key_of_value()(value),
                                      key_node_comp(cmp),
                                      commit_data);
        return ret.second ? insert_unique_commit(value, commit_data)
                          : iterator(ret.first, priv_value_traits_ptr());
    }
};

template<typename Elem,
         intrusive_set_external_comparator_member_hook Elem::* PtrToMember>
const typename intrusive_set_external_comparator<Elem, PtrToMember>::value_traits intrusive_set_external_comparator<Elem, PtrToMember>::_value_traits;
<|endoftext|>


<commit_before>#ifndef JARNGREIPR_CLEMENTI_GO
#define JARNGREIPR_CLEMENTI_GO
#include <jarngreipr/forcefield/ForceFieldGenerator.hpp>
#include <jarngreipr/geometry/distance.hpp>
#include <jarngreipr/geometry/angle.hpp>
#include <jarngreipr/geometry/dihedral.hpp>
#include <iterator>
#include <iostream>
#include <vector>

namespace jarngreipr
{

template<typename realT>
class ClementiGo final : public IntraChainForceFieldGenerator<realT>
{
  public:
    typedef IntraChainForceFieldGenerator<realT> base_type;
    typedef typename base_type::real_type real_type;
    typedef typename base_type::bead_type bead_type;

  public:

    ClementiGo()
        : contact_threshold_(6.5), k_bond_length_(100.0), k_bond_angle_(20.0),
          k_dihedral_angle_1_(1.0), k_dihedral_angle_3_(0.5), k_intra_go_(0.3)
    {}
    ~ClementiGo() override = default;

    explicit ClementiGo(const real_type th)
        : contact_threshold_(th), k_bond_length_(100.0), k_bond_angle_(20.0),
          k_dihedral_angle_1_(1.0), k_dihedral_angle_3_(0.5), k_intra_go_(0.3)
    {}

    ClementiGo(const real_type threshold,
        const real_type k_bl,   const real_type k_ba,
        const real_type k_dih1, const real_type k_dih3, const real_type k_igo)
        : contact_threshold_(threshold), k_bond_length_(k_bl), k_bond_angle_(k_ba),
          k_dihedral_angle_1_(k_dih1), k_dihedral_angle_3_(k_dih3),
          k_intra_go_(k_igo)
    {}

    // generate parameters and write out to `ostrm`.
    void generate(toml::Table& out,
        const std::vector<std::unique_ptr<bead_type>>& chain) const override;

    bool check_beads_kind(
        const std::vector<std::unique_ptr<bead_type>>& chain) const override;

    real_type& contact_threshold()       noexcept {return contact_threshold_;}
    real_type  contact_threshold() const noexcept {return contact_threshold_;}

  private:

    real_type min_distance_sq(
            const typename bead_type::container_type& lhs,
            const typename bead_type::container_type& rhs) const
    {
        real_type dist2 = std::numeric_limits<real_type>::max();
        for(const auto& l : lhs)
        {
            if(l.element == " H")
            {
                continue;
            }
            for(const auto& r : rhs)
            {
                if(r.element == " H")
                {
                    continue;
                }
                const auto d2 = distance_sq(l.position, r.position);
                dist2 = std::min(dist2, d2);
            }
        }
        return dist2;
    }

  private:
    real_type contact_threshold_;
    real_type k_bond_length_;
    real_type k_bond_angle_;
    real_type k_dihedral_angle_1_;
    real_type k_dihedral_angle_3_;
    real_type k_intra_go_;
};

template<typename realT>
void ClementiGo<realT>::generate(toml::Table& ff,
        const std::vector<std::unique_ptr<bead_type>>& chain) const
{
    if(!this->check_beads_kind(chain))
    {
        std::cerr << "ClementiGo: stop generating forcefield..." << std::endl;
        return ;
    }

    if(ff.count("local") == 0)
    {
        ff["local"] = toml::Array();
    }

    /* bond-length */ {
        toml::Table bond_length;
        bond_length["interaction"] = toml::String("BondLength");
        bond_length["potential"]   = toml::String("Harmonic");
        bond_length["topology"]    = toml::String("bond");

        toml::Array params;
        for(std::size_t i=0, sz = chain.size() - 1; i<sz; ++i)
        {
            const auto& bead1 = chain.at(i);
            const auto& bead2 = chain.at(i+1);
            const std::size_t i1 = bead1->index();
            const std::size_t i2 = bead2->index();
            toml::Table para;
            para["indices"] = toml::value{i1, i2};
            para["native"]  = distance(bead1->position(), bead2->position());
            para["k"]       = this->k_bond_length_;
            params.push_back(std::move(para));
        }
        bond_length["parameters"] = std::move(params);
        ff["local"].cast<toml::value_t::Array>().push_back(std::move(bond_length));
    }
    /* bond-angle */{
        toml::Table bond_angle;
        bond_angle["interaction"] = toml::String("BondAngle");
        bond_angle["potential"]   = toml::String("Harmonic");
        bond_angle["topology"]    = toml::String("none");

        toml::Array params;
        for(std::size_t i=0, sz = chain.size() - 2; i<sz; ++i)
        {
            const auto& bead1 = chain.at(i);
            const auto& bead2 = chain.at(i+1);
            const auto& bead3 = chain.at(i+2);
            const std::size_t i1 = bead1->index();
            const std::size_t i2 = bead2->index();
            const std::size_t i3 = bead3->index();

            toml::Table para;
            para["indices"] = toml::value{i1, i2, i3};
            para["native"]  = angle(bead1->position(), bead2->position(),
                                    bead3->position());
            para["k"]  = this->k_bond_angle_;
            params.push_back(std::move(para));
        }
        bond_angle["parameters"] = std::move(params);
        ff["local"].cast<toml::value_t::Array>().push_back(std::move(bond_angle));
    }
    /* dihedral-angle */{
        toml::Table dihd_angle;
        dihd_angle["interaction"] = toml::String("DihedralAngle");
        dihd_angle["potential"]   = toml::String("ClementiDihedral");
        dihd_angle["topology"]    = toml::String("none");

        toml::Array params;
        for(std::size_t i=0, sz = chain.size() - 3; i<sz; ++i)
        {
            const auto& bead1 = chain.at(i);
            const auto& bead2 = chain.at(i+1);
            const auto& bead3 = chain.at(i+2);
            const auto& bead4 = chain.at(i+3);
            const std::size_t i1 = bead1->index();
            const std::size_t i2 = bead2->index();
            const std::size_t i3 = bead3->index();
            const std::size_t i4 = bead4->index();

            toml::Table para;
            para["indices"] = toml::value{i1, i2, i3, i4};
            para["native"]  = dihedral_angle(bead1->position(),
                    bead2->position(), bead3->position(), bead4->position());
            para["k1"]  = this->k_dihedral_angle_1_;
            para["k3"]  = this->k_dihedral_angle_3_;
            params.push_back(std::move(para));
        }
        dihd_angle["parameters"] = std::move(params);
        ff["local"].cast<toml::value_t::Array>().push_back(std::move(dihd_angle));
    }

    const real_type th2 = this->contact_threshold_ * this->contact_threshold_;
    /* intra-chain-go-contacts */{
        toml::Table go_contact;
        go_contact["interaction"] = toml::String("BondLength");
        go_contact["potential"]   = toml::String("Go1012Contact");
        go_contact["topology"]    = toml::String("contact");

        toml::Array params;
        for(std::size_t i=0, sz_i = chain.size()-4; i<sz_i; ++i)
        {
            const auto& group1 = chain.at(i)->atoms();
            for(std::size_t j=i+4, sz_j = chain.size(); j<sz_j; ++j)
            {
                const auto& group2 = chain.at(j)->atoms();
                if(this->min_distance_sq(group1, group2) < th2)
                {
                    const auto& bead1 = chain.at(i);
                    const auto& bead2 = chain.at(j);
                    const std::size_t i1 = bead1->index();
                    const std::size_t i2 = bead2->index();

                    toml::Table para;
                    para["indices"] = toml::value{i1, i2};
                    para["native"]  = distance(bead1->position(), bead2->position());
                    para["k"]       = this->k_intra_go_;
                    params.push_back(std::move(para));
                }
            }
        }
        go_contact["parameters"]  = std::move(params);
        ff["local"].cast<toml::value_t::Array>().push_back(std::move(go_contact));
    }
    return;
}

template<typename realT>
bool ClementiGo<realT>::check_beads_kind(
        const std::vector<std::unique_ptr<bead_type>>& chain) const
{
    for(const auto& bead : chain)
    {
        if(bead->kind() != "CarbonAlpha")
        {
            std::cerr << "ClementiGo: invalid coarse-grained bead kind: "
                      << bead->kind() << '\n';
            std::cerr << "it allows only CarbonAlpha beads.\n";
            return false;
        }
    }
    return true;
}

}//jarngreipr
#endif /* JARNGREIPR_CLEMENTI_GO */
<commit_msg>use toml::Table to store parameter<commit_after>#ifndef JARNGREIPR_CLEMENTI_GO
#define JARNGREIPR_CLEMENTI_GO
#include <jarngreipr/forcefield/ForceFieldGenerator.hpp>
#include <jarngreipr/geometry/distance.hpp>
#include <jarngreipr/geometry/angle.hpp>
#include <jarngreipr/geometry/dihedral.hpp>
#include <mjolnir/util/get_toml_value.hpp>
#include <iterator>
#include <iostream>
#include <vector>

namespace jarngreipr
{

template<typename realT>
class ClementiGo final : public IntraChainForceFieldGenerator<realT>
{
  public:
    typedef IntraChainForceFieldGenerator<realT> base_type;
    typedef typename base_type::real_type real_type;
    typedef typename base_type::bead_type bead_type;

  public:

    ClementiGo(const toml::Table& para): parameters_(para){}
    ~ClementiGo() override = default;

    // generate parameters and write out to `ostrm`.
    void generate(toml::Table& out,
        const std::vector<std::unique_ptr<bead_type>>& chain) const override;

    bool check_beads_kind(
        const std::vector<std::unique_ptr<bead_type>>& chain) const override;

  private:

    real_type min_distance_sq(const std::unique_ptr<bead_type>& bead1,
                              const std::unique_ptr<bead_type>& bead2) const
    {
        real_type min_dist_sq = std::numeric_limits<real_type>::max();
        for(const auto& atom1 : bead1->atoms())
        {
            if(atom1.element == " H"){continue;}
            for(const auto& atom2 : bead2->atoms())
            {
                if(atom2.element == " H") {continue;}
                const auto dsq = distance_sq(atom1.position, atom2.position);
                min_dist_sq = std::min(dsq, min_dist_sq);
            }
        }
        return min_dist_sq;
    }

  private:

    toml::Table parameters_;
};

template<typename realT>
void ClementiGo<realT>::generate(toml::Table& ff,
        const std::vector<std::unique_ptr<bead_type>>& chain) const
{
    if(!this->check_beads_kind(chain))
    {
        std::cerr << "ClementiGo: stop generating forcefield..." << std::endl;
        return ;
    }

    if(ff.count("local") == 0)
    {
        ff["local"] = toml::Array();
    }

    /* bond-length */ {
        toml::Table bond_length;
        bond_length["interaction"] = toml::String("BondLength");
        bond_length["potential"]   = toml::String("Harmonic");
        bond_length["topology"]    = toml::String("bond");

        toml::Array params;
        for(std::size_t i=0, sz = chain.size() - 1; i<sz; ++i)
        {
            const auto& bead1 = chain.at(i);
            const auto& bead2 = chain.at(i+1);
            const std::size_t i1 = bead1->index();
            const std::size_t i2 = bead2->index();
            toml::Table para;
            para["indices"] = toml::value{i1, i2};
            para["native"]  = distance(bead1->position(), bead2->position());
            para["k"]       = toml::get<toml::Float>(mjolnir::toml_value_at(
                    this->parameters_, "coef_bond", "[parameter.ClementiGo]"));
            params.push_back(std::move(para));
        }
        bond_length["parameters"] = std::move(params);
        ff["local"].cast<toml::value_t::Array>().push_back(std::move(bond_length));
    }
    /* bond-angle */{
        toml::Table bond_angle;
        bond_angle["interaction"] = toml::String("BondAngle");
        bond_angle["potential"]   = toml::String("Harmonic");
        bond_angle["topology"]    = toml::String("none");

        toml::Array params;
        for(std::size_t i=0, sz = chain.size() - 2; i<sz; ++i)
        {
            const auto& bead1 = chain.at(i);
            const auto& bead2 = chain.at(i+1);
            const auto& bead3 = chain.at(i+2);
            const std::size_t i1 = bead1->index();
            const std::size_t i2 = bead2->index();
            const std::size_t i3 = bead3->index();

            toml::Table para;
            para["indices"] = toml::value{i1, i2, i3};
            para["native" ] = angle(bead1->position(), bead2->position(),
                                    bead3->position());
            para["k"      ] = toml::get<toml::Float>(mjolnir::toml_value_at(
                    this->parameters_, "coef_angle", "[parameter.ClementiGo]"));
            params.push_back(std::move(para));
        }
        bond_angle["parameters"] = std::move(params);
        ff["local"].cast<toml::value_t::Array>().push_back(std::move(bond_angle));
    }
    /* dihedral-angle */{
        toml::Table dihd_angle;
        dihd_angle["interaction"] = toml::String("DihedralAngle");
        dihd_angle["potential"]   = toml::String("ClementiDihedral");
        dihd_angle["topology"]    = toml::String("none");

        toml::Array params;
        for(std::size_t i=0, sz = chain.size() - 3; i<sz; ++i)
        {
            const auto& bead1 = chain.at(i);
            const auto& bead2 = chain.at(i+1);
            const auto& bead3 = chain.at(i+2);
            const auto& bead4 = chain.at(i+3);
            const std::size_t i1 = bead1->index();
            const std::size_t i2 = bead2->index();
            const std::size_t i3 = bead3->index();
            const std::size_t i4 = bead4->index();

            toml::Table para;
            para["indices"] = toml::value{i1, i2, i3, i4};
            para["native" ] = dihedral_angle(bead1->position(),
                    bead2->position(), bead3->position(), bead4->position());
            para["k1"     ] = toml::get<toml::Float>(mjolnir::toml_value_at(
                this->parameters_, "coef_dihedral_1", "[parameter.ClementiGo]"));
            para["k3"     ] = toml::get<toml::Float>(mjolnir::toml_value_at(
                this->parameters_, "coef_dihedral_3", "[parameter.ClementiGo]"));
            params.push_back(std::move(para));
        }
        dihd_angle["parameters"] = std::move(params);
        ff["local"].cast<toml::value_t::Array>().push_back(std::move(dihd_angle));
    }

    /* intra-chain-go-contacts */{
        const toml::Float threshold = toml::get<toml::Float>(
            mjolnir::toml_value_at(this->parameters_, "contact_threshold",
                                   "[parameter.ClementiGo]"));
        const real_type th2 = threshold * threshold;

        toml::Table go_contact;
        go_contact["interaction"] = toml::String("BondLength");
        go_contact["potential"  ] = toml::String("Go1012Contact");
        go_contact["topology"   ] = toml::String("contact");

        toml::Array params;
        for(std::size_t i=0, sz_i = chain.size()-4; i<sz_i; ++i)
        {
            for(std::size_t j=i+4, sz_j = chain.size(); j<sz_j; ++j)
            {
                if(this->min_distance_sq(chain.at(i), chain.at(j)) < th2)
                {
                    const auto& bead1 = chain.at(i);
                    const auto& bead2 = chain.at(j);
                    const std::size_t i1 = bead1->index();
                    const std::size_t i2 = bead2->index();

                    toml::Table para;
                    para["indices"] = toml::value{i1, i2};
                    para["native" ] = distance(bead1->position(), bead2->position());
                    para["k"      ] = toml::get<toml::Float>(mjolnir::toml_value_at(
                        this->parameters_, "coef_contact", "[parameter.ClementiGo]"));
                    params.push_back(std::move(para));
                }
            }
        }
        go_contact["parameters"]  = std::move(params);
        ff["local"].cast<toml::value_t::Array>().push_back(std::move(go_contact));
    }
    return;
}

template<typename realT>
bool ClementiGo<realT>::check_beads_kind(
        const std::vector<std::unique_ptr<bead_type>>& chain) const
{
    for(const auto& bead : chain)
    {
        if(bead->kind() != "CarbonAlpha")
        {
            std::cerr << "ClementiGo: invalid coarse-grained bead kind: "
                      << bead->kind() << '\n';
            std::cerr << "it allows only CarbonAlpha beads.\n";
            return false;
        }
    }
    return true;
}

}//jarngreipr
#endif /* JARNGREIPR_CLEMENTI_GO */
<|endoftext|>


<commit_before>#include "resource_data_byte_stream.h"
#include "halley/concurrency/concurrent.h"
#include <atlbase.h>
using namespace Halley;

class AsyncReadOp : public IUnknown
{
public:
	size_t from = 0;
	gsl::span<gsl::byte> dst;
	ULONG nRead = 0;

    AsyncReadOp(size_t from, gsl::span<gsl::byte> dst)
		: from(from)
		, dst(dst)
	{}

    HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
    {
        static const QITAB qit[] =
        {
            QITABENT(AsyncReadOp, IUnknown),
            { 0 }
        };
        return QISearch(this, qit, riid, ppv);
    }

    ULONG __stdcall AddRef()
    {
        return InterlockedIncrement(&refCount);
    }

    ULONG __stdcall Release()
    {
        long ref = InterlockedDecrement(&refCount);
        if (ref == 0) {
            delete this;
        }
        return ref;
    }

private:
	long refCount = 0;
};

Halley::ResourceDataByteStream::ResourceDataByteStream(std::shared_ptr<ResourceDataStream> data)
	: reader(data->getReader())
{
	len = reader->size();
}

HRESULT __stdcall ResourceDataByteStream::QueryInterface(const IID& riid, void** ppv)
{
    static const QITAB qit[] =
    {
        QITABENT(ResourceDataByteStream, IMFAsyncCallback),
		QITABENT(ResourceDataByteStream, IMFByteStream),
        { 0 }
    };
    return QISearch(this, qit, riid, ppv);
}

ULONG __stdcall ResourceDataByteStream::AddRef()
{
	return InterlockedIncrement(&refCount);
}

ULONG __stdcall ResourceDataByteStream::Release()
{
	ULONG uCount = InterlockedDecrement(&refCount);
    if (uCount == 0) {
		delete this;
    }
    return uCount;
}

HRESULT __stdcall ResourceDataByteStream::GetCapabilities(DWORD* pdwCapabilities)
{
	*pdwCapabilities = MFBYTESTREAM_IS_READABLE | MFBYTESTREAM_IS_SEEKABLE;
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::GetLength(QWORD* pqwLength)
{
	*pqwLength = len;
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::SetLength(QWORD qwLength)
{
	return E_NOTIMPL;
}

HRESULT __stdcall ResourceDataByteStream::GetCurrentPosition(QWORD* pqwPosition)
{
	std::unique_lock<std::mutex> lock(mutex);
	*pqwPosition = QWORD(pos);
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::SetCurrentPosition(QWORD qwPosition)
{
	std::unique_lock<std::mutex> lock(mutex);
	pos = size_t(qwPosition);
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::IsEndOfStream(BOOL* pfEndOfStream)
{
	std::unique_lock<std::mutex> lock(mutex);
	*pfEndOfStream = pos >= len;
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::Read(BYTE* pb, ULONG cb, ULONG* pcbRead)
{
	std::unique_lock<std::mutex> lock(mutex);
	reader->seek(pos, SEEK_SET);
	const auto nRead = reader->read(gsl::as_writeable_bytes(gsl::span<BYTE>(pb, cb)));
	pos += nRead;
	*pcbRead = nRead;
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::BeginRead(BYTE* pb, ULONG cb, IMFAsyncCallback* pCallback, IUnknown* punkState)
{
	/*
	punkState->AddRef();
	pCallback->AddRef();
	Concurrent::execute([=] () {
		IMFAsyncResult* result;
		MFCreateAsyncResult(nullptr, pCallback, punkState, &result);
		{
			std::unique_lock<std::mutex> lock(mutex);
			ULONG nRead = reader->read(gsl::as_writeable_bytes(gsl::span<BYTE>(pb, cb)));
			asyncNumRead[result] = nRead;
		}
		pCallback->Invoke(result);
		punkState->Release();
		pCallback->Release();
	});
	*/

	auto op = new AsyncReadOp(pos, gsl::as_writeable_bytes(gsl::span<BYTE>(pb, cb)));
	pos += cb;
	if (pos > len) {
		pos = len;
	}

	IMFAsyncResult* result;
	auto hr = MFCreateAsyncResult(op, pCallback, punkState, &result);
	if (!SUCCEEDED(hr)) {
		throw Exception("Error in ResourceDataByteStream", HalleyExceptions::MoviePlugin);
	}
	hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, this, result);
	//result->Release();

	return hr;
}

HRESULT ResourceDataByteStream::Invoke(IMFAsyncResult* pAsyncResult)
{
	IUnknown* state;
	IUnknown* unknown;
	IMFAsyncResult* callerResult = nullptr;
	auto hr = pAsyncResult->GetState(&state);
	if (!SUCCEEDED(hr)) {
		throw Exception("Error in ResourceDataByteStream", HalleyExceptions::MoviePlugin);
	}
	hr = state->QueryInterface(IID_PPV_ARGS(&callerResult));
	if (!SUCCEEDED(hr)) {
		throw Exception("Error in ResourceDataByteStream", HalleyExceptions::MoviePlugin);
	}
	hr = callerResult->GetObject(&unknown);
	if (!SUCCEEDED(hr)) {
		throw Exception("Error in ResourceDataByteStream", HalleyExceptions::MoviePlugin);
	}

	auto readOp = static_cast<AsyncReadOp*>(unknown);

	{
		std::unique_lock<std::mutex> lock(mutex);
		reader->seek(readOp->from, SEEK_SET);
		readOp->nRead = reader->read(readOp->dst);
	}

	if (callerResult) {
		callerResult->SetStatus(S_OK);
		hr = MFInvokeCallback(callerResult);
		if (!SUCCEEDED(hr)) {
			throw Exception("Error in ResourceDataByteStream", HalleyExceptions::MoviePlugin);
		}
	}

	if (state) {
		state->Release();
	}
	if (unknown) {
		unknown->Release();
	}
	if (callerResult) {
		callerResult->Release();
	}

	//EndRead(pAsyncResult, nullptr);
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::EndRead(IMFAsyncResult* pResult, ULONG* pcbRead)
{
	IUnknown* unknown;
	pResult->GetObject(&unknown);
	auto readOp = static_cast<AsyncReadOp*>(unknown);
	*pcbRead = readOp->nRead;

	pResult->Release();
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::Write(const BYTE* pb, ULONG cb, ULONG* pcbWritten)
{
	return E_NOTIMPL;
}

HRESULT __stdcall ResourceDataByteStream::BeginWrite(const BYTE* pb, ULONG cb, IMFAsyncCallback* pCallback, IUnknown* punkState)
{
	return E_NOTIMPL;
}

HRESULT __stdcall ResourceDataByteStream::EndWrite(IMFAsyncResult* pResult, ULONG* pcbWritten)
{
	return E_NOTIMPL;
}

HRESULT __stdcall ResourceDataByteStream::Seek(MFBYTESTREAM_SEEK_ORIGIN SeekOrigin, LONGLONG llSeekOffset, DWORD dwSeekFlags, QWORD* pqwCurrentPosition)
{
	std::unique_lock<std::mutex> lock(mutex);
	if (SeekOrigin == msoCurrent) {
		pos += llSeekOffset;
	} else {
		pos = llSeekOffset;
	}
	*pqwCurrentPosition = QWORD(pos);

	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::Flush()
{
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::Close()
{
	reader->close();
	return S_OK;
}

HRESULT ResourceDataByteStream::GetParameters(DWORD* pdwFlags, DWORD* pdwQueue)
{
	return E_NOTIMPL;
}
<commit_msg>32-bit woes<commit_after>#include "resource_data_byte_stream.h"
#include "halley/concurrency/concurrent.h"
#include <atlbase.h>
using namespace Halley;

class AsyncReadOp : public IUnknown
{
public:
	size_t from = 0;
	gsl::span<gsl::byte> dst;
	ULONG nRead = 0;

    AsyncReadOp(size_t from, gsl::span<gsl::byte> dst)
		: from(from)
		, dst(dst)
	{}

    HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
    {
        static const QITAB qit[] =
        {
            QITABENT(AsyncReadOp, IUnknown),
            { 0 }
        };
        return QISearch(this, qit, riid, ppv);
    }

    ULONG __stdcall AddRef()
    {
        return InterlockedIncrement(&refCount);
    }

    ULONG __stdcall Release()
    {
        long ref = InterlockedDecrement(&refCount);
        if (ref == 0) {
            delete this;
        }
        return ref;
    }

private:
	long refCount = 0;
};

Halley::ResourceDataByteStream::ResourceDataByteStream(std::shared_ptr<ResourceDataStream> data)
	: reader(data->getReader())
{
	len = reader->size();
}

HRESULT __stdcall ResourceDataByteStream::QueryInterface(const IID& riid, void** ppv)
{
    static const QITAB qit[] =
    {
        QITABENT(ResourceDataByteStream, IMFAsyncCallback),
		QITABENT(ResourceDataByteStream, IMFByteStream),
        { 0 }
    };
    return QISearch(this, qit, riid, ppv);
}

ULONG __stdcall ResourceDataByteStream::AddRef()
{
	return InterlockedIncrement(&refCount);
}

ULONG __stdcall ResourceDataByteStream::Release()
{
	ULONG uCount = InterlockedDecrement(&refCount);
    if (uCount == 0) {
		delete this;
    }
    return uCount;
}

HRESULT __stdcall ResourceDataByteStream::GetCapabilities(DWORD* pdwCapabilities)
{
	*pdwCapabilities = MFBYTESTREAM_IS_READABLE | MFBYTESTREAM_IS_SEEKABLE;
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::GetLength(QWORD* pqwLength)
{
	*pqwLength = len;
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::SetLength(QWORD qwLength)
{
	return E_NOTIMPL;
}

HRESULT __stdcall ResourceDataByteStream::GetCurrentPosition(QWORD* pqwPosition)
{
	std::unique_lock<std::mutex> lock(mutex);
	*pqwPosition = QWORD(pos);
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::SetCurrentPosition(QWORD qwPosition)
{
	std::unique_lock<std::mutex> lock(mutex);
	pos = size_t(qwPosition);
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::IsEndOfStream(BOOL* pfEndOfStream)
{
	std::unique_lock<std::mutex> lock(mutex);
	*pfEndOfStream = pos >= len;
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::Read(BYTE* pb, ULONG cb, ULONG* pcbRead)
{
	std::unique_lock<std::mutex> lock(mutex);
	reader->seek(pos, SEEK_SET);
	const auto nRead = reader->read(gsl::as_writeable_bytes(gsl::span<BYTE>(pb, cb)));
	pos += nRead;
	*pcbRead = nRead;
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::BeginRead(BYTE* pb, ULONG cb, IMFAsyncCallback* pCallback, IUnknown* punkState)
{
	/*
	punkState->AddRef();
	pCallback->AddRef();
	Concurrent::execute([=] () {
		IMFAsyncResult* result;
		MFCreateAsyncResult(nullptr, pCallback, punkState, &result);
		{
			std::unique_lock<std::mutex> lock(mutex);
			ULONG nRead = reader->read(gsl::as_writeable_bytes(gsl::span<BYTE>(pb, cb)));
			asyncNumRead[result] = nRead;
		}
		pCallback->Invoke(result);
		punkState->Release();
		pCallback->Release();
	});
	*/

	auto op = new AsyncReadOp(pos, gsl::as_writeable_bytes(gsl::span<BYTE>(pb, cb)));
	pos += cb;
	if (pos > len) {
		pos = len;
	}

	IMFAsyncResult* result;
	auto hr = MFCreateAsyncResult(op, pCallback, punkState, &result);
	if (!SUCCEEDED(hr)) {
		throw Exception("Error in ResourceDataByteStream", HalleyExceptions::MoviePlugin);
	}
	hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, this, result);
	//result->Release();

	return hr;
}

HRESULT ResourceDataByteStream::Invoke(IMFAsyncResult* pAsyncResult)
{
	IUnknown* state;
	IUnknown* unknown;
	IMFAsyncResult* callerResult = nullptr;
	auto hr = pAsyncResult->GetState(&state);
	if (!SUCCEEDED(hr)) {
		throw Exception("Error in ResourceDataByteStream", HalleyExceptions::MoviePlugin);
	}
	hr = state->QueryInterface(IID_PPV_ARGS(&callerResult));
	if (!SUCCEEDED(hr)) {
		throw Exception("Error in ResourceDataByteStream", HalleyExceptions::MoviePlugin);
	}
	hr = callerResult->GetObject(&unknown);
	if (!SUCCEEDED(hr)) {
		throw Exception("Error in ResourceDataByteStream", HalleyExceptions::MoviePlugin);
	}

	auto readOp = static_cast<AsyncReadOp*>(unknown);

	{
		std::unique_lock<std::mutex> lock(mutex);
		reader->seek(readOp->from, SEEK_SET);
		readOp->nRead = reader->read(readOp->dst);
	}

	if (callerResult) {
		callerResult->SetStatus(S_OK);
		hr = MFInvokeCallback(callerResult);
		if (!SUCCEEDED(hr)) {
			throw Exception("Error in ResourceDataByteStream", HalleyExceptions::MoviePlugin);
		}
	}

	if (state) {
		state->Release();
	}
	if (unknown) {
		unknown->Release();
	}
	if (callerResult) {
		callerResult->Release();
	}

	//EndRead(pAsyncResult, nullptr);
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::EndRead(IMFAsyncResult* pResult, ULONG* pcbRead)
{
	IUnknown* unknown;
	pResult->GetObject(&unknown);
	auto readOp = static_cast<AsyncReadOp*>(unknown);
	*pcbRead = readOp->nRead;

	pResult->Release();
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::Write(const BYTE* pb, ULONG cb, ULONG* pcbWritten)
{
	return E_NOTIMPL;
}

HRESULT __stdcall ResourceDataByteStream::BeginWrite(const BYTE* pb, ULONG cb, IMFAsyncCallback* pCallback, IUnknown* punkState)
{
	return E_NOTIMPL;
}

HRESULT __stdcall ResourceDataByteStream::EndWrite(IMFAsyncResult* pResult, ULONG* pcbWritten)
{
	return E_NOTIMPL;
}

HRESULT __stdcall ResourceDataByteStream::Seek(MFBYTESTREAM_SEEK_ORIGIN SeekOrigin, LONGLONG llSeekOffset, DWORD dwSeekFlags, QWORD* pqwCurrentPosition)
{
	std::unique_lock<std::mutex> lock(mutex);
	if (SeekOrigin == msoCurrent) {
		pos += size_t(llSeekOffset);
	} else {
		pos = size_t(llSeekOffset);
	}
	*pqwCurrentPosition = QWORD(pos);

	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::Flush()
{
	return S_OK;
}

HRESULT __stdcall ResourceDataByteStream::Close()
{
	reader->close();
	return S_OK;
}

HRESULT ResourceDataByteStream::GetParameters(DWORD* pdwFlags, DWORD* pdwQueue)
{
	return E_NOTIMPL;
}
<|endoftext|>