1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 /* string table: holds all strings used by script engine */
17 
18 #ifndef C4STRINGTABLE_H
19 #define C4STRINGTABLE_H
20 
21 class C4RefCnt
22 {
23 public:
24 	C4RefCnt() = default;
25 	virtual ~C4RefCnt() = default;
26 	// Add/Remove Reference
IncRef()27 	void IncRef() { RefCnt++; }
DecRef()28 	void DecRef() { if (!--RefCnt) delete this; }
29 protected:
30 	// Reference counter
31 	unsigned int RefCnt{0};
32 };
33 
34 class C4String: public C4RefCnt
35 {
36 public:
37 	unsigned int Hash;
38 private:
39 	StdCopyStrBuf Data; // string data
40 
41 	explicit C4String(StdStrBuf strString);
42 	C4String();
43 	void operator=(const char * s);
44 
45 	friend class C4StringTable;
46 public:
47 	~C4String() override;
48 
GetCStr()49 	const char * GetCStr() const { return Data.getData(); }
GetData()50 	StdStrBuf GetData() const { return Data.getRef(); }
51 
52 };
53 
54 template <class T>
55 class C4RefCntPointer
56 {
57 public:
C4RefCntPointer(T * p)58 	C4RefCntPointer(T* p): p(p) { IncRef(); }
C4RefCntPointer()59 	C4RefCntPointer(): p(nullptr) { }
C4RefCntPointer(const C4RefCntPointer<T> & r)60 	C4RefCntPointer(const C4RefCntPointer<T> & r) : p(r.p) { IncRef(); }
C4RefCntPointer(const C4RefCntPointer<U> & r)61 	template <class U> C4RefCntPointer(const C4RefCntPointer<U> & r): p(r.p) { IncRef(); }
62 	// Move constructor
C4RefCntPointer(C4RefCntPointer<T> && r)63 	C4RefCntPointer(C4RefCntPointer<T> &&r) : p(r.p) { r.p = nullptr; }
C4RefCntPointer(C4RefCntPointer<U> && r)64 	template <class U> C4RefCntPointer(C4RefCntPointer<U> &&r): p(r.p) { r.p = 0; }
65 	// Move assignment
66 	C4RefCntPointer& operator = (C4RefCntPointer<T> &&r)
67 	{
68 		if (p != r.p)
69 		{
70 			DecRef();
71 			p = r.p;
72 			r.p = nullptr;
73 		}
74 		return *this;
75 	}
76 	template <class U> C4RefCntPointer& operator = (C4RefCntPointer<U> &&r)
77 	{
78 		if (p != r.p)
79 		{
80 			DecRef();
81 			p = r.p;
82 			r.p = 0;
83 		}
84 		return *this;
85 	}
~C4RefCntPointer()86 	~C4RefCntPointer() { DecRef(); }
87 	template <class U> C4RefCntPointer& operator = (U* new_p)
88 	{
89 		if (p != new_p)
90 		{
91 			DecRef();
92 			p = new_p;
93 			IncRef();
94 		}
95 		return *this;
96 	}
97 	C4RefCntPointer& operator = (const C4RefCntPointer<T>& r)
98 	{
99 		return *this = r.p;
100 	}
101 	template <class U> C4RefCntPointer& operator = (const C4RefCntPointer<U>& r)
102 	{
103 		return *this = r.p;
104 	}
105 	T& operator * () { return *p; }
106 	const T& operator * () const { return *p; }
107 	T* operator -> () { return p; }
108 	const T* operator -> () const { return p; }
109 	operator T * () { return p; }
110 	operator const T * () const { return p; }
Get()111 	T *Get() const { return p; }
112 private:
IncRef()113 	void IncRef() { if (p) p->IncRef(); }
DecRef()114 	void DecRef() { if (p) p->DecRef(); }
115 	T * p;
116 };
117 
118 template<typename T> class C4Set
119 {
120 	unsigned int Capacity{2};
121 	unsigned int Size{0};
122 	T * Table;
GetPlaceFor(T const & e)123 	T * GetPlaceFor(T const & e)
124 	{
125 		unsigned int h = Hash(e);
126 		T * p = &Table[h % Capacity];
127 		while (*p && !Equals(*p, e))
128 		{
129 			p = &Table[++h % Capacity];
130 		}
131 		return p;
132 	}
AddInternal(T const & e)133 	T * AddInternal(T const & e)
134 	{
135 		T * p = GetPlaceFor(e);
136 		*p = e;
137 		return p;
138 	}
AddInternal(T && e)139 	T * AddInternal(T && e)
140 	{
141 		T * p = GetPlaceFor(e);
142 		*p = std::move(e);
143 		return p;
144 	}
ClearTable()145 	void ClearTable()
146 	{
147 		for (unsigned int i = 0; i < Capacity; ++i)
148 			Table[i] = nullptr;
149 	}
MaintainCapacity()150 	void MaintainCapacity()
151 	{
152 		if (Capacity - Size < std::max(2u, Capacity / 4))
153 		{
154 			unsigned int OCapacity = Capacity;
155 			Capacity *= 2;
156 			T * OTable = Table;
157 			Table = new T[Capacity];
158 			ClearTable();
159 			for (unsigned int i = 0; i < OCapacity; ++i)
160 			{
161 				if (OTable[i])
162 					AddInternal(std::move(OTable[i]));
163 			}
164 			delete [] OTable;
165 		}
166 	}
167 public:
168 	template<typename H> static unsigned int Hash(const H &);
169 	template<typename H> static bool Equals(const T &, const H &);
Equals(const T & a,const T & b)170 	static bool Equals(const T & a, const T & b) { return a == b; }
C4Set()171 	C4Set(): Table(new T[Capacity])
172 	{
173 		ClearTable();
174 	}
~C4Set()175 	~C4Set()
176 	{
177 		delete[] Table;
178 	}
C4Set(const C4Set & b)179 	C4Set(const C4Set & b): Capacity(0), Size(0), Table(0)
180 	{
181 		*this = b;
182 	}
183 	C4Set & operator = (const C4Set & b)
184 	{
185 		Capacity = b.Capacity;
186 		Size = b.Size;
187 		delete[] Table;
188 		Table = new T[Capacity];
189 		for (unsigned int i = 0; i < Capacity; ++i)
190 			Table[i] = b.Table[i];
191 		return *this;
192 	}
193 	void CompileFunc(class StdCompiler *pComp, class C4ValueNumbers *);
Clear()194 	void Clear()
195 	{
196 		ClearTable();
197 		Size = 0;
198 	}
Get(H e)199 	template<typename H> T & Get(H e) const
200 	{
201 		unsigned int h = Hash(e);
202 		T * r = &Table[h % Capacity];
203 		while (*r && !Equals(*r, e))
204 		{
205 			r = &Table[++h % Capacity];
206 		}
207 		return *r;
208 	}
Has(H e)209 	template<typename H> bool Has(H e) const
210 	{
211 		unsigned int h = Hash(e);
212 		T * r = &Table[h % Capacity];
213 		while (*r && !Equals(*r, e))
214 		{
215 			r = &Table[++h % Capacity];
216 		}
217 		return !!*r;
218 	}
GetSize()219 	unsigned int GetSize() const { return Size; }
Add(T const & e)220 	T * Add(T const & e)
221 	{
222 		MaintainCapacity();
223 		T * r = AddInternal(e);
224 		++Size;
225 		return r;
226 	}
Add(T && e)227 	T * Add(T && e)
228 	{
229 		MaintainCapacity();
230 		T * r = AddInternal(std::move(e));
231 		++Size;
232 		return r;
233 	}
Remove(H e)234 	template<typename H> void Remove(H e)
235 	{
236 		unsigned int h = Hash(e);
237 		T * r = &Table[h % Capacity];
238 		while (*r && !Equals(*r, e))
239 		{
240 			r = &Table[++h % Capacity];
241 		}
242 		assert(*r);
243 		*r = nullptr;
244 		--Size;
245 		// Move entries which might have collided with e
246 		while (*(r = &Table[++h % Capacity]))
247 		{
248 			T m = *r;
249 			*r = nullptr;
250 			AddInternal(std::move(m));
251 		}
252 	}
First()253 	T const * First() const { return Next(Table - 1); }
Next(T const * p)254 	T const * Next(T const * p) const
255 	{
256 		while (++p != &Table[Capacity])
257 		{
258 			if (*p) return p;
259 		}
260 		return nullptr;
261 	}
Swap(C4Set<T> * S2)262 	void Swap(C4Set<T> * S2)
263 	{
264 		unsigned int Capacity2 = S2->Capacity;
265 		unsigned int Size2 = S2->Size;
266 		T * Table2 = S2->Table;
267 		S2->Capacity = Capacity;
268 		S2->Size = Size;
269 		S2->Table = Table;
270 		Capacity = Capacity2;
271 		Size = Size2;
272 		Table = Table2;
273 	}
SortFunc(const T * p1,const T * p2)274 	static bool SortFunc(const T *p1, const T*p2)
275 	{
276 		// elements are guarantueed to be non-nullptr
277 		return *p1<*p2;
278 	}
GetSortedListOfElementPointers()279 	std::list<const T *> GetSortedListOfElementPointers() const
280 	{
281 		// return a list of pointers to all elements in this set sorted by the standard less-than operation
282 		// of the elements
283 		// elements of resulting lists are guarantueed to be non-nullptr
284 		// list remains valid as long as this set is not changed
285 		std::list<const T *> result;
286 		for (const T *p = First(); p; p = Next(p)) result.push_back(p);
287 		result.sort(C4Set<T>::SortFunc);
288 		return result;
289 	}
290 };
291 
292 template<> template<>
293 inline unsigned int C4Set<C4String *>::Hash<const C4String *>(const C4String * const & e)
294 {
295 	return e->Hash;
296 }
297 template<> template<>
298 inline unsigned int C4Set<C4String *>::Hash<C4String *>(C4String * const & e)
299 {
300 	return e->Hash;
301 }
302 
303 enum C4PropertyName
304 {
305 	// TODO: documentation comments can be removed
306 	// as soon as all properties are documented
307 
308 	P_Prototype,
309 	P_Name,
310 	P_Priority,
311 	P_Interval,
312 	P_CommandTarget,
313 	P_Time,
314 	P_Construction,
315 	P_Destruction,
316 	P_Start,
317 	P_Stop,
318 	P_Timer,
319 	P_Effect,
320 	P_Damage,
321 	P_Collectible,
322 	P_Touchable,
323 	P_ActMap,
324 	P_Attach,
325 	P_Visibility,
326 	P_Parallaxity,
327 	P_LineColors,
328 	P_LineAttach,
329 	P_PictureTransformation,
330 	P_MeshTransformation,
331 	P_Procedure,
332 	P_Speed,
333 	P_Accel,
334 	P_Decel,
335 	P_Directions,
336 	P_FlipDir,
337 	P_Length,
338 	P_Delay,
339 	P_X,
340 	P_Y,
341 	P_x,
342 	P_y,
343 	P_Wdt,
344 	P_Hgt,
345 	P_wdt,
346 	P_hgt,
347 	P_Vertices,
348 	P_Edges,
349 	P_LineWidth,
350 	P_OffX,
351 	P_OffY,
352 	P_proplist,
353 	P_Proplist,
354 	P_FacetBase,
355 	P_FacetTopFace,
356 	P_FacetTargetStretch,
357 	P_NextAction,
358 	P_Hold,
359 	P_Idle,
360 	P_NoOtherAction,
361 	P_StartCall,
362 	P_EndCall,
363 	P_AbortCall,
364 	P_PhaseCall,
365 	P_Sound,
366 	P_ObjectDisabled,
367 	P_DigFree,
368 	P_InLiquidAction,
369 	P_TurnAction,
370 	P_Reverse,
371 	P_Step,
372 	P_MouseDrag,
373 	P_MouseDragImage,
374 	P_Animation,
375 	P_Action,
376 	P_BreatheWater,
377 	P_CorrosionResist,
378 	P_MaxEnergy,
379 	P_MaxBreath,
380 	P_ThrowSpeed,
381 	P_Mode,					// unused?
382 	P_CausedBy,				// unused?
383 	P_Blasted,				// unused?
384 	P_IncineratingObj,		// unused?
385 	P_Plane,
386 	P_BorderBound,
387 	P_ContactCalls,
388 	P_SolidMaskPlane,
389 	P_Tooltip,
390 	P_Placement,
391 	P_ContainBlast,
392 	P_BlastIncinerate,
393 	P_ContactIncinerate,
394 	P_MaterialIncinerate,
395 	P_Global,
396 	P_Scenario,
397 	P_JumpSpeed,
398 	P_BackgroundColor,
399 	P_Decoration,
400 	P_Symbol,
401 	P_Target,
402 	P_Std,
403 	P_Text,
404 	P_GraphicsName,
405 	P_ID,
406 	P_OnClick,
407 	P_OnMouseIn,
408 	P_OnMouseOut,
409 	P_OnClose,
410 	P_Style,
411 	P_Player,
412 	P_Margin,
413 	P_Algo,
414 	P_Layer,
415 	P_Seed,
416 	P_Ratio,
417 	P_FixedOffset,
418 	P_Op,
419 	P_R,
420 	P_Scale,
421 	P_Amplitude,
422 	P_Iterations,
423 	P_Empty,
424 	P_Open,
425 	P_Left,
426 	P_Top,
427 	P_Right,
428 	P_Bottom,
429 	P_Filter,
430 	P_ForceX,
431 	P_ForceY,
432 	P_G,
433 	P_B,
434 	P_Alpha,
435 	P_DampingX,
436 	P_DampingY,
437 	P_Size,
438 	P_Rotation,
439 	P_BlitMode,
440 	P_Phase,
441 	P_Stretch,
442 	P_CollisionVertex,
443 	P_CollisionDensity,
444 	P_OnCollision,
445 	P_Distance,
446 	P_Smoke,
447 	P_Source,
448 	P_Color,
449 	P_EditCursorCommands,
450 	P_IsPointContained,
451 	P_GetRandomPoint,
452 	P_Type,
453 	P_Reverb_Density,
454 	P_Reverb_Diffusion,
455 	P_Reverb_Gain,
456 	P_Reverb_GainHF,
457 	P_Reverb_Decay_Time,
458 	P_Reverb_Decay_HFRatio,
459 	P_Reverb_Reflections_Gain,
460 	P_Reverb_Reflections_Delay,
461 	P_Reverb_Late_Reverb_Gain,
462 	P_Reverb_Late_Reverb_Delay,
463 	P_Reverb_Air_Absorption_GainHF,
464 	P_Reverb_Room_Rolloff_Factor,
465 	P_Reverb_Decay_HFLimit,
466 	P_Echo_Delay,
467 	P_Echo_LRDelay,
468 	P_Echo_Damping,
469 	P_Echo_Feedback,
470 	P_Echo_Spread,
471 	P_Equalizer_Low_Gain,
472 	P_Equalizer_Low_Cutoff,
473 	P_Equalizer_Mid1_Gain,
474 	P_Equalizer_Mid1_Center,
475 	P_Equalizer_Mid1_Width,
476 	P_Equalizer_Mid2_Gain,
477 	P_Equalizer_Mid2_Center,
478 	P_Equalizer_Mid2_Width,
479 	P_Equalizer_High_Gain,
480 	P_Equalizer_High_Cutoff,
481 	P_LightOffset,
482 	P_PlayList,
483 	P_MusicBreakMin,
484 	P_MusicBreakMax,
485 	P_MusicBreakChance,
486 	P_MusicMaxPositionMemory,
487 	P_InflameLandscape,
488 	P_OptionKey,
489 	P_ValueKey,
490 	P_Value,
491 	P_DefaultValueFunction,
492 	P_Delegate,
493 	P_VertexDelegate,
494 	P_EdgeDelegate,
495 	P_HorizontalFix,
496 	P_VerticalFix,
497 	P_StructureFix,
498 	P_OnUpdate,
499 	P_EditorPropertyChanged,
500 	P_Min,
501 	P_Max,
502 	P_Set,
503 	P_SetGlobal,
504 	P_SetRoot,
505 	P_Options,
506 	P_Key,
507 	P_AsyncGet,
508 	P_Get,
509 	P_Relative,
510 	P_CanMoveCenter,
511 	P_StartFromObject,
512 	P_Storage,
513 	P_Elements,
514 	P_EditOnSelection,
515 	P_EditorProps,
516 	P_DefaultEditorProp,
517 	P_EditorActions,
518 	P_CopyDefault,
519 	P_Display,
520 	P_DefaultValue,
521 	P_DefinitionPriority,
522 	P_Group,
523 	P_Command,
524 	P_Select,
525 	P_DescendPath,
526 	P_EmptyName,
527 	P_ShortName,
528 	P_EditorHelp,
529 	P_Description,
530 	P_AllowEditing,
531 	P_EditorInitialize,
532 	P_EditorPlacementLimit,
533 	P_EditorCollection,
534 	P_Sorted,
535 	P_Uniforms,
536 	P_ForceSerialization,
537 	P_DrawArrows,
538 	P_SCENPAR,
539 	P_Translatable,
540 	P_Function,
541 	P_Translate,
542 // Default Action Procedures
543 	DFA_WALK,
544 	DFA_FLIGHT,
545 	DFA_KNEEL,
546 	DFA_SCALE,
547 	DFA_HANGLE,
548 	DFA_DIG,
549 	DFA_SWIM,
550 	DFA_THROW,
551 	DFA_BRIDGE,
552 	DFA_PUSH,
553 	DFA_LIFT,
554 	DFA_FLOAT,
555 	DFA_ATTACH,
556 	DFA_CONNECT,
557 	DFA_PULL,
558 	P_LAST
559 };
560 
561 // There is only one Stringtable
562 class C4StringTable
563 {
564 public:
565 	C4StringTable();
566 	virtual ~C4StringTable();
567 
568 	C4String *RegString(StdStrBuf String);
RegString(const char * s)569 	C4String *RegString(const char * s) { return RegString(StdStrBuf(s)); }
570 	// Find existing C4String
571 	C4String *FindString(const char *strString) const;
572 
573 private:
574 	C4Set<C4String *> Set;
575 	friend class C4String;
576 
577 public:
578 	// After the set, so these are destroyed with the set still alive
579 	C4String P[P_LAST];
580 };
581 
582 extern C4StringTable Strings;
583 
584 #endif
585