aboutsummaryrefslogtreecommitdiff
path: root/mp/src/public/tier0/dynfunction.h
blob: bd976b7353c2b2e32500f0d0e2c716a23060b863 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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