summaryrefslogtreecommitdiff
path: root/public/tier0/dynfunction.h
diff options
context:
space:
mode:
Diffstat (limited to 'public/tier0/dynfunction.h')
-rw-r--r--public/tier0/dynfunction.h136
1 files changed, 136 insertions, 0 deletions
diff --git a/public/tier0/dynfunction.h b/public/tier0/dynfunction.h
new file mode 100644
index 0000000..bd976b7
--- /dev/null
+++ b/public/tier0/dynfunction.h
@@ -0,0 +1,136 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+// This makes it easy to dynamically load a shared library and lookup a
+// function in that library.
+//
+// Usage:
+// CDynamicFunction<void (*)(const char *)> MyPuts(libname, "puts");
+// if (MyPuts)
+// MyPuts("Hello world!");
+//
+// Please note that this interface does not distinguish between functions and
+// data. If you look up a global variable in your shared library, or simply
+// mess up the function signature, you'll get a valid pointer and a crash
+// if you call it as a function.
+
+#ifndef DYNFUNCTION_H
+#define DYNFUNCTION_H
+#pragma once
+
+#include "tier0/platform.h"
+
+// The heavy lifting isn't template-specific, so we move it out of the header.
+DLL_EXPORT void *VoidFnPtrLookup_Tier0(const char *libname, const char *fn, void *fallback);
+
+template < class FunctionType >
+class CDynamicFunction
+{
+public:
+ // Construct with a NULL function pointer. You must manually call
+ // Lookup() before you can call a dynamic function through this interface.
+ CDynamicFunction() : m_pFn(NULL) {}
+
+ // Construct and do a lookup right away. You will need to make sure that
+ // the lookup actually succeeded, as (libname) might have failed to load
+ // or (fn) might not exist in it.
+ CDynamicFunction(const char *libname, const char *fn, FunctionType fallback=NULL) : m_pFn(NULL)
+ {
+ Lookup(libname, fn, fallback);
+ }
+
+ // Construct and do a lookup right away. See comments in Lookup() about what (okay) does.
+ CDynamicFunction(const char *libname, const char *fn, bool &okay, FunctionType fallback=NULL) : m_pFn(NULL)
+ {
+ Lookup(libname, fn, okay, fallback);
+ }
+
+ // Load library if necessary, look up symbol. Returns true and sets
+ // m_pFn on successful lookup, returns false otherwise. If the
+ // function pointer is already looked up, this return true immediately.
+ // Use Reset() first if you want to look up the symbol again.
+ // This function will return false immediately unless (okay) is true.
+ // This allows you to chain lookups like this:
+ // bool okay = true;
+ // x.Lookup(lib, "x", okay);
+ // y.Lookup(lib, "y", okay);
+ // z.Lookup(lib, "z", okay);
+ // if (okay) { printf("All functions were loaded successfully!\n"); }
+ // If you supply a fallback, it'll be used if the lookup fails (and if
+ // non-NULL, means this will always return (okay)).
+ bool Lookup(const char *libname, const char *fn, bool &okay, FunctionType fallback=NULL)
+ {
+ if (!okay)
+ return false;
+ else if (m_pFn == NULL)
+ m_pFn = (FunctionType) VoidFnPtrLookup_Tier0(libname, fn, (void *) fallback);
+ okay = m_pFn != NULL;
+ return okay;
+ }
+
+ // Load library if necessary, look up symbol. Returns true and sets
+ // m_pFn on successful lookup, returns false otherwise. If the
+ // function pointer is already looked up, this return true immediately.
+ // Use Reset() first if you want to look up the symbol again.
+ // This function will return false immediately unless (okay) is true.
+ // If you supply a fallback, it'll be used if the lookup fails (and if
+ // non-NULL, means this will always return true).
+ bool Lookup(const char *libname, const char *fn, FunctionType fallback=NULL)
+ {
+ bool okay = true;
+ return Lookup(libname, fn, okay, fallback);
+ }
+
+ // Invalidates the current lookup. Makes the function pointer NULL. You
+ // will need to call Lookup() before you can call a dynamic function
+ // through this interface again.
+ void Reset() { m_pFn = NULL; }
+
+ // Force this to be a specific function pointer.
+ void Force(FunctionType ptr) { m_pFn = ptr; }
+
+ // Retrieve the actual function pointer.
+ FunctionType Pointer() const { return m_pFn; }
+ operator FunctionType() const { return m_pFn; }
+
+ // Can be used to verify that we have an actual function looked up and
+ // ready to call: if (!MyDynFunc) { printf("Function not found!\n"); }
+ operator bool () const { return m_pFn != NULL; }
+ bool operator !() const { return m_pFn == NULL; }
+
+protected:
+ FunctionType m_pFn;
+};
+
+
+// This is the same as CDynamicFunction, but we made the default constructor
+// private, forcing you to do loading/lookup during construction.
+// The usage pattern is to have a list of dynamic functions that are
+// constructed en masse as part of another class's constructor, with the
+// possibility of human error removed (the compiler will complain if you
+// forget to initialize one).
+template < class FunctionType >
+class CDynamicFunctionMustInit : public CDynamicFunction < FunctionType >
+{
+private: // forbid default constructor.
+ CDynamicFunctionMustInit() {}
+
+public:
+ CDynamicFunctionMustInit(const char *libname, const char *fn, FunctionType fallback=NULL)
+ : CDynamicFunction< FunctionType >(libname, fn, fallback)
+ {
+ }
+
+ CDynamicFunctionMustInit(const char *libname, const char *fn, bool &okay, FunctionType fallback=NULL)
+ : CDynamicFunction< FunctionType >(libname, fn, okay, fallback)
+ {
+ }
+};
+
+#endif // DYNFUNCTION_H
+