source-engine/public/tier0/dynfunction.h

137 lines
5.0 KiB
C
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= 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