Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

425 lines
11 KiB

  1. //========= Copyright c 1996-2008, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifndef DATA_LINKER_INTERFACE_H
  8. #define DATA_LINKER_INTERFACE_H
  9. #include "tier0/platform.h"
  10. #include "tier0/basetypes.h"
  11. #include "tier0/dbg.h"
  12. template <uint nAlignment = 1, uint nCookie = 0>
  13. struct DataLinkerClassProperties
  14. {
  15. enum {kDataAlignment = nAlignment};
  16. enum {kDataCookie = nCookie};// 0 means no cookie
  17. };
  18. template <typename T>
  19. struct DataLinkerClassPropertiesSelector: public DataLinkerClassProperties<sizeof(T)&1?1:sizeof(T)&3?2:4> // heuristic: 1-, 2- and 4-byte aligned type size calls for 1-, 2- and 4-byte alignment by default
  20. {
  21. };
  22. //#define DATALINKER_ALIGNMENT(ALIGNMENT) enum {kDataAlignment = ALIGNMENT}
  23. #define DATALINKER_CLASS_ALIGNMENT(CLASS, ALIGNMENT) template <> struct DataLinkerClassPropertiesSelector<CLASS> {enum {kDataAlignment = ALIGNMENT};}
  24. DATALINKER_CLASS_ALIGNMENT(float,4);
  25. DATALINKER_CLASS_ALIGNMENT(int32,4);
  26. DATALINKER_CLASS_ALIGNMENT(int16,2);
  27. DATALINKER_CLASS_ALIGNMENT(int8,1);
  28. DATALINKER_CLASS_ALIGNMENT(uint32,4);
  29. DATALINKER_CLASS_ALIGNMENT(uint16,2);
  30. DATALINKER_CLASS_ALIGNMENT(uint8,1);
  31. // undefine DATALINKER_CHECK_COOKIES if you don't want runtime cookie checks
  32. #define DATALINKER_CHECK_COOKIES
  33. namespace DataLinker
  34. {
  35. inline byte *ResolveOffset(int32 *pOffset)
  36. {
  37. int offset = *pOffset;
  38. return offset ? ((byte*)pOffset) + offset : NULL;
  39. }
  40. inline byte *ResolveOffsetFast(const int32 *pOffset)
  41. {
  42. int offset = *pOffset;
  43. Assert(offset != 0);
  44. return ((byte*)pOffset) + offset;
  45. }
  46. // AT RUN-TIME ONLY the offset converts automatically into pointers to the appropritate type
  47. // at tool-time, you should use LinkSource_t and LinkTarget_t
  48. template <typename T, int32 nCookie = 0>
  49. struct Offset_t
  50. {
  51. enum {kDataAlignment = 4};
  52. int32 offset;
  53. bool operator == (int zero)const {Assert(zero == 0); return offset == zero;}
  54. bool IsNull()const {return offset == 0;}
  55. int32 NotNull()const {return offset;}
  56. const T* GetPtr()const
  57. {
  58. // validate
  59. byte *ptr = ResolveOffsetFast(&offset);
  60. #ifdef DATALINKER_CHECK_COOKIES
  61. if(nCookie)
  62. {
  63. if(nCookie != ((int*)ptr)[-1])
  64. {
  65. Error("Invalid data cookie %d != %d\n", ((int*)ptr)[-1], nCookie);
  66. }
  67. }
  68. #endif
  69. return (const T*)ptr;
  70. }
  71. //const T* GetPtrFast()const {return (const T*)ResolveOffsetFast(&offset);}
  72. operator const T* ()const{return GetPtr();}
  73. const T* operator ->() const{return GetPtr();}
  74. };
  75. template <typename T,int32 nCookie = 0>
  76. struct OffsetAndSize_t: public Offset_t<T,nCookie>
  77. {
  78. int32 size;
  79. const T& operator []( int index ) const
  80. {
  81. Assert(index < size);
  82. return this->GetPtr()[index];
  83. }
  84. };
  85. template <typename T,int32 nCookie = 0>
  86. struct OffsetSizeAndStride_t : public OffsetAndSize_t<T,nCookie>
  87. {
  88. int32 stride;
  89. const T& operator []( int index ) const
  90. {
  91. Assert(index < this->size);
  92. return *(const T*)(ResolveOffsetFast(&this->offset) + stride * index);
  93. }
  94. };
  95. enum {kSpecialTargetUndefined = -1};
  96. enum {kSpecialTargetNull = 0};
  97. enum {kSpecialTargetDefault = 1};// resolved pointer/offset right in the LinkSource
  98. // this is resolved or unresolved reference within the data block
  99. // it's unique for the life cycle of the Stream and must either be resolved or
  100. // never referenced by the end
  101. struct LinkTarget_t
  102. {
  103. int m_id;
  104. friend class Stream;
  105. LinkTarget_t(){m_id = kSpecialTargetUndefined;} // -1 is anonymous/undefined reference
  106. };
  107. struct LinkTargetNull_t: public LinkTarget_t
  108. {
  109. LinkTargetNull_t(){m_id = kSpecialTargetNull;} // 0 is special default case meaning null pointer/offset
  110. };
  111. /*
  112. template <typename T>
  113. struct Target_t
  114. {
  115. T* m_ptr;
  116. operator T* () {return m_ptr;}
  117. T* operator -> () {return m_ptr;}
  118. };
  119. */
  120. struct LinkSource_t
  121. {
  122. protected:
  123. int m_offset;
  124. friend class Stream;
  125. LinkSource_t(){}
  126. };
  127. enum OffsetTypeEnum
  128. {
  129. kOtRelative32bit,
  130. kOtRelative16bit,
  131. kOtAbsolute32bit
  132. };
  133. //////////////////////////////////////////////////////////////////////////
  134. // this class may be useful at runtime to use fast serialize interface (without data linking)
  135. //
  136. abstract_class IBasicStream
  137. {
  138. public:
  139. virtual void* WriteBytes(uint numBytes) = 0;
  140. virtual void Align(uint nAlignment, int nOffset = 0) = 0;
  141. inline void AlignPointer(){Align(4);}
  142. virtual long Tell() = 0;
  143. // the Begin/End semantics differ in different implementations
  144. // in some, it can be ignored, some others can use it for statistics and some others may set fixed page boundaries based on the names and/or flags
  145. virtual void Begin(const char *nName, uint flags = 0) = 0;
  146. virtual void End() = 0;
  147. virtual void PrintStats() = 0;
  148. virtual void ClearStats() = 0;
  149. template <typename T>
  150. T* Write(uint count = 1);
  151. template <typename T, int32 nCookie>
  152. T* WriteWithCookie(uint count = 1);
  153. template <typename T, int32 nCookie>
  154. T* WriteWithCookieStrided(uint count, uint stride);
  155. template <typename T>
  156. void WriteSimple(const T x)
  157. {
  158. *Write<T>() = x;
  159. }
  160. virtual void EnsureAvailable(uint addCapacity) = 0;
  161. inline void WriteFloat(float x)
  162. {
  163. WriteSimple(x);
  164. }
  165. inline void WriteU32(uint32 x)
  166. {
  167. WriteSimple(x);
  168. }
  169. inline void WriteU16(uint16 x)
  170. {
  171. WriteSimple(x);
  172. }
  173. inline void WriteByte(byte x)
  174. {
  175. WriteSimple(x);
  176. }
  177. };
  178. //////////////////////////////////////////////////////////////////////////
  179. // this is light-weight version of IStream with Links
  180. // It can link on-the-fly, has minimal overhead but cannot late-bind symbols
  181. // you basically have to manage all your late-bindings by managing
  182. // pointers to offsets, which is fine in 99% of use cases.
  183. // WARNING: there are no error-checking facilities here. If you forget to set
  184. // a link, you'll have a NULL offset and no warnings or errors
  185. //
  186. abstract_class IStream: public IBasicStream
  187. {
  188. public:
  189. template <typename T,int32 nCookie> T* WriteAndLink(Offset_t<T,nCookie>*pOffset, uint count = 1);
  190. template <typename T,int32 nCookie> T* WriteAndLink(OffsetAndSize_t<T,nCookie>*pOffset, uint count = 1); // intentionally not implemented - use explicit WriteAndLinkArray()
  191. template <typename T,int32 nCookie> T* WriteAndLinkArray(OffsetAndSize_t<T,nCookie>*pOffsetAndSize, uint count = 1);
  192. template <typename T,int32 nCookie> T* WriteAndLinkStrided(OffsetSizeAndStride_t<T,nCookie>*pOffset, uint nStride, uint count = 1);
  193. template <typename T,int32 nCookie> void Link(Offset_t<T,nCookie>*pOffset, const T* pTarget);
  194. virtual void Link(int32 *pOffset, const void *pTarget) = 0;
  195. virtual void Link(int16 *pOffset, const void *pTarget) = 0;
  196. virtual bool Compile(void *pBuffer) = 0;
  197. virtual uint GetTotalSize()const = 0;
  198. };
  199. //////////////////////////////////////////////////////////////////////////
  200. // This is IStream with late-binding capabilities. You can link multiple sources to
  201. // the same target, then change your mind and reset the target somewhere and it'll
  202. // automatically track all sources and reset them to the latest target at compilation.
  203. // You can create unresolved targets to resolve them later.
  204. // You can extend this to multiple object files linked at later stage (szDescription
  205. // must be unique identifiers)
  206. //
  207. abstract_class ILinkStream: public IStream
  208. {
  209. public:
  210. virtual LinkSource_t WriteOffset(const char *szDescription) = 0;
  211. virtual LinkSource_t WriteOffset(LinkTarget_t linkTarget, const char *szDescription) = 0;
  212. virtual LinkSource_t WriteNullOffset(const char *szDescription) = 0;
  213. virtual void Link(LinkSource_t, LinkTarget_t, const char *szDescription) = 0;
  214. virtual LinkSource_t LinkToHere(int32 *pOffset, const char *szDescription) = 0;
  215. virtual LinkSource_t Link(int32 *pOffset, LinkTarget_t linkTarget, const char *szDescription) = 0;
  216. virtual LinkTarget_t NewTarget() = 0; // create new, unresolved target
  217. virtual LinkTarget_t NewTarget(void *pWhere) = 0;
  218. virtual LinkTarget_t NewTargetHere() = 0; // creates a target right here
  219. virtual void SetTargetHere(LinkTarget_t) = 0; // sets the given target to point to right here
  220. virtual void SetTargetNull(LinkTarget_t) = 0; // set this target to point to NULL
  221. virtual LinkSource_t NewOffset(int *pOffset, const char *szDescription) = 0;
  222. virtual bool IsDeclared(LinkTarget_t linkTarget)const = 0;
  223. virtual bool IsSet(LinkTarget_t linkTarget)const = 0;
  224. virtual bool IsDefined(LinkSource_t linkSource)const = 0;
  225. virtual bool IsLinked(LinkSource_t linkSource)const = 0;
  226. };
  227. template <typename T>
  228. inline T* IBasicStream::Write(uint count)
  229. {
  230. // TODO: insert reflection code here
  231. uint nAlignment = DataLinkerClassPropertiesSelector<T>::kDataAlignment;
  232. Align(nAlignment);
  233. return (T*)WriteBytes(count * sizeof(T));
  234. }
  235. template <typename T, int32 nCookie>
  236. inline T* IBasicStream::WriteWithCookie(uint count)
  237. {
  238. // TODO: insert reflection code here
  239. uint nAlignment = DataLinkerClassPropertiesSelector<T>::kDataAlignment;
  240. if(nCookie)
  241. {
  242. if(nAlignment > sizeof(int32))
  243. {
  244. Align(nAlignment, -4);
  245. }
  246. else
  247. {
  248. Align(sizeof(int32));// we want the cookie itself aligned properly
  249. }
  250. WriteSimple<int32>(nCookie);
  251. Assert((Tell()&(nAlignment-1)) == 0); // must be correctly aligned by now
  252. }
  253. else
  254. {
  255. if(nAlignment > 1)
  256. {
  257. Align(nAlignment);
  258. }
  259. }
  260. return (T*)WriteBytes(count * sizeof(T));
  261. }
  262. template <typename T, int32 nCookie>
  263. inline T* IBasicStream::WriteWithCookieStrided(uint count, uint stride)
  264. {
  265. // TODO: insert reflection code here
  266. uint nAlignment = DataLinkerClassPropertiesSelector<T>::kDataAlignment;
  267. if(nCookie)
  268. {
  269. if(nAlignment > sizeof(int32))
  270. {
  271. Align(nAlignment, -4);
  272. }
  273. else
  274. {
  275. Align(sizeof(int32));// we want the cookie itself aligned properly
  276. }
  277. WriteSimple<int32>(nCookie);
  278. Assert((Tell()&(nAlignment-1)) == 0); // must be correctly aligned by now
  279. }
  280. else
  281. {
  282. if(nAlignment > 1)
  283. {
  284. Align(nAlignment);
  285. }
  286. }
  287. if(count)
  288. return (T*)WriteBytes((count-1) * stride + sizeof(T));
  289. else
  290. return (T*)WriteBytes(0);
  291. }
  292. template <typename T,int32 nCookie>
  293. inline void IStream::Link(Offset_t<T,nCookie>*pOffset, const T* pTarget)
  294. {
  295. Link(&pOffset->offset, pTarget);
  296. }
  297. template <typename T, int32 nCookie>
  298. inline T* IStream::WriteAndLink(Offset_t<T,nCookie>*pOffset, uint count)
  299. {
  300. T* p = WriteWithCookie<T,nCookie>(count);
  301. Link(&pOffset->offset, p);
  302. return p;
  303. }
  304. template <typename T, int32 nCookie>
  305. inline T* IStream::WriteAndLinkArray(OffsetAndSize_t<T,nCookie>*pOffsetAndSize, uint count)
  306. {
  307. pOffsetAndSize->size = count;
  308. if(count)
  309. {
  310. T* p = WriteWithCookie<T,nCookie>(count);
  311. Link(&pOffsetAndSize->offset, p);
  312. return p;
  313. }
  314. else
  315. {
  316. pOffsetAndSize->offset = 0;
  317. return NULL;
  318. }
  319. }
  320. template <typename T, int32 nCookie>
  321. inline T* IStream::WriteAndLinkStrided(OffsetSizeAndStride_t<T,nCookie>*pOffset, uint stride, uint count)
  322. {
  323. pOffset->size = count;
  324. pOffset->stride = stride;
  325. if(count)
  326. {
  327. T* p = WriteWithCookieStrided<T,nCookie>(count, stride);
  328. Link(&pOffset->offset, p);
  329. return p;
  330. }
  331. else
  332. {
  333. pOffset->offset = 0;
  334. return NULL;
  335. }
  336. }
  337. }
  338. struct DataLinkerBasicStreamRange_t
  339. {
  340. DataLinker::IBasicStream *m_pStream;
  341. DataLinkerBasicStreamRange_t(DataLinker::IBasicStream *pStream, const char *name): m_pStream(pStream){pStream->Begin(name);}
  342. ~DataLinkerBasicStreamRange_t(){m_pStream->End();}
  343. };
  344. #define DATALINKER_RANGE(STREAM,NAME) DataLinkerBasicStreamRange_t dataLinker_basicStreamRange##__LINE((STREAM),(NAME))
  345. #endif