3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #ifndef UTILITY_HEADER
21 #define UTILITY_HEADER
29 #include <jmutexautolock.h>
31 #include "common_irrlicht.h"
34 #include "exceptions.h"
37 extern const v3s16 g_26dirs[26];
40 extern const v3s16 g_27dirs[27];
42 inline void writeU32(u8 *data, u32 i)
44 data[0] = ((i>>24)&0xff);
45 data[1] = ((i>>16)&0xff);
46 data[2] = ((i>> 8)&0xff);
47 data[3] = ((i>> 0)&0xff);
50 inline void writeU16(u8 *data, u16 i)
52 data[0] = ((i>> 8)&0xff);
53 data[1] = ((i>> 0)&0xff);
56 inline void writeU8(u8 *data, u8 i)
58 data[0] = ((i>> 0)&0xff);
61 inline u32 readU32(u8 *data)
63 return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
66 inline u16 readU16(u8 *data)
68 return (data[0]<<8) | (data[1]<<0);
71 inline u8 readU8(u8 *data)
76 // Signed variants of the above
78 inline void writeS32(u8 *data, s32 i){
79 writeU32(data, (u32)i);
81 inline s32 readS32(u8 *data){
82 return (s32)readU32(data);
85 inline void writeS16(u8 *data, s16 i){
86 writeU16(data, (u16)i);
88 inline s16 readS16(u8 *data){
89 return (s16)readU16(data);
92 inline void writeV3S32(u8 *data, v3s32 p)
94 writeS32(&data[0], p.X);
95 writeS32(&data[4], p.Y);
96 writeS32(&data[8], p.Z);
99 inline v3s32 readV3S32(u8 *data)
102 p.X = readS32(&data[0]);
103 p.Y = readS32(&data[4]);
104 p.Z = readS32(&data[8]);
108 inline void writeV2S16(u8 *data, v2s16 p)
110 writeS16(&data[0], p.X);
111 writeS16(&data[2], p.Y);
114 inline v2s16 readV2S16(u8 *data)
117 p.X = readS16(&data[0]);
118 p.Y = readS16(&data[2]);
122 inline void writeV2S32(u8 *data, v2s32 p)
124 writeS32(&data[0], p.X);
125 writeS32(&data[2], p.Y);
128 inline v2s32 readV2S32(u8 *data)
131 p.X = readS32(&data[0]);
132 p.Y = readS32(&data[2]);
136 inline void writeV3S16(u8 *data, v3s16 p)
138 writeS16(&data[0], p.X);
139 writeS16(&data[2], p.Y);
140 writeS16(&data[4], p.Z);
143 inline v3s16 readV3S16(u8 *data)
146 p.X = readS16(&data[0]);
147 p.Y = readS16(&data[2]);
148 p.Z = readS16(&data[4]);
153 None of these are used at the moment
156 template <typename T>
166 SharedPtr(SharedPtr<T> &t)
170 refcount = t.refcount;
178 SharedPtr<T> & operator=(T *t)
186 SharedPtr<T> & operator=(SharedPtr<T> &t)
189 refcount = t.refcount;
202 bool operator!=(T *t)
206 bool operator==(T *t)
210 T & operator[](unsigned int i)
217 assert((*refcount) > 0);
230 template <typename T>
234 Buffer(unsigned int size)
239 Buffer(const Buffer &buffer)
241 m_size = buffer.m_size;
242 data = new T[buffer.m_size];
243 memcpy(data, buffer.data, buffer.m_size);
245 Buffer(T *t, unsigned int size)
249 memcpy(data, t, size);
255 T & operator[](unsigned int i) const
259 T * operator*() const
263 unsigned int getSize() const
272 template <typename T>
276 SharedBuffer(unsigned int size)
280 refcount = new unsigned int;
283 SharedBuffer(const SharedBuffer &buffer)
285 //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
286 m_size = buffer.m_size;
288 refcount = buffer.refcount;
291 SharedBuffer & operator=(const SharedBuffer & buffer)
293 //std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
297 m_size = buffer.m_size;
299 refcount = buffer.refcount;
306 SharedBuffer(T *t, unsigned int size)
310 memcpy(data, t, size);
311 refcount = new unsigned int;
317 SharedBuffer(const Buffer<T> &buffer)
319 m_size = buffer.m_size;
320 data = new T[buffer.getSize()];
321 memcpy(data, *buffer, buffer.getSize());
322 refcount = new unsigned int;
329 T & operator[](unsigned int i) const
333 T * operator*() const
337 unsigned int getSize() const
344 assert((*refcount) > 0);
354 unsigned int *refcount;
357 inline SharedBuffer<u8> SharedBufferFromString(const char *string)
359 SharedBuffer<u8> b((u8*)string, strlen(string)+1);
364 class MutexedVariable
367 MutexedVariable(T value):
375 JMutexAutoLock lock(m_mutex);
381 JMutexAutoLock lock(m_mutex);
385 // You'll want to grab this in a SharedPtr
386 JMutexAutoLock * getLock()
388 return new JMutexAutoLock(m_mutex);
391 // You pretty surely want to grab the lock when accessing this
402 class IrrlichtWrapper;
407 TimeTaker(const char *name, u32 *result=NULL);
414 u32 stop(bool quiet=false);
425 // Calculates the borders of a "d-radius" cube
426 inline void getFacePositions(core::list<v3s16> &list, u16 d)
430 list.push_back(v3s16(0,0,0));
436 This is an optimized sequence of coordinates.
438 list.push_back(v3s16( 0, 1, 0)); // top
439 list.push_back(v3s16( 0, 0, 1)); // back
440 list.push_back(v3s16(-1, 0, 0)); // left
441 list.push_back(v3s16( 1, 0, 0)); // right
442 list.push_back(v3s16( 0, 0,-1)); // front
443 list.push_back(v3s16( 0,-1, 0)); // bottom
445 list.push_back(v3s16(-1, 0, 1)); // back left
446 list.push_back(v3s16( 1, 0, 1)); // back right
447 list.push_back(v3s16(-1, 0,-1)); // front left
448 list.push_back(v3s16( 1, 0,-1)); // front right
449 list.push_back(v3s16(-1,-1, 0)); // bottom left
450 list.push_back(v3s16( 1,-1, 0)); // bottom right
451 list.push_back(v3s16( 0,-1, 1)); // bottom back
452 list.push_back(v3s16( 0,-1,-1)); // bottom front
453 list.push_back(v3s16(-1, 1, 0)); // top left
454 list.push_back(v3s16( 1, 1, 0)); // top right
455 list.push_back(v3s16( 0, 1, 1)); // top back
456 list.push_back(v3s16( 0, 1,-1)); // top front
458 list.push_back(v3s16(-1, 1, 1)); // top back-left
459 list.push_back(v3s16( 1, 1, 1)); // top back-right
460 list.push_back(v3s16(-1, 1,-1)); // top front-left
461 list.push_back(v3s16( 1, 1,-1)); // top front-right
462 list.push_back(v3s16(-1,-1, 1)); // bottom back-left
463 list.push_back(v3s16( 1,-1, 1)); // bottom back-right
464 list.push_back(v3s16(-1,-1,-1)); // bottom front-left
465 list.push_back(v3s16( 1,-1,-1)); // bottom front-right
470 // Take blocks in all sides, starting from y=0 and going +-y
471 for(s16 y=0; y<=d-1; y++)
473 // Left and right side, including borders
474 for(s16 z=-d; z<=d; z++)
476 list.push_back(v3s16(d,y,z));
477 list.push_back(v3s16(-d,y,z));
480 list.push_back(v3s16(d,-y,z));
481 list.push_back(v3s16(-d,-y,z));
484 // Back and front side, excluding borders
485 for(s16 x=-d+1; x<=d-1; x++)
487 list.push_back(v3s16(x,y,d));
488 list.push_back(v3s16(x,y,-d));
491 list.push_back(v3s16(x,-y,d));
492 list.push_back(v3s16(x,-y,-d));
497 // Take the bottom and top face with borders
498 // -d<x<d, y=+-d, -d<z<d
499 for(s16 x=-d; x<=d; x++)
500 for(s16 z=-d; z<=d; z++)
502 list.push_back(v3s16(x,-d,z));
503 list.push_back(v3s16(x,d,z));
507 class IndentationRaiser
510 IndentationRaiser(u16 *indentation)
512 m_indentation = indentation;
523 inline s16 getContainerPos(s16 p, s16 d)
525 return (p>=0 ? p : p-d+1) / d;
528 inline v2s16 getContainerPos(v2s16 p, s16 d)
531 getContainerPos(p.X, d),
532 getContainerPos(p.Y, d)
536 inline v3s16 getContainerPos(v3s16 p, s16 d)
539 getContainerPos(p.X, d),
540 getContainerPos(p.Y, d),
541 getContainerPos(p.Z, d)
545 inline v2s16 getContainerPos(v2s16 p, v2s16 d)
548 getContainerPos(p.X, d.X),
549 getContainerPos(p.Y, d.Y)
553 inline v3s16 getContainerPos(v3s16 p, v3s16 d)
556 getContainerPos(p.X, d.X),
557 getContainerPos(p.Y, d.Y),
558 getContainerPos(p.Z, d.Z)
562 inline bool isInArea(v3s16 p, s16 d)
565 p.X >= 0 && p.X < d &&
566 p.Y >= 0 && p.Y < d &&
571 inline bool isInArea(v2s16 p, s16 d)
574 p.X >= 0 && p.X < d &&
579 inline bool isInArea(v3s16 p, v3s16 d)
582 p.X >= 0 && p.X < d.X &&
583 p.Y >= 0 && p.Y < d.Y &&
584 p.Z >= 0 && p.Z < d.Z
588 inline s16 rangelim(s16 i, s16 max)
597 #define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(max)?(max):(d)))
599 inline v3s16 arealim(v3s16 p, s16 d)
616 inline std::wstring narrow_to_wide(const std::string& mbs)
618 size_t wcl = mbs.size();
619 SharedBuffer<wchar_t> wcs(wcl+1);
620 size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
625 inline std::string wide_to_narrow(const std::wstring& wcs)
627 size_t mbl = wcs.size()*4;
628 SharedBuffer<char> mbs(mbl+1);
629 size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
638 See test.cpp for example cases.
639 wraps degrees to the range of -360...360
640 NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
642 inline float wrapDegrees(float f)
644 // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
650 // NOTE: This would be used for wrapping to 0...360
656 // 10, 0.5, -0.5, -0.5
661 inline std::string lowercase(const std::string &s)
664 for(size_t i=0; i<s.size(); i++)
667 if(c >= 'A' && c <= 'Z')
674 inline bool is_yes(const std::string &s)
676 std::string s2 = lowercase(trim(s));
677 if(s2 == "y" || s2 == "yes" || s2 == "true" || s2 == "1")
682 inline s32 stoi(const std::string &s, s32 min, s32 max)
684 s32 i = atoi(s.c_str());
692 inline s32 stoi(std::string s)
694 return atoi(s.c_str());
697 inline float stof(std::string s)
700 std::istringstream ss(s);
705 inline std::string itos(s32 i)
707 std::ostringstream o;
712 inline std::string ftos(float f)
714 std::ostringstream o;
719 inline void str_replace(std::string & str, std::string const & pattern,
720 std::string const & replacement)
722 std::string::size_type start = str.find(pattern, 0);
723 while(start != str.npos)
725 str.replace(start, pattern.size(), replacement);
726 start = str.find(pattern, start+replacement.size());
730 inline void str_replace_char(std::string & str, char from, char to)
732 for(unsigned int i=0; i<str.size(); i++)
740 A base class for simple background thread implementation
743 class SimpleThread : public JThread
757 virtual ~SimpleThread()
760 virtual void * Thread() = 0;
764 JMutexAutoLock lock(run_mutex);
767 void setRun(bool a_run)
769 JMutexAutoLock lock(run_mutex);
788 VALUETYPE_FLAG // Doesn't take any arguments
793 ValueSpec(ValueType a_type, const char *a_help=NULL)
806 void writeLines(std::ostream &os)
808 for(core::map<std::string, std::string>::Iterator
809 i = m_settings.getIterator();
810 i.atEnd() == false; i++)
812 std::string name = i.getNode()->getKey();
813 std::string value = i.getNode()->getValue();
814 os<<name<<" = "<<value<<"\n";
818 bool parseConfigLine(const std::string &line)
820 std::string trimmedline = trim(line);
823 if(trimmedline[0] == '#')
826 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
828 Strfnd sf(trim(line));
830 std::string name = sf.next("=");
836 std::string value = sf.next("\n");
839 /*dstream<<"Config name=\""<<name<<"\" value=\""
840 <<value<<"\""<<std::endl;*/
842 m_settings[name] = value;
847 // Returns false on EOF
848 bool parseConfigObject(std::istream &is)
854 NOTE: This function might be expanded to allow multi-line
858 std::getline(is, line);
859 //dstream<<"got line: \""<<line<<"\""<<std::endl;
861 return parseConfigLine(line);
865 Read configuration file
867 Returns true on success
869 bool readConfigFile(const char *filename)
871 std::ifstream is(filename);
872 if(is.good() == false)
874 dstream<<"Error opening configuration file \""
875 <<filename<<"\""<<std::endl;
879 dstream<<"Parsing configuration file: \""
880 <<filename<<"\""<<std::endl;
882 while(parseConfigObject(is));
888 Reads a configuration object from stream (usually a single line)
891 Preserves comments and empty lines.
893 Settings that were added to dst are also added to updated.
894 key of updated is setting name, value of updated is dummy.
898 bool getUpdatedConfigObject(std::istream &is,
899 core::list<std::string> &dst,
900 core::map<std::string, bool> &updated)
905 // NOTE: This function will be expanded to allow multi-line settings
907 std::getline(is, line);
909 std::string trimmedline = trim(line);
911 std::string line_end = "";
912 if(is.eof() == false)
916 if(trimmedline[0] == '#')
918 dst.push_back(line+line_end);
922 Strfnd sf(trim(line));
924 std::string name = sf.next("=");
929 dst.push_back(line+line_end);
933 std::string value = sf.next("\n");
936 if(m_settings.find(name))
938 std::string newvalue = m_settings[name];
940 if(newvalue != value)
942 dstream<<"Changing value of \""<<name<<"\" = \""
943 <<value<<"\" -> \""<<newvalue<<"\""
947 dst.push_back(name + " = " + newvalue + line_end);
949 updated[name] = true;
956 Updates configuration file
958 Returns true on success
960 bool updateConfigFile(const char *filename)
962 dstream<<"Updating configuration file: \""
963 <<filename<<"\""<<std::endl;
965 core::list<std::string> objects;
966 core::map<std::string, bool> updated;
968 // Read and modify stuff
970 std::ifstream is(filename);
971 if(is.good() == false)
973 dstream<<"Error opening configuration file"
975 <<filename<<"\""<<std::endl;
979 while(getUpdatedConfigObject(is, objects, updated));
984 std::ofstream os(filename);
985 if(os.good() == false)
987 dstream<<"Error opening configuration file"
989 <<filename<<"\""<<std::endl;
996 for(core::list<std::string>::Iterator
998 i != objects.end(); i++)
1004 Write stuff that was not already in the file
1006 for(core::map<std::string, std::string>::Iterator
1007 i = m_settings.getIterator();
1008 i.atEnd() == false; i++)
1010 if(updated.find(i.getNode()->getKey()))
1012 std::string name = i.getNode()->getKey();
1013 std::string value = i.getNode()->getValue();
1014 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
1016 os<<name<<" = "<<value<<"\n";
1024 NOTE: Types of allowed_options are ignored
1026 returns true on success
1028 bool parseCommandLine(int argc, char *argv[],
1029 core::map<std::string, ValueSpec> &allowed_options)
1036 std::string argname = argv[i];
1037 if(argname.substr(0, 2) != "--")
1039 dstream<<"Invalid command-line parameter \""
1040 <<argname<<"\": --<option> expected."<<std::endl;
1045 std::string name = argname.substr(2);
1047 core::map<std::string, ValueSpec>::Node *n;
1048 n = allowed_options.find(name);
1051 dstream<<"Unknown command-line parameter \""
1052 <<argname<<"\""<<std::endl;
1056 ValueType type = n->getValue().type;
1058 std::string value = "";
1060 if(type == VALUETYPE_FLAG)
1068 dstream<<"Invalid command-line parameter \""
1069 <<name<<"\": missing value"<<std::endl;
1077 dstream<<"Valid command-line parameter: \""
1078 <<name<<"\" = \""<<value<<"\""
1086 void set(std::string name, std::string value)
1088 m_settings[name] = value;
1091 void setDefault(std::string name, std::string value)
1093 m_defaults[name] = value;
1096 bool exists(std::string name)
1098 return (m_settings.find(name) || m_defaults.find(name));
1101 std::string get(std::string name)
1103 core::map<std::string, std::string>::Node *n;
1104 n = m_settings.find(name);
1107 n = m_defaults.find(name);
1110 dstream<<"INFO: Settings: Setting not found: \""
1111 <<name<<"\""<<std::endl;
1112 throw SettingNotFoundException("Setting not found");
1116 return n->getValue();
1119 bool getBool(std::string name)
1121 return is_yes(get(name));
1124 bool getFlag(std::string name)
1128 return getBool(name);
1130 catch(SettingNotFoundException &e)
1137 bool getBoolAsk(std::string name, std::string question, bool def)
1139 // If it is in settings
1140 if(m_settings.find(name))
1141 return getBool(name);
1145 std::cout<<question<<" [y/N]: ";
1146 std::cin.getline(templine, 10);
1155 float getFloat(std::string name)
1157 return stof(get(name));
1160 u16 getU16(std::string name)
1162 return stoi(get(name), 0, 65535);
1165 u16 getU16Ask(std::string name, std::string question, u16 def)
1167 // If it is in settings
1168 if(m_settings.find(name))
1169 return getU16(name);
1173 std::cout<<question<<" ["<<def<<"]: ";
1174 std::cin.getline(templine, 10);
1180 return stoi(s, 0, 65535);
1183 s16 getS16(std::string name)
1185 return stoi(get(name), -32768, 32767);
1188 s32 getS32(std::string name)
1190 return stoi(get(name));
1193 v3f getV3F(std::string name)
1196 Strfnd f(get(name));
1198 value.X = stof(f.next(","));
1199 value.Y = stof(f.next(","));
1200 value.Z = stof(f.next(")"));
1204 u64 getU64(std::string name)
1207 std::string s = get(name);
1208 std::istringstream ss(s);
1213 void setS32(std::string name, s32 value)
1215 set(name, itos(value));
1218 void setFloat(std::string name, float value)
1220 set(name, ftos(value));
1223 void setV3F(std::string name, v3f value)
1225 std::ostringstream os;
1226 os<<"("<<value.X<<","<<value.Y<<","<<value.Z<<")";
1227 set(name, os.str());
1230 void setU64(std::string name, u64 value)
1232 std::ostringstream os;
1234 set(name, os.str());
1243 Settings & operator+=(Settings &other)
1248 for(core::map<std::string, std::string>::Iterator
1249 i = other.m_settings.getIterator();
1250 i.atEnd() == false; i++)
1252 m_settings.insert(i.getNode()->getKey(),
1253 i.getNode()->getValue());
1256 for(core::map<std::string, std::string>::Iterator
1257 i = other.m_defaults.getIterator();
1258 i.atEnd() == false; i++)
1260 m_defaults.insert(i.getNode()->getKey(),
1261 i.getNode()->getValue());
1266 Settings & operator=(Settings &other)
1278 core::map<std::string, std::string> m_settings;
1279 core::map<std::string, std::string> m_defaults;
1285 template<typename T>
1291 m_list.push_back(t);
1296 if(m_list.size() == 0)
1297 throw ItemNotFoundException("MutexedQueue: queue is empty");
1299 typename core::list<T>::Iterator begin = m_list.begin();
1301 m_list.erase(begin);
1307 return m_list.size();
1311 core::list<T> m_list;
1315 Thread-safe FIFO queue
1318 template<typename T>
1328 return m_list.size();
1332 JMutexAutoLock lock(m_mutex);
1333 m_list.push_back(t);
1335 T pop_front(u32 wait_time_max_ms=0)
1337 u32 wait_time_ms = 0;
1342 JMutexAutoLock lock(m_mutex);
1344 if(m_list.size() > 0)
1346 typename core::list<T>::Iterator begin = m_list.begin();
1348 m_list.erase(begin);
1352 if(wait_time_ms >= wait_time_max_ms)
1353 throw ItemNotFoundException("MutexedQueue: queue is empty");
1356 // Wait a while before trying again
1367 core::list<T> & getList()
1374 core::list<T> m_list;
1377 template<typename Caller, typename Data>
1385 template<typename Key, typename T, typename Caller, typename CallerData>
1391 core::list<CallerInfo<Caller, CallerData> > callers;
1394 template<typename Key, typename T, typename Caller, typename CallerData>
1395 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
1399 template<typename Key, typename T, typename Caller, typename CallerData>
1407 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
1411 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
1422 ResultQueue<Key, T, Caller, CallerData> *dest;
1423 core::list<CallerInfo<Caller, CallerData> > callers;
1427 Quickhands for typical request-result queues.
1428 Used for distributing work between threads.
1431 template<typename Key, typename T, typename Caller, typename CallerData>
1437 return m_queue.size();
1440 void add(Key key, Caller caller, CallerData callerdata,
1441 ResultQueue<Key, T, Caller, CallerData> *dest)
1443 JMutexAutoLock lock(m_queue.getMutex());
1446 If the caller is already on the list, only update CallerData
1448 for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
1449 i = m_queue.getList().begin();
1450 i != m_queue.getList().end(); i++)
1452 GetRequest<Key, T, Caller, CallerData> &request = *i;
1454 if(request.key == key)
1456 for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
1457 i = request.callers.begin();
1458 i != request.callers.end(); i++)
1460 CallerInfo<Caller, CallerData> &ca = *i;
1461 if(ca.caller == caller)
1463 ca.data = callerdata;
1467 CallerInfo<Caller, CallerData> ca;
1469 ca.data = callerdata;
1470 request.callers.push_back(ca);
1476 Else add a new request to the queue
1479 GetRequest<Key, T, Caller, CallerData> request;
1481 CallerInfo<Caller, CallerData> ca;
1483 ca.data = callerdata;
1484 request.callers.push_back(ca);
1485 request.dest = dest;
1487 m_queue.getList().push_back(request);
1490 GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
1492 return m_queue.pop_front(wait_if_empty);
1496 MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
1500 Pseudo-random (VC++ rand() sucks)
1503 void mysrand(unsigned seed);
1504 #define MYRAND_MAX 32767
1506 inline int myrand_range(int min, int max)
1513 return (myrand()%(max-min+1))+min;
1517 Miscellaneous functions
1520 bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range,
1521 f32 *distance_ptr=NULL);
1524 Queue with unique values with fast checking of value existence
1527 template<typename Value>
1533 Does nothing if value is already queued.
1536 false: value already exists
1538 bool push_back(Value value)
1540 // Check if already exists
1541 if(m_map.find(value) != NULL)
1545 m_map.insert(value, 0);
1546 m_list.push_back(value);
1553 typename core::list<Value>::Iterator i = m_list.begin();
1555 m_map.remove(value);
1562 assert(m_list.size() == m_map.size());
1563 return m_list.size();
1567 core::map<Value, u8> m_map;
1568 core::list<Value> m_list;
1572 template<typename Key, typename Value>
1579 assert(m_mutex.IsInitialized());
1582 void set(const Key &name, const Value &value)
1584 JMutexAutoLock lock(m_mutex);
1586 m_values[name] = value;
1589 bool get(const Key &name, Value *result)
1591 JMutexAutoLock lock(m_mutex);
1593 typename core::map<Key, Value>::Node *n;
1594 n = m_values.find(name);
1599 *result = n->getValue();
1604 core::map<Key, Value> m_values;
1610 Generates ids for comparable values.
1611 Id=0 is reserved for "no value".
1614 - Returning value by id (very fast)
1615 - Returning id by value
1616 - Generating a new id for a value
1619 - Remove an id/value pair (is possible to implement but slow)
1621 template<typename T>
1622 class MutexedIdGenerator
1625 MutexedIdGenerator()
1628 assert(m_mutex.IsInitialized());
1631 // Returns true if found
1632 bool getValue(u32 id, T &value)
1636 JMutexAutoLock lock(m_mutex);
1637 if(m_id_to_value.size() < id)
1639 value = m_id_to_value[id-1];
1643 // If id exists for value, returns the id.
1644 // Otherwise generates an id for the value.
1645 u32 getId(const T &value)
1647 JMutexAutoLock lock(m_mutex);
1648 typename core::map<T, u32>::Node *n;
1649 n = m_value_to_id.find(value);
1651 return n->getValue();
1652 m_id_to_value.push_back(value);
1653 u32 new_id = m_id_to_value.size();
1654 m_value_to_id.insert(value, new_id);
1660 // Values are stored here at id-1 position (id 1 = [0])
1661 core::array<T> m_id_to_value;
1662 core::map<T, u32> m_value_to_id;
1666 Checks if a string contains only supplied characters
1668 inline bool string_allowed(const std::string &s, const std::string &allowed_chars)
1670 for(u32 i=0; i<s.size(); i++)
1672 bool confirmed = false;
1673 for(u32 j=0; j<allowed_chars.size(); j++)
1675 if(s[i] == allowed_chars[j])
1681 if(confirmed == false)
1690 #define MYMIN(a,b) ((a)<(b)?(a):(b))
1691 #define MYMAX(a,b) ((a)>(b)?(a):(b))