Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / pd_lib / pd_utils.h
blobea707821e6992815b716fc846088332f2bf27a68
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2015 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #ifndef RY_PDS_UTILS_H
21 #define RY_PDS_UTILS_H
24 * NeL Includes
26 #include <nel/misc/types_nl.h>
27 #include <nel/misc/common.h>
28 #include <nel/misc/time_nl.h>
29 #include <nel/misc/stream.h>
30 #include <nel/misc/entity_id.h>
31 #include <nel/misc/sheet_id.h>
32 #include <nel/misc/variable.h>
35 namespace RY_PDS
38 /**
39 * Definition of streamable persistent data.
40 * Used to fetch data from PDS to service classes
42 typedef NLMISC::IStream CPData;
48 /**
49 * PD System Verbosity control
51 extern NLMISC::CVariable<bool> PDVerbose;
53 /**
54 * PD System Verbosity level
56 extern NLMISC::CVariable<sint> PDVerboseLevel;
58 /**
59 * PDS Resolve Unmapped rows
60 * If true, PDS continue loading when it finds a row not mapped in a mapped table,
61 * and keeps it unmapped.
62 * Otherwise, loading fails.
64 extern NLMISC::CVariable<bool> ResolveUnmappedRows;
66 /**
67 * PDS Resolve Double Mapped Rows
68 * If true, PDS continue loading when it finds a row already mapped, and keeps it unmapped.
69 * Otherwise, loading fails.
70 * See also ResolveDoubleMappedKeepOlder
72 extern NLMISC::CVariable<bool> ResolveDoubleMappedRows;
74 /**
75 * PDS Resolve Double Mapped Keep Older
76 * If true, when finds a doubly mapped row at loading, keep only older row as mapped (lesser row index)
77 * See also ResolveDoubleMappedRows.
79 extern NLMISC::CVariable<bool> ResolveDoubleMappedKeepOlder;
81 /**
82 * PDS Resolve Unallocated rows
83 * If true, when finds a reference to an unallocated row or an invalid row, force reference to null.
85 extern NLMISC::CVariable<bool> ResolveInvalidRow;
92 /**
93 * Definition of Table indices
95 typedef uint16 TTableIndex;
97 /**
98 * Definition of Row indices
100 typedef uint32 TRowIndex;
103 * Definition of Column indices
105 typedef uint16 TColumnIndex;
108 * Definition of index Checksum validator
110 typedef uint16 TIndexChecksum;
114 * Table & Row indices constants
116 const TTableIndex INVALID_TABLE_INDEX = 0xffff;
117 const TRowIndex INVALID_ROW_INDEX = 0xffffffff;
118 const TColumnIndex INVALID_COLUMN_INDEX = 0xffff;
121 * Checksum
123 const TIndexChecksum VALID_INDEX_CHECKSUM = 0xdead;
126 * Default Hashing Function
128 /*template<typename T>
129 class CDefaultHash
131 public:
132 size_t operator() (const T& value) const { return (uint32)value; }
133 };*/
136 * Table Container Interface
138 class ITableContainer
140 public:
142 /// Get Table Index
143 virtual TTableIndex getTableIndex(const std::string& tableName) const = 0;
145 /// Get Table Name
146 virtual std::string getTableName(TTableIndex tableIndex) const = 0;
152 * Definition of Object indices
153 * An object is pointed by a table index and a row index
154 * \author Benjamin Legros
155 * \author Nevrax France
156 * \date 2004
158 class CObjectIndex
160 public:
162 /// Constructor of invalid index
163 explicit CObjectIndex(bool validateChecksum = false) : _Row(INVALID_ROW_INDEX), _Table(INVALID_TABLE_INDEX), _Checksum((TIndexChecksum)~VALID_INDEX_CHECKSUM)
165 if (validateChecksum)
166 validate();
167 else
168 invalidate();
171 /// Constructor
172 CObjectIndex(TTableIndex table, TRowIndex row) : _Row(row), _Table(table) { validate(); }
174 /// Constructor
175 CObjectIndex(const CObjectIndex &index) { *this = index; }
181 /// Cast operator
182 operator uint64 () const { return _FullIndex; }
184 /// Get Table index
185 TTableIndex table() const { return _Table; }
187 /// Get Row index
188 TRowIndex row() const { return _Row; }
193 /// Copy
194 CObjectIndex & operator = (const CObjectIndex &index) { _FullIndex = index._FullIndex; return *this; }
196 /// Equal?
197 bool operator == (const CObjectIndex &index) const { return _FullIndex == index._FullIndex; }
199 /// Not equal?
200 bool operator != (const CObjectIndex &index) const { return !(*this == index); }
204 /// Return null
205 static CObjectIndex null()
207 return CObjectIndex(true);
212 /// Checksum valid?
213 bool isChecksumValid() const
215 return getChecksum() == VALID_INDEX_CHECKSUM;
218 /// Is it Null Ptr?
219 bool isNull() const
221 return _Table == INVALID_TABLE_INDEX && _Row == INVALID_ROW_INDEX && isChecksumValid();
224 /// Validity check
225 bool isValid() const
227 return _Table != INVALID_TABLE_INDEX && _Row != INVALID_ROW_INDEX && isChecksumValid();
233 /// transform to string
234 std::string toString(const ITableContainer* container = NULL) const
236 if (isValid())
238 if (container != NULL)
240 return NLMISC::toString("(%s:%u)", container->getTableName(_Table).c_str(), _Row);
242 else
244 return NLMISC::toString("(%u:%u)", _Table, _Row);
247 else if (isNull())
249 return "<Null>";
251 else
253 return NLMISC::toString("(%u:%u <invalid>)", _Table, _Row);
257 /// get from string
258 void fromString(const char* str, const ITableContainer* container = NULL)
260 uint table;
261 uint row;
262 uint valid;
264 if (sscanf(str, "(%d:%d:%d)", &table, &row, &valid) == 3)
266 _Table = (TTableIndex)table;
267 _Row = (TRowIndex)row;
269 if (valid != 0)
270 validate();
271 else
272 invalidate();
274 return;
276 else if (sscanf(str, "(%d:%d)", &table, &row) == 2)
278 _Table = (TTableIndex)table;
279 _Row = (TRowIndex)row;
280 validate();
282 return;
284 else if (container != NULL && parseIndexWithName(str, container))
286 validate();
287 return;
290 *this = CObjectIndex::null();
291 return;
294 void serial(NLMISC::IStream& f)
296 f.serial(_FullIndex);
299 private:
301 bool parseIndexWithName(const char* str, const ITableContainer* container)
303 TRowIndex row;
304 TTableIndex table;
306 if (*(str++) != '(')
307 return false;
309 std::string tableName;
311 while (*str != '\0' && *str != ':')
312 tableName += *(str++);
314 if (*(str++) != ':')
315 return false;
317 table = container->getTableIndex(tableName);
318 if (table == INVALID_TABLE_INDEX)
319 return false;
321 NLMISC::fromString(std::string(str), row);
323 while (*str >= '0' && *str <= '9')
324 ++str;
326 if (*str != ')')
327 return false;
329 _Row = row;
330 _Table = table;
332 return true;
336 #ifdef NL_OS_WINDOWS
338 #define PDS_ROW_LO_WORD 0
339 #define PDS_ROW_HI_WORD 1
340 #define PDS_TABLE_WORD 2
341 #define PDS_CHECKSUM_WORD 3
343 #else
345 #define PDS_ROW_LO_WORD 0
346 #define PDS_ROW_HI_WORD 1
347 #define PDS_TABLE_WORD 2
348 #define PDS_CHECKSUM_WORD 3
350 #endif
352 union
354 struct
356 TRowIndex _Row;
357 TTableIndex _Table;
358 TIndexChecksum _Checksum;
360 uint64 _FullIndex;
361 uint16 _Words[4];
364 /// Compute partial checksum of the index
365 TIndexChecksum getPartialChecksum() const
367 return _Words[PDS_ROW_LO_WORD] ^ _Words[PDS_ROW_HI_WORD] ^ _Words[PDS_TABLE_WORD];
370 /// Get checksum of the index
371 TIndexChecksum getChecksum() const
373 return getPartialChecksum() ^ _Words[PDS_CHECKSUM_WORD];
376 /// Force validation of an index
377 void validate()
379 _Checksum = getPartialChecksum() ^ VALID_INDEX_CHECKSUM;
382 /// Force invalidation of an index
383 void invalidate()
385 _Checksum = getPartialChecksum() ^ (~VALID_INDEX_CHECKSUM);
392 * Definition of column index
393 * \author Benjamin Legros
394 * \author Nevrax France
395 * \date 2004
397 class CColumnIndex
399 public:
401 /// Constructor
402 explicit CColumnIndex(TTableIndex table = INVALID_TABLE_INDEX, TRowIndex row = INVALID_ROW_INDEX, TColumnIndex column = INVALID_COLUMN_INDEX)
403 : _Table(table), _Column(column), _Row(row)
407 /// Constructor
408 explicit CColumnIndex(const CObjectIndex& object, TColumnIndex column)
409 : _Table(INVALID_TABLE_INDEX), _Column(INVALID_COLUMN_INDEX), _Row(INVALID_ROW_INDEX)
411 if (!object.isValid())
412 return;
414 _Table = object.table();
415 _Row = object.row();
416 _Column = column;
420 /// Get Table Index
421 TTableIndex table() const { return _Table; }
422 /// Get Row Index
423 TRowIndex row() const { return _Row; }
424 /// Get Column Index
425 TColumnIndex column() const { return _Column; }
427 /// Test if is null
428 bool isNull() const { return _Table == INVALID_TABLE_INDEX && _Row == INVALID_ROW_INDEX && _Column == INVALID_COLUMN_INDEX; }
431 /// Cast to 64 bits
432 operator uint64() const { return _FullIndex; }
434 /// 32 bits hash key
435 uint32 hash() const { return (uint32) ((_Table<<2) ^ (_Row<<1) ^ _Column); }
437 /// Operator <
438 bool operator < (const CColumnIndex& b) const { return _FullIndex < b._FullIndex; }
440 /// transform to string
441 std::string toString(const ITableContainer* container = NULL) const
443 if (isNull())
445 return "<Null>";
447 else if (container != NULL)
449 return NLMISC::toString("(%s:%u:%u)", container->getTableName(_Table).c_str(), _Row, _Column);
451 else
453 return NLMISC::toString("(%u:%u:%u)", _Table, _Row, _Column);
457 private:
459 union
461 struct
463 /// Table Index
464 TTableIndex _Table;
466 /// Column Index in row
467 TColumnIndex _Column;
469 /// Row Index in table
470 TRowIndex _Row;
473 /// Full 64 bits index
474 uint64 _FullIndex;
479 * Definition of set of object indexes
480 * This is actually a index on the first element of a list contained in each database
482 typedef std::vector<CObjectIndex> TIndexList;
486 * A container of index lists
487 * \author Benjamin Legros
488 * \author Nevrax France
489 * \date 2004
492 //#define DEBUG_SETMAP_ACCESSOR
494 struct CColumnIndexHashMapTraits
496 enum { bucket_size = 4, min_buckets = 8 };
497 CColumnIndexHashMapTraits() { }
498 size_t operator() (const CColumnIndex &id) const
500 return id.hash();
502 bool operator()(const CColumnIndex &left, const CColumnIndex &right)
504 return left < right;
508 class CSetMap
510 public:
512 /// Hash Key
513 /*class CKeyHash
515 public:
516 size_t operator() (const CColumnIndex& key) const { return (uint32)(key.hash()); }
517 };*/
519 /// Map of lists
520 typedef CHashMap<CColumnIndex, TIndexList, CColumnIndexHashMapTraits> TListMap;
522 /// An Accessor on a list
523 class CAccessor
525 public:
527 /// Constructor, only builds invalid accessor
528 CAccessor() : _Valid(false) { }
530 /// Is Valid
531 bool isValid() const { return _Valid; }
533 /// Get whole list
534 const TIndexList& get() const { nlassert(isValid()); return (*_It).second; }
536 /// Test if object belongs to list
537 bool belongsTo(const CObjectIndex& test) const
539 nlassert(isValid());
540 return std::find((*_It).second.begin(), (*_It).second.end(), test) != (*_It).second.end();
543 /// Add index to list
544 void add(const CObjectIndex& index)
546 nlassert(isValid());
547 if (!belongsTo(index))
549 (*_It).second.push_back(index);
553 /// Remove index from list
554 void erase(const CObjectIndex& index)
556 nlassert(isValid());
558 TIndexList& iList = (*_It).second;
559 TIndexList::iterator itr;
560 for (itr=iList.begin(); itr!=iList.end(); )
561 itr = ((*itr == index) ? iList.erase(itr) : (itr+1));
563 // gcc can't resolve this:
564 //(*_It).second.erase(std::remove((*_It).second.begin(), (*_It).second.end(), index), (*_It).second.end());
567 /// Dump list
568 void display() const
570 if (!isValid())
572 nlinfo("<can't display set>");
573 return;
576 #ifdef DEBUG_SETMAP_ACCESSOR
577 nlinfo("Set '%s' content:", _Debug.toString().c_str());
578 #else
579 nlinfo("Set content:");
580 #endif
581 TIndexList::const_iterator it;
582 for (it=(*_It).second.begin(); it!=(*_It).second.end(); ++it)
583 nlinfo("%s", (*it).toString().c_str());
586 private:
588 friend class CSetMap;
590 /// Internal pointer to list
591 TListMap::iterator _It;
593 /// Is Valid
594 bool _Valid;
596 #ifdef DEBUG_SETMAP_ACCESSOR
598 CColumnIndex _Debug;
600 /// constructor for CIndexListMap
601 CAccessor(TListMap::iterator it, const CColumnIndex& index) : _It(it), _Valid(true), _Debug(index) { }
603 #else
605 /// constructor for CIndexListMap
606 CAccessor(TListMap::iterator it, const CColumnIndex& index) : _It(it), _Valid(true) { }
608 #endif
613 /// Get the list associated to this column
614 CAccessor get(const CColumnIndex& index)
616 TListMap::iterator it = _Map.find(index);
617 if (it == _Map.end())
619 it = _Map.insert(TListMap::value_type(index, TIndexList())).first;
621 return CAccessor(it, index);
624 /// Clear up whole map
625 void clear() { _Map.clear(); }
627 private:
629 friend class CAccessor;
631 TListMap _Map;
640 * Base class for Row accessible objects.
641 * Contains a Row index, used to represent the object in the database
642 * Classes that derive from this class are assumed to know their own Table index.
643 * \author Benjamin Legros
644 * \author Nevrax France
645 * \date 2004
647 class IPDBaseData
649 public:
651 /// Constructor
652 IPDBaseData() : __BaseRow(INVALID_ROW_INDEX), __BaseTable(INVALID_TABLE_INDEX) {}
654 /// Get Row index
655 TRowIndex getRow() const { return __BaseRow; }
657 /// Get Table index
658 TTableIndex getTable() const { return __BaseTable; }
660 protected:
662 TRowIndex __BaseRow;
663 TTableIndex __BaseTable;
665 friend class CPDSLib;
671 * A class that allocates and deallocate indices in PDS database.
672 * The allocator is able to init itself from a PDS command
673 * \author Benjamin Legros
674 * \author Nevrax France
675 * \date 2004
677 class CIndexAllocator
679 public:
681 CIndexAllocator() : _NextIndex(0) { }
683 TRowIndex allocate()
685 // no index in stack, get next
686 if (_FreeIndices.empty())
687 return _NextIndex++;
689 // pop a free index
690 TRowIndex index = _FreeIndices.front();
691 _FreeIndices.pop_front();
692 return index;
695 void deallocate(TRowIndex index)
697 // push index on stack
698 _FreeIndices.push_back(index);
701 void forceAllocated(TRowIndex index)
703 for (; _NextIndex<index; ++_NextIndex)
704 _FreeIndices.push_back(_NextIndex);
706 // remove index from free if was there
707 std::deque<TRowIndex>::iterator it = std::find(_FreeIndices.begin(), _FreeIndices.end(), index);
708 if (it != _FreeIndices.end())
709 _FreeIndices.erase(it);
711 if (_NextIndex < index+1)
712 _NextIndex = index+1;
715 void clear()
717 _NextIndex = 0;
718 _FreeIndices.clear();
721 void serial(NLMISC::IStream& f)
723 f.serialCheck(NELID("IALC"));
724 f.serialVersion(0);
726 f.serial(_NextIndex);
727 f.serialCont(_FreeIndices);
730 private:
732 /// Next free index
733 TRowIndex _NextIndex;
735 /// Free items
736 std::deque<TRowIndex> _FreeIndices;
744 typedef IPDBaseData* (*TPDFactory)();
745 typedef void (*TPDFetch)(IPDBaseData*, CPData&);
746 typedef void (*TPDFetchFailure)(uint64 key);
751 * Get Value as String
753 template<typename T>
754 std::string pdsToString(const T& value) { return NLMISC::toString(value); }
756 inline std::string pdsToString(const bool& value) { return value ? std::string("true") : std::string("false"); }
757 inline std::string pdsToString(const CObjectIndex& value) { return value.toString(); }
758 inline std::string pdsToString(const CColumnIndex& value) { return value.toString(); }
759 inline std::string pdsToString(const NLMISC::CSheetId& value) { return value.toString(); }
760 inline std::string pdsToString(const NLMISC::CEntityId& value) { return value.toString(); }
763 }; // RY_PDS
765 #endif //RY_PDS_UTILS_H