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 s16 rangelim(s16 i, s16 min, s16 max)
562 inline s16 rangelim(s16 i, s16 max)
571 inline v3s16 arealim(v3s16 p, s16 d)
588 inline std::wstring narrow_to_wide(const std::string& mbs)
590 size_t wcl = mbs.size();
591 SharedBuffer<wchar_t> wcs(wcl+1);
592 size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
597 inline std::string wide_to_narrow(const std::wstring& wcs)
599 size_t mbl = wcs.size()*4;
600 SharedBuffer<char> mbs(mbl+1);
601 size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
610 See test.cpp for example cases.
611 wraps degrees to the range of -360...360
612 NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
614 inline float wrapDegrees(float f)
616 // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
622 // NOTE: This would be used for wrapping to 0...360
628 // 10, 0.5, -0.5, -0.5
633 inline std::string lowercase(const std::string &s)
636 for(size_t i=0; i<s.size(); i++)
639 if(c >= 'A' && c <= 'Z')
646 inline bool is_yes(const std::string &s)
648 std::string s2 = lowercase(trim(s));
649 if(s2 == "y" || s2 == "yes" || s2 == "true")
654 inline s32 stoi(const std::string &s, s32 min, s32 max)
656 s32 i = atoi(s.c_str());
664 inline s32 stoi(std::string s)
666 return atoi(s.c_str());
670 A base class for simple background thread implementation
673 class SimpleThread : public JThread
687 virtual ~SimpleThread()
690 virtual void * Thread() = 0;
694 JMutexAutoLock lock(run_mutex);
697 void setRun(bool a_run)
699 JMutexAutoLock lock(run_mutex);
718 VALUETYPE_FLAG // Doesn't take any arguments
723 ValueSpec(ValueType a_type, const char *a_help=NULL)
736 // Returns false on EOF
737 bool parseConfigObject(std::istream &is)
742 // NOTE: This function will be expanded to allow multi-line settings
744 std::getline(is, line);
745 //dstream<<"got line: \""<<line<<"\""<<std::endl;
747 std::string trimmedline = trim(line);
750 if(trimmedline[0] == '#')
753 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
755 Strfnd sf(trim(line));
757 std::string name = sf.next("=");
763 std::string value = sf.next("\n");
766 dstream<<"Config name=\""<<name<<"\" value=\""
767 <<value<<"\""<<std::endl;
769 m_settings[name] = value;
775 Read configuration file
777 Returns true on success
779 bool readConfigFile(const char *filename)
781 std::ifstream is(filename);
782 if(is.good() == false)
784 dstream<<"Error opening configuration file \""
785 <<filename<<"\""<<std::endl;
789 dstream<<"Parsing configuration file: \""
790 <<filename<<"\""<<std::endl;
792 while(parseConfigObject(is));
798 Reads a configuration object from stream (usually a single line)
801 Preserves comments and empty lines.
803 Settings that were added to dst are also added to updated.
804 key of updated is setting name, value of updated is dummy.
808 bool getUpdatedConfigObject(std::istream &is,
809 core::list<std::string> &dst,
810 core::map<std::string, bool> &updated)
815 // NOTE: This function will be expanded to allow multi-line settings
817 std::getline(is, line);
819 std::string trimmedline = trim(line);
821 std::string line_end = "";
822 if(is.eof() == false)
826 if(trimmedline[0] == '#')
828 dst.push_back(line+line_end);
832 Strfnd sf(trim(line));
834 std::string name = sf.next("=");
839 dst.push_back(line+line_end);
843 std::string value = sf.next("\n");
846 if(m_settings.find(name))
848 std::string newvalue = m_settings[name];
850 if(newvalue != value)
852 dstream<<"Changing value of \""<<name<<"\" = \""
853 <<value<<"\" -> \""<<newvalue<<"\""
857 dst.push_back(name + " = " + newvalue + line_end);
859 updated[name] = true;
866 Updates configuration file
868 Returns true on success
870 bool updateConfigFile(const char *filename)
872 dstream<<"Updating configuration file: \""
873 <<filename<<"\""<<std::endl;
875 core::list<std::string> objects;
876 core::map<std::string, bool> updated;
878 // Read and modify stuff
880 std::ifstream is(filename);
881 if(is.good() == false)
883 dstream<<"Error opening configuration file"
885 <<filename<<"\""<<std::endl;
889 while(getUpdatedConfigObject(is, objects, updated));
894 std::ofstream os(filename);
895 if(os.good() == false)
897 dstream<<"Error opening configuration file"
899 <<filename<<"\""<<std::endl;
906 for(core::list<std::string>::Iterator
908 i != objects.end(); i++)
914 Write stuff that was not already in the file
916 for(core::map<std::string, std::string>::Iterator
917 i = m_settings.getIterator();
918 i.atEnd() == false; i++)
920 if(updated.find(i.getNode()->getKey()))
922 std::string name = i.getNode()->getKey();
923 std::string value = i.getNode()->getValue();
924 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
926 os<<name<<" = "<<value<<"\n";
934 NOTE: Types of allowed_options are ignored
936 returns true on success
938 bool parseCommandLine(int argc, char *argv[],
939 core::map<std::string, ValueSpec> &allowed_options)
946 std::string argname = argv[i];
947 if(argname.substr(0, 2) != "--")
949 dstream<<"Invalid command-line parameter \""
950 <<argname<<"\": --<option> expected."<<std::endl;
955 std::string name = argname.substr(2);
957 core::map<std::string, ValueSpec>::Node *n;
958 n = allowed_options.find(name);
961 dstream<<"Unknown command-line parameter \""
962 <<argname<<"\""<<std::endl;
966 ValueType type = n->getValue().type;
968 std::string value = "";
970 if(type == VALUETYPE_FLAG)
978 dstream<<"Invalid command-line parameter \""
979 <<name<<"\": missing value"<<std::endl;
987 dstream<<"Valid command-line parameter: \""
988 <<name<<"\" = \""<<value<<"\""
996 void set(std::string name, std::string value)
998 m_settings[name] = value;
1001 void setDefault(std::string name, std::string value)
1003 m_defaults[name] = value;
1006 bool exists(std::string name)
1008 return (m_settings.find(name) || m_defaults.find(name));
1011 std::string get(std::string name)
1013 core::map<std::string, std::string>::Node *n;
1014 n = m_settings.find(name);
1017 n = m_defaults.find(name);
1020 throw SettingNotFoundException("Setting not found");
1024 return n->getValue();
1027 bool getBool(std::string name)
1029 return is_yes(get(name));
1032 bool getFlag(std::string name)
1036 return getBool(name);
1038 catch(SettingNotFoundException &e)
1045 bool getBoolAsk(std::string name, std::string question, bool def)
1047 // If it is in settings
1048 if(m_settings.find(name))
1049 return getBool(name);
1053 std::cout<<question<<" [y/N]: ";
1054 std::cin.getline(templine, 10);
1063 float getFloat(std::string name)
1066 std::istringstream vis(get(name));
1071 u16 getU16(std::string name)
1073 return stoi(get(name), 0, 65535);
1076 u16 getU16Ask(std::string name, std::string question, u16 def)
1078 // If it is in settings
1079 if(m_settings.find(name))
1080 return getU16(name);
1084 std::cout<<question<<" ["<<def<<"]: ";
1085 std::cin.getline(templine, 10);
1091 return stoi(s, 0, 65535);
1094 s16 getS16(std::string name)
1096 return stoi(get(name), -32768, 32767);
1099 s32 getS32(std::string name)
1101 return stoi(get(name));
1105 core::map<std::string, std::string> m_settings;
1106 core::map<std::string, std::string> m_defaults;
1112 template<typename T>
1118 m_list.push_back(t);
1123 if(m_list.size() == 0)
1124 throw ItemNotFoundException("MutexedQueue: queue is empty");
1126 typename core::list<T>::Iterator begin = m_list.begin();
1128 m_list.erase(begin);
1134 return m_list.size();
1138 core::list<T> m_list;
1142 Thread-safe FIFO queue
1145 template<typename T>
1155 return m_list.size();
1159 JMutexAutoLock lock(m_mutex);
1160 m_list.push_back(t);
1162 T pop_front(u32 wait_time_max_ms=0)
1164 u32 wait_time_ms = 0;
1169 JMutexAutoLock lock(m_mutex);
1171 if(m_list.size() > 0)
1173 typename core::list<T>::Iterator begin = m_list.begin();
1175 m_list.erase(begin);
1179 if(wait_time_ms >= wait_time_max_ms)
1180 throw ItemNotFoundException("MutexedQueue: queue is empty");
1183 // Wait a while before trying again
1194 core::list<T> & getList()
1201 core::list<T> m_list;
1204 template<typename Caller, typename Data>
1212 template<typename Key, typename T, typename Caller, typename CallerData>
1218 core::list<CallerInfo<Caller, CallerData> > callers;
1221 template<typename Key, typename T, typename Caller, typename CallerData>
1222 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
1226 template<typename Key, typename T, typename Caller, typename CallerData>
1234 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
1238 GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
1249 ResultQueue<Key, T, Caller, CallerData> *dest;
1250 core::list<CallerInfo<Caller, CallerData> > callers;
1254 Quickhands for typical request-result queues.
1255 Used for distributing work between threads.
1258 template<typename Key, typename T, typename Caller, typename CallerData>
1264 return m_queue.size();
1267 void add(Key key, Caller caller, CallerData callerdata,
1268 ResultQueue<Key, T, Caller, CallerData> *dest)
1270 JMutexAutoLock lock(m_queue.getMutex());
1273 If the caller is already on the list, only update CallerData
1275 for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
1276 i = m_queue.getList().begin();
1277 i != m_queue.getList().end(); i++)
1279 GetRequest<Key, T, Caller, CallerData> &request = *i;
1281 if(request.key == key)
1283 for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
1284 i = request.callers.begin();
1285 i != request.callers.end(); i++)
1287 CallerInfo<Caller, CallerData> &ca = *i;
1288 if(ca.caller == caller)
1290 ca.data = callerdata;
1294 CallerInfo<Caller, CallerData> ca;
1296 ca.data = callerdata;
1297 request.callers.push_back(ca);
1303 Else add a new request to the queue
1306 GetRequest<Key, T, Caller, CallerData> request;
1308 CallerInfo<Caller, CallerData> ca;
1310 ca.data = callerdata;
1311 request.callers.push_back(ca);
1312 request.dest = dest;
1314 m_queue.getList().push_back(request);
1317 GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
1319 return m_queue.pop_front(wait_if_empty);
1323 MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
1327 Pseudo-random (VC++ rand() sucks)
1330 void mysrand(unsigned seed);
1331 #define MYRAND_MAX 32767
1334 TODO: Some kind of a thing that stores arbitary data related to
1335 2D coordinate points