Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2018-2023 The plumed team 3 : (see the PEOPLE file at the root of the distribution for a list of names) 4 : 5 : See http://www.plumed.org for more information. 6 : 7 : This file is part of plumed, version 2. 8 : 9 : plumed is free software: you can redistribute it and/or modify 10 : it under the terms of the GNU Lesser General Public License as published by 11 : the Free Software Foundation, either version 3 of the License, or 12 : (at your option) any later version. 13 : 14 : plumed is distributed in the hope that it will be useful, 15 : but WITHOUT ANY WARRANTY; without even the implied warranty of 16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 : GNU Lesser General Public License for more details. 18 : 19 : You should have received a copy of the GNU Lesser General Public License 20 : along with plumed. If not, see <http://www.gnu.org/licenses/>. 21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 22 : #include "PlumedHandle.h" 23 : #include "core/PlumedMain.h" 24 : #include "Tools.h" 25 : #include "lepton/Exception.h" 26 : #include <cstring> 27 : #ifdef __PLUMED_HAS_DLOPEN 28 : #include <dlfcn.h> 29 : #endif 30 : 31 : // Including Plumed.h in this manner allows to create a local 32 : // implementation of the wrapper in an anonymous namespace. 33 : // This allows to avoid recoding all the Plumed.h stuff here 34 : // and at the same time avoids possible conflicts. 35 : #define __PLUMED_WRAPPER_IMPLEMENTATION 1 36 : #define __PLUMED_WRAPPER_EXTERN 0 37 : #define __PLUMED_WRAPPER_CXX_ANONYMOUS_NAMESPACE 1 38 : #define __PLUMED_WRAPPER_CXX_ANONYMOUS_NAMESPACE_PLMD_EXCEPTIONS 1 39 : #include "../wrapper/Plumed.h" 40 : 41 : namespace PLMD 42 : { 43 : 44 : 45 11 : PlumedHandle::PlumedHandle(): 46 11 : local(Tools::make_unique<PlumedMain>()) 47 : { 48 11 : } 49 : 50 1 : PlumedHandle::PlumedHandle(const char* kernel) 51 : #ifdef __PLUMED_HAS_DLOPEN 52 : : 53 1 : loaded(plumed_c2v(plumed_create_dlopen(kernel))) 54 : { 55 : if(!plumed_valid(plumed_v2c(loaded))) { 56 : // this is necessary to make sure loaded is properly destroyed 57 0 : plumed_finalize(plumed_v2c(loaded)); 58 0 : plumed_error() << "You are trying to dynamically load a kernel, but the path " << kernel <<" could not be opened"; 59 : } 60 1 : } 61 : #else 62 : { 63 : plumed_error() << "You are trying to dynamically load a kernel, but PLUMED was compiled without dlopen"; 64 : } 65 : #endif 66 : 67 12 : PlumedHandle::~PlumedHandle() { 68 12 : if(loaded) plumed_finalize(plumed_v2c(loaded)); 69 12 : } 70 : 71 1 : PlumedHandle PlumedHandle::dlopen(const char* path) { 72 1 : return PlumedHandle(path); 73 : } 74 : 75 1476 : void PlumedHandle::cmd(std::string_view key,const TypesafePtr & ptr) { 76 1476 : if(local) { 77 1254 : local->cmd(key,ptr); 78 222 : } else if(loaded) { 79 : plumed_safeptr safe; 80 222 : safe.ptr=ptr.getRaw(); 81 222 : safe.nelem=ptr.getNelem(); 82 222 : safe.shape=const_cast<std::size_t*>(ptr.getShape()); 83 222 : safe.flags=ptr.getFlags(); 84 222 : safe.opt=nullptr; 85 : 86 : // String must be null terminated. 87 : // This is to ensure null termination without the penalty of dynamic allocation. 88 : // It's a tiny optimization: it just removes one extra allocation when cmd() is called with a key 89 : // longer than the buffer for SSO (typically 15 chars) 90 : // It's included here only because PlumedHandle is used in benchmarks. 91 : constexpr unsigned key_buffer_size=64; 92 : // no allocation - on stack 93 : char key_buffer_char[key_buffer_size]; 94 : std::string key_buffer_string; 95 : const char* key_buffer=nullptr; 96 : 97 222 : if(key.length()<key_buffer_size) { 98 : // in this case, the string_view fits in the local buffer 99 222 : std::size_t nchars=key.copy(key_buffer_char,key_buffer_size-1); 100 222 : key_buffer_char[nchars]='\0'; // ensure null termination 101 : key_buffer=key_buffer_char; 102 : } else { 103 : // in this case, the string_view does not fit in the local buffer 104 : // hence we allocate a new std::string 105 : key_buffer_string=key; 106 : key_buffer=key_buffer_string.c_str(); 107 : } 108 : // in both cases, key_buffer is pointing to a proper null terminated copy 109 : 110 222 : plumed_cmd(plumed_v2c(loaded),key_buffer,safe); 111 : 112 0 : } else plumed_error() << "should never arrive here (either one or the other should work)"; 113 1476 : } 114 : 115 0 : PlumedHandle::PlumedHandle(PlumedHandle && other) noexcept: 116 : local(std::move(other.local)), 117 0 : loaded(other.loaded) 118 : { 119 0 : other.loaded=nullptr; 120 0 : } 121 : 122 0 : PlumedHandle & PlumedHandle::operator=(PlumedHandle && other) noexcept { 123 0 : if(this!=&other) { 124 0 : if(loaded) plumed_finalize(plumed_v2c(loaded)); 125 : local=std::move(other.local); 126 0 : loaded=other.loaded; 127 0 : other.loaded=nullptr; 128 : } 129 0 : return *this; 130 : } 131 : 132 : }