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 // If it is in settings
1013 if(m_settings.find(name))
1014 return getBool(name);
1018 std::cout<<question<<" [y/N]: ";
1019 std::cin.getline(templine, 10);
1028 float getFloat(std::string name)
1031 std::istringstream vis(get(name));
1036 u16 getU16(std::string name)
1038 return stoi(get(name), 0, 65535);
1041 u16 getU16Ask(std::string name, std::string question, u16 def)
1043 // If it is in settings
1044 if(m_settings.find(name))
1045 return getU16(name);
1049 std::cout<<question<<" ["<<def<<"]: ";
1050 std::cin.getline(templine, 10);
1056 return stoi(s, 0, 65535);
1059 s16 getS16(std::string name)
1061 return stoi(get(name), -32768, 32767);
1064 s32 getS32(std::string name)
1066 return stoi(get(name));
1070 core::map<std::string, std::string> m_settings;
1071 core::map<std::string, std::string> m_defaults;
1077 template<typename T>
1083 m_list.push_back(t);
1088 if(m_list.size() == 0)
1089 throw ItemNotFoundException("MutexedQueue: queue is empty");
1091 typename core::list<T>::Iterator begin = m_list.begin();
1093 m_list.erase(begin);
1099 return m_list.size();
1103 core::list<T> m_list;
1107 Thread-safe FIFO queue
1110 template<typename T>
1120 return m_list.size();
1124 JMutexAutoLock lock(m_mutex);
1125 m_list.push_back(t);
1127 T pop_front(u32 wait_time_max_ms=0)
1129 u32 wait_time_ms = 0;
1134 JMutexAutoLock lock(m_mutex);
1136 if(m_list.size() > 0)
1138 typename core::list<T>::Iterator begin = m_list.begin();
1140 m_list.erase(begin);
1144 if(wait_time_ms >= wait_time_max_ms)
1145 throw ItemNotFoundException("MutexedQueue: queue is empty");
1148 // Wait a while before trying again
1159 core::list<T> & getList()
1166 core::list<T> m_list;
1169 template<typename Caller, typename Data>
1177 template<typename Key, typename T, typename Caller, typename CallerData>
1183 core::list<CallerInfo<Caller, CallerData> > callers;
1186 template<typename Key, typename T, typename Caller, typename CallerData>
1187 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
1191 template<typename Key, typename T, typename Caller, typename CallerData>
1199 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
1203 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
1214 ResultQueue<Key, T, Caller, CallerData> *dest;
1215 core::list<CallerInfo<Caller, CallerData> > callers;
1219 Quickhands for typical request-result queues.
1220 Used for distributing work between threads.
1223 template<typename Key, typename T, typename Caller, typename CallerData>
1229 return m_queue.size();
1232 void add(Key key, Caller caller, CallerData callerdata,
1233 ResultQueue<Key, T, Caller, CallerData> *dest)
1235 JMutexAutoLock lock(m_queue.getMutex());
1238 If the caller is already on the list, only update CallerData
1240 for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
1241 i = m_queue.getList().begin();
1242 i != m_queue.getList().end(); i++)
1244 GetRequest<Key, T, Caller, CallerData> &request = *i;
1246 if(request.key == key)
1248 for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
1249 i = request.callers.begin();
1250 i != request.callers.end(); i++)
1252 CallerInfo<Caller, CallerData> &ca = *i;
1253 if(ca.caller == caller)
1255 ca.data = callerdata;
1259 CallerInfo<Caller, CallerData> ca;
1261 ca.data = callerdata;
1262 request.callers.push_back(ca);
1268 Else add a new request to the queue
1271 GetRequest<Key, T, Caller, CallerData> request;
1273 CallerInfo<Caller, CallerData> ca;
1275 ca.data = callerdata;
1276 request.callers.push_back(ca);
1277 request.dest = dest;
1279 m_queue.getList().push_back(request);
1282 GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
1284 return m_queue.pop_front(wait_if_empty);
1288 MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;