diff options
Diffstat (limited to 'public/tier0/dynfunction.h')
| -rw-r--r-- | public/tier0/dynfunction.h | 136 |
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 + |