SeExpr
ExprFunc.cpp
Go to the documentation of this file.
1 /*
2  Copyright Disney Enterprises, Inc. All rights reserved.
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License
6  and the following modification to it: Section 6 Trademarks.
7  deleted and replaced with:
8 
9  6. Trademarks. This License does not grant permission to use the
10  trade names, trademarks, service marks, or product names of the
11  Licensor and its affiliates, except as required for reproducing
12  the content of the NOTICE file.
13 
14  You may obtain a copy of the License at
15  http://www.apache.org/licenses/LICENSE-2.0
16 */
17 #include <string>
18 #include <map>
19 #include <stdlib.h>
20 #include <iostream>
21 #ifndef SEEXPR_WIN32
22 #include <dlfcn.h>
23 #include <dirent.h>
24 #endif
25 
26 #include "Expression.h"
27 #include "ExprFunc.h"
28 #include "ExprNode.h"
29 #include "ExprBuiltins.h"
30 
31 #include "Mutex.h"
32 
33 namespace {
34 // FuncTable - table of pre-defined functions
35 class FuncTable {
36  public:
37  void define(const char* name, SeExpr2::ExprFunc f, const char* docString = 0) {
38  if (docString)
39  funcmap[name] = FuncMapItem(std::string(docString), f);
40  else
41  funcmap[name] = FuncMapItem(name, f);
42  }
43 
44  const SeExpr2::ExprFunc* lookup(const std::string& name) {
45  FuncMap::iterator iter;
46  if ((iter = funcmap.find(name)) != funcmap.end()) return &iter->second.second;
47  return 0;
48  }
49  void initBuiltins();
50 
51  void getFunctionNames(std::vector<std::string>& names) {
52  for (FuncMap::iterator i = funcmap.begin(); i != funcmap.end(); ++i) names.push_back(i->first);
53  }
54 
55  std::string getDocString(const char* functionName) {
56  FuncMap::iterator i = funcmap.find(functionName);
57  if (i == funcmap.end())
58  return "";
59  else
60  return i->second.first;
61  }
62 
63  size_t sizeInBytes() const {
64  size_t totalSize = 0;
65  for (FuncMap::const_iterator it = funcmap.begin(); it != funcmap.end(); ++it) {
66  totalSize += it->first.size() + sizeof(FuncMapItem);
67  const SeExpr2::ExprFunc& function = it->second.second;
68  if (const SeExpr2::ExprFuncX* funcx = function.funcx()) {
69  totalSize += funcx->sizeInBytes();
70  }
71  }
72  return totalSize;
73  }
74 
75  SeExpr2::Statistics statistics() const {
76  SeExpr2::Statistics statisticsDump;
77  size_t totalSize = 0;
78  for (FuncMap::const_iterator it = funcmap.begin(); it != funcmap.end(); ++it) {
79  totalSize += it->first.size() + sizeof(FuncMapItem);
80  const SeExpr2::ExprFunc& function = it->second.second;
81  if (const SeExpr2::ExprFuncX* funcx = function.funcx()) {
82  funcx->statistics(statisticsDump);
83  }
84  }
85  return statisticsDump;
86  }
87 
88  private:
89  typedef std::pair<std::string, SeExpr2::ExprFunc> FuncMapItem;
90  typedef std::map<std::string, FuncMapItem> FuncMap;
91  FuncMap funcmap;
92 };
93 
94 FuncTable* Functions = 0;
95 }
96 
97 // ExprType ExprFuncX::prep(ExprFuncNode* node, bool scalarWanted, ExprVarEnv & env) const
98 //{
99 // /* call base node prep by default:
100 // this passes wantVec to all the children and sets isVec true if any
101 // child is a vec */
102 // /* TODO: check that this is correct behavior */
103 // return node->ExprNode::prep(scalarWanted, env);
104 //}
105 
106 namespace SeExpr2 {
107 
108 std::vector<void*> ExprFunc::dynlib;
109 
111 
114  initInternal();
115 }
116 
119  delete Functions;
120  Functions = nullptr;
121 #ifdef SEEXPR_WIN32
122 #else
123  for(size_t i=0; i<dynlib.size(); i++){
124  dlclose(dynlib[i]);
125  }
126 #endif
127 
128 }
129 
130 const ExprFunc* ExprFunc::lookup(const std::string& name) {
131  mutex.lock();
132  if (!Functions) initInternal();
133  const ExprFunc* ret = Functions->lookup(name);
134  mutex.unlock();
135  return ret;
136 }
137 
138 inline static void defineInternal(const char* name, ExprFunc f) {
139  // THIS FUNCTION IS NOT THREAD SAFE, it assumes you have a mutex from callee
140  // ALSO YOU MUST BE VERY CAREFUL NOT TO CALL ANYTHING THAT TRIES TO REACQUIRE MUTEX!
141  Functions->define(name, f);
142 }
143 
144 inline static void defineInternal3(const char* name, ExprFunc f, const char* docString) {
145  // THIS FUNCTION IS NOT THREAD SAFE, it assumes you have a mutex from callee
146  // ALSO YOU MUST BE VERY CAREFUL NOT TO CALL ANYTHING THAT TRIES TO REACQUIRE MUTEX!
147  Functions->define(name, f, docString);
148 }
149 
151  // THIS FUNCTION IS NOT THREAD SAFE, it assumes you have a mutex from callee
152  // ALSO YOU MUST BE VERY CAREFUL NOT TO CALL ANYTHING THAT TRIES TO REACQUIRE MUTEX!
153 
154  // TODO: make thread safe
155  if (Functions) return;
156  Functions = new FuncTable;
158  const char* path = getenv("SE_EXPR_PLUGINS");
159  if (path) loadPlugins(path);
160 }
161 
162 void ExprFunc::define(const char* name, ExprFunc f) {
163  mutex.lock();
164  if (!Functions) initInternal();
165  defineInternal(name, f);
166  mutex.unlock();
167 }
168 
169 void ExprFunc::define(const char* name, ExprFunc f, const char* docString) {
170  mutex.lock();
171  if (!Functions) initInternal();
172  defineInternal3(name, f, docString);
173  mutex.unlock();
174 }
175 
176 void ExprFunc::getFunctionNames(std::vector<std::string>& names) {
177  mutex.lock();
178  if (!Functions) initInternal();
179  Functions->getFunctionNames(names);
180  mutex.unlock();
181 }
182 
183 std::string ExprFunc::getDocString(const char* functionName) {
184  mutex.lock();
185  if (!Functions) initInternal();
186  std::string ret = Functions->getDocString(functionName);
187  mutex.unlock();
188  return ret;
189 }
190 
193  if (!Functions) initInternal();
194  return Functions->sizeInBytes();
195 }
196 
199  if (!Functions) initInternal();
200  return Functions->statistics();
201 }
202 
203 #ifndef SEEXPR_WIN32
204 
205 #if defined(__APPLE__) && !defined(__MAC_10_9)
206 static int MatchPluginName(const struct dirent* dir)
207 #else
208 static int MatchPluginName(const struct dirent* dir)
209 #endif
210 {
211  const char* name = dir->d_name;
212  // return true if name matches SeExpr*.so
213  return !strncmp(name, "SeExpr", 6) && !strcmp(name + strlen(name) - 3, ".so");
214 }
215 #endif
216 
217 void ExprFunc::loadPlugins(const char* path) {
218 #ifdef SEEXPR_WIN32
219 
220 #else
221  // first split path into individual entries
222  char* pathdup = strdup(path);
223  char* state = 0;
224  char* entry = strtok_r(pathdup, ":", &state);
225  while (entry) {
226  // if entry ends with ".so", load directly
227  if ((!strcmp(entry + strlen(entry) - 3, ".so")))
228  loadPlugin(entry);
229  else {
230  // assume it's a dir - search it for plugins
231  struct dirent** matches = 0;
232  int numMatches = scandir(entry, &matches, MatchPluginName, alphasort);
233  for (int i = 0; i < numMatches; i++) {
234  std::string fullpath = entry;
235  fullpath += "/";
236  fullpath += matches[i]->d_name;
237  loadPlugin(fullpath.c_str());
238  }
239  if (matches)
240  free(matches);
241  else {
242  std::cerr << "No plugins found matching " << path << "/SeExpr*.so" << std::endl;
243  }
244  }
245 
246  entry = strtok_r(0, ":", &state);
247  }
248  free(pathdup);
249 #endif
250 }
251 
252 void ExprFunc::loadPlugin(const char* path) {
253 #ifdef SEEXPR_WIN32
254  std::cerr << "SeExpr: warning Plugins are not supported on windows currently" << std::endl;
255 #else
256  void* handle = dlopen(path, RTLD_LAZY);
257  if (!handle) {
258  std::cerr << "Error reading expression plugin: " << path << std::endl;
259  const char* err = dlerror();
260  if (err) std::cerr << err << std::endl;
261  return;
262  }
263 
264  typedef void (*initfn_v3)(ExprFunc::Define3);
265  initfn_v3 init_v3 = (initfn_v3)dlsym(handle, "SeExpr2PluginInit");
266 
267  if (init_v3) {
268  init_v3(defineInternal3);
269  dynlib.push_back(handle);
270  } else {
271  std::cerr << "Error reading expression plugin: " << path << std::endl;
272  std::cerr << "No function named SeExpr2PluginInit defined" << std::endl;
273  dlclose(handle);
274  }
275  return;
276 #endif
277 }
278 }
SeExprInternal2::DebugLock::unlock
void unlock()
Definition: Mutex.h:35
f
with numParticles numAttributes A variable block contains variable names and types but doesn t care what the values are< pre > void f(const std::string &s, MyParticleData *p, int outputDim=3)
Definition: varblocks.txt:35
SeExpr2::defineInternal3
static void defineInternal3(const char *name, ExprFunc f, const char *docString)
Definition: ExprFunc.cpp:144
SeExpr2::ExprFunc::cleanup
static void cleanup()
cleanup all functions
Definition: ExprFunc.cpp:117
SeExpr2::ExprFunc::init
static void init()
call to define built-in funcs and load standard plugins
Definition: ExprFunc.cpp:112
SeExpr2::ExprFunc::Define3
void(* Define3)(const char *name, ExprFunc f, const char *docString)
Definition: ExprFunc.h:65
SeExpr2::ExprFunc::getFunctionNames
static void getFunctionNames(std::vector< std::string > &names)
Get a list of registered builtin and DSO generated functions.
Definition: ExprFunc.cpp:176
SeExpr2::mutex
static SeExprInternal2::Mutex mutex
Definition: ExprFunc.cpp:110
SeExpr2::ExprFunc::sizeInBytes
static size_t sizeInBytes()
Get the total size estimate of all plugins.
Definition: ExprFunc.cpp:191
SeExpr2::defineBuiltins
void defineBuiltins(ExprFunc::Define define, ExprFunc::Define3 define3)
Definition: ExprBuiltins.cpp:1603
SeExpr2::MatchPluginName
static int MatchPluginName(const struct dirent *dir)
Definition: ExprFunc.cpp:208
SeExpr2::ExprFuncX
Extension function spec, used for complicated argument custom functions.
Definition: ExprFuncX.h:35
ExprFunc.h
SeExpr2::ExprFunc
Function Definition, used in parse tree and func table.
Definition: ExprFunc.h:44
SeExpr2
Definition: Context.h:22
SeExpr2::ExprFunc::statistics
static Statistics statistics()
Dump statistics.
Definition: ExprFunc.cpp:197
ExprNode.h
SeExpr2::ExprFunc::dynlib
static std::vector< void * > dynlib
Definition: ExprFunc.h:132
ExprBuiltins.h
SeExpr2::defineInternal
static void defineInternal(const char *name, ExprFunc f)
Definition: ExprFunc.cpp:138
it
you may not use this file except in compliance with the License and the following modification to it
Definition: license.txt:10
SeExprInternal2::AutoLock
Definition: Mutex.h:49
Mutex.h
SeExpr2::ExprFunc::loadPlugins
static void loadPlugins(const char *path)
load all plugins in a given path
Definition: ExprFunc.cpp:217
SeExpr2::ExprFunc::lookup
static const ExprFunc * lookup(const std::string &name)
Lookup a builtin function by name.
Definition: ExprFunc.cpp:130
SeExprInternal2::DebugLock
Definition: Mutex.h:28
SeExpr2::ExprFunc::define
static void define(const char *name, ExprFunc f, const char *docString)
Definition: ExprFunc.cpp:169
SeExpr2::ExprFunc::initInternal
static void initInternal()
Definition: ExprFunc.cpp:150
SeExpr2::ExprFunc::getDocString
static std::string getDocString(const char *functionName)
Get doc string for a specific function.
Definition: ExprFunc.cpp:183
Expression.h
SeExpr2::Statistics
std::map< std::string, double > Statistics
Definition: ExprFuncX.h:27
SeExpr2::ExprFunc::loadPlugin
static void loadPlugin(const char *path)
load a given plugin
Definition: ExprFunc.cpp:252
SeExprInternal2::DebugLock::lock
void lock()
Definition: Mutex.h:31