You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							475 lines
						
					
					
						
							20 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							475 lines
						
					
					
						
							20 KiB
						
					
					
				| /* | |
|     Copyright 2005-2013 Intel Corporation.  All Rights Reserved. | |
|  | |
|     This file is part of Threading Building Blocks. | |
|  | |
|     Threading Building Blocks is free software; you can redistribute it | |
|     and/or modify it under the terms of the GNU General Public License | |
|     version 2 as published by the Free Software Foundation. | |
|  | |
|     Threading Building Blocks is distributed in the hope that it will be | |
|     useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
|     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
|     GNU General Public License for more details. | |
|  | |
|     You should have received a copy of the GNU General Public License | |
|     along with Threading Building Blocks; if not, write to the Free Software | |
|     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | |
|  | |
|     As a special exception, you may use this file as part of a free software | |
|     library without restriction.  Specifically, if other files instantiate | |
|     templates or use macros or inline functions from this file, or you compile | |
|     this file and link it with other files to produce an executable, this | |
|     file does not by itself cause the resulting executable to be covered by | |
|     the GNU General Public License.  This exception does not however | |
|     invalidate any other reasons why the executable file might be covered by | |
|     the GNU General Public License. | |
| */ | |
| 
 | |
| #ifndef UTILITY_H_ | |
| #define UTILITY_H_ | |
| #include <string> | |
| #include <cstring> | |
| #include <vector> | |
| #include <map> | |
| #include <set> | |
| #include <algorithm> | |
| #include <sstream> | |
| #include <numeric> | |
| #include <stdexcept> | |
| //TODO: for C++11 mode replace usage of auto_ptr with unique_ptr | |
| #include <memory> | |
| #include <cassert> | |
|  | |
| namespace utility{ | |
|     namespace internal{ | |
|         //TODO: add tcs | |
|         template<class dest_type> | |
|         dest_type& string_to(std::string const& s, dest_type& result){ | |
|             std::stringstream stream(s); | |
|             stream>>result; | |
|             if ((!stream)||(stream.fail())){ | |
|                 throw std::invalid_argument("error converting string \""+std::string(s)+"\""); | |
|             } | |
|             return result; | |
|         } | |
| 
 | |
|         template<class dest_type> | |
|         dest_type string_to(std::string const& s){ | |
|             dest_type result; | |
|             return string_to(s,result); | |
|         } | |
| 
 | |
| 
 | |
|         template<typename> | |
|         struct is_bool          { bool static value(){return false;}}; | |
|         template<> | |
|         struct is_bool<bool>    { bool static value(){return true;}}; | |
| 
 | |
|         class type_base { | |
|             type_base& operator=(const type_base&); | |
|             public: | |
|             const std::string name; | |
|             const std::string description; | |
| 
 | |
|             type_base (std::string name, std::string description) : name(name), description(description) {} | |
|             virtual void parse_and_store (const std::string & s)=0; | |
|             virtual std::string value() const =0; | |
|             virtual std::auto_ptr<type_base> clone()const =0; | |
|             virtual ~type_base(){} | |
|         }; | |
|         template <typename type> | |
|         class type_impl : public type_base { | |
|         private: | |
|             type_impl& operator=(const type_impl&); | |
|             typedef bool(*validating_function_type)(const type&); | |
|         private: | |
|             type & target; | |
|             validating_function_type validating_function; | |
|         public: | |
|             type_impl(std::string name, std::string description, type & target, validating_function_type validating_function = NULL) | |
|                 : type_base (name,description), target(target),validating_function(validating_function) | |
|             {}; | |
|             void parse_and_store (const std::string & s){ | |
|                 try{ | |
|                     const bool is_bool = internal::is_bool<type>::value(); | |
|                     if (is_bool &&(s.empty())){ | |
|                         //to avoid directly assigning true | |
|                         //(as it will impose additional layer of indirection) | |
|                         //so, simply pass it as string | |
|                         internal::string_to("1",target); | |
|                     }else { | |
|                         internal::string_to(s,target); | |
|                     } | |
|                 }catch(std::invalid_argument& ){ | |
|                     std::stringstream str; | |
|                     str | |
|                         <<"\""<<s<<"\""<<" is incorrect input for argument " | |
|                         <<"\""<<name<<"\"" | |
|                     ; | |
|                     throw std::invalid_argument(str.str()); | |
|                 } | |
|                 if (validating_function){ | |
|                     if (!((validating_function)(target))){ | |
|                         std::stringstream str; | |
|                         str | |
|                             <<"\""<<target<<"\" is invalid value for argument " | |
|                             <<"\""<<name<<"\"" | |
|                         ; | |
|                         throw std::invalid_argument(str.str()); | |
|                     } | |
|                 } | |
|             } | |
|             virtual std::string value()const{ | |
|                 std::stringstream str; | |
|                 str<<target; | |
|                 return str.str(); | |
|             } | |
|             virtual std::auto_ptr<type_base> clone()const { | |
|                 return std::auto_ptr<type_base>(new type_impl(*this)); | |
|             } | |
|         }; | |
| 
 | |
|         class argument{ | |
|         private: | |
|             std::auto_ptr<type_base> p_type; | |
|             bool matched_; | |
|         public: | |
|             argument(argument const& other): p_type(other.p_type.get() ? other.p_type->clone():std::auto_ptr<type_base>()),matched_(other.matched_){} | |
|             argument& operator=(argument a){ | |
|                 this->swap(a); | |
|                 return *this; | |
|             } | |
|             void swap(argument& other){ | |
|                 std::auto_ptr<type_base> tmp; tmp=p_type; p_type=other.p_type; other.p_type=tmp; | |
|                 std::swap(matched_,other.matched_); | |
|             } | |
|             template<class type> | |
|             argument(std::string name, std::string description, type& dest, bool(*validating_function)(const type&)= NULL) | |
|                 :p_type(new type_impl<type>(name,description,dest,validating_function)) | |
|                  ,matched_(false) | |
|             {} | |
|             std::string value()const{ | |
|                 return p_type->value(); | |
|             } | |
|             std::string name()const{ | |
|                 return p_type->name; | |
|             } | |
|             std::string description() const{ | |
|                 return p_type->description; | |
|             } | |
|             void parse_and_store(const std::string & s){ | |
|                 p_type->parse_and_store(s); | |
|                 matched_=true; | |
|             } | |
|             bool is_matched() const{return matched_;} | |
|         }; | |
|     } | |
|     class cli_argument_pack{ | |
|         typedef std::map<std::string,internal::argument> args_map_type; | |
|         typedef std::vector<std::string> args_display_order_type; | |
|         typedef std::vector<std::string> positional_arg_names_type; | |
|     private: | |
|         args_map_type args_map; | |
|         args_display_order_type args_display_order; | |
|         positional_arg_names_type positional_arg_names; | |
|         std::set<std::string> bool_args_names; | |
|     private: | |
|         void add_arg(internal::argument const& a){ | |
|             std::pair<args_map_type::iterator, bool> result = args_map.insert(std::make_pair(a.name(),a)); | |
|             if (!result.second){ | |
|                 throw std::invalid_argument("argument with name: \""+a.name()+"\" already registered"); | |
|             } | |
|             args_display_order.push_back(a.name()); | |
|         } | |
|     public: | |
|         template<typename type> | |
|         cli_argument_pack& arg(type& dest,std::string const& name, std::string const& description, bool(*validate)(const type &)= NULL){ | |
|             internal::argument a(name,description,dest,validate); | |
|             add_arg(a); | |
|             if (internal::is_bool<type>::value()){ | |
|                 bool_args_names.insert(name); | |
|             } | |
|             return *this; | |
|         } | |
| 
 | |
|         //Positional means that argument name can be omitted in actual CL | |
|         //only key to match values for parameters with | |
|         template<typename type> | |
|         cli_argument_pack& positional_arg(type& dest,std::string const& name, std::string const& description, bool(*validate)(const type &)= NULL){ | |
|             internal::argument a(name,description,dest,validate); | |
|             add_arg(a); | |
|             if (internal::is_bool<type>::value()){ | |
|                 bool_args_names.insert(name); | |
|             } | |
|             positional_arg_names.push_back(name); | |
|             return *this; | |
|         } | |
| 
 | |
|         void parse(int argc, char const* argv[]){ | |
|             { | |
|                 std::size_t current_positional_index=0; | |
|                 for (int j=1;j<argc;j++){ | |
|                     internal::argument* pa = NULL; | |
|                     std::string argument_value; | |
| 
 | |
|                     const char * const begin=argv[j]; | |
|                     const char * const end=begin+std::strlen(argv[j]); | |
| 
 | |
|                     const char * const assign_sign = std::find(begin,end,'='); | |
| 
 | |
|                     struct throw_unknow_parameter{ static void _(std::string const& location){ | |
|                         throw std::invalid_argument(std::string("unknown parameter starting at:\"")+location+"\""); | |
|                     }}; | |
|                     //first try to interpret it like parameter=value string | |
|                     if (assign_sign!=end){ | |
|                         std::string name_found = std::string(begin,assign_sign); | |
|                         args_map_type::iterator it = args_map.find(name_found ); | |
| 
 | |
|                         if(it!=args_map.end()){ | |
|                             pa= &((*it).second); | |
|                             argument_value = std::string(assign_sign+1,end); | |
|                         }else { | |
|                             throw_unknow_parameter::_(argv[j]); | |
|                         } | |
|                     } | |
|                     //then see is it a named flag | |
|                     else{ | |
|                         args_map_type::iterator it = args_map.find(argv[j] ); | |
|                         if(it!=args_map.end()){ | |
|                             pa= &((*it).second); | |
|                             argument_value = ""; | |
|                         } | |
|                         //then try it as positional argument without name specified | |
|                         else if (current_positional_index < positional_arg_names.size()){ | |
|                             std::stringstream str(argv[j]); | |
|                             args_map_type::iterator it = args_map.find(positional_arg_names.at(current_positional_index)); | |
|                             //TODO: probably use of smarter assert would help here | |
|                             assert(it!=args_map.end()/*&&"positional_arg_names and args_map are out of sync"*/); | |
|                             if (it==args_map.end()){ | |
|                                 throw std::logic_error("positional_arg_names and args_map are out of sync"); | |
|                             } | |
|                             pa= &((*it).second); | |
|                             argument_value = argv[j]; | |
| 
 | |
|                             current_positional_index++; | |
|                         }else { | |
|                             //TODO: add tc to check | |
|                             throw_unknow_parameter::_(argv[j]); | |
|                         } | |
|                     } | |
|                     assert(pa); | |
|                     if (pa->is_matched()){ | |
|                         throw std::invalid_argument(std::string("several values specified for: \"")+pa->name()+"\" argument"); | |
|                     } | |
|                     pa->parse_and_store(argument_value); | |
|                 } | |
|             } | |
|         } | |
|         std::string usage_string(const std::string& binary_name)const{ | |
|             std::string command_line_params; | |
|             std::string summary_description; | |
| 
 | |
|             for (args_display_order_type::const_iterator it = args_display_order.begin();it!=args_display_order.end();++it){ | |
|                 const bool is_bool = (0!=bool_args_names.count((*it))); | |
|                 args_map_type::const_iterator argument_it = args_map.find(*it); | |
|                 //TODO: probably use of smarter assert would help here | |
|                 assert(argument_it!=args_map.end()/*&&"args_display_order and args_map are out of sync"*/); | |
|                 if (argument_it==args_map.end()){ | |
|                     throw std::logic_error("args_display_order and args_map are out of sync"); | |
|                 } | |
|                 const internal::argument & a = (*argument_it).second; | |
|                 command_line_params +=" [" + a.name() + (is_bool ?"":"=value")+ "]"; | |
|                 summary_description +=" " + a.name() + " - " + a.description() +" ("+a.value() +")" + "\n"; | |
|             } | |
| 
 | |
|             std::string positional_arg_cl; | |
|             for (positional_arg_names_type::const_iterator it = positional_arg_names.begin();it!=positional_arg_names.end();++it){ | |
|                 positional_arg_cl +=" ["+(*it); | |
|             } | |
|             for (std::size_t i=0;i<positional_arg_names.size();++i){ | |
|                 positional_arg_cl+="]"; | |
|             } | |
|             command_line_params+=positional_arg_cl; | |
|             std::stringstream str; | |
|             using std::endl; | |
|             str << " Program usage is:" << endl | |
|                  << " " << binary_name << command_line_params | |
|                  << endl << endl | |
|                  << " where:" << endl | |
|                  << summary_description | |
|             ; | |
|             return str.str(); | |
|         } | |
|     }; | |
| } | |
| 
 | |
| namespace utility{ | |
| 
 | |
|     namespace internal { | |
|         int step_function_plus(int previous,double step){ | |
|             return static_cast<int>(previous+step); | |
|         } | |
|         int step_function_multiply(int previous,double multiply){ | |
|             return static_cast<int>(previous*multiply); | |
|         } | |
|         typedef int (* step_function_ptr_type)(int,double); | |
|         struct step_function_descriptor  { | |
|             char mnemonic; | |
|             step_function_ptr_type function; | |
|         public: | |
|             step_function_descriptor(char a_mnemonic, step_function_ptr_type a_function) : mnemonic(a_mnemonic), function(a_function) {} | |
|         private: | |
|             void operator=(step_function_descriptor  const&); | |
|         }; | |
| 
 | |
|         step_function_descriptor step_function_descriptors[] = { | |
|                 step_function_descriptor('*',step_function_multiply), | |
|                 step_function_descriptor('+',step_function_plus) | |
|         }; | |
| 
 | |
|         template<typename T, size_t N> | |
|         inline size_t array_length(const T(&)[N]) | |
|         { | |
|            return N; | |
|         } | |
| 
 | |
|         struct thread_range_step { | |
|             step_function_ptr_type step_function; | |
|             double step_function_argument; | |
| 
 | |
|             thread_range_step ( step_function_ptr_type step_function_, double step_function_argument_) | |
|                 :step_function(step_function_),step_function_argument(step_function_argument_) | |
|             { | |
|                 if (!step_function_) | |
|                     throw std::invalid_argument("step_function for thread range step should not be NULL"); | |
|             } | |
|             int operator()(int previous)const { | |
|                 return step_function(previous,step_function_argument); | |
|             } | |
|             friend std::istream& operator>>(std::istream& input_stream, thread_range_step& step){ | |
|                 char function_char; | |
|                 double function_argument; | |
|                 input_stream>>function_char >> function_argument; | |
|                 size_t i = 0; | |
|                 for ( ;(i < array_length(step_function_descriptors)) && step_function_descriptors[i].mnemonic != function_char; ++i ); | |
|                 if (i >= array_length(step_function_descriptors)){ | |
|                     throw std::invalid_argument("step_function for thread range step should be known"); | |
|                 } | |
|                 step.step_function = step_function_descriptors[i].function; | |
|                 step.step_function_argument = function_argument; | |
|                 return input_stream; | |
|             } | |
|         }; | |
|     } | |
|     struct thread_number_range{ | |
|         int (*auto_number_of_threads)(); | |
|         int first; | |
|         int last; | |
| 
 | |
|         internal::thread_range_step step; | |
| 
 | |
|         thread_number_range( int (*auto_number_of_threads_)(),int low_=1, int high_=-1 | |
|                 , internal::thread_range_step step_ =  internal::thread_range_step(internal::step_function_plus,1) | |
|         ) | |
|             : auto_number_of_threads(auto_number_of_threads_), first(low_), last((high_>-1) ? high_ : auto_number_of_threads_()) | |
|               ,step(step_) | |
|         { | |
|             if (first>last){ | |
|                 throw std::invalid_argument(""); | |
|             } | |
|         } | |
|         friend std::istream& operator>>(std::istream& i, thread_number_range& range){ | |
|             try{ | |
|                 std::string s; | |
|                 i>>s; | |
|                 struct string_to_number_of_threads{ | |
|                     int auto_value; | |
|                     string_to_number_of_threads(int auto_value_):auto_value(auto_value_){} | |
|                     int operator()(const std::string & value)const{ | |
|                         int result=0; | |
|                         if (value=="auto"){ | |
|                             result = auto_value; | |
|                         } | |
|                         else{ | |
|                             internal::string_to(value,result); | |
|                         } | |
|                         return result; | |
|                     } | |
|                 }; | |
|                 string_to_number_of_threads string_to_number_of_threads(range.auto_number_of_threads()); | |
|                 int low =0; | |
|                 int high=0; | |
|                 std::size_t semicolon = s.find(':'); | |
|                 if (semicolon == std::string::npos ){ | |
|                     high= (low = string_to_number_of_threads(s)); | |
|                 }else { | |
|                     //it is a range | |
|                     std::size_t second_semicolon = s.find(':',semicolon+1); | |
| 
 | |
|                     low  = string_to_number_of_threads(std::string(s, 0, semicolon)); //not copying the ':' char | |
|                     high = string_to_number_of_threads(std::string(s, semicolon+1, second_semicolon - (semicolon+1))); //not copying the ':' chars | |
|                     if (second_semicolon != std::string::npos){ | |
|                         internal::string_to(std::string(s,second_semicolon + 1),range.step); | |
|                     } | |
|                 } | |
|                 range = thread_number_range(range.auto_number_of_threads,low,high,range.step); | |
|             }catch(std::invalid_argument&){ | |
|                 i.setstate(std::ios::failbit); | |
|             } | |
|             return i; | |
|         } | |
| 
 | |
|         friend std::ostream& operator<<(std::ostream& o, thread_number_range const& range){ | |
|             using namespace internal; | |
|             size_t i = 0; | |
|             for ( ;(i < array_length(step_function_descriptors)) && step_function_descriptors[i].function != range.step.step_function; ++i ); | |
|             if (i >= array_length(step_function_descriptors)){ | |
|                 throw std::invalid_argument("step_function for thread range step should be known"); | |
|             } | |
|             o<<range.first<<":"<<range.last<<":"<<step_function_descriptors[i].mnemonic<<range.step.step_function_argument; | |
|             return o; | |
|         } | |
| 
 | |
|     }; | |
|     //TODO: update the thread range description in the .html files | |
|     static const char* thread_number_range_desc="number of threads to use; a range of the form low[:high[:(+|*)step]]" | |
|                                                 ", where low and optional high are non-negative integers or 'auto' for the TBB default" | |
|                                                 ", and optional step expression specifies how next thread number is chosen." | |
|                                                 " E.g. expression '1:16:*2' means threads from 1 to 16 , where each next thread number" | |
|                                                 " is twice bigger (*2) than previous one." | |
|    ; | |
| } | |
| #include <iostream> | |
| namespace utility{ | |
|     inline void report_elapsed_time(double seconds){ | |
|         std::cout << "elapsed time : "<<seconds<<" seconds \n"; | |
|     } | |
| } | |
| #include <cstdlib> | |
| namespace utility{ | |
|     inline void parse_cli_arguments(int argc, const char* argv[], utility::cli_argument_pack cli_pack){ | |
|         bool show_help = false; | |
|         cli_pack.arg(show_help,"-h","show this message"); | |
| 
 | |
|         bool invalid_input=false; | |
|         try { | |
|             cli_pack.parse(argc,argv); | |
|         }catch(std::exception& e){ | |
|             std::cerr | |
|                     <<"error occurred while parsing command line."<<std::endl | |
|                     <<"error text:\""<<e.what()<<"\""<<std::endl | |
|                     <<std::flush; | |
|             invalid_input =true; | |
|         } | |
|         if (show_help || invalid_input){ | |
|             std::cout<<cli_pack.usage_string(argv[0])<<std::flush; | |
|             std::exit(0); | |
|         } | |
| 
 | |
|     } | |
|     inline void parse_cli_arguments(int argc, char* argv[], utility::cli_argument_pack cli_pack){ | |
|          parse_cli_arguments(argc, const_cast<const char**>(argv), cli_pack); | |
|     } | |
| } | |
| #endif /* UTILITY_H_ */
 |