aboutsummaryrefslogtreecommitdiff
path: root/sp/src/public/dt_utlvector_recv.cpp
blob: 7fa86fdc0864667161129a3d2f81fd173fe85737 (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//
//=============================================================================//

#include "dt_utlvector_recv.h"

#include "tier0/memdbgon.h"


extern const char *s_ClientElementNames[MAX_ARRAY_ELEMENTS];


class CRecvPropExtra_UtlVector
{
public:
	DataTableRecvVarProxyFn m_DataTableProxyFn;	// If it's a datatable, then this is the proxy they specified.
	RecvVarProxyFn m_ProxyFn;				// If it's a non-datatable, then this is the proxy they specified.
	ResizeUtlVectorFn m_ResizeFn;			// The function used to resize the CUtlVector.
	EnsureCapacityFn m_EnsureCapacityFn;
	int m_ElementStride;					// Distance between each element in the array.
	int m_Offset;							// Offset of the CUtlVector from its parent structure.
	int m_nMaxElements;						// For debugging...
};

void RecvProxy_UtlVectorLength( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
	CRecvPropExtra_UtlVector *pExtra = (CRecvPropExtra_UtlVector*)pData->m_pRecvProp->GetExtraData();
	pExtra->m_ResizeFn( pStruct, pExtra->m_Offset, pData->m_Value.m_Int );
}

void RecvProxy_UtlVectorElement( const CRecvProxyData *pData, void *pStruct, void *pOut )
{
	CRecvPropExtra_UtlVector *pExtra = (CRecvPropExtra_UtlVector*)pData->m_pRecvProp->GetExtraData();

	// Kind of lame overloading element stride to hold the element index,
	// but we can easily move it into its SetExtraData stuff if we need to.
	int iElement = pData->m_pRecvProp->GetElementStride();

	// NOTE: this is cheesy, but it does the trick.
	CUtlVector<int> *pUtlVec = (CUtlVector<int>*)((char*)pStruct + pExtra->m_Offset);

	// Call through to the proxy they passed in, making pStruct=the CUtlVector.
	// Note: there should be space here as long as the element is < the max # elements
	// that we ensured capacity for in DataTableRecvProxy_LengthProxy.
	pExtra->m_ProxyFn( pData, pOut, (char*)pUtlVec->Base() + iElement*pExtra->m_ElementStride );
}

void RecvProxy_UtlVectorElement_DataTable( const RecvProp *pProp, void **pOut, void *pData, int objectID )
{
	CRecvPropExtra_UtlVector *pExtra = (CRecvPropExtra_UtlVector*)pProp->GetExtraData();

	int iElement = pProp->GetElementStride();
	Assert( iElement < pExtra->m_nMaxElements );

	// NOTE: this is cheesy, but it does the trick.
	CUtlVector<int> *pUtlVec = (CUtlVector<int>*)((char*)pData + pExtra->m_Offset);

	// Call through to the proxy they passed in, making pStruct=the CUtlVector and forcing iElement to 0.
	pExtra->m_DataTableProxyFn( pProp, pOut, (char*)pUtlVec->Base() + iElement*pExtra->m_ElementStride, objectID );
}


void DataTableRecvProxy_LengthProxy( const RecvProp *pProp, void **pOut, void *pData, int objectID )
{
	// This is VERY important - since it calls all the datatable proxies in the tree first, 
	// particularly BEFORE it calls our array length proxy, we need to make sure we return 
	// valid pointers that aren't going to change when it starts to copy the data into 
	// the datatable elements.
	CRecvPropExtra_UtlVector *pExtra = (CRecvPropExtra_UtlVector*)pProp->GetExtraData();
	pExtra->m_EnsureCapacityFn( pData, pExtra->m_Offset, pExtra->m_nMaxElements );
	
	*pOut = pData;
}


RecvProp RecvPropUtlVector(
	const char *pVarName,		// Use RECVINFO_UTLVECTOR to generate these 4.
	int offset,			// Used to generate pData in the function specified in varProxy.
	int sizeofVar,		// The size of each element in the utlvector.
	ResizeUtlVectorFn fn,
	EnsureCapacityFn ensureFn,
	int nMaxElements,											// Max # of elements in the array. Keep this as low as possible.
	RecvProp pArrayProp
	)
{
	RecvProp ret;

	Assert( nMaxElements <= MAX_ARRAY_ELEMENTS );

	ret.m_RecvType = DPT_DataTable;
	ret.m_pVarName = pVarName;
	ret.SetOffset( 0 );
	ret.SetDataTableProxyFn( DataTableRecvProxy_StaticDataTable );
	
	RecvProp *pProps = new RecvProp[nMaxElements+1]; // TODO free that again

	
	// Extra data bound to each of the properties.
	CRecvPropExtra_UtlVector *pExtraData = new CRecvPropExtra_UtlVector;
	
	pExtraData->m_nMaxElements = nMaxElements;
	pExtraData->m_ElementStride = sizeofVar;
	pExtraData->m_ResizeFn = fn;
	pExtraData->m_EnsureCapacityFn = ensureFn;
	pExtraData->m_Offset = offset;
	
	if ( pArrayProp.m_RecvType == DPT_DataTable )
		pExtraData->m_DataTableProxyFn = pArrayProp.GetDataTableProxyFn();
	else
		pExtraData->m_ProxyFn = pArrayProp.GetProxyFn();


	// The first property is datatable with an int that tells the length of the array.
	// It has to go in a datatable, otherwise if this array holds datatable properties, it will be received last.
	RecvProp *pLengthProp = new RecvProp;
	*pLengthProp = RecvPropInt( AllocateStringHelper( "lengthprop%d", nMaxElements ), 0, 0, 0, RecvProxy_UtlVectorLength );
	pLengthProp->SetExtraData( pExtraData );

	char *pLengthProxyTableName = AllocateUniqueDataTableName( false, "_LPT_%s_%d", pVarName, nMaxElements );
	RecvTable *pLengthTable = new RecvTable( pLengthProp, 1, pLengthProxyTableName );
	pProps[0] = RecvPropDataTable( "lengthproxy", 0, 0, pLengthTable, DataTableRecvProxy_LengthProxy );
	pProps[0].SetExtraData( pExtraData );

	// The first element is a sub-datatable.
	for ( int i = 1; i < nMaxElements+1; i++ )
	{
		pProps[i] = pArrayProp;	// copy array element property setting
		pProps[i].SetOffset( 0 ); // leave offset at 0 so pStructBase is always a pointer to the CUtlVector
		pProps[i].m_pVarName = s_ClientElementNames[i-1];	// give unique name
		pProps[i].SetExtraData( pExtraData );
		pProps[i].SetElementStride( i-1 );	// Kind of lame overloading element stride to hold the element index,
											// but we can easily move it into its SetExtraData stuff if we need to.
		
		// We provide our own proxy here.
		if ( pArrayProp.m_RecvType == DPT_DataTable )
		{
			pProps[i].SetDataTableProxyFn( RecvProxy_UtlVectorElement_DataTable );
		}
		else
		{
			pProps[i].SetProxyFn( RecvProxy_UtlVectorElement );
		}
	}

	RecvTable *pTable = new RecvTable( 
		pProps, 
		nMaxElements+1, 
		AllocateUniqueDataTableName( false, "_ST_%s_%d", pVarName, nMaxElements )
		); // TODO free that again

	ret.SetDataTable( pTable );
	return ret;
}