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<<"INFO: updateConfigFile():"
974 " Error opening configuration file"
976 <<filename<<"\""<<std::endl;
980 while(getUpdatedConfigObject(is, objects, updated));
986 std::ofstream os(filename);
987 if(os.good() == false)
989 dstream<<"Error opening configuration file"
991 <<filename<<"\""<<std::endl;
998 for(core::list<std::string>::Iterator
1000 i != objects.end(); i++)
1006 Write stuff that was not already in the file
1008 for(core::map<std::string, std::string>::Iterator
1009 i = m_settings.getIterator();
1010 i.atEnd() == false; i++)
1012 if(updated.find(i.getNode()->getKey()))
1014 std::string name = i.getNode()->getKey();
1015 std::string value = i.getNode()->getValue();
1016 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
1018 os<<name<<" = "<<value<<"\n";
1026 NOTE: Types of allowed_options are ignored
1028 returns true on success
1030 bool parseCommandLine(int argc, char *argv[],
1031 core::map<std::string, ValueSpec> &allowed_options)
1038 std::string argname = argv[i];
1039 if(argname.substr(0, 2) != "--")
1041 dstream<<"Invalid command-line parameter \""
1042 <<argname<<"\": --<option> expected."<<std::endl;
1047 std::string name = argname.substr(2);
1049 core::map<std::string, ValueSpec>::Node *n;
1050 n = allowed_options.find(name);
1053 dstream<<"Unknown command-line parameter \""
1054 <<argname<<"\""<<std::endl;
1058 ValueType type = n->getValue().type;
1060 std::string value = "";
1062 if(type == VALUETYPE_FLAG)
1070 dstream<<"Invalid command-line parameter \""
1071 <<name<<"\": missing value"<<std::endl;
1079 dstream<<"Valid command-line parameter: \""
1080 <<name<<"\" = \""<<value<<"\""
1088 void set(std::string name, std::string value)
1090 m_settings[name] = value;
1093 void setDefault(std::string name, std::string value)
1095 m_defaults[name] = value;
1098 bool exists(std::string name)
1100 return (m_settings.find(name) || m_defaults.find(name));
1103 std::string get(std::string name)
1105 core::map<std::string, std::string>::Node *n;
1106 n = m_settings.find(name);
1109 n = m_defaults.find(name);
1112 dstream<<"INFO: Settings: Setting not found: \""
1113 <<name<<"\""<<std::endl;
1114 throw SettingNotFoundException("Setting not found");
1118 return n->getValue();
1121 bool getBool(std::string name)
1123 return is_yes(get(name));
1126 bool getFlag(std::string name)
1130 return getBool(name);
1132 catch(SettingNotFoundException &e)
1139 bool getBoolAsk(std::string name, std::string question, bool def)
1141 // If it is in settings
1142 if(m_settings.find(name))
1143 return getBool(name);
1147 std::cout<<question<<" [y/N]: ";
1148 std::cin.getline(templine, 10);
1157 float getFloat(std::string name)
1159 return stof(get(name));
1162 u16 getU16(std::string name)
1164 return stoi(get(name), 0, 65535);
1167 u16 getU16Ask(std::string name, std::string question, u16 def)
1169 // If it is in settings
1170 if(m_settings.find(name))
1171 return getU16(name);
1175 std::cout<<question<<" ["<<def<<"]: ";
1176 std::cin.getline(templine, 10);
1182 return stoi(s, 0, 65535);
1185 s16 getS16(std::string name)
1187 return stoi(get(name), -32768, 32767);
1190 s32 getS32(std::string name)
1192 return stoi(get(name));
1195 v3f getV3F(std::string name)
1198 Strfnd f(get(name));
1200 value.X = stof(f.next(","));
1201 value.Y = stof(f.next(","));
1202 value.Z = stof(f.next(")"));
1206 u64 getU64(std::string name)
1209 std::string s = get(name);
1210 std::istringstream ss(s);
1215 void setS32(std::string name, s32 value)
1217 set(name, itos(value));
1220 void setFloat(std::string name, float value)
1222 set(name, ftos(value));
1225 void setV3F(std::string name, v3f value)
1227 std::ostringstream os;
1228 os<<"("<<value.X<<","<<value.Y<<","<<value.Z<<")";
1229 set(name, os.str());
1232 void setU64(std::string name, u64 value)
1234 std::ostringstream os;
1236 set(name, os.str());
1245 Settings & operator+=(Settings &other)
1250 for(core::map<std::string, std::string>::Iterator
1251 i = other.m_settings.getIterator();
1252 i.atEnd() == false; i++)
1254 m_settings.insert(i.getNode()->getKey(),
1255 i.getNode()->getValue());
1258 for(core::map<std::string, std::string>::Iterator
1259 i = other.m_defaults.getIterator();
1260 i.atEnd() == false; i++)
1262 m_defaults.insert(i.getNode()->getKey(),
1263 i.getNode()->getValue());
1268 Settings & operator=(Settings &other)
1280 core::map<std::string, std::string> m_settings;
1281 core::map<std::string, std::string> m_defaults;
1287 template<typename T>
1293 m_list.push_back(t);
1298 if(m_list.size() == 0)
1299 throw ItemNotFoundException("MutexedQueue: queue is empty");
1301 typename core::list<T>::Iterator begin = m_list.begin();
1303 m_list.erase(begin);
1309 return m_list.size();
1313 core::list<T> m_list;
1317 Thread-safe FIFO queue
1320 template<typename T>
1330 return m_list.size();
1334 JMutexAutoLock lock(m_mutex);
1335 m_list.push_back(t);
1337 T pop_front(u32 wait_time_max_ms=0)
1339 u32 wait_time_ms = 0;
1344 JMutexAutoLock lock(m_mutex);
1346 if(m_list.size() > 0)
1348 typename core::list<T>::Iterator begin = m_list.begin();
1350 m_list.erase(begin);
1354 if(wait_time_ms >= wait_time_max_ms)
1355 throw ItemNotFoundException("MutexedQueue: queue is empty");
1358 // Wait a while before trying again
1369 core::list<T> & getList()
1376 core::list<T> m_list;
1379 template<typename Caller, typename Data>
1387 template<typename Key, typename T, typename Caller, typename CallerData>
1393 core::list<CallerInfo<Caller, CallerData> > callers;
1396 template<typename Key, typename T, typename Caller, typename CallerData>
1397 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
1401 template<typename Key, typename T, typename Caller, typename CallerData>
1409 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
1413 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
1424 ResultQueue<Key, T, Caller, CallerData> *dest;
1425 core::list<CallerInfo<Caller, CallerData> > callers;
1429 Quickhands for typical request-result queues.
1430 Used for distributing work between threads.
1433 template<typename Key, typename T, typename Caller, typename CallerData>
1439 return m_queue.size();
1442 void add(Key key, Caller caller, CallerData callerdata,
1443 ResultQueue<Key, T, Caller, CallerData> *dest)
1445 JMutexAutoLock lock(m_queue.getMutex());
1448 If the caller is already on the list, only update CallerData
1450 for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
1451 i = m_queue.getList().begin();
1452 i != m_queue.getList().end(); i++)
1454 GetRequest<Key, T, Caller, CallerData> &request = *i;
1456 if(request.key == key)
1458 for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
1459 i = request.callers.begin();
1460 i != request.callers.end(); i++)
1462 CallerInfo<Caller, CallerData> &ca = *i;
1463 if(ca.caller == caller)
1465 ca.data = callerdata;
1469 CallerInfo<Caller, CallerData> ca;
1471 ca.data = callerdata;
1472 request.callers.push_back(ca);
1478 Else add a new request to the queue
1481 GetRequest<Key, T, Caller, CallerData> request;
1483 CallerInfo<Caller, CallerData> ca;
1485 ca.data = callerdata;
1486 request.callers.push_back(ca);
1487 request.dest = dest;
1489 m_queue.getList().push_back(request);
1492 GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
1494 return m_queue.pop_front(wait_if_empty);
1498 MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
1502 Pseudo-random (VC++ rand() sucks)
1505 void mysrand(unsigned seed);
1506 #define MYRAND_MAX 32767
1508 inline int myrand_range(int min, int max)
1515 return (myrand()%(max-min+1))+min;
1519 Miscellaneous functions
1522 bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range,
1523 f32 *distance_ptr=NULL);
1526 Queue with unique values with fast checking of value existence
1529 template<typename Value>
1535 Does nothing if value is already queued.
1538 false: value already exists
1540 bool push_back(Value value)
1542 // Check if already exists
1543 if(m_map.find(value) != NULL)
1547 m_map.insert(value, 0);
1548 m_list.push_back(value);
1555 typename core::list<Value>::Iterator i = m_list.begin();
1557 m_map.remove(value);
1564 assert(m_list.size() == m_map.size());
1565 return m_list.size();
1569 core::map<Value, u8> m_map;
1570 core::list<Value> m_list;
1574 template<typename Key, typename Value>
1581 assert(m_mutex.IsInitialized());
1584 void set(const Key &name, const Value &value)
1586 JMutexAutoLock lock(m_mutex);
1588 m_values[name] = value;
1591 bool get(const Key &name, Value *result)
1593 JMutexAutoLock lock(m_mutex);
1595 typename core::map<Key, Value>::Node *n;
1596 n = m_values.find(name);
1601 *result = n->getValue();
1606 core::map<Key, Value> m_values;
1612 Generates ids for comparable values.
1613 Id=0 is reserved for "no value".
1616 - Returning value by id (very fast)
1617 - Returning id by value
1618 - Generating a new id for a value
1621 - Remove an id/value pair (is possible to implement but slow)
1623 template<typename T>
1624 class MutexedIdGenerator
1627 MutexedIdGenerator()
1630 assert(m_mutex.IsInitialized());
1633 // Returns true if found
1634 bool getValue(u32 id, T &value)
1638 JMutexAutoLock lock(m_mutex);
1639 if(m_id_to_value.size() < id)
1641 value = m_id_to_value[id-1];
1645 // If id exists for value, returns the id.
1646 // Otherwise generates an id for the value.
1647 u32 getId(const T &value)
1649 JMutexAutoLock lock(m_mutex);
1650 typename core::map<T, u32>::Node *n;
1651 n = m_value_to_id.find(value);
1653 return n->getValue();
1654 m_id_to_value.push_back(value);
1655 u32 new_id = m_id_to_value.size();
1656 m_value_to_id.insert(value, new_id);
1662 // Values are stored here at id-1 position (id 1 = [0])
1663 core::array<T> m_id_to_value;
1664 core::map<T, u32> m_value_to_id;
1668 Checks if a string contains only supplied characters
1670 inline bool string_allowed(const std::string &s, const std::string &allowed_chars)
1672 for(u32 i=0; i<s.size(); i++)
1674 bool confirmed = false;
1675 for(u32 j=0; j<allowed_chars.size(); j++)
1677 if(s[i] == allowed_chars[j])
1683 if(confirmed == false)
1690 Forcefully wraps string into rows using \n
1691 (no word wrap, used for showing paths in gui)
1693 inline std::string wrap_rows(const std::string &from, u32 rowlen)
1696 for(u32 i=0; i<from.size(); i++)
1698 if(i != 0 && i%rowlen == 0)
1708 #define MYMIN(a,b) ((a)<(b)?(a):(b))
1709 #define MYMAX(a,b) ((a)>(b)?(a):(b))