summaryrefslogtreecommitdiff
path: root/ext/dsent/libutil
diff options
context:
space:
mode:
Diffstat (limited to 'ext/dsent/libutil')
-rw-r--r--ext/dsent/libutil/Assert.h22
-rw-r--r--ext/dsent/libutil/Calculator.cc239
-rw-r--r--ext/dsent/libutil/Calculator.h86
-rw-r--r--ext/dsent/libutil/Config.cc144
-rw-r--r--ext/dsent/libutil/Config.h37
-rw-r--r--ext/dsent/libutil/Exception.cc17
-rw-r--r--ext/dsent/libutil/Exception.h29
-rw-r--r--ext/dsent/libutil/LibUtil.h37
-rw-r--r--ext/dsent/libutil/Log.cc86
-rw-r--r--ext/dsent/libutil/Log.h43
-rw-r--r--ext/dsent/libutil/Makefile43
-rw-r--r--ext/dsent/libutil/Map.h242
-rw-r--r--ext/dsent/libutil/MathUtil.cc7
-rw-r--r--ext/dsent/libutil/MathUtil.h21
-rw-r--r--ext/dsent/libutil/OptionParser.cc177
-rw-r--r--ext/dsent/libutil/OptionParser.h57
-rw-r--r--ext/dsent/libutil/String.cc347
-rw-r--r--ext/dsent/libutil/String.h218
18 files changed, 1852 insertions, 0 deletions
diff --git a/ext/dsent/libutil/Assert.h b/ext/dsent/libutil/Assert.h
new file mode 100644
index 000000000..0fdd364b2
--- /dev/null
+++ b/ext/dsent/libutil/Assert.h
@@ -0,0 +1,22 @@
+#ifndef __ASSERT_H__
+#define __ASSERT_H__
+
+#include "String.h"
+#include "Exception.h"
+
+#ifdef NDEBUG
+#define ASSERT(test_value_,exception_msg_)
+#else
+#define ASSERT(test_value_,msg_) \
+ do \
+ { \
+ if(!(test_value_)) \
+ { \
+ const LibUtil::String& exception_msg = LibUtil::String::format("\nAt %s:%d\n", __FILE__, __LINE__) + (String)(msg_); \
+ throw LibUtil::Exception(exception_msg); \
+ } \
+ } while(0);
+#endif
+
+#endif // __ASSERT_H__
+
diff --git a/ext/dsent/libutil/Calculator.cc b/ext/dsent/libutil/Calculator.cc
new file mode 100644
index 000000000..e78e67287
--- /dev/null
+++ b/ext/dsent/libutil/Calculator.cc
@@ -0,0 +1,239 @@
+#include "Calculator.h"
+
+#include <cctype>
+#include <iostream>
+
+namespace LibUtil
+{
+ using std::cout;
+ using std::endl;
+ using std::scientific;
+
+ Calculator::Calculator()
+ {
+ m_reserved_chars_ = "+-*/;=()\\";
+ }
+
+ Calculator::~Calculator()
+ {}
+
+ void Calculator::reset()
+ {
+ m_var_.clear();
+ return;
+ }
+
+ void Calculator::evaluateString(const String& str_)
+ {
+ istringstream ist(str_);
+ while(ist)
+ {
+ getToken(ist);
+ if(m_curr_token_ == END) break;
+ if(m_curr_token_ == SEP) continue;
+ if((m_curr_token_ == NAME) && (m_value_string_ == "print"))
+ {
+ getToken(ist);
+
+ if(m_curr_token_ == STRING)
+ {
+ String print_str = m_value_string_;
+
+ getToken(ist);
+ if(m_curr_token_ == SEP)
+ {
+ cout << print_str << endl;
+ }
+ else
+ {
+ double v = expr(ist, false);
+ cout << scientific << print_str << v << endl;
+ }
+ }
+ else
+ {
+ double v = expr(ist, false);
+ cout << scientific << v << endl;
+ }
+ }
+ else
+ {
+ expr(ist, false);
+ }
+ }
+ return;
+ }
+
+ Calculator::Token Calculator::getToken(istringstream& ist_)
+ {
+ char ch;
+ do
+ {
+ ist_.get(ch);
+ if(!ist_)
+ {
+ m_curr_token_ = END;
+ return m_curr_token_;
+ }
+ }
+ while(ch != '\n' && isspace(ch));
+
+ switch(ch)
+ {
+ case '\n':
+ m_curr_token_ = END;
+ return m_curr_token_;
+ case ';':
+ m_curr_token_ = SEP;
+ return m_curr_token_;
+ case '*':
+ case '/':
+ case '+':
+ case '-':
+ case '(':
+ case ')':
+ case '=':
+ m_curr_token_ = Token(ch);
+ return m_curr_token_;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '.':
+ ist_.putback(ch);
+ ist_ >> m_value_number_;
+ m_curr_token_ = NUMBER;
+ return m_curr_token_;
+ case '"':
+ ist_.get(ch);
+ m_value_string_ = "";
+ while(ist_ && ('"' != ch))
+ {
+ m_value_string_ += String(1, ch);
+ ist_.get(ch);
+ }
+ m_curr_token_ = STRING;
+ return m_curr_token_;
+ case '$':
+ ist_.get(ch);
+ ASSERT((ch == '('), "[Error] Bad token: '(' expected");
+ ist_.get(ch);
+ m_value_string_ = "";
+ while(ist_ && (!isspace(ch)) && (')' != ch))
+ {
+ m_value_string_ += String(1, ch);
+ ist_.get(ch);
+ }
+ m_curr_token_ = NAME2;
+ return m_curr_token_;
+ default:
+ if(isalpha(ch))
+ {
+ m_value_string_ = ch;
+ ist_.get(ch);
+ while(ist_ && (isalnum(ch) || ('_' == ch)))
+ {
+ m_value_string_ += String(1, ch);
+ ist_.get(ch);
+ }
+ ist_.putback(ch);
+ m_curr_token_ = NAME;
+ return m_curr_token_;
+ }
+ else
+ {
+ String error_msg = "[Error] Bad token: '" + String(ch) + "'";
+ throw Exception(error_msg);
+ }
+ }
+ }
+
+ double Calculator::prim(istringstream& ist_, bool is_get_)
+ {
+ if(is_get_)
+ {
+ getToken(ist_);
+ }
+
+ double v;
+ switch(m_curr_token_)
+ {
+ case NUMBER:
+ v = m_value_number_;
+ getToken(ist_);
+ return v;
+ case NAME:
+ if(getToken(ist_) == ASSIGN)
+ {
+ String var_name = m_value_string_;
+ v = expr(ist_, true);
+ m_var_.set(var_name, v);
+ }
+ else
+ {
+ v = m_var_.get(m_value_string_);
+ }
+ return v;
+ case NAME2:
+ v = getEnvVar(m_value_string_);
+ getToken(ist_);
+ return v;
+ case MINUS:
+ return -prim(ist_, true);
+ case LP:
+ v = expr(ist_, true);
+ ASSERT((m_curr_token_ == RP), "[Error] ')' expected");
+ getToken(ist_);
+ return v;
+ default:
+ ASSERT(0, "[Error] primary expected, get: '" + String(int(m_curr_token_)) + "'");
+ }
+ }
+
+ double Calculator::term(istringstream& ist_, bool is_get_)
+ {
+ double left = prim(ist_, is_get_);
+
+ while(1)
+ {
+ double d;
+ switch(m_curr_token_)
+ {
+ case MUL:
+ left *= prim(ist_, true);
+ break;
+ case DIV:
+ d = prim(ist_, true);
+ ASSERT(d, "[Error] divided by 0");
+ left /= d;
+ break;
+ default:
+ return left;
+ }
+ }
+ }
+
+ double Calculator::expr(istringstream& ist_, bool is_get_)
+ {
+ double left = term(ist_, is_get_);
+
+ while(1)
+ {
+ switch(m_curr_token_)
+ {
+ case PLUS:
+ left += term(ist_, true);
+ break;
+ case MINUS:
+ left -= term(ist_, true);
+ break;
+ default:
+ return left;
+ }
+ }
+ }
+
+ double Calculator::getEnvVar(const String& var_name_) const
+ {
+ return m_var_.get(var_name_);
+ }
+} // namespace LibUtil
+
diff --git a/ext/dsent/libutil/Calculator.h b/ext/dsent/libutil/Calculator.h
new file mode 100644
index 000000000..4fcdf471f
--- /dev/null
+++ b/ext/dsent/libutil/Calculator.h
@@ -0,0 +1,86 @@
+#ifndef __LIBUTIL_CALCULATOR_H__
+#define __LIBUTIL_CALCULATOR_H__
+
+#include <sstream>
+
+#include "String.h"
+#include "Map.h"
+#include "Assert.h"
+
+namespace LibUtil
+{
+ using std::istringstream;
+
+ /*
+ * program:
+ * END // END is end-of-input
+ * expr_list END
+ *
+ * expr_list:
+ * expression SEP expr_list // SEP is semicolon
+ * expression
+ * print expression
+ * print STRING
+ * print STRING expression
+ * print STRING expression SEP expr_list
+ *
+ *
+ * expression:
+ * expression + term
+ * expression - term
+ * term
+ *
+ * term:
+ * term / primary
+ * term * primary
+ * primary
+ *
+ * primary:
+ * NUMBER
+ * NAME
+ * NAME = expression
+ * NAME string expression // NAME is print
+ * - primary
+ * ( expression )
+ *
+ * string:
+ *
+ **/
+
+ class Calculator
+ {
+ protected:
+ enum Token
+ {
+ NAME, NAME2, NUMBER, STRING, END,
+ PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',
+ SEP = ';', ASSIGN = '=', LP = '(', RP = ')'
+ };
+
+ public:
+ Calculator();
+ virtual ~Calculator();
+
+ public:
+ void reset();
+ void evaluateString(const String& str_);
+
+ protected:
+ Token getToken(istringstream& ist_);
+ double prim(istringstream& ist_, bool is_get_);
+ double term(istringstream& ist_, bool is_get_);
+ double expr(istringstream& ist_, bool is_get_);
+ virtual double getEnvVar(const String& var_name_) const;
+
+ protected:
+ String m_reserved_chars_;
+ Map<double> m_var_;
+
+ Token m_curr_token_;
+ double m_value_number_;
+ String m_value_string_;
+ }; // class Calculator
+} // namespace LibUtil
+
+#endif // __LIBUTIL_CALCULATOR_H__
+
diff --git a/ext/dsent/libutil/Config.cc b/ext/dsent/libutil/Config.cc
new file mode 100644
index 000000000..f858c6926
--- /dev/null
+++ b/ext/dsent/libutil/Config.cc
@@ -0,0 +1,144 @@
+#include "Config.h"
+
+#include <fstream>
+
+#include "Assert.h"
+
+namespace LibUtil
+{
+ Config::Config(const String& delimiter_, const String& comment_, const String& sentry_)
+ : mDelimiter(delimiter_), mComment(comment_), mSentry(sentry_)
+ {}
+
+ Config::Config(const Config& config_)
+ : StringMap(config_)
+ {
+ mDelimiter = config_.mDelimiter;
+ mComment = config_.mComment;
+ mSentry = config_.mSentry;
+ }
+
+ Config::~Config()
+ {}
+
+ Config* Config::clone() const
+ {
+ return new Config(*this);
+ }
+
+ void Config::readFile(const String& filename_)
+ {
+ std::ifstream fin(filename_.c_str());
+
+ ASSERT(fin, "File not found: " + filename_);
+ fin >> (*this);
+ return;
+ }
+
+ void Config::readString(const String& str_)
+ {
+ String newString = str_;
+ newString.substitute(";", "\n");
+ std::istringstream iss(newString, std::istringstream::in);
+
+ iss >> (*this);
+ }
+
+ std::ostream& operator<<(std::ostream& ost_, const Config& config_)
+ {
+ Config::ConstIterator it;
+ for(it = config_.begin(); it != config_.end(); it++)
+ {
+ ost_ << it->first << " " << config_.mDelimiter << " ";
+ ost_ << it->second << std::endl;
+ }
+ return ost_;
+ }
+
+ std::istream& operator>>(std::istream& ist_, Config& config_)
+ {
+ // Set a Config from ist_
+ // Read in keys and values, keeping internal whitespace
+ typedef String::size_type pos;
+ const String& delim = config_.mDelimiter; // separator
+ const String& comm = config_.mComment; // comment
+ const String& sentry = config_.mSentry; // end of file sentry
+ const pos skip = delim.length(); // length of separator
+
+ String nextline = ""; // might need to read ahead to see where value ends
+
+ while(ist_ || nextline.length() > 0)
+ {
+ // Read an entire line at a time
+ String line;
+ if(nextline.length() > 0)
+ {
+ line = nextline; // we read ahead; use it now
+ nextline = "";
+ }
+ else
+ {
+ //std::getline(ist_, line);
+ safeGetline(ist_, line);
+ }
+
+ // Ignore comments and the spaces on both ends
+ line = line.substr(0, line.find(comm));
+ line.trim();
+
+ // Check for end of file sentry
+ if((sentry != "") && (line.find(sentry) != String::npos)) return ist_;
+
+ if(line.length() == 0)
+ continue;
+
+ // Parse the line if it contains a delimiter
+ pos delimPos = line.find(delim);
+ ASSERT((delimPos < String::npos), "Invalid config line: '" + line + "'");
+
+ // Extract the key
+ String key = line.substr(0, delimPos);
+ line.replace(0, delimPos+skip, "");
+
+ // See if value continues on the next line
+ // Stop at blank line, next line with a key, end of stream,
+ // or end of file sentry
+ bool terminate = false;
+ while(!terminate && ist_)
+ {
+ if(line.at(line.size() - 1) == '\\')
+ line.erase(line.size() - 1);
+ else
+ break;
+
+ //std::getline(ist_, nextline);
+ safeGetline(ist_, nextline);
+ terminate = true;
+
+ String nlcopy = nextline;
+ nlcopy.trim();
+ if(nlcopy == "") continue;
+
+ nextline = nextline.substr(0, nextline.find(comm));
+ //if(nextline.find(delim) != String::npos)
+ // continue;
+ if((sentry != "") && (nextline.find(sentry) != String::npos))
+ continue;
+
+ //nlcopy = nextline;
+ //nlcopy.trim();
+ //if(nlcopy != "") line += "\n";
+ line += nextline;
+ nextline = "";
+ terminate = false;
+ }
+
+ // Store key and value
+ key.trim();
+ line.trim();
+ config_.set(key, line); // overwrites if key is repeated
+ }
+ return ist_;
+ }
+}
+
diff --git a/ext/dsent/libutil/Config.h b/ext/dsent/libutil/Config.h
new file mode 100644
index 000000000..a60c4b8fd
--- /dev/null
+++ b/ext/dsent/libutil/Config.h
@@ -0,0 +1,37 @@
+#ifndef __LIBUTIL_CONFIG_H__
+#define __LIBUTIL_CONFIG_H__
+
+#include <iostream>
+
+#include "Map.h"
+
+namespace LibUtil
+{
+ class Config : public StringMap
+ {
+ public:
+ Config(const String& delimiter_ = "=", const String& comment_ = "#", const String& sentry_ = "End");
+ Config(const Config& config_);
+ virtual ~Config();
+
+ public:
+ // Make a copy of this instance
+ virtual Config* clone() const;
+ // Load the config from file
+ virtual void readFile(const String& filename_);
+ // Parse string and overwrite the Config instance if keys exist
+ virtual void readString(const String& str_);
+
+ // Write or read map using standard IO
+ friend std::ostream& operator<<(std::ostream& ost_, const Config& config_);
+ friend std::istream& operator>>(std::istream& ist_, Config& config_);
+
+ protected:
+ String mDelimiter;
+ String mComment;
+ String mSentry;
+ };
+}
+
+#endif // __LIBUTIL_CONFIG_H__
+
diff --git a/ext/dsent/libutil/Exception.cc b/ext/dsent/libutil/Exception.cc
new file mode 100644
index 000000000..c6db0e3fb
--- /dev/null
+++ b/ext/dsent/libutil/Exception.cc
@@ -0,0 +1,17 @@
+#include "Exception.h"
+
+namespace LibUtil
+{
+ Exception::Exception(const String& exception_msg_) throw()
+ : exception(), mExceptionMsg(exception_msg_)
+ {}
+
+ Exception::~Exception() throw()
+ {}
+
+ const char* Exception::what() const throw()
+ {
+ return mExceptionMsg.c_str();
+ }
+}
+
diff --git a/ext/dsent/libutil/Exception.h b/ext/dsent/libutil/Exception.h
new file mode 100644
index 000000000..88d68cce2
--- /dev/null
+++ b/ext/dsent/libutil/Exception.h
@@ -0,0 +1,29 @@
+#ifndef __EXCEPTION_H__
+#define __EXCEPTION_H__
+
+#include <exception>
+
+#include "String.h"
+
+namespace LibUtil
+{
+ using std::exception;
+
+ // Exception class handles the all exception messages in the program
+ class Exception : public exception
+ {
+ public:
+ // All constructors/destructors/functions in this class don't throw any events
+ Exception(const String& exception_msg_) throw();
+ ~Exception() throw();
+
+ // Derived from std::exception class that returns a null-terminated char string
+ const char* what() const throw();
+
+ private:
+ String mExceptionMsg;
+ };
+}
+
+#endif // __EXCEPTION_H__
+
diff --git a/ext/dsent/libutil/LibUtil.h b/ext/dsent/libutil/LibUtil.h
new file mode 100644
index 000000000..12eb76fa0
--- /dev/null
+++ b/ext/dsent/libutil/LibUtil.h
@@ -0,0 +1,37 @@
+#ifndef __LIBUTIL_H__
+#define __LIBUTIL_H__
+
+#include <vector>
+
+#include "String.h"
+#include "Exception.h"
+#include "Assert.h"
+#include "Map.h"
+#include "Log.h"
+#include "Config.h"
+#include "MathUtil.h"
+
+namespace LibUtil
+{
+ template<class T> void clearPtrVector(std::vector<T*>* vec_)
+ {
+ for(typename std::vector<T*>::iterator it = vec_->begin(); it != vec_->end(); ++it)
+ {
+ T* temp_T = (*it);
+ delete temp_T;
+ }
+ vec_->clear();
+ return;
+ }
+
+ template<class T> void deletePtrVector(std::vector<T*>* vec_)
+ {
+ clearPtrVector<T>(vec_);
+ delete vec_;
+ return;
+ }
+
+} // namespace LibUtil
+
+#endif // __LIBUTIL_H__
+
diff --git a/ext/dsent/libutil/Log.cc b/ext/dsent/libutil/Log.cc
new file mode 100644
index 000000000..cb4266bf9
--- /dev/null
+++ b/ext/dsent/libutil/Log.cc
@@ -0,0 +1,86 @@
+#include "Log.h"
+
+#include "Assert.h"
+
+namespace LibUtil
+{
+ using std::ostream;
+ using std::endl;
+
+ Log* Log::msSingleton = NULL;
+ const bool Log::msIsLog = LIBUTIL_IS_LOG;
+
+ void Log::allocate(const String& log_file_name_)
+ {
+ if(msIsLog)
+ {
+ // Allocate static Config instance
+ ASSERT(!msSingleton, "Log singleton is allocated");
+ msSingleton = new Log(log_file_name_);
+ }
+ }
+
+ void Log::release()
+ {
+ if(msIsLog)
+ {
+ ASSERT(msSingleton, "Log singleton is not allocated");
+ delete msSingleton;
+ msSingleton = NULL;
+ }
+ return;
+ }
+
+ void Log::print(const String& str_)
+ {
+ if(msIsLog)
+ {
+ ASSERT(msSingleton, "Log singleton is not allocated");
+ msSingleton->ofs << str_;
+ }
+ return;
+ }
+
+ void Log::print(ostream& stream_, const String& str_)
+ {
+ if(msIsLog)
+ {
+ ASSERT(msSingleton, "Log singleton is not allocated");
+ msSingleton->ofs << str_;
+ }
+ stream_ << str_;
+ return;
+ }
+
+ void Log::printLine(const String& str_)
+ {
+ if(msIsLog)
+ {
+ ASSERT(msSingleton, "Log singleton is not allocated");
+ msSingleton->ofs << str_ << endl;
+ }
+ return;
+ }
+
+ void Log::printLine(ostream& stream_, const String& str_)
+ {
+ if(msIsLog)
+ {
+ ASSERT(msSingleton, "Log singleton is not allocated");
+ msSingleton->ofs << str_ << endl;
+ }
+ stream_ << str_ << endl;
+ return;
+ }
+
+ Log::Log(const String& log_file_name_)
+ {
+ ofs.open(log_file_name_.c_str());
+ }
+
+ Log::~Log()
+ {
+ ofs.close();
+ }
+}
+
diff --git a/ext/dsent/libutil/Log.h b/ext/dsent/libutil/Log.h
new file mode 100644
index 000000000..9c759e702
--- /dev/null
+++ b/ext/dsent/libutil/Log.h
@@ -0,0 +1,43 @@
+#ifndef __LOG_H__
+#define __LOG_H__
+
+#include <cstdio>
+#include <iostream>
+#include <fstream>
+
+#include "String.h"
+
+#ifndef LIBUTIL_IS_LOG
+#define LIBUTIL_IS_LOG false
+#endif
+
+namespace LibUtil
+{
+ using std::cerr;
+
+ class Log
+ {
+ public:
+ static void allocate(const String& log_file_name_);
+ static void release();
+
+ static void print(const String& str_);
+ static void print(std::ostream& stream_, const String& str_);
+ static void printLine(const String& str_);
+ static void printLine(std::ostream& stream_, const String& str_);
+
+ protected:
+ static Log* msSingleton;
+ static const bool msIsLog;
+
+ protected:
+ Log(const String& log_file_name_);
+ ~Log();
+
+ protected:
+ std::ofstream ofs;
+ };
+}
+
+#endif // __LOG_H__
+
diff --git a/ext/dsent/libutil/Makefile b/ext/dsent/libutil/Makefile
new file mode 100644
index 000000000..150028346
--- /dev/null
+++ b/ext/dsent/libutil/Makefile
@@ -0,0 +1,43 @@
+
+# Define the directories that will be compiled
+DIRS_TO_COMPILE := . \
+
+DIRS = $(patsubst %,$(CURDIR)/%,$(DIRS_TO_COMPILE))
+
+SRCS = $(foreach dir, $(DIRS), $(wildcard $(dir)/*.cc))
+
+OBJS = $(SRCS:%.cc=%.o)
+
+DEF_FLAGS =
+
+ifdef LIBUTIL_IS_LOG
+ LIBUTIL_IS_LOG = true
+else
+ LIBUTIL_IS_LOG = false
+endif
+DEF_FLAGS += -DLIBUTIL_IS_LOG=$(LIBUTIL_IS_LOG)
+
+INCLUDE_FLAGS = $(foreach dir, $(DIRS), -I$(dir))
+OPT_FLAGS = -O2 -g
+WARN_FLAGS = -pedantic -Wall -W -Wextra -Werror
+CXXFLAGS = $(OPT_FLAGS) $(WARN_FLAGS) $(INCLUDE_FLAGS) $(DEF_FLAGS)
+
+TARGET = $(CURDIR)/libutil.a
+
+all: $(TARGET)
+
+$(TARGET): $(OBJS)
+ ar rcs $@ $^
+#$(TARGET): $(OBJS)
+# $(CXX) $(CXXFLAGS) $^ -o $(TARGET)
+
+%.o: %.cc
+ $(CXX) $(CXXFLAGS) -c $< -o $@
+
+%/created:
+ mkdir -p $(dir $@)
+ touch $@
+
+clean:
+ $(RM) -rf $(OBJS) $(TARGET)
+
diff --git a/ext/dsent/libutil/Map.h b/ext/dsent/libutil/Map.h
new file mode 100644
index 000000000..0352c8634
--- /dev/null
+++ b/ext/dsent/libutil/Map.h
@@ -0,0 +1,242 @@
+#ifndef __MAP_H__
+#define __MAP_H__
+
+#include <iostream>
+#include <map>
+
+#include "String.h"
+#include "Assert.h"
+
+namespace LibUtil
+{
+ using std::map;
+
+ template<class T> class Map
+ {
+ public:
+ typedef typename map<String, T>::iterator Iterator;
+ typedef typename map<String, T>::const_iterator ConstIterator;
+ typedef typename map<String, T>::size_type SizeType;
+
+ public:
+ Map();
+ virtual ~Map();
+
+ public:
+ // Return a new copy of this Map instance
+ Map* clone() const;
+ // Copy map_ to this instance
+ void copyFrom(const Map<T>* map_);
+ // Return the size of the map
+ SizeType size() const;
+ // Check if the map is empty
+ bool isEmpty() const;
+ // Check if the key exists
+ bool keyExist(const String& key_) const;
+ // Get the value_ corresponding to the key_
+ const T& get(const String& key_) const;
+ // Get the value_ corresponding to the key_ if the key_ exist, otherwise, the default_value_is returned
+ const T& getIfKeyExist(const String& key_, const T& default_value_ = T()) const;
+ // Add/Update a <key_, value_> entry
+ void set(const String& key_, const T& value_);
+ // Get iterator to the element
+ Iterator find(const String& key_);
+ ConstIterator find(const String& key_) const;
+ // Remove an entry corresponding to key_
+ void remove(const String& key_);
+ // Remove an entry at 'it'
+ void remove(Iterator it);
+ // Remove all keys
+ void clear();
+ // Merge a map. Values with same key will be overwritten.
+ void merge(const Map<T>* map_);
+ // Returns a MapIterator referring to the first element in the map
+ Iterator begin();
+ ConstIterator begin() const;
+ // Returns a MapIterator referring to the past-the-end element in the map
+ Iterator end();
+ ConstIterator end() const;
+
+ protected:
+ Map(const Map& map_);
+
+ protected:
+ map<String, T> mMap;
+ };
+
+ template<class T> Map<T>::Map()
+ {}
+
+ template<class T> Map<T>::~Map()
+ {}
+
+ template<class T> Map<T>* Map<T>::clone() const
+ {
+ return new Map<T>(*this);
+ }
+
+ template<class T> void Map<T>::copyFrom(const Map<T>* map_)
+ {
+ // Remove all keys (it won't free the content if T is a pointer)
+ mMap.clear();
+
+ // Copy the contents
+ mMap = map_->mMap;
+ }
+
+ template<class T> typename Map<T>::SizeType Map<T>::size() const
+ {
+ return mMap.size();
+ }
+
+ template<class T> bool Map<T>::isEmpty() const
+ {
+ return (mMap.empty());
+ }
+
+ template<class T> bool Map<T>::keyExist(const String& key_) const
+ {
+ ConstIterator it = mMap.find(key_);
+ return (it != mMap.end());
+ }
+
+ template<class T> const T& Map<T>::get(const String& key_) const
+ {
+ ConstIterator it;
+
+ it = mMap.find(key_);
+ ASSERT((it != mMap.end()), "Key not found: " + key_);
+ return (it->second);
+ }
+
+ template<class T> const T& Map<T>::getIfKeyExist(const String& key_, const T& default_value_) const
+ {
+ if(keyExist(key_))
+ {
+ return get(key_);
+ }
+ else
+ {
+ return default_value_;
+ }
+ }
+
+ template<class T> void Map<T>::set(const String& key_, const T& value_)
+ {
+ mMap[key_] = value_;
+ return;
+ }
+
+ template<class T> typename Map<T>::Iterator Map<T>::find(const String& key_)
+ {
+ return mMap.find(key_);
+ }
+
+ template<class T> typename Map<T>::ConstIterator Map<T>::find(const String& key_) const
+ {
+ return mMap.find(key_);
+ }
+
+ template<class T> void Map<T>::remove(const String& key_)
+ {
+ mMap.erase(key_);
+ return;
+ }
+
+ template<class T> void Map<T>::remove(Iterator it)
+ {
+ mMap.erase(it);
+ return;
+ }
+
+ template<class T> void Map<T>::clear()
+ {
+ mMap.clear();
+ return;
+ }
+
+ template<class T> void Map<T>::merge(const Map<T>* map_)
+ {
+ ConstIterator it;
+ for(it = map_->begin(); it != map_->end(); it++)
+ {
+ const String& key = it->first;
+ const T& value = it->second;
+ set(key, value);
+ }
+ return;
+ }
+
+ template<class T> typename Map<T>::Iterator Map<T>::begin()
+ {
+ return mMap.begin();
+ }
+
+ template<class T> typename Map<T>::ConstIterator Map<T>::begin() const
+ {
+ return mMap.begin();
+ }
+
+ template<class T> typename Map<T>::Iterator Map<T>::end()
+ {
+ return mMap.end();
+ }
+
+ template<class T> typename Map<T>::ConstIterator Map<T>::end() const
+ {
+ return mMap.end();
+ }
+
+ inline std::ostream& operator<<(std::ostream& ost_, const Map<String>& map_)
+ {
+ Map<String>::ConstIterator it;
+ for(it = map_.begin(); it != map_.end(); it++)
+ {
+ ost_ << it->first << " = " << it->second << std::endl;
+ }
+ return ost_;
+ }
+
+ template<class T> Map<T>::Map(const Map<T>& map_)
+ : mMap(map_.mMap)
+ {}
+
+ typedef Map<String> StringMap;
+
+
+ // Handy function to delete all pointers in a map
+ template<class T> void clearPtrMap(Map<T*>* map_)
+ {
+ for(typename Map<T*>::Iterator it = map_->begin(); it != map_->end(); ++it)
+ {
+ T* temp_T = it->second;
+ delete temp_T;
+ }
+ map_->clear();
+ return;
+ }
+
+ // Handy function to delete all pointers in a map and the map itself
+ template<class T> void deletePtrMap(Map<T*>* map_)
+ {
+ clearPtrMap<T>(map_);
+ delete map_;
+ return;
+ }
+
+ // Handy function to clone all pointers in a map
+ template<class T> Map<T*>* clonePtrMap(const Map<T*>* map_)
+ {
+ Map<T*>* new_T_map = new Map<T*>;
+ for(typename Map<T*>::ConstIterator it = map_->begin(); it != map_->end(); ++it)
+ {
+ const String& temp_name = it->first;
+ const T* temp_T = it->second;
+ new_T_map->set(temp_name, temp_T->clone());
+ }
+ return new_T_map;
+ }
+}
+
+#endif // __MAP_H__
+
diff --git a/ext/dsent/libutil/MathUtil.cc b/ext/dsent/libutil/MathUtil.cc
new file mode 100644
index 000000000..0e177b5fc
--- /dev/null
+++ b/ext/dsent/libutil/MathUtil.cc
@@ -0,0 +1,7 @@
+#include "MathUtil.h"
+
+namespace LibUtil
+{
+ const double Math::epsilon = 1e-15;
+} // namespace LibUtil
+
diff --git a/ext/dsent/libutil/MathUtil.h b/ext/dsent/libutil/MathUtil.h
new file mode 100644
index 000000000..1f3341ee1
--- /dev/null
+++ b/ext/dsent/libutil/MathUtil.h
@@ -0,0 +1,21 @@
+#ifndef __MATH_H__
+#define __MATH_H__
+
+#include <cmath>
+
+namespace LibUtil
+{
+ class Math
+ {
+ public:
+ static const double epsilon;
+
+ static inline bool isEqual(double value1_, double value2_)
+ {
+ return (std::fabs(value1_ - value2_) < epsilon);
+ }
+ };
+} // namespace LibUtil
+
+#endif // __MATH_H__
+
diff --git a/ext/dsent/libutil/OptionParser.cc b/ext/dsent/libutil/OptionParser.cc
new file mode 100644
index 000000000..6d2695f2d
--- /dev/null
+++ b/ext/dsent/libutil/OptionParser.cc
@@ -0,0 +1,177 @@
+#include "OptionParser.h"
+
+#include <cstdlib>
+#include <iostream>
+
+namespace LibUtil
+{
+ using std::cout;
+ using std::cerr;
+ using std::endl;
+
+ OptionParser::OptionInfo::OptionInfo(
+ const String& var_name_,
+ bool has_arg_,
+ const String& arg_name_,
+ bool has_default_arg_value_,
+ const String& default_arg_value_,
+ const String& description_
+ )
+ : m_var_name_(var_name_),
+ m_has_arg_(has_arg_),
+ m_arg_name_(arg_name_),
+ m_has_default_arg_value_(has_default_arg_value_),
+ m_default_arg_value_(default_arg_value_),
+ m_description_(description_)
+ {}
+
+ OptionParser::OptionInfo::~OptionInfo()
+ {
+ }
+
+ OptionParser::OptionParser()
+ {}
+
+ OptionParser::~OptionParser()
+ {
+ clearPtrMap(&m_option_infos_);
+ }
+
+ void OptionParser::addOption(
+ const String& option_name_,
+ const String& var_name_,
+ bool has_arg_,
+ const String& arg_name_,
+ bool has_default_arg_value_,
+ const String& default_arg_value_,
+ const String& description_)
+ {
+ OptionInfo* option_info = new OptionInfo(var_name_, has_arg_, arg_name_,
+ has_default_arg_value_, default_arg_value_, description_);
+
+ ASSERT(!m_option_infos_.keyExist(option_name_), "Option exists: " + option_name_);
+
+ // Add the option name to an array for sorting
+ m_option_names_.push_back(option_name_);
+
+ // Add option info
+ m_option_infos_.set(option_name_, option_info);
+
+ // Set the default argument value
+ if(has_default_arg_value_)
+ {
+ set(var_name_, default_arg_value_);
+ }
+
+ return;
+ }
+
+ void OptionParser::parseArguments(int argc_, char** argv_)
+ {
+ bool is_print_options = false;
+ int arg_idx = 0;
+
+ while(arg_idx < argc_)
+ {
+ String option_name = String(argv_[arg_idx]);
+
+ // Print the options page if -help is specified
+ if(option_name == "-help")
+ {
+ is_print_options = true;
+ break;
+ }
+ else if(m_option_infos_.keyExist(option_name))
+ {
+ const OptionInfo* option_info = m_option_infos_.get(option_name);
+ const String& var_name = option_info->getVarName();
+ if(option_info->hasArg())
+ {
+ if((arg_idx + 1) >= argc_)
+ {
+ cerr << "[Error] Missing argument for option: '" << option_name << "'" << endl;
+ is_print_options = true;
+ break;
+ }
+
+ String option_arg = String(argv_[arg_idx + 1]);
+ set(var_name, option_arg);
+
+ arg_idx += 2;
+ }
+ else
+ {
+ // If the option does not require an argument
+ // then set it to true
+ set(var_name, "true");
+
+ arg_idx += 1;
+ }
+ }
+ else
+ {
+ cerr << "[Error] Unknown option: '" << option_name << "'" << endl;
+ is_print_options = true;
+ break;
+ }
+ }
+
+ // Check if all required options are set (the ones without default values)
+ vector<String>::const_iterator it;
+ for(it = m_option_names_.begin(); it != m_option_names_.end(); ++it)
+ {
+ const String& option_name = *it;
+ const OptionInfo* option_info = m_option_infos_.get(option_name);
+
+ if(!option_info->hasDefaultArgValue())
+ {
+ const String& var_name = option_info->getVarName();
+ if(!keyExist(var_name))
+ {
+ cerr << "[Error] Missing required option: '" << option_name << "'" << endl;
+ is_print_options = true;
+ }
+ }
+ }
+
+ if(is_print_options)
+ {
+ printOptions();
+ exit(0);
+ }
+ return;
+ }
+
+ void OptionParser::printOptions() const
+ {
+ cout << endl;
+ cout << "Available options:" << endl;
+ cout << "==================" << endl << endl;
+
+ vector<String>::const_iterator it;
+ for(it = m_option_names_.begin(); it != m_option_names_.end(); ++it)
+ {
+ const String& option_name = *it;
+ const OptionInfo* option_info = m_option_infos_.get(option_name);
+
+ cout << option_name;
+ if(option_info->hasArg())
+ {
+ cout << " <" << option_info->getArgName() << ">";
+ }
+ cout << endl;
+
+ cout << " " << option_info->getDescription() << endl;
+ if(option_info->hasArg() && option_info->hasDefaultArgValue())
+ {
+ cout << " " << "Default: " << option_info->getDefaultArgValue() << endl;
+ }
+ cout << endl;
+ }
+ cout << "-help" << endl;
+ cout << " " << "Print this page" << endl;
+ cout << endl;
+ return;
+ }
+
+} // namespace LibUtil
diff --git a/ext/dsent/libutil/OptionParser.h b/ext/dsent/libutil/OptionParser.h
new file mode 100644
index 000000000..b98012a80
--- /dev/null
+++ b/ext/dsent/libutil/OptionParser.h
@@ -0,0 +1,57 @@
+#ifndef __LIBUTIL_OPTION_PARSER_H__
+#define __LIBUTIL_OPTION_PARSER_H__
+
+#include <vector>
+
+#include "Map.h"
+
+namespace LibUtil
+{
+ using std::vector;
+
+ // Simple option parser
+ class OptionParser : public StringMap
+ {
+ private:
+ class OptionInfo
+ {
+ public:
+ OptionInfo(const String& var_name_, bool has_arg_, const String& arg_name_, bool has_default_arg_value_, const String& default_arg_value_, const String& description_);
+ ~OptionInfo();
+
+ public:
+ inline const String& getVarName() const { return m_var_name_; }
+ inline bool hasArg() const { return m_has_arg_; }
+ inline const String& getArgName() const { return m_arg_name_; }
+ inline bool hasDefaultArgValue() const { return m_has_default_arg_value_; }
+ inline const String& getDefaultArgValue() const { return m_default_arg_value_; }
+ inline const String& getDescription() const { return m_description_; }
+
+ private:
+ String m_var_name_;
+ bool m_has_arg_;
+ String m_arg_name_;
+ bool m_has_default_arg_value_;
+ String m_default_arg_value_;
+ String m_description_;
+ }; // class Option
+
+ public:
+ OptionParser();
+ virtual ~OptionParser();
+
+ public:
+ void addOption(const String& option_name_, const String& var_name_, bool has_arg_, const String& arg_name_, bool has_default_arg_value_, const String& default_arg_value_, const String& description_);
+
+ void parseArguments(int argc_, char** argv_);
+
+ void printOptions() const;
+
+ protected:
+ vector<String> m_option_names_;
+ Map<OptionInfo*> m_option_infos_;
+ }; // class OptionParser
+} // LibUtil
+
+#endif // __LIBUTIL_OPTION_PARSER_H__
+
diff --git a/ext/dsent/libutil/String.cc b/ext/dsent/libutil/String.cc
new file mode 100644
index 000000000..146e9f824
--- /dev/null
+++ b/ext/dsent/libutil/String.cc
@@ -0,0 +1,347 @@
+#include "String.h"
+
+#include <cstdarg>
+#include <cstdio>
+#include <iostream>
+#include <ios>
+
+namespace LibUtil
+{
+ const unsigned int String::msBufferSize = 4096;
+
+ String String::format(const String& format_, ...)
+ {
+ char buffer[msBufferSize];
+
+ va_list args;
+ va_start(args, format_);
+ vsnprintf(buffer, msBufferSize, format_.c_str(), args);
+ va_end(args);
+
+ return (String)(buffer);
+ }
+
+ String String::format(const String& format_, va_list args_)
+ {
+ char buffer[msBufferSize];
+
+ vsnprintf(buffer, msBufferSize, format_.c_str(), args_);
+
+ return (String)(buffer);
+ }
+
+ String::String()
+ {}
+
+ String::String(const string& str_)
+ : string(str_)
+ {}
+
+ String::String(const char* str_, size_t n_)
+ : string(str_, n_)
+ {}
+
+ String::String(const char* str_)
+ : string(str_)
+ {}
+
+ String::String(size_t n_, char c_)
+ : string(n_, c_)
+ {}
+
+ String::String(int value_)
+ : string(toString<int>(value_))
+ {}
+
+ String::String(unsigned int value_)
+ : string(toString<unsigned int>(value_))
+ {}
+
+ String::String(long value_)
+ : string(toString<long>(value_))
+ {}
+
+ String::String(unsigned long value_)
+ : string(toString<unsigned long>(value_))
+ {}
+
+ String::String(float value_)
+ : string(toString<float>(value_))
+ {}
+
+ String::String(double value_)
+ : string(toString<double>(value_))
+ {}
+
+ String::String(bool value_)
+ : string(toString<bool>(value_))
+ {}
+
+ String::~String()
+ {}
+
+ String& String::trim()
+ {
+ // Remove leading and trailing whitespace
+ static const char whitespace[] = " \n\t\v\r\f";
+ erase(0, find_first_not_of(whitespace));
+ erase(find_last_not_of(whitespace) + 1U);
+ return (*this);
+ }
+
+ String& String::substitute(const String& str1_, const String& str2_)
+ {
+ size_t str1Size = str1_.size();
+ size_t str2Size = str2_.size();
+
+ size_t pos;
+ pos = find(str1_);
+ while(pos != string::npos)
+ {
+ replace(pos, str1Size, str2_);
+ pos += str2Size;
+ pos = find(str1_, pos);
+ }
+ return (*this);
+ }
+
+ vector<String> String::split(const char* delimiters_) const
+ {
+ vector<String> result;
+
+ if(size() == 0)
+ {
+ return result;
+ }
+
+ size_t currPos, nextPos;
+ currPos = 0;
+ nextPos = find_first_of(delimiters_);
+ while(1)
+ {
+ if(nextPos == string::npos)
+ {
+ if(currPos != size())
+ {
+ result.push_back(substr(currPos));
+ }
+ break;
+ }
+
+ if(nextPos != currPos)
+ {
+ result.push_back(substr(currPos, nextPos - currPos));
+ }
+ currPos = nextPos + 1;
+ nextPos = find_first_of(delimiters_, currPos);
+ }
+
+ return result;
+ }
+
+ vector<String> String::split(const String* delimiters_, unsigned int num_delimiters_) const
+ {
+ vector<String> result;
+
+ if(size() == 0)
+ {
+ return result;
+ }
+
+ if(num_delimiters_ == 1)
+ {
+ size_t currPos, nextPos;
+ currPos = 0;
+ nextPos = find(delimiters_[0]);
+ while(1)
+ {
+ if(nextPos == String::npos)
+ {
+ result.push_back(substr(currPos));
+ break;
+ }
+
+ if(nextPos != currPos)
+ {
+ result.push_back(substr(currPos, nextPos - currPos));
+ }
+ currPos = nextPos + delimiters_[0].size();
+ nextPos = find(delimiters_[0], currPos);
+ }
+ }
+ else
+ {
+ // Currently the length of the delimiters are not checked
+ unsigned int delimiterLength = 0;
+ size_t currPos, nextPos;
+ currPos = 0;
+ nextPos = size();
+ for(unsigned int i = 0; i < num_delimiters_; ++i)
+ {
+ size_t tempPos = find(delimiters_[i], currPos);
+ if((tempPos != String::npos) && (tempPos < nextPos))
+ {
+ nextPos = tempPos;
+ delimiterLength = delimiters_[i].size();
+ }
+ }
+ while(1)
+ {
+ if((nextPos == String::npos) || (nextPos == size()))
+ {
+ result.push_back(substr(currPos));
+ break;
+ }
+
+ if(nextPos != currPos)
+ {
+ result.push_back(substr(currPos, nextPos - currPos));
+ }
+ currPos = nextPos + delimiterLength;
+ nextPos = size();
+ delimiterLength = 0;
+ for(unsigned int i = 0; i < num_delimiters_; ++i)
+ {
+ size_t tempPos = find(delimiters_[i], currPos);
+ if((tempPos != String::npos) && (tempPos < nextPos))
+ {
+ nextPos = tempPos;
+ delimiterLength = delimiters_[i].size();
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ vector<String> String::splitByString(const String& delimiter_) const
+ {
+ return split(&delimiter_, 1);
+ }
+
+ bool String::contain(const String& str_) const
+ {
+ return (find(str_) != String::npos);
+ }
+
+ const char* String::toCString() const
+ {
+ return this->c_str();
+ }
+
+ int String::toInt() const
+ {
+ return fromString<int>(*this);
+ }
+
+ unsigned int String::toUInt() const
+ {
+ return fromString<unsigned int>(*this);
+ }
+
+ long String::toLong() const
+ {
+ return fromString<long>(*this);
+ }
+
+ unsigned long String::toULong() const
+ {
+ return fromString<unsigned long>(*this);
+ }
+
+ float String::toFloat() const
+ {
+ return fromString<float>(*this);
+ }
+
+ double String::toDouble() const
+ {
+ return fromString<double>(*this);
+ }
+
+ bool String::toBool() const
+ {
+ return fromString<bool>(*this);
+ }
+
+ String::operator const char*() const
+ {
+ return this->c_str();
+ }
+
+ String::operator int() const
+ {
+ return fromString<int>(*this);
+ }
+
+ String::operator unsigned int() const
+ {
+ return fromString<unsigned int>(*this);
+ }
+
+ String::operator long() const
+ {
+ return fromString<long>(*this);
+ }
+
+ String::operator unsigned long() const
+ {
+ return fromString<unsigned long>(*this);
+ }
+
+ String::operator float() const
+ {
+ return fromString<float>(*this);
+ }
+
+ String::operator double() const
+ {
+ return fromString<double>(*this);
+ }
+
+ String::operator bool() const
+ {
+ return fromString<bool>(*this);
+ }
+
+ String& String::operator=(char c_)
+ {
+ this->assign(1, c_);
+ return *this;
+ }
+
+ std::istream& safeGetline(std::istream& is_, String& str_)
+ {
+ str_.clear();
+
+ // The characters in the stream are read one-by-one using a std::streambuf.
+ // That is faster than reading them one-by-one using the std::istream.
+ // Code that uses streambuf this way must be guarded by a sentry object.
+ // The sentry object performs various tasks,
+ // such as thread synchronization and updating the stream state.
+
+ std::istream::sentry se(is_, true);
+ std::streambuf* sb = is_.rdbuf();
+
+ while(1)
+ {
+ int c = sb->sbumpc();
+ switch(c)
+ {
+ case '\r':
+ c = sb->sgetc();
+ if(c == '\n')
+ sb->sbumpc();
+ return is_;
+ case '\n':
+ return is_;
+ case EOF:
+ is_.setstate(std::ios_base::failbit|std::ios_base::eofbit);
+ return is_;
+ default:
+ str_ += String(1, (char)c);
+ }
+ }
+ }
+} // namespace LibUtil
+
diff --git a/ext/dsent/libutil/String.h b/ext/dsent/libutil/String.h
new file mode 100644
index 000000000..95fe17565
--- /dev/null
+++ b/ext/dsent/libutil/String.h
@@ -0,0 +1,218 @@
+#ifndef __STRING_H__
+#define __STRING_H__
+
+#include <string>
+#include <cstdarg>
+#include <vector>
+#include <sstream>
+#include <bitset>
+
+namespace LibUtil
+{
+ using std::string;
+ using std::vector;
+
+ class String : public string
+ {
+ public:
+ static String format(const String& format_, ...);
+ static String format(const String& format_, va_list args_);
+ template<class T> static String toString(const T& value_);
+ static String toBitString(unsigned int value_, unsigned int num_bits_);
+ template<class T> static T fromString(const String& str_);
+
+ private:
+ static const unsigned int msBufferSize;
+
+ public:
+ String();
+ String(const string& str_);
+ String(const char* str_, size_t n);
+ String(const char* str_);
+ String(size_t n, char c);
+ String(int value_);
+ String(unsigned int value_);
+ String(long value_);
+ String(unsigned long value_);
+ String(float value_);
+ String(double value_);
+ String(bool value_);
+ ~String();
+
+ public:
+ // Remove leading and trailing whitespace
+ String& trim();
+ // Substitute str1 with str2
+ String& substitute(const String& str1_, const String& str2_);
+ // Split the String into vector of Strings separated by delimiters_
+ vector<String> split(const char* delimiters_) const;
+ vector<String> split(const String* delimiters_, unsigned int num_delimiters_ = 1) const;
+ vector<String> splitByString(const String& delimiters_) const;
+
+ // Check if contains str
+ bool contain(const String& str_) const;
+
+ public:
+ // Convertions
+ const char* toCString() const;
+ int toInt() const;
+ unsigned int toUInt() const;
+ long toLong() const;
+ unsigned long toULong() const;
+ float toFloat() const;
+ double toDouble() const;
+ bool toBool() const;
+ operator const char*() const;
+ operator int() const;
+ operator unsigned int() const;
+ operator long() const;
+ operator unsigned long() const;
+ operator float() const;
+ operator double() const;
+ operator bool() const;
+ String& operator=(char c_);
+ };
+
+ template<class T> String String::toString(const T& value_)
+ {
+ std::ostringstream ost;
+ ost << value_;
+ return ost.str();
+ }
+
+ template<> inline String String::toString<bool>(const bool& value_)
+ {
+ if(value_ == true)
+ {
+ return "TRUE";
+ }
+ else
+ {
+ return "FALSE";
+ }
+ }
+
+ inline String String::toBitString(unsigned int value_, unsigned int num_bits_)
+ {
+ std::bitset<sizeof(unsigned int)*8> bitSet(value_);
+ String ret = String(bitSet.to_string());
+ ret = ret.substr(ret.length()-num_bits_);
+ return ret;
+ }
+
+ template<class T> T String::fromString(const String& str_)
+ {
+ T ret;
+ std::istringstream ist(str_);
+ ist >> ret;
+ return ret;
+ }
+
+ template<> inline String String::fromString<String>(const String& str_)
+ {
+ return str_;
+ }
+
+ template<> inline bool String::fromString<bool>(const String& str_)
+ {
+ bool ret;
+ if((str_ == String("TRUE")) || (str_ == String("true")))
+ {
+ ret = true;
+ }
+ else if((str_ == string("FALSE")) || (str_ == String("false")))
+ {
+ ret = false;
+ }
+ else
+ {
+ //std::cerr << "Invalid bool value: " << str_ << std::endl;
+ throw ("Invalid bool value: " + str_);
+ }
+ return ret;
+ }
+
+ template<class T> String arrayToString(
+ const T* array_, unsigned int start_index_, unsigned int end_index_,
+ const String& delimiters_
+ )
+ {
+ // Ensure end_index_ >= start_index_ + 1
+ if(end_index_ <= start_index_)
+ {
+ throw("Invalid index range: start_index = " + (String)start_index_ + ", end_index = " + (String)end_index_);
+ }
+
+ String ret = "[";
+ for(unsigned int i = start_index_; i < (end_index_-1); ++i)
+ {
+ ret += (String)array_[i] + delimiters_;
+ }
+ ret += (String)array_[end_index_-1] + "]";
+ return ret;
+ }
+
+ template<class T> String arrayToString(const T* array_, unsigned int num_elements_)
+ {
+ return arrayToString(array_, 0, num_elements_, ", ");
+ }
+
+ template<class T> String arrayToString(const T* array_, unsigned int start_index_, unsigned int end_index_)
+ {
+ return arrayToString(array_, start_index_, end_index_);
+ }
+
+ template<class T> String vectorToString(
+ const vector<T>& vector_, unsigned int start_index_, unsigned int end_index_,
+ const String& delimiters_
+ )
+ {
+ // Ensure end_index_ >= start_index_ + 1, or if the vector is empty
+ if((end_index_ <= start_index_) || (end_index_ > vector_.size()))
+ {
+ // If the vector is empty, return empty array
+ if (vector_.size() == 0)
+ return "[]";
+
+ throw("Invalid index range: start_index = " + (String)start_index_ + ", end_index = " + (String)end_index_);
+ }
+
+ String ret = "[";
+ for(unsigned int i = start_index_; i < (end_index_-1); ++i)
+ {
+ ret += (String)vector_[i] + delimiters_;
+ }
+ ret += (String)vector_[end_index_-1] + "]";
+ return ret;
+ }
+
+ template<class T> String vectorToString(const vector<T>& vector_)
+ {
+ return vectorToString(vector_, 0, vector_.size(), ", ");
+ }
+
+ template<class T> String vectorToString(const vector<T>& vector_, unsigned int num_elements_)
+ {
+ return vectorToString(vector_, 0, num_elements_, ", ");
+ }
+
+ template<class T> String vectorToString(const vector<T>& vector_, unsigned int start_index_, unsigned int end_index_)
+ {
+ return vectorToString(vector_, start_index_, end_index_);
+ }
+
+ template<class T> vector<T> castStringVector(const vector<String>& vector_)
+ {
+ vector<T> ret_vector;
+ for(unsigned int i = 0; i < vector_.size(); ++i)
+ {
+ ret_vector.push_back((T)vector_[i]);
+ }
+ return ret_vector;
+ }
+
+ std::istream& safeGetline(std::istream& is_, String& str_);
+} // namespace LibUtil
+
+#endif // __STRING_H__
+