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];
39 inline void writeU32(u8 *data, u32 i)
41 data[0] = ((i>>24)&0xff);
42 data[1] = ((i>>16)&0xff);
43 data[2] = ((i>> 8)&0xff);
44 data[3] = ((i>> 0)&0xff);
47 inline void writeU16(u8 *data, u16 i)
49 data[0] = ((i>> 8)&0xff);
50 data[1] = ((i>> 0)&0xff);
53 inline void writeU8(u8 *data, u8 i)
55 data[0] = ((i>> 0)&0xff);
58 inline u32 readU32(u8 *data)
60 return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
63 inline u16 readU16(u8 *data)
65 return (data[0]<<8) | (data[1]<<0);
68 inline u8 readU8(u8 *data)
73 // Signed variants of the above
75 inline void writeS32(u8 *data, s32 i){
76 writeU32(data, (u32)i);
78 inline s32 readS32(u8 *data){
79 return (s32)readU32(data);
82 inline void writeS16(u8 *data, s16 i){
83 writeU16(data, (u16)i);
85 inline s16 readS16(u8 *data){
86 return (s16)readU16(data);
89 inline void writeV3S32(u8 *data, v3s32 p)
91 writeS32(&data[0], p.X);
92 writeS32(&data[4], p.Y);
93 writeS32(&data[8], p.Z);
96 inline v3s32 readV3S32(u8 *data)
99 p.X = readS32(&data[0]);
100 p.Y = readS32(&data[4]);
101 p.Z = readS32(&data[8]);
105 inline void writeV2S16(u8 *data, v2s16 p)
107 writeS16(&data[0], p.X);
108 writeS16(&data[2], p.Y);
111 inline v2s16 readV2S16(u8 *data)
114 p.X = readS16(&data[0]);
115 p.Y = readS16(&data[2]);
119 inline void writeV2S32(u8 *data, v2s32 p)
121 writeS32(&data[0], p.X);
122 writeS32(&data[2], p.Y);
125 inline v2s32 readV2S32(u8 *data)
128 p.X = readS32(&data[0]);
129 p.Y = readS32(&data[2]);
133 inline void writeV3S16(u8 *data, v3s16 p)
135 writeS16(&data[0], p.X);
136 writeS16(&data[2], p.Y);
137 writeS16(&data[4], p.Z);
140 inline v3s16 readV3S16(u8 *data)
143 p.X = readS16(&data[0]);
144 p.Y = readS16(&data[2]);
145 p.Z = readS16(&data[4]);
150 None of these are used at the moment
153 template <typename T>
163 SharedPtr(SharedPtr<T> &t)
167 refcount = t.refcount;
175 SharedPtr<T> & operator=(T *t)
183 SharedPtr<T> & operator=(SharedPtr<T> &t)
186 refcount = t.refcount;
199 bool operator!=(T *t)
203 bool operator==(T *t)
210 assert((*refcount) > 0);
223 template <typename T>
227 Buffer(unsigned int size)
232 Buffer(const Buffer &buffer)
234 m_size = buffer.m_size;
235 data = new T[buffer.m_size];
236 memcpy(data, buffer.data, buffer.m_size);
238 Buffer(T *t, unsigned int size)
242 memcpy(data, t, size);
248 T & operator[](unsigned int i) const
252 T * operator*() const
256 unsigned int getSize() const
265 template <typename T>
269 SharedBuffer(unsigned int size)
273 refcount = new unsigned int;
276 SharedBuffer(const SharedBuffer &buffer)
278 //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
279 m_size = buffer.m_size;
281 refcount = buffer.refcount;
284 SharedBuffer & operator=(const SharedBuffer & buffer)
286 //std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
290 m_size = buffer.m_size;
292 refcount = buffer.refcount;
299 SharedBuffer(T *t, unsigned int size)
303 memcpy(data, t, size);
304 refcount = new unsigned int;
310 SharedBuffer(const Buffer<T> &buffer)
312 m_size = buffer.m_size;
313 data = new T[buffer.getSize()];
314 memcpy(data, *buffer, buffer.getSize());
315 refcount = new unsigned int;
322 T & operator[](unsigned int i) const
326 T * operator*() const
330 unsigned int getSize() const
337 assert((*refcount) > 0);
347 unsigned int *refcount;
350 inline SharedBuffer<u8> SharedBufferFromString(const char *string)
352 SharedBuffer<u8> b((u8*)string, strlen(string)+1);
357 class MutexedVariable
360 MutexedVariable(T value):
368 JMutexAutoLock lock(m_mutex);
374 JMutexAutoLock lock(m_mutex);
378 // You'll want to grab this in a SharedPtr
379 JMutexAutoLock * getLock()
381 return new JMutexAutoLock(m_mutex);
384 // You pretty surely want to grab the lock when accessing this
395 class IrrlichtWrapper;
400 TimeTaker(const char *name, u32 *result=NULL);
407 u32 stop(bool quiet=false);
416 // Calculates the borders of a "d-radius" cube
417 inline void getFacePositions(core::list<v3s16> &list, u16 d)
421 list.push_back(v3s16(0,0,0));
427 This is an optimized sequence of coordinates.
429 list.push_back(v3s16( 0, 1, 0)); // top
430 list.push_back(v3s16( 0, 0, 1)); // back
431 list.push_back(v3s16(-1, 0, 0)); // left
432 list.push_back(v3s16( 1, 0, 0)); // right
433 list.push_back(v3s16( 0, 0,-1)); // front
434 list.push_back(v3s16( 0,-1, 0)); // bottom
436 list.push_back(v3s16(-1, 0, 1)); // back left
437 list.push_back(v3s16( 1, 0, 1)); // back right
438 list.push_back(v3s16(-1, 0,-1)); // front left
439 list.push_back(v3s16( 1, 0,-1)); // front right
440 list.push_back(v3s16(-1,-1, 0)); // bottom left
441 list.push_back(v3s16( 1,-1, 0)); // bottom right
442 list.push_back(v3s16( 0,-1, 1)); // bottom back
443 list.push_back(v3s16( 0,-1,-1)); // bottom front
444 list.push_back(v3s16(-1, 1, 0)); // top left
445 list.push_back(v3s16( 1, 1, 0)); // top right
446 list.push_back(v3s16( 0, 1, 1)); // top back
447 list.push_back(v3s16( 0, 1,-1)); // top front
449 list.push_back(v3s16(-1, 1, 1)); // top back-left
450 list.push_back(v3s16( 1, 1, 1)); // top back-right
451 list.push_back(v3s16(-1, 1,-1)); // top front-left
452 list.push_back(v3s16( 1, 1,-1)); // top front-right
453 list.push_back(v3s16(-1,-1, 1)); // bottom back-left
454 list.push_back(v3s16( 1,-1, 1)); // bottom back-right
455 list.push_back(v3s16(-1,-1,-1)); // bottom front-left
456 list.push_back(v3s16( 1,-1,-1)); // bottom front-right
461 // Take blocks in all sides, starting from y=0 and going +-y
462 for(s16 y=0; y<=d-1; y++)
464 // Left and right side, including borders
465 for(s16 z=-d; z<=d; z++)
467 list.push_back(v3s16(d,y,z));
468 list.push_back(v3s16(-d,y,z));
471 list.push_back(v3s16(d,-y,z));
472 list.push_back(v3s16(-d,-y,z));
475 // Back and front side, excluding borders
476 for(s16 x=-d+1; x<=d-1; x++)
478 list.push_back(v3s16(x,y,d));
479 list.push_back(v3s16(x,y,-d));
482 list.push_back(v3s16(x,-y,d));
483 list.push_back(v3s16(x,-y,-d));
488 // Take the bottom and top face with borders
489 // -d<x<d, y=+-d, -d<z<d
490 for(s16 x=-d; x<=d; x++)
491 for(s16 z=-d; z<=d; z++)
493 list.push_back(v3s16(x,-d,z));
494 list.push_back(v3s16(x,d,z));
498 class IndentationRaiser
501 IndentationRaiser(u16 *indentation)
503 m_indentation = indentation;
514 inline s16 getContainerPos(s16 p, s16 d)
516 return (p>=0 ? p : p-d+1) / d;
519 inline v2s16 getContainerPos(v2s16 p, s16 d)
522 getContainerPos(p.X, d),
523 getContainerPos(p.Y, d)
527 inline v3s16 getContainerPos(v3s16 p, s16 d)
530 getContainerPos(p.X, d),
531 getContainerPos(p.Y, d),
532 getContainerPos(p.Z, d)
536 inline bool isInArea(v3s16 p, s16 d)
539 p.X >= 0 && p.X < d &&
540 p.Y >= 0 && p.Y < d &&
545 inline bool isInArea(v2s16 p, s16 d)
548 p.X >= 0 && p.X < d &&
553 inline std::wstring narrow_to_wide(const std::string& mbs)
555 size_t wcl = mbs.size();
556 SharedBuffer<wchar_t> wcs(wcl+1);
557 size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
562 inline std::string wide_to_narrow(const std::wstring& wcs)
564 size_t mbl = wcs.size()*4;
565 SharedBuffer<char> mbs(mbl+1);
566 size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
575 See test.cpp for example cases.
576 wraps degrees to the range of -360...360
577 NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
579 inline float wrapDegrees(float f)
581 // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
587 // NOTE: This would be used for wrapping to 0...360
593 // 10, 0.5, -0.5, -0.5
598 inline std::string lowercase(const std::string &s)
601 for(size_t i=0; i<s.size(); i++)
604 if(c >= 'A' && c <= 'Z')
611 inline bool is_yes(const std::string &s)
613 std::string s2 = lowercase(trim(s));
614 if(s2 == "y" || s2 == "yes" || s2 == "true")
619 inline s32 stoi(const std::string &s, s32 min, s32 max)
621 s32 i = atoi(s.c_str());
629 inline s32 stoi(std::string s)
631 return atoi(s.c_str());
635 A base class for simple background thread implementation
638 class SimpleThread : public JThread
652 virtual ~SimpleThread()
655 virtual void * Thread() = 0;
659 JMutexAutoLock lock(run_mutex);
662 void setRun(bool a_run)
664 JMutexAutoLock lock(run_mutex);
683 VALUETYPE_FLAG // Doesn't take any arguments
688 ValueSpec(ValueType a_type, const char *a_help=NULL)
701 // Returns false on EOF
702 bool parseConfigObject(std::istream &is)
707 // NOTE: This function will be expanded to allow multi-line settings
709 std::getline(is, line);
710 //dstream<<"got line: \""<<line<<"\""<<std::endl;
712 std::string trimmedline = trim(line);
715 if(trimmedline[0] == '#')
718 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
720 Strfnd sf(trim(line));
722 std::string name = sf.next("=");
728 std::string value = sf.next("\n");
731 dstream<<"Config name=\""<<name<<"\" value=\""
732 <<value<<"\""<<std::endl;
734 m_settings[name] = value;
740 Read configuration file
742 Returns true on success
744 bool readConfigFile(const char *filename)
746 std::ifstream is(filename);
747 if(is.good() == false)
749 dstream<<"Error opening configuration file \""
750 <<filename<<"\""<<std::endl;
754 dstream<<"Parsing configuration file: \""
755 <<filename<<"\""<<std::endl;
757 while(parseConfigObject(is));
763 Reads a configuration object from stream (usually a single line)
766 Preserves comments and empty lines.
768 Settings that were added to dst are also added to updated.
769 key of updated is setting name, value of updated is dummy.
773 bool getUpdatedConfigObject(std::istream &is,
774 core::list<std::string> &dst,
775 core::map<std::string, bool> &updated)
780 // NOTE: This function will be expanded to allow multi-line settings
782 std::getline(is, line);
784 std::string trimmedline = trim(line);
786 std::string line_end = "";
787 if(is.eof() == false)
791 if(trimmedline[0] == '#')
793 dst.push_back(line+line_end);
797 Strfnd sf(trim(line));
799 std::string name = sf.next("=");
804 dst.push_back(line+line_end);
808 std::string value = sf.next("\n");
811 if(m_settings.find(name))
813 std::string newvalue = m_settings[name];
815 if(newvalue != value)
817 dstream<<"Changing value of \""<<name<<"\" = \""
818 <<value<<"\" -> \""<<newvalue<<"\""
822 dst.push_back(name + " = " + newvalue + line_end);
824 updated[name] = true;
831 Updates configuration file
833 Returns true on success
835 bool updateConfigFile(const char *filename)
837 dstream<<"Updating configuration file: \""
838 <<filename<<"\""<<std::endl;
840 core::list<std::string> objects;
841 core::map<std::string, bool> updated;
843 // Read and modify stuff
845 std::ifstream is(filename);
846 if(is.good() == false)
848 dstream<<"Error opening configuration file"
850 <<filename<<"\""<<std::endl;
854 while(getUpdatedConfigObject(is, objects, updated));
859 std::ofstream os(filename);
860 if(os.good() == false)
862 dstream<<"Error opening configuration file"
864 <<filename<<"\""<<std::endl;
871 for(core::list<std::string>::Iterator
873 i != objects.end(); i++)
879 Write stuff that was not already in the file
881 for(core::map<std::string, std::string>::Iterator
882 i = m_settings.getIterator();
883 i.atEnd() == false; i++)
885 if(updated.find(i.getNode()->getKey()))
887 std::string name = i.getNode()->getKey();
888 std::string value = i.getNode()->getValue();
889 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
891 os<<name<<" = "<<value<<"\n";
899 NOTE: Types of allowed_options are ignored
901 returns true on success
903 bool parseCommandLine(int argc, char *argv[],
904 core::map<std::string, ValueSpec> &allowed_options)
911 std::string argname = argv[i];
912 if(argname.substr(0, 2) != "--")
914 dstream<<"Invalid command-line parameter \""
915 <<argname<<"\": --<option> expected."<<std::endl;
920 std::string name = argname.substr(2);
922 core::map<std::string, ValueSpec>::Node *n;
923 n = allowed_options.find(name);
926 dstream<<"Unknown command-line parameter \""
927 <<argname<<"\""<<std::endl;
931 ValueType type = n->getValue().type;
933 std::string value = "";
935 if(type == VALUETYPE_FLAG)
943 dstream<<"Invalid command-line parameter \""
944 <<name<<"\": missing value"<<std::endl;
952 dstream<<"Valid command-line parameter: \""
953 <<name<<"\" = \""<<value<<"\""
961 void set(std::string name, std::string value)
963 m_settings[name] = value;
966 void setDefault(std::string name, std::string value)
968 m_defaults[name] = value;
971 bool exists(std::string name)
973 return (m_settings.find(name) || m_defaults.find(name));
976 std::string get(std::string name)
978 core::map<std::string, std::string>::Node *n;
979 n = m_settings.find(name);
982 n = m_defaults.find(name);
985 throw SettingNotFoundException("Setting not found");
989 return n->getValue();
992 bool getBool(std::string name)
994 return is_yes(get(name));
997 bool getFlag(std::string name)
1001 return getBool(name);
1003 catch(SettingNotFoundException &e)
1010 bool getBoolAsk(std::string name, std::string question, bool def)
1012 std::string s = get(name);
1017 std::cout<<question<<" [y/N]: ";
1018 std::cin.getline(templine, 10);
1027 float getFloat(std::string name)
1030 std::istringstream vis(get(name));
1035 u16 getU16(std::string name)
1037 return stoi(get(name), 0, 65535);
1040 u16 getU16Ask(std::string name, std::string question, u16 def)
1042 std::string s = get(name);
1044 return stoi(s, 0, 65535);
1047 std::cout<<question<<" ["<<def<<"]: ";
1048 std::cin.getline(templine, 10);
1054 return stoi(s, 0, 65535);
1057 s16 getS16(std::string name)
1059 return stoi(get(name), -32768, 32767);
1062 s32 getS32(std::string name)
1064 return stoi(get(name));
1068 core::map<std::string, std::string> m_settings;
1069 core::map<std::string, std::string> m_defaults;
1075 template<typename T>
1081 m_list.push_back(t);
1086 if(m_list.size() == 0)
1087 throw ItemNotFoundException("MutexedQueue: queue is empty");
1089 typename core::list<T>::Iterator begin = m_list.begin();
1091 m_list.erase(begin);
1097 return m_list.size();
1101 core::list<T> m_list;
1105 Thread-safe FIFO queue
1108 template<typename T>
1118 return m_list.size();
1122 JMutexAutoLock lock(m_mutex);
1123 m_list.push_back(t);
1125 T pop_front(u32 wait_time_max_ms=0)
1127 u32 wait_time_ms = 0;
1132 JMutexAutoLock lock(m_mutex);
1134 if(m_list.size() > 0)
1136 typename core::list<T>::Iterator begin = m_list.begin();
1138 m_list.erase(begin);
1142 if(wait_time_ms >= wait_time_max_ms)
1143 throw ItemNotFoundException("MutexedQueue: queue is empty");
1146 // Wait a while before trying again
1157 core::list<T> & getList()
1164 core::list<T> m_list;
1167 template<typename Caller, typename Data>
1175 template<typename Key, typename T, typename Caller, typename CallerData>
1181 core::list<CallerInfo<Caller, CallerData> > callers;
1184 template<typename Key, typename T, typename Caller, typename CallerData>
1185 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
1189 template<typename Key, typename T, typename Caller, typename CallerData>
1197 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
1201 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
1212 ResultQueue<Key, T, Caller, CallerData> *dest;
1213 core::list<CallerInfo<Caller, CallerData> > callers;
1217 Quickhands for typical request-result queues.
1218 Used for distributing work between threads.
1221 template<typename Key, typename T, typename Caller, typename CallerData>
1227 return m_queue.size();
1230 void add(Key key, Caller caller, CallerData callerdata,
1231 ResultQueue<Key, T, Caller, CallerData> *dest)
1233 JMutexAutoLock lock(m_queue.getMutex());
1236 If the caller is already on the list, only update CallerData
1238 for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
1239 i = m_queue.getList().begin();
1240 i != m_queue.getList().end(); i++)
1242 GetRequest<Key, T, Caller, CallerData> &request = *i;
1244 if(request.key == key)
1246 for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
1247 i = request.callers.begin();
1248 i != request.callers.end(); i++)
1250 CallerInfo<Caller, CallerData> &ca = *i;
1251 if(ca.caller == caller)
1253 ca.data = callerdata;
1257 CallerInfo<Caller, CallerData> ca;
1259 ca.data = callerdata;
1260 request.callers.push_back(ca);
1266 Else add a new request to the queue
1269 GetRequest<Key, T, Caller, CallerData> request;
1271 CallerInfo<Caller, CallerData> ca;
1273 ca.data = callerdata;
1274 request.callers.push_back(ca);
1275 request.dest = dest;
1277 m_queue.getList().push_back(request);
1280 GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
1282 return m_queue.pop_front(wait_if_empty);
1286 MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;