File indexing completed on 2026-04-09 07:49:28
0001 #ifndef NPU_HH
0002 #define NPU_HH
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <csignal>
0016 #include <sstream>
0017 #include <iostream>
0018 #include <iomanip>
0019 #include <string>
0020 #include <cstring>
0021 #include <vector>
0022 #include <cassert>
0023 #include <complex>
0024 #include <fstream>
0025 #include <cstdlib>
0026 #include <cstdint>
0027 #include <algorithm>
0028 #include <chrono>
0029 #include <cctype>
0030 #include <locale>
0031 #include <tuple>
0032
0033
0034 #include <sys/types.h>
0035 #include <sys/stat.h>
0036 #include <unistd.h>
0037
0038
0039
0040
0041
0042
0043
0044
0045 template<typename T>
0046 struct desc
0047 {
0048 static constexpr char code = '?' ;
0049 static constexpr unsigned size = 0 ;
0050 };
0051
0052 template<> struct desc<float> { static constexpr char code = 'f' ; static constexpr unsigned size = sizeof(float) ; };
0053 template<> struct desc<double> { static constexpr char code = 'f' ; static constexpr unsigned size = sizeof(double) ; };
0054
0055 template<> struct desc<char> { static constexpr char code = 'i' ; static constexpr unsigned size = sizeof(char) ; };
0056 template<> struct desc<short> { static constexpr char code = 'i' ; static constexpr unsigned size = sizeof(short) ; };
0057 template<> struct desc<int> { static constexpr char code = 'i' ; static constexpr unsigned size = sizeof(int) ; };
0058 template<> struct desc<long> { static constexpr char code = 'i' ; static constexpr unsigned size = sizeof(long) ; };
0059 template<> struct desc<long long> { static constexpr char code = 'i' ; static constexpr unsigned size = sizeof(long long) ; };
0060
0061 template<> struct desc<unsigned char> { static constexpr char code = 'u' ; static constexpr unsigned size = sizeof(unsigned char) ; };
0062 template<> struct desc<unsigned short> { static constexpr char code = 'u' ; static constexpr unsigned size = sizeof(unsigned short) ; };
0063 template<> struct desc<unsigned int> { static constexpr char code = 'u' ; static constexpr unsigned size = sizeof(unsigned int) ; };
0064 template<> struct desc<unsigned long> { static constexpr char code = 'u' ; static constexpr unsigned size = sizeof(unsigned long) ; };
0065 template<> struct desc<unsigned long long> { static constexpr char code = 'u' ; static constexpr unsigned size = sizeof(unsigned long long) ; };
0066
0067 template<> struct desc<std::complex<float> > { static constexpr char code = 'c' ; static constexpr unsigned size = sizeof(std::complex<float>) ; } ;
0068 template<> struct desc<std::complex<double> > { static constexpr char code = 'c' ; static constexpr unsigned size = sizeof(std::complex<double>) ; } ;
0069
0070 struct endian
0071 {
0072 static char constexpr LITTLE = '<' ;
0073 static char constexpr BIG = '>' ;
0074 static char detect() { unsigned one = 1u ; return (*(char *)&one == 1) ? LITTLE : BIG ; } ;
0075 };
0076
0077 template<typename T>
0078 struct descr_
0079 {
0080 static std::string dtype()
0081 {
0082 std::stringstream ss ;
0083 ss << endian::detect() << desc<T>::code << desc<T>::size ;
0084 return ss.str();
0085 }
0086 static std::string dtype_name()
0087 {
0088 std::stringstream ss ;
0089 switch(desc<T>::code)
0090 {
0091 case 'f': ss << "float" ; break ;
0092 case 'i': ss << "int" ; break ;
0093 case 'u': ss << "uint" ; break ;
0094 case 'c': ss << "complex" ; break ;
0095 }
0096 ss << desc<T>::size*8 ;
0097 return ss.str();
0098 }
0099 };
0100
0101 template struct descr_<float> ;
0102 template struct descr_<double> ;
0103
0104 template struct descr_<char> ;
0105 template struct descr_<short> ;
0106 template struct descr_<int> ;
0107 template struct descr_<long> ;
0108 template struct descr_<long long> ;
0109
0110 template struct descr_<unsigned char> ;
0111 template struct descr_<unsigned short> ;
0112 template struct descr_<unsigned int> ;
0113 template struct descr_<unsigned long> ;
0114 template struct descr_<unsigned long long> ;
0115
0116 template struct descr_<std::complex<float> > ;
0117 template struct descr_<std::complex<double> > ;
0118
0119
0120 struct dtype_convert
0121 {
0122 static std::string from_name(const char* name)
0123 {
0124 std::stringstream ss ;
0125 ss << endian::detect() ;
0126 if( strstr(name,"float")) ss << 'f' ;
0127 else if(strstr(name,"uint")) ss << 'u' ;
0128 else if(strstr(name,"int")) ss << 'i' ;
0129 else if(strstr(name,"complex")) ss << 'c' ;
0130
0131 std::stringstream ii;
0132 for (int i=0 ; i < int(strlen(name)) ; i++) ii << (std::isdigit(name[i]) ? name[i] : ' ' ) ;
0133 int nbit(0);
0134 ii >> nbit ;
0135
0136 bool expect = nbit % 8 == 0 ;
0137 ss << ( expect ? nbit/8 : 0 ) ;
0138
0139 return ss.str();
0140 }
0141 };
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153 #include <arpa/inet.h> // htonl
0154
0155
0156 struct net_hdr
0157 {
0158 static constexpr unsigned LENGTH = 4*4 ;
0159
0160 union uc4_t {
0161 uint32_t u ;
0162 char c[4] ;
0163 };
0164 static std::string pack(const std::vector<unsigned> items);
0165 static void unpack( const std::string& hdr , std::vector<unsigned>& items );
0166 static void unpack( char* data, unsigned num_bytes , std::vector<unsigned>& items );
0167
0168 static unsigned unpack( const std::string& hdr, unsigned index );
0169 };
0170
0171
0172 inline std::string net_hdr::pack(const std::vector<unsigned> items)
0173 {
0174 unsigned ni = items.size();
0175
0176 assert( ni == 4 );
0177 assert( sizeof(unsigned) == 4);
0178 assert( ni*sizeof(unsigned) == LENGTH );
0179
0180 uc4_t uc4 ;
0181 std::string hdr(LENGTH, '\0' );
0182 for(unsigned i=0 ; i < ni ; i++)
0183 {
0184 uc4.u = htonl(items[i]) ;
0185 memcpy( (void*)(hdr.data() + i*sizeof(unsigned)), &(uc4.c[0]), 4 );
0186 }
0187 return hdr ;
0188 }
0189
0190 inline void net_hdr::unpack( const std::string& hdr, std::vector<unsigned>& items )
0191 {
0192 unpack((char*)hdr.data(), hdr.length(), items );
0193 }
0194
0195 inline unsigned net_hdr::unpack( const std::string& hdr, unsigned index )
0196 {
0197 std::vector<unsigned> items ;
0198 unpack(hdr, items);
0199 return index < items.size() ? items[index] : 0 ;
0200 }
0201
0202 inline void net_hdr::unpack( char* data, unsigned num_bytes, std::vector<unsigned>& items )
0203 {
0204 assert( 4 == sizeof(unsigned));
0205 unsigned ni = num_bytes/sizeof(unsigned);
0206
0207 items.clear();
0208 items.resize(ni);
0209
0210 uc4_t uc4 ;
0211 for(unsigned i=0 ; i < ni ; i++)
0212 {
0213 memcpy( &(uc4.c[0]), data + i*4, 4 );
0214 items[i] = ntohl(uc4.u) ;
0215 }
0216 }
0217
0218
0219
0220 struct NPS
0221 {
0222 typedef std::int64_t INT ;
0223 typedef std::uint64_t UINT ;
0224 static constexpr const INT ONE = 1 ;
0225
0226 NPS(std::vector<INT>& shape_ ) : shape(shape_) {} ;
0227
0228 static NPS::INT set_shape(std::vector<INT>& shape_, INT ni, INT nj=-1, INT nk=-1, INT nl=-1, INT nm=-1, INT no=-1 )
0229 {
0230 NPS sh(shape_);
0231 sh.set_shape(ni,nj,nk,nl,nm,no);
0232 return sh.size();
0233 }
0234
0235 static NPS::INT copy_shape(std::vector<INT>& dst, const std::vector<INT>& src)
0236 {
0237 for(INT i=0 ; i < INT(src.size()) ; i++) dst.push_back(src[i]);
0238 return size(dst);
0239 }
0240
0241 static size_t copy_shape(std::vector<size_t>& dst, const std::vector<INT>& src)
0242 {
0243 for(size_t i=0 ; i < src.size() ; i++) dst.push_back(src[i]);
0244 return size(dst);
0245 }
0246
0247
0248 static NPS::INT copy_shape(std::vector<INT>& dst, INT ni=-1, INT nj=-1, INT nk=-1, INT nl=-1, INT nm=-1, INT no=-1)
0249 {
0250 if(ni >= 0) dst.push_back(ni);
0251 if(nj > 0) dst.push_back(nj);
0252 if(nk > 0) dst.push_back(nk);
0253 if(nl > 0) dst.push_back(nl);
0254 if(nm > 0) dst.push_back(nm);
0255 if(no > 0) dst.push_back(no);
0256 return size(dst);
0257 }
0258
0259 void set_shape(INT ni, INT nj=-1, INT nk=-1, INT nl=-1, INT nm=-1, INT no=-1)
0260 {
0261 if(ni >= 0) shape.push_back(ni);
0262 if(nj > 0) shape.push_back(nj);
0263 if(nk > 0) shape.push_back(nk);
0264 if(nl > 0) shape.push_back(nl);
0265 if(nm > 0) shape.push_back(nm);
0266 if(no > 0) shape.push_back(no);
0267 }
0268 void set_shape(const std::vector<INT>& other)
0269 {
0270 copy_shape(shape, other);
0271 }
0272
0273 static NPS::INT change_shape(std::vector<INT>& shp, INT ni_, INT nj_=-1, INT nk_=-1, INT nl_=-1, INT nm_=-1, INT no_=-1)
0274 {
0275 INT nv0 = size(shp);
0276 INT nv1 = std::max(ONE,ni_)*std::max(ONE,nj_)*std::max(ONE,nk_)*std::max(ONE,nl_)*std::max(ONE,nm_)*std::max(ONE,no_) ;
0277
0278 if( nv0 != nv1 )
0279 {
0280 if( ni_ < 0 ) ni_ = nv0/nv1 ;
0281 else if( nj_ < 0 ) nj_ = nv0/nv1 ;
0282 else if( nk_ < 0 ) nk_ = nv0/nv1 ;
0283 else if( nl_ < 0 ) nl_ = nv0/nv1 ;
0284 else if( nm_ < 0 ) nm_ = nv0/nv1 ;
0285 else if( no_ < 0 ) no_ = nv0/nv1 ;
0286
0287 INT nv2 = std::max(ONE,ni_)*std::max(ONE,nj_)*std::max(ONE,nk_)*std::max(ONE,nl_)*std::max(ONE,nm_)*std::max(ONE,no_) ;
0288 bool expect = nv0 % nv1 == 0 && nv2 == nv0 ;
0289
0290 if(!expect) std::cout
0291 << " NPS::change_shape INVALID SHAPE CHANGE : SIZE MUST STAY CONSTANT : ONLY ONE -1 ENTRY CAN BE AUTO-FILLED "
0292 << std::endl
0293 << " nv0 " << nv0
0294 << " nv1 " << nv1
0295 << " nv2 " << nv2
0296 << " ni_ " << ni_
0297 << " nj_ " << nj_
0298 << " nk_ " << nk_
0299 << " nl_ " << nl_
0300 << " nm_ " << nm_
0301 << " no_ " << no_
0302 << std::endl
0303 ;
0304
0305 assert(expect);
0306 }
0307
0308 shp.clear();
0309 return copy_shape(shp, ni_, nj_, nk_, nl_, nm_, no_ );
0310 }
0311
0312 static NPS::INT product(const std::vector<INT>& src )
0313 {
0314 INT nd = src.size();
0315 INT prod = 1 ;
0316 for(INT i=0 ; i < nd ; i++) prod *= src[i] ;
0317 return prod ;
0318 }
0319 static void reshape(std::vector<INT>& dst, const std::vector<INT>& src )
0320 {
0321 assert( product(dst) == product(src) );
0322 dst = src ;
0323 }
0324
0325 template<int P>
0326 static void size_2D( INT& width, INT& height, const std::vector<INT>& sh )
0327 {
0328 INT nd = sh.size() ;
0329 assert( nd > 1 && sh[nd-1] == P );
0330 width = sh[nd-2] ;
0331 height = 1 ;
0332 for(INT i=0 ; i < nd-2 ; i++) height *= sh[i] ;
0333 }
0334
0335 static std::string desc(const std::vector<INT>& shape)
0336 {
0337 std::stringstream ss ;
0338 ss << "(" ;
0339 for(unsigned i=0 ; i < shape.size() ; i++) ss << shape[i] << ", " ;
0340 ss << ")" ;
0341 return ss.str();
0342 }
0343
0344 static std::string json(const std::vector<INT>& shape)
0345 {
0346 std::stringstream ss ;
0347 ss << "[" ;
0348 for(unsigned i=0 ; i < shape.size() ; i++)
0349 {
0350 ss << shape[i] ;
0351 if( i < shape.size() - 1 ) ss << ", " ;
0352 }
0353 ss << "]" ;
0354 return ss.str();
0355 }
0356
0357 static NPS::INT size(const std::vector<INT>& shape)
0358 {
0359 INT ndim = INT(shape.size());
0360 INT sz = 1;
0361 for(INT i=0; i<ndim; ++i) sz *= shape[i] ;
0362 return ndim == 0 ? 0 : sz ;
0363 }
0364
0365 static NPS::UINT usize(const std::vector<INT>& shape)
0366 {
0367 INT ndim = INT(shape.size());
0368 UINT sz = 1;
0369 for(INT i=0; i<ndim; ++i) sz *= shape[i] ;
0370 return ndim == 0 ? 0 : sz ;
0371 }
0372
0373
0374
0375 static size_t size(const std::vector<size_t>& shape)
0376 {
0377 size_t ndim = shape.size();
0378 size_t sz = 1;
0379 for(size_t i=0; i<ndim; ++i) sz *= shape[i] ;
0380 return ndim == 0 ? 0 : sz ;
0381 }
0382
0383
0384 static NPS::INT itemsize(const std::vector<INT>& shape)
0385 {
0386 INT sz = 1;
0387 for(unsigned i=1; i<shape.size(); ++i) sz *= shape[i] ;
0388 return sz ;
0389 }
0390
0391 static NPS::INT itemsize_(const std::vector<INT>& shape, INT i=-1, INT j=-1, INT k=-1, INT l=-1, INT m=-1, INT o=-1 )
0392 {
0393
0394 if( i == -1 ) assert( j == -1 && k == -1 && l == -1 && m == -1 && o == -1 ) ;
0395 if( i > -1 && j == -1 ) assert( k == -1 && l == -1 && m == -1 && o == -1 ) ;
0396 if( i > -1 && j > -1 && k == -1 ) assert( l == -1 && m == -1 && o == -1 ) ;
0397 if( i > -1 && j > -1 && k > -1 && l == -1 ) assert( m == -1 && o == -1 ) ;
0398 if( i > -1 && j > -1 && k > -1 && l > -1 && m == -1 ) assert( o == -1 ) ;
0399 if( i > -1 && j > -1 && k > -1 && l > -1 && m > -1 && o == -1 ) assert( true ) ;
0400
0401 unsigned dim0 = 0 ;
0402 if( i == -1 ) dim0 = 0 ;
0403 if( i > -1 && j == -1 ) dim0 = 1 ;
0404 if( i > -1 && j > -1 && k == -1 ) dim0 = 2 ;
0405 if( i > -1 && j > -1 && k > -1 && l == -1 ) dim0 = 3 ;
0406 if( i > -1 && j > -1 && k > -1 && l > -1 && m == -1 ) dim0 = 4 ;
0407 if( i > -1 && j > -1 && k > -1 && l > -1 && m > -1 && o == -1 ) dim0 = 5 ;
0408 if( i > -1 && j > -1 && k > -1 && l > -1 && m > -1 && o > -1 ) dim0 = 6 ;
0409
0410 INT sz = 1;
0411 if( dim0 < shape.size() )
0412 {
0413 for(unsigned d=dim0; d<shape.size(); ++d) sz *= shape[d] ;
0414 }
0415 #ifdef DEBUG_NPU
0416 std::cout
0417 << "NPS::itemsize_"
0418 << "(" << std::setw(3) << i
0419 << " " << std::setw(3) << j
0420 << " " << std::setw(3) << k
0421 << " " << std::setw(3) << l
0422 << " " << std::setw(3) << m
0423 << " " << std::setw(3) << o
0424 << ")"
0425 << " " << sz
0426 << std::endl
0427 ;
0428 #endif
0429 return sz ;
0430 }
0431
0432 std::string desc() const { return desc(shape) ; }
0433 std::string json() const { return json(shape) ; }
0434 NPS::INT size() const { return size(shape) ; }
0435
0436
0437 static NPS::INT ni_(const std::vector<INT>& shape) { return shape.size() > 0 ? shape[0] : 1 ; }
0438 static NPS::INT nj_(const std::vector<INT>& shape) { return shape.size() > 1 ? shape[1] : 1 ; }
0439 static NPS::INT nk_(const std::vector<INT>& shape) { return shape.size() > 2 ? shape[2] : 1 ; }
0440 static NPS::INT nl_(const std::vector<INT>& shape) { return shape.size() > 3 ? shape[3] : 1 ; }
0441 static NPS::INT nm_(const std::vector<INT>& shape) { return shape.size() > 4 ? shape[4] : 1 ; }
0442 static NPS::INT no_(const std::vector<INT>& shape) { return shape.size() > 5 ? shape[5] : 1 ; }
0443
0444 NPS::INT ni_() const { return ni_(shape) ; }
0445 NPS::INT nj_() const { return nj_(shape) ; }
0446 NPS::INT nk_() const { return nk_(shape) ; }
0447 NPS::INT nl_() const { return nl_(shape) ; }
0448 NPS::INT nm_() const { return nm_(shape) ; }
0449 NPS::INT no_() const { return no_(shape) ; }
0450
0451 NPS::INT idx(INT i, INT j, INT k, INT l, INT m, INT o)
0452 {
0453 [[maybe_unused]] INT ni = ni_() ;
0454 INT nj = nj_() ;
0455 INT nk = nk_() ;
0456 INT nl = nl_() ;
0457 INT nm = nm_() ;
0458 INT no = no_() ;
0459
0460 return i*nj*nk*nl*nm*no + j*nk*nl*nm*no + k*nl*nm*no + l*nm*no + m*no + o ;
0461 }
0462
0463
0464 std::vector<INT>& shape ;
0465 };
0466
0467
0468
0469 struct U
0470 {
0471 typedef std::vector<std::string> VS ;
0472 typedef std::vector<int64_t> VT ;
0473
0474
0475 static constexpr const bool VERBOSE = false ;
0476 static constexpr const bool RAISE = true ;
0477
0478 enum { ERROR_PATH=-1, DIR_PATH=1 , FILE_PATH=2, OTHER_PATH=3 } ;
0479
0480 static void sizeof_check();
0481
0482 static bool EndsWith( const char* s, const char* q) ;
0483 static std::string ChangeExt( const char* s, const char* x1, const char* x2) ;
0484 static std::string DirName( const char* path );
0485
0486 static std::string BaseName( const char* path );
0487 static const char* BaseName_( const char* path );
0488
0489 static std::string BaseName_NoSepAsis( const char* path );
0490 static const char* BaseName_NoSepAsis_( const char* path );
0491
0492
0493 static std::string FormSiblingPath0( const char* sibname , const char* dirpath );
0494 static std::string FormSiblingPath( const char* sibname , const char* dirpath );
0495 static std::string FormExecutableSiblingPath( const char* argv0 , const char* dirpath );
0496 static bool IsExecutableSiblingPath( const char* argv0, const char* dirpath );
0497 static int SetEnvDefaultExecutableSiblingPath(const char* ekey, char* argv0, const char* dirpath );
0498
0499 static int setenvvar( const char* ekey, const char* value, bool overwrite=true, char special_empty_token='\0' );
0500
0501
0502 template<typename ... Args>
0503 static std::string Format_( const char* fmt, Args ... args );
0504
0505 template<typename ... Args>
0506 static const char* Format( const char* fmt, Args ... args );
0507
0508
0509
0510 static std::string FormNameWithPrefix_( char prefix, int idx, int wid=3 );
0511 static const char* FormNameWithPrefix( char prefix, int idx, int wid=3 );
0512
0513 static std::string FormName_( int idx, int wid=3 );
0514 static const char* FormName( int idx, int wid=3 );
0515
0516 static std::string FormName_( const char* prefix, int idx, const char* ext, int wid=-1 );
0517 static const char* FormName( const char* prefix, int idx, const char* ext, int wid=-1 );
0518
0519 static std::string FormName_( const char* prefix, const char* body, const char* ext );
0520 static const char* FormName( const char* prefix, const char* body, const char* ext );
0521
0522 static bool IsIntegerString(const char* str);
0523
0524 static bool isdigit_(char c );
0525 static bool isalnum_(char c );
0526 static bool isupper_(char c );
0527 static bool islower_(char c );
0528
0529
0530 static void Summarize( std::vector<std::string>& smry_labels, const std::vector<std::string>* labels, int wid );
0531 static const char* Summarize( const char* label, int wid );
0532 static std::string Summarize_( const char* label, int wid );
0533
0534
0535 static void LineVector( std::vector<std::string>& lines, const char* LINES, const char* PREFIX=nullptr );
0536
0537 static void LiteralTrim( std::string& line );
0538 static void Literal( std::vector<std::string>& lines, const char* LINES );
0539 static void LiteralAnno( std::vector<std::string>& field, std::vector<std::string>& anno, const char* LINES, const char* delim="#" );
0540
0541 static std::string Space(int wid);
0542
0543
0544
0545 static std::string form_name(const char* stem, const char* ext);
0546 static std::string form_path(const char* dir, const char* name);
0547 static std::string form_path(const char* dir, const char* reldir, const char* name);
0548
0549
0550
0551 static constexpr const char* DEFAULT_PATH_ARG_0 = "/tmp" ;
0552 template<typename ... Args>
0553 static std::string Path_( Args ... args_ );
0554
0555 template<typename ... Args>
0556 static const char* Path( Args ... args );
0557
0558
0559 template<typename T>
0560 static inline void MakeVec(std::vector<T>& vec, const char* line, char delim=',');
0561
0562 template<typename T>
0563 static std::vector<T>* MakeVec(const char* line, char delim=',');
0564
0565 static void Zip(
0566 std::vector<std::string>& kvs,
0567 const std::vector<std::string>& keys,
0568 const std::vector<std::string>& vals,
0569 char delim=':');
0570
0571
0572 template<typename T>
0573 static long LoadVec(std::vector<T>& vec, const char* path_);
0574
0575 template<typename T>
0576 static int Category(const std::vector<T>& cats, const T& val );
0577
0578 static bool StartsWith( const char* s, const char* q) ;
0579 static bool Contains( const char* s, const char* q) ;
0580
0581 template<typename T> static unsigned NumSteps( T x0, T x1, T dx );
0582
0583 template<typename T> static T To( const char* a );
0584 template<typename T> static bool ConvertsTo( const char* a );
0585
0586 static char* PWD();
0587
0588 template<typename T>
0589 static std::vector<T>* GetEnvVec(const char* ekey, const char* fallback, char delim=',');
0590 static int GetEnvInt( const char* envkey, int fallback );
0591
0592 static size_t StringToSize(const std::string& str);
0593 static size_t GetEnvSize(const char* envkey, size_t fallback);
0594
0595 static const char* GetEnv( const char* envkey, const char* fallback);
0596 static bool HasEnv( const char* envkey );
0597
0598 template<typename T>
0599 static T GetE(const char* ekey, T fallback);
0600
0601 static int MakeDirs( const char* dirpath, int mode=0 );
0602 static int MakeDirsForFile( const char* filepath, int mode=0);
0603
0604 static int PathType( const char* path );
0605 static int PathType( const char* base, const char* name );
0606
0607 static void DirList(std::vector<std::string>& names, const char* _path,
0608 const char* ext=nullptr, bool exclude=false, bool allow_nonexisting=false );
0609 static void Trim(std::vector<std::string>& names, const char* ext);
0610 static void Split(const char* str, char delim, std::vector<std::string>& elem);
0611 static bool prefix_suffix( char** pfx, char** sfx, const char* start_sfx, const char* str );
0612
0613 static int FindIndex(const std::vector<std::string>& names, const char* name);
0614
0615 static std::string Desc(const std::vector<std::string>& names);
0616
0617 static const char* Resolve0(const char* spec, const char* relp=nullptr );
0618
0619
0620 static const char* Resolve( const char* spec, const char* rel1=nullptr, const char* rel2=nullptr );
0621
0622
0623 static void WriteString( const char* dir, const char* reldir, const char* name, const char* str );
0624 static void WriteString( const char* dir, const char* name, const char* str );
0625 static void WriteString( const char* path, const char* str );
0626
0627 static const char* ReadString( const char* dir, const char* reldir, const char* name);
0628 static const char* ReadString( const char* dir, const char* name);
0629
0630 static std::string ReadString_( const char* path_ );
0631 static const char* ReadString( const char* path );
0632
0633 static std::string ReadString2_( const char* path_ );
0634 static const char* ReadString2( const char* path );
0635
0636 static uint64_t Now();
0637 static bool LooksLikeStampInt( const char* str);
0638 template<typename T>
0639 static bool LooksLikeTimestamp( T value );
0640
0641 static bool LooksLikeProfileTriplet(const char* str);
0642
0643 static std::string Format(uint64_t t=0, const char* fmt="%FT%T.", int _wsubsec=3 );
0644
0645 static constexpr const char* LOG_FMT = "%Y-%m-%d %H:%M:%S" ;
0646 static std::string FormatLog(const char* msg=nullptr);
0647 static std::string Log(const char* msg=nullptr);
0648
0649 static std::string FormatInt(int64_t t, int wid );
0650
0651 static char* LastDigit(const char* str);
0652 static char* FirstDigit(const char* str);
0653 static char* FirstToLastDigit(const char* str);
0654
0655
0656 static void GetMetaKVS_(const char* metadata, VS* keys, VS* vals, VT* stamps, bool only_with_stamp );
0657 static void GetMetaKVS( const std::string& meta, VS* keys, VS* vals, VT* stamps, bool only_with_stamp );
0658
0659 static void KeyIndices( std::vector<int>& indices, const std::vector<std::string>& keys, const char* key );
0660 static int KeyIndex( const std::vector<std::string>& keys, const char* key );
0661 static int FormattedKeyIndex( std::string& fkey, const std::vector<std::string>& keys, const char* key, int idx0, int idx1 );
0662
0663 static void SplitTuple( std::vector<std::string>& keys, std::vector<int64_t>& tt, const std::vector<std::tuple<std::string, int64_t>>& kt );
0664 };
0665
0666
0667
0668 inline void U::sizeof_check()
0669 {
0670 assert( sizeof(float) == 4 );
0671 assert( sizeof(double) == 8 );
0672
0673 assert( sizeof(char) == 1 );
0674 assert( sizeof(short) == 2 );
0675 assert( sizeof(int) == 4 );
0676 assert( sizeof(long) == 8 );
0677 assert( sizeof(long long) == 8 );
0678 }
0679
0680
0681 template<typename T>
0682 inline void U::MakeVec(std::vector<T>& vec, const char* line, char delim)
0683 {
0684 if(line == nullptr) return ;
0685 std::stringstream ss;
0686 ss.str(line);
0687 std::string s;
0688 while (std::getline(ss, s, delim))
0689 {
0690 std::istringstream iss(s);
0691 T t ;
0692 iss >> t ;
0693 vec.push_back(t) ;
0694 }
0695 }
0696
0697 inline void U::Zip(
0698 std::vector<std::string>& kvs,
0699 const std::vector<std::string>& keys,
0700 const std::vector<std::string>& vals,
0701 char delim )
0702 {
0703 assert( keys.size() == vals.size() );
0704 kvs.clear();
0705
0706 char s_delim[2] ;
0707 s_delim[0] = delim ;
0708 s_delim[1] = '\0' ;
0709
0710 for(int i=0 ; i < int(keys.size()) ; i++)
0711 {
0712 std::string kv = U::FormName_( keys[i].c_str(), s_delim, vals[i].c_str() );
0713 kvs.push_back(kv);
0714 }
0715 }
0716
0717
0718
0719
0720
0721
0722
0723
0724
0725
0726
0727 template<typename T>
0728 inline std::vector<T>* U::MakeVec(const char* line, char delim)
0729 {
0730 if(line == nullptr) return nullptr ;
0731 std::vector<T> vec ;
0732 MakeVec(vec, line, delim) ;
0733 return vec.size() == 0 ? nullptr : new std::vector<T>(vec) ;
0734 }
0735
0736
0737
0738
0739
0740
0741
0742
0743
0744
0745
0746 template<typename T>
0747 inline long U::LoadVec(std::vector<T>& vec, const char* path_)
0748 {
0749 assert( sizeof(T) == 1 ) ;
0750
0751 const char* path = U::Resolve(path_);
0752 FILE *fp = fopen(path,"rb");
0753
0754 fseek(fp, 0L, SEEK_END);
0755 long file_size = ftell(fp);
0756 rewind(fp);
0757
0758 vec.resize(file_size);
0759
0760 long bytes_read = fread(vec.data(), sizeof(T), file_size, fp );
0761 fclose(fp);
0762 assert( file_size == bytes_read );
0763
0764 return bytes_read ;
0765 }
0766
0767
0768
0769
0770 template<typename T>
0771 inline int U::Category(const std::vector<T>& cats, const T& val )
0772 {
0773 int cat = std::distance( cats.begin(), std::find(cats.begin(), cats.end(), val ) );
0774 if( cat == int(cats.size()) ) cat = -1 ;
0775 return cat ;
0776 }
0777
0778
0779
0780
0781 inline bool U::StartsWith( const char* s, const char* q)
0782 {
0783 return s && q && strlen(q) <= strlen(s) && strncmp(s, q, strlen(q)) == 0 ;
0784 }
0785 inline bool U::Contains( const char* s, const char* q)
0786 {
0787 return s && q && strlen(q) <= strlen(s) && strstr(s, q) != nullptr ;
0788 }
0789
0790
0791
0792 template <typename T> unsigned U::NumSteps( T x0, T x1, T dx )
0793 {
0794 assert( x1 > x0 );
0795 assert( dx > T(0.) ) ;
0796
0797 unsigned ns = 0 ;
0798 for(T x=x0 ; x <= x1 ; x+=dx ) ns+=1 ;
0799 return ns ;
0800 }
0801
0802
0803 template <typename T> inline T U::To( const char* a )
0804 {
0805 std::string s(a);
0806 std::istringstream iss(s);
0807 T v ;
0808 iss >> v ;
0809 return v ;
0810 }
0811
0812
0813 template<> inline std::string U::To(const char* a )
0814 {
0815 std::string s(a);
0816 return s ;
0817 }
0818
0819
0820
0821
0822
0823 template <typename T> inline bool U::ConvertsTo( const char* a )
0824 {
0825 if( a == nullptr ) return false ;
0826 if( strlen(a) == 0) return false ;
0827 std::string s(a);
0828 std::istringstream iss(s);
0829 T v ;
0830 iss >> v ;
0831 return iss.fail() == false ;
0832 }
0833
0834
0835 inline char* U::PWD()
0836 {
0837 return getenv("PWD");
0838 }
0839
0840 template<typename T>
0841 inline std::vector<T>* U::GetEnvVec(const char* ekey, const char* fallback, char delim)
0842 {
0843 char* line = getenv(ekey);
0844 return MakeVec<T>( line ? line : fallback, delim ) ;
0845 }
0846
0847
0848 inline int U::GetEnvInt(const char* envkey, int fallback)
0849 {
0850 char* val = getenv(envkey);
0851 int ival = val ? std::atoi(val) : fallback ;
0852 return ival ;
0853 }
0854
0855
0856 inline size_t U::StringToSize(const std::string& str)
0857 {
0858 try
0859 {
0860 size_t pos;
0861 size_t result = std::stoul(str, &pos);
0862 if (pos != str.length()) throw std::invalid_argument("U::StringToSize - string contains invalid characters");
0863 return result;
0864 } catch (const std::invalid_argument&) {
0865 throw std::invalid_argument("U::StringToSize - Invalid input: not a valid number");
0866 } catch (const std::out_of_range&) {
0867 throw std::out_of_range("Number out of range for size_t");
0868 }
0869 }
0870
0871
0872 inline size_t U::GetEnvSize(const char* envkey, size_t fallback)
0873 {
0874 char* val = std::getenv(envkey);
0875 if (!val) return fallback;
0876 try
0877 {
0878 return StringToSize(val);
0879 }
0880 catch (const std::exception&)
0881 {
0882 return fallback;
0883 }
0884 }
0885
0886
0887 inline const char* U::GetEnv(const char* envkey, const char* fallback)
0888 {
0889 const char* evalue = getenv(envkey);
0890 return evalue ? evalue : fallback ;
0891 }
0892
0893 inline bool U::HasEnv(const char* envkey)
0894 {
0895 const char* evalue = getenv(envkey);
0896 return evalue ? true : false ;
0897 }
0898
0899
0900 template<typename T>
0901 inline T U::GetE(const char* ekey, T fallback)
0902 {
0903 char* v = getenv(ekey);
0904 if(v == nullptr) return fallback ;
0905
0906 std::string s(v);
0907 std::istringstream iss(s);
0908 T t ;
0909 iss >> t ;
0910 return t ;
0911 }
0912
0913 template int U::GetE(const char*, int );
0914 template unsigned U::GetE(const char*, unsigned );
0915 template float U::GetE(const char*, float );
0916 template double U::GetE(const char*, double );
0917 template char U::GetE(const char*, char );
0918 template unsigned char U::GetE(const char*, unsigned char );
0919
0920
0921
0922
0923
0924
0925
0926 inline bool U::EndsWith( const char* s, const char* q)
0927 {
0928 int pos = strlen(s) - strlen(q) ;
0929 return pos > 0 && strncmp(s + pos, q, strlen(q)) == 0 ;
0930 }
0931
0932 inline std::string U::ChangeExt( const char* s, const char* x1, const char* x2)
0933 {
0934 assert( EndsWith(s, x1) );
0935
0936 std::string st = s ;
0937 std::stringstream ss ;
0938
0939 ss << st.substr(0, strlen(s) - strlen(x1) ) ;
0940 ss << x2 ;
0941 return ss.str() ;
0942 }
0943
0944 inline std::string U::DirName( const char* path )
0945 {
0946 std::string p = path ;
0947 std::size_t pos = p.find_last_of("/") ;
0948 return pos == std::string::npos ? "" : p.substr(0, pos);
0949 }
0950
0951 inline std::string U::BaseName( const char* path )
0952 {
0953 std::string p = path ;
0954 std::size_t pos = p.find_last_of("/") ;
0955 return pos == std::string::npos ? "" : p.substr(pos+1);
0956 }
0957 inline const char* U::BaseName_( const char* path )
0958 {
0959 std::string name = BaseName(path);
0960 return strdup(name.c_str());
0961 }
0962
0963
0964
0965
0966
0967
0968
0969
0970
0971
0972
0973
0974
0975
0976
0977
0978
0979 inline std::string U::BaseName_NoSepAsis( const char* path )
0980 {
0981 std::string p = path ;
0982 std::size_t pos = p.find_last_of("/") ;
0983 return pos == std::string::npos ? p : p.substr(pos+1);
0984 }
0985 inline const char* U::BaseName_NoSepAsis_( const char* path )
0986 {
0987 std::string name = BaseName_NoSepAsis(path);
0988 return strdup(name.c_str());
0989 }
0990
0991
0992
0993
0994
0995
0996
0997
0998
0999
1000
1001
1002
1003
1004
1005 inline std::string U::FormSiblingPath0( const char* sibname , const char* dirpath )
1006 {
1007 std::stringstream ss ;
1008 std::string container = DirName(dirpath) ;
1009 ss << container << "/" << sibname ;
1010 std::string str = ss.str();
1011 return str ;
1012 }
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027 inline std::string U::FormSiblingPath( const char* sibname , const char* dirpath )
1028 {
1029 std::stringstream ss ;
1030 ss << dirpath << "_" << sibname ;
1031 std::string str = ss.str();
1032 return str ;
1033 }
1034
1035
1036 inline std::string U::FormExecutableSiblingPath( const char* argv0 , const char* dirpath )
1037 {
1038 const char* exename = BaseName_NoSepAsis_(argv0) ;
1039 std::string sibpath = FormSiblingPath( exename, dirpath );
1040
1041 if(VERBOSE) std::cout
1042 << "[U::FormExecutableSiblingPath"
1043 << std::endl
1044 << " argv0 " << ( argv0 ? argv0 : "-" )
1045 << std::endl
1046 << " dirpath " << ( dirpath ? dirpath : "-" )
1047 << std::endl
1048 << " exename " << ( exename ? exename : "-" )
1049 << std::endl
1050 << " sibpath " << sibpath
1051 << std::endl
1052 << "]U::FormExecutableSiblingPath"
1053 << std::endl
1054 ;
1055
1056 return sibpath ;
1057 }
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074 inline bool U::IsExecutableSiblingPath(const char* argv0, const char* dirpath )
1075 {
1076 const char* exename = BaseName_NoSepAsis_(argv0) ;
1077 const char* basename = BaseName_NoSepAsis_(dirpath) ;
1078 bool is_executable_sibling_path = basename && exename && EndsWith(basename, exename) && strlen(basename) > strlen(exename) ;
1079
1080 if(VERBOSE) std::cout
1081 << "[U::IsExecutableSiblingPath"
1082 << std::endl
1083 << " argv0 " << ( argv0 ? argv0 : "-" )
1084 << std::endl
1085 << " dirpath " << ( dirpath ? dirpath : "-" )
1086 << std::endl
1087 << " exename " << ( exename ? exename : "-" )
1088 << std::endl
1089 << " basename " << ( basename ? basename : "-" )
1090 << std::endl
1091 << " is_executable_sibling_path " << ( is_executable_sibling_path ? "YES" : "NO " )
1092 << "]U::IsExecutableSiblingPath"
1093 << std::endl
1094 ;
1095
1096 return is_executable_sibling_path ;
1097 }
1098
1099 inline int U::SetEnvDefaultExecutableSiblingPath(const char* ekey, char* argv0, const char* dirpath )
1100 {
1101 std::string _sibfold = FormExecutableSiblingPath(argv0, dirpath);
1102 const char* sibfold = _sibfold.empty() ? nullptr : _sibfold.c_str() ;
1103 bool overwrite = false ;
1104 int rc = setenvvar( ekey, sibfold, overwrite );
1105
1106 if(VERBOSE) std::cout
1107 << "[U::SetEnvDefaultExecutableSiblingPath"
1108 << std::endl
1109 << " ekey " << ( ekey ? ekey : "-" )
1110 << std::endl
1111 << " argv0 " << ( argv0 ? argv0 : "-" )
1112 << std::endl
1113 << " ditpath " << ( dirpath ? dirpath : "-" )
1114 << std::endl
1115 << " sibfold " << ( sibfold ? sibfold : "-" )
1116 << std::endl
1117 << " rc " << rc
1118 << std::endl
1119 << "]U::SetEnvDefaultExecutableSiblingPath"
1120 << std::endl
1121 ;
1122
1123 return rc ;
1124 }
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141 inline int U::setenvvar( const char* ekey, const char* value, bool overwrite, char special_empty_token)
1142 {
1143 std::stringstream ss ;
1144 ss << ekey << "=" ;
1145
1146 if(value)
1147 {
1148 if(special_empty_token != '\0' && strlen(value) == 1 && value[0] == special_empty_token)
1149 {
1150 ss << "" ;
1151 }
1152 else
1153 {
1154 ss << value ;
1155 }
1156 }
1157
1158 std::string ekv = ss.str();
1159 const char* prior = getenv(ekey) ;
1160
1161 char* ekv_ = const_cast<char*>(strdup(ekv.c_str()));
1162
1163 int rc = ( overwrite || !prior ) ? putenv(ekv_) : 0 ;
1164
1165 const char* after = getenv(ekey) ;
1166
1167 if(VERBOSE) std::cerr
1168 << "U::setenvvar"
1169 << " ekey " << ekey
1170 << " ekv " << ekv
1171 << " overwrite " << overwrite
1172 << " prior " << ( prior ? prior : "NULL" )
1173 << " value " << ( value ? value : "NULL" )
1174 << " after " << ( after ? after : "NULL" )
1175 << " rc " << rc
1176 << std::endl
1177 ;
1178
1179 return rc ;
1180 }
1181
1182
1183
1184
1185
1186
1187
1188
1189 template<typename ... Args>
1190 inline std::string U::Format_( const char* fmt, Args ... args )
1191 {
1192 int sz = std::snprintf( nullptr, 0, fmt, args ... ) + 1 ;
1193 assert( sz > 0 );
1194 std::vector<char> buf(sz) ;
1195 std::snprintf( buf.data(), sz, fmt, args ... );
1196 return std::string( buf.begin(), buf.begin() + sz - 1 );
1197 }
1198
1199 template std::string U::Format_( const char*, const char*, int, int );
1200 template std::string U::Format_( const char*, int );
1201 template std::string U::Format_( const char*, unsigned long long );
1202
1203
1204 template<typename ... Args>
1205 inline const char* U::Format( const char* fmt, Args ... args )
1206 {
1207 std::string str = Format_(fmt, std::forward<Args>(args)... );
1208 return strdup(str.c_str());
1209 }
1210
1211 template const char* U::Format( const char*, const char*, int, int );
1212 template const char* U::Format( const char*, int );
1213 template const char* U::Format( const char*, unsigned long long );
1214
1215
1216
1217
1218
1219
1220 inline std::string U::FormNameWithPrefix_( char prefix, int idx, int wid )
1221 {
1222 std::stringstream ss ;
1223 ss << prefix << std::setfill('0') << std::setw(wid) << idx ;
1224 std::string s = ss.str();
1225 return s ;
1226 }
1227
1228 inline const char* U::FormNameWithPrefix( char prefix, int idx, int wid )
1229 {
1230 std::string str = FormNameWithPrefix_(prefix, idx, wid) ;
1231 return strdup(str.c_str());
1232 }
1233
1234 inline std::string U::FormName_( int idx, int wid )
1235 {
1236 std::stringstream ss ;
1237 ss << std::setfill('0') << std::setw(wid) << idx ;
1238 std::string str = ss.str();
1239 return str ;
1240 }
1241 inline const char* U::FormName( int idx, int wid )
1242 {
1243 std::string str = FormName_(idx, wid) ;
1244 return strdup(str.c_str());
1245 }
1246
1247
1248 inline std::string U::FormName_( const char* prefix, int idx, const char* ext, int wid )
1249 {
1250 std::stringstream ss ;
1251 if(prefix) ss << prefix ;
1252
1253 if( wid > 0 )
1254 {
1255 ss << std::setfill('0') << std::setw(wid) << idx ;
1256 }
1257 else
1258 {
1259 ss << idx ;
1260 }
1261
1262 if(ext) ss << ext ;
1263 std::string s = ss.str();
1264 return s ;
1265 }
1266 inline const char* U::FormName( const char* prefix, int idx, const char* ext, int wid )
1267 {
1268 std::string name = FormName_(prefix, idx, ext, wid );
1269 return strdup(name.c_str());
1270 }
1271
1272
1273
1274
1275
1276 inline std::string U::FormName_( const char* prefix, const char* body, const char* ext )
1277 {
1278 std::stringstream ss ;
1279 if(prefix) ss << prefix ;
1280 if(body) ss << body ;
1281 if(ext) ss << ext ;
1282 std::string s = ss.str();
1283 return s ;
1284 }
1285 inline const char* U::FormName( const char* prefix, const char* body, const char* ext )
1286 {
1287 std::string name = FormName_(prefix, body, ext );
1288 return strdup(name.c_str());
1289 }
1290
1291
1292 inline bool U::IsIntegerString(const char* str)
1293 {
1294 if(!str) return false ;
1295 if(strlen(str)==0) return false ;
1296
1297 std::string s(str);
1298 return s.find_first_not_of("0123456789") == std::string::npos ;
1299 }
1300
1301
1302
1303
1304
1305 inline bool U::isdigit_(char c ) { return std::isdigit(static_cast<unsigned char>(c)) ; }
1306 inline bool U::isalnum_(char c ) { return std::isalnum(static_cast<unsigned char>(c)) ; }
1307 inline bool U::isupper_(char c ) { return std::isupper(static_cast<unsigned char>(c)) ; }
1308 inline bool U::islower_(char c ) { return std::islower(static_cast<unsigned char>(c)) ; }
1309
1310
1311 inline void U::Summarize( std::vector<std::string>& smry_labels, const std::vector<std::string>* labels, int wid )
1312 {
1313 int num_labels = labels ? labels->size() : 0 ;
1314 for(int i=0 ; i < num_labels ; i++)
1315 {
1316 const char* label = (*labels)[i].c_str() ;
1317 smry_labels.push_back( U::Summarize(label, wid) ) ;
1318 }
1319 }
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337 inline const char* U::Summarize( const char* label, int wid )
1338 {
1339 if(label == nullptr) return nullptr ;
1340 std::string smry = U::Summarize_(label, wid);
1341 char* _smry = const_cast<char*>(smry.c_str()) ;
1342 int len = strlen(_smry) ;
1343 if(len > wid) _smry[wid+1] = '\0' ;
1344 return strdup(_smry) ;
1345 }
1346 inline std::string U::Summarize_( const char* label, int wid )
1347 {
1348 int len = strlen(label) ;
1349 std::string str ;
1350 if( len <= wid )
1351 {
1352 str = label ;
1353 }
1354 else
1355 {
1356 std::stringstream ss ;
1357 char p = '\0' ;
1358 for(int i=0 ; i < len ; i++)
1359 {
1360 char c = label[i] ;
1361 bool take = ( p == '\0' )
1362 || ( isalnum_(c) && p == '_' )
1363 || ( isalnum_(c) && p == '_' )
1364 || ( isupper_(c) && islower_(p) )
1365 || ( p == 'P' && ( c == 'r' || c == 'o' ) )
1366 ;
1367 p = c ;
1368 if(take) ss << c ;
1369 }
1370 str = ss.str();
1371 }
1372 return str ;
1373 }
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383 inline void U::LineVector( std::vector<std::string>& lines, const char* LINES, const char* PREFIX )
1384 {
1385 std::stringstream fss(LINES);
1386 std::string _line ;
1387 while(getline(fss, _line))
1388 {
1389 const char* line = _line.c_str();
1390 size_t len = strlen(line) ;
1391 if(len==0) continue ;
1392 bool match = PREFIX == nullptr ? true : len >= strlen(PREFIX) && strncmp(line, PREFIX, strlen(PREFIX)) == 0 ;
1393 if(!match) continue ;
1394 lines.push_back(line);
1395 }
1396 }
1397
1398
1399
1400
1401
1402 inline void U::LiteralTrim( std::string& line )
1403 {
1404 const char* trim = " " ;
1405 if(strlen(line.c_str())==0) return ;
1406 line.erase(0, line.find_first_not_of(trim));
1407 line.erase(line.find_last_not_of(trim) + 1);
1408 }
1409
1410 inline void U::Literal( std::vector<std::string>& lines, const char* LINES )
1411 {
1412 std::stringstream fss(LINES);
1413 std::string line ;
1414 while(getline(fss, line))
1415 {
1416 LiteralTrim(line);
1417 if(line.size() == 0) continue ;
1418 lines.push_back(line);
1419 }
1420 }
1421
1422 inline void U::LiteralAnno( std::vector<std::string>& field, std::vector<std::string>& anno, const char* LINES, const char* delim )
1423 {
1424 std::vector<std::string> lines ;
1425 U::Literal(lines, LINES );
1426 int num_lines = lines.size();
1427 bool dump = false ;
1428
1429 if(dump) std::cout << "U::LiteralAnno num_lines " << num_lines << std::endl ;
1430
1431 for(int i=0 ; i < num_lines ; i++)
1432 {
1433 const std::string& line = lines[i] ;
1434 std::size_t pfirst = line.find_first_of(delim) ;
1435 std::size_t plast = line.find_last_of(delim) ;
1436
1437 if(dump) std::cout
1438 << " line [" << line << "]"
1439 << " pfirst " << pfirst
1440 << " plast " << plast
1441 << std::endl
1442 ;
1443
1444 if( pfirst != std::string::npos && plast != std::string::npos && plast - pfirst == 1 )
1445 {
1446 std::string _field = line.substr(0, pfirst) ;
1447 std::string _anno = line.substr(plast+1) ;
1448 LiteralTrim(_field);
1449 LiteralTrim(_anno);
1450 field.push_back( _field );
1451 anno.push_back( _anno );
1452 }
1453 else
1454 {
1455 field.push_back(line);
1456 anno.push_back("");
1457 }
1458 }
1459 }
1460
1461
1462
1463
1464
1465 inline std::string U::Space(int wid)
1466 {
1467 std::stringstream ss ;
1468 for(int i=0 ; i < wid ; i++) ss << " " ;
1469 std::string str = ss.str();
1470 return str ;
1471 }
1472
1473
1474
1475 inline std::string U::form_name(const char* stem, const char* ext)
1476 {
1477 std::stringstream ss ;
1478 ss << stem ;
1479 ss << ext ;
1480 return ss.str();
1481 }
1482 inline std::string U::form_path(const char* dir, const char* name)
1483 {
1484 std::stringstream ss ;
1485 ss << dir ;
1486 if(name) ss << "/" << name ;
1487 return ss.str();
1488 }
1489
1490 inline std::string U::form_path(const char* dir, const char* reldir, const char* name)
1491 {
1492 std::stringstream ss ;
1493 ss << dir ;
1494 if(reldir) ss << "/" << reldir ;
1495 if(name) ss << "/" << name ;
1496 return ss.str();
1497 }
1498
1499
1500
1501
1502
1503
1504
1505 template<typename ... Args>
1506 std::string U::Path_( Args ... args_ )
1507 {
1508 std::vector<const char*> args = {args_...} ;
1509
1510 std::vector<std::string> elem ;
1511 for(unsigned i=0 ; i < args.size() ; i++)
1512 {
1513 const char* arg = args[i] ;
1514 if( i == 0 && arg == nullptr ) arg = DEFAULT_PATH_ARG_0 ;
1515 if(arg) elem.push_back(arg);
1516 }
1517
1518 unsigned num_elem = elem.size() ;
1519 std::stringstream ss ;
1520 for(unsigned i=0 ; i < num_elem ; i++)
1521 {
1522 const std::string& ele = elem[i] ;
1523 ss << ele << ( i < num_elem - 1 ? "/" : "" ) ;
1524 }
1525 std::string s = ss.str();
1526
1527 return s ;
1528 }
1529
1530 template std::string U::Path_( const char*, const char* );
1531 template std::string U::Path_( const char*, const char*, const char* );
1532 template std::string U::Path_( const char*, const char*, const char*, const char* );
1533
1534 template<typename ... Args>
1535 const char* U::Path( Args ... args )
1536 {
1537 std::string s = Path_(args...) ;
1538 return strdup(s.c_str()) ;
1539 }
1540
1541 template const char* U::Path( const char*, const char* );
1542 template const char* U::Path( const char*, const char*, const char* );
1543 template const char* U::Path( const char*, const char*, const char*, const char* );
1544
1545
1546
1547
1548
1549
1550
1551 #include <cstring>
1552 #include <cstdlib>
1553 #include <cstdio>
1554 #include <sys/stat.h>
1555 #include <errno.h>
1556 #include "dirent.h"
1557
1558 inline int U::MakeDirs( const char* dirpath_, int mode_ )
1559 {
1560 mode_t default_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ;
1561 mode_t mode = mode_ == 0 ? default_mode : mode_ ;
1562
1563 char* dirpath = strdup(dirpath_);
1564 char* p = dirpath ;
1565 int rc = 0 ;
1566
1567 while (*p != '\0' && rc == 0)
1568 {
1569 p++;
1570 while(*p != '\0' && *p != '/') p++;
1571 char v = *p;
1572 *p = '\0' ;
1573
1574 rc = mkdir(dirpath, mode) == -1 && errno != EEXIST ? 1 : 0 ;
1575 *p = v;
1576 }
1577 free(dirpath);
1578 return rc ;
1579 }
1580
1581 inline int U::MakeDirsForFile( const char* filepath, int mode_ )
1582 {
1583 if(filepath == nullptr) return 1 ;
1584 std::string dirpath = U::DirName(filepath);
1585 return MakeDirs(dirpath.c_str(), mode_ );
1586 }
1587
1588 inline int U::PathType( const char* base, const char* name )
1589 {
1590 const char* path = Path(base, name);
1591 return PathType(path) ;
1592 }
1593 inline int U::PathType( const char* path )
1594 {
1595 int rc = ERROR_PATH ;
1596 struct stat st ;
1597 if(0 == stat(path, &st))
1598 {
1599 if( S_ISDIR(st.st_mode)) rc = DIR_PATH ;
1600 else if(S_ISREG(st.st_mode)) rc = FILE_PATH ;
1601 else rc = OTHER_PATH ;
1602 }
1603 return rc ;
1604 }
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618 inline void U::DirList(
1619 std::vector<std::string>& names,
1620 const char* _path,
1621 const char* ext,
1622 bool exclude,
1623 bool allow_nonexisting
1624 )
1625 {
1626 const char* path = Resolve(_path);
1627
1628 DIR* dir = opendir(path) ;
1629 if(!dir && allow_nonexisting) return ;
1630 if(!dir) std::cout << "U::DirList FAILED TO OPEN DIR " << ( path ? path : "-" ) << std::endl ;
1631 if(!dir && RAISE) std::raise(SIGINT) ;
1632 if(!dir) return ;
1633 struct dirent* entry ;
1634 while ((entry = readdir(dir)) != nullptr)
1635 {
1636 const char* name = entry->d_name ;
1637 bool dot_name = strcmp(name,".") == 0 || strcmp(name,"..") == 0 ;
1638 if(dot_name) continue ;
1639
1640 bool ext_match = ext == nullptr ? true : ( strlen(name) > strlen(ext) && strcmp(name + strlen(name) - strlen(ext), ext)==0) ;
1641 if(ext_match == true && exclude == false) names.push_back(name);
1642 if(ext_match == false && exclude == true) names.push_back(name);
1643 }
1644 closedir (dir);
1645 std::sort( names.begin(), names.end() );
1646
1647 if(names.size() == 0 ) std::cout
1648 << "U::DirList"
1649 << " path " << ( path ? path : "-" )
1650 << " ext " << ( ext ? ext : "-" )
1651 << " NO ENTRIES FOUND "
1652 << " exclude " << exclude
1653 << std::endl
1654 ;
1655 }
1656
1657 inline void U::Trim(std::vector<std::string>& names, const char* ext)
1658 {
1659 for(int i=0 ; i < int(names.size()) ; i++)
1660 {
1661 std::string& name = names[i];
1662 const char* n = name.c_str();
1663 bool ends_with_ext = strlen(n) > strlen(ext) && strncmp(n + strlen(n) - strlen(ext), ext, strlen(ext) ) == 0 ;
1664 if(!ends_with_ext) std::cerr << "U::Trim NOT ends_with_ext " << std::endl ;
1665 assert( ends_with_ext );
1666 name = name.substr(0, strlen(n) - strlen(ext));
1667 }
1668 }
1669
1670 inline void U::Split(const char* str, char delim, std::vector<std::string>& elem)
1671 {
1672 std::stringstream ss;
1673 ss.str(str) ;
1674 std::string s;
1675 while (std::getline(ss, s, delim)) elem.push_back(s) ;
1676 }
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698 inline bool U::prefix_suffix( char** pfx, char** sfx, const char* start_sfx, const char* str )
1699 {
1700 if(!str || !start_sfx) return false ;
1701
1702 *pfx = strdup(str);
1703 char* p = strstr(*pfx, start_sfx);
1704
1705 bool has_suffix = p && (p > *pfx) ;
1706 if(has_suffix)
1707 {
1708 *sfx = strdup(p);
1709 p[0] = '\0' ;
1710 }
1711 return has_suffix ;
1712 }
1713
1714
1715
1716 inline int U::FindIndex(const std::vector<std::string>& names, const char* name)
1717 {
1718 size_t idx = std::distance( names.begin(), std::find( names.begin(), names.end(), name ));
1719 return idx >= names.size() ? -1 : int(idx) ;
1720 }
1721
1722
1723
1724
1725
1726 inline std::string U::Desc(const std::vector<std::string>& names)
1727 {
1728 std::stringstream ss ;
1729 for(unsigned i=0 ; i < names.size() ; i++) ss << "[" << names[i] << "]" << std::endl ;
1730 std::string s = ss.str();
1731 return s ;
1732 }
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748 inline const char* U::Resolve0(const char* spec_, const char* relp_)
1749 {
1750 if(spec_ == nullptr) return nullptr ;
1751
1752 std::string spec_relp = form_path(spec_, relp_);
1753 char* spec = strdup(spec_relp.c_str()) ;
1754
1755 std::stringstream ss ;
1756 if( spec[0] == '$' )
1757 {
1758 char* sep = strchr(spec, '/');
1759 char* end = strchr(spec, '\0' );
1760 bool tok_plus = sep && end && sep != end ;
1761 if(tok_plus) *sep = '\0' ;
1762 char* pfx = getenv(spec+1) ;
1763 if(pfx == nullptr) return nullptr ;
1764 if(tok_plus) *sep = '/' ;
1765 ss << pfx << ( sep ? sep : "" ) ;
1766 }
1767 else
1768 {
1769 ss << spec ;
1770 }
1771
1772 std::string str = ss.str();
1773 const char* path = str.c_str();
1774 return strdup(path) ;
1775 }
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796 inline const char* U::Resolve(const char* spec_, const char* rel1_, const char* rel2_ )
1797 {
1798 if(spec_ == nullptr) return nullptr ;
1799 std::string spec_relp = form_path(spec_, rel1_, rel2_ );
1800 char* spec = strdup(spec_relp.c_str()) ;
1801
1802 std::stringstream ss ;
1803 int speclen = int(strlen(spec)) ;
1804 char* end = strchr(spec, '\0' );
1805 int i = 0 ;
1806
1807 if(VERBOSE) std::cout << " spec " << spec << " speclen " << speclen << std::endl ;
1808
1809 while( i < speclen )
1810 {
1811 if(VERBOSE) std::cout << " i " << i << " spec[i] " << spec[i] << std::endl ;
1812 if( spec[i] == '$' )
1813 {
1814 char* p = spec + i ;
1815 char* sep = strchr( p, '/' ) ;
1816 bool tok_plus = sep && end && sep != end ;
1817 if(tok_plus) *sep = '\0' ;
1818 char* val = getenv(p+1) ;
1819 int toklen = int(strlen(p)) ;
1820 if(VERBOSE) std::cout << " toklen " << toklen << std::endl ;
1821 if(val == nullptr)
1822 {
1823 std::cerr
1824 << "U::Resolve token ["
1825 << p+1
1826 << "] does not resolve "
1827 << std::endl
1828 ;
1829 return nullptr ;
1830 }
1831 if(tok_plus) *sep = '/' ;
1832 ss << val ;
1833
1834 i += toklen ;
1835 }
1836 else
1837 {
1838 ss << spec[i] ;
1839 i += 1 ;
1840 }
1841 }
1842 std::string str = ss.str();
1843 const char* path = str.c_str();
1844 return strdup(path) ;
1845 }
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855 inline void U::WriteString( const char* dir, const char* reldir, const char* name, const char* str )
1856 {
1857 std::string path = form_path(dir, reldir, name);
1858 WriteString(path.c_str(), str);
1859 }
1860
1861 inline void U::WriteString( const char* dir, const char* name, const char* str )
1862 {
1863 std::string path = form_path(dir, name);
1864 WriteString(path.c_str(), str);
1865 }
1866
1867 inline void U::WriteString( const char* path, const char* str )
1868 {
1869 if(str == nullptr) return ;
1870
1871 MakeDirsForFile(path);
1872
1873 std::ofstream fp(path, std::ios::out);
1874 fp << str ;
1875 fp.close();
1876 }
1877
1878
1879 inline const char* U::ReadString( const char* dir, const char* reldir, const char* name)
1880 {
1881 std::string path = form_path(dir, reldir, name);
1882 return ReadString(path.c_str());
1883 }
1884
1885 inline const char* U::ReadString( const char* dir, const char* name)
1886 {
1887 std::string path = form_path(dir, name);
1888 return ReadString(path.c_str());
1889 }
1890
1891
1892 inline std::string U::ReadString_( const char* path_ )
1893 {
1894 const char* path = Resolve(path_);
1895 std::vector<std::string> lines ;
1896 std::string line ;
1897 std::ifstream ifs(path);
1898 while(std::getline(ifs, line)) lines.push_back(line);
1899 unsigned num_lines = lines.size();
1900 std::stringstream ss ;
1901 for(unsigned i=0 ; i < num_lines ; i++)
1902 {
1903 ss << lines[i] ;
1904 if( i < num_lines - 1 ) ss << std::endl ;
1905 }
1906 std::string str = ss.str();
1907 return str ;
1908 }
1909
1910 inline const char* U::ReadString( const char* path_ )
1911 {
1912 std::string str = ReadString_(path_);
1913 return str.empty() ? nullptr : strdup(str.c_str()) ;
1914 }
1915
1916
1917 inline std::string U::ReadString2_(const char* path_)
1918 {
1919 const char* path = Resolve(path_);
1920 std::ifstream ifs(path);
1921 std::stringstream ss ;
1922 ss << ifs.rdbuf();
1923 std::string str = ss.str();
1924 return str ;
1925 }
1926
1927 inline const char* U::ReadString2(const char* path_)
1928 {
1929 std::string str = ReadString2_(path_);
1930 return str.empty() ? nullptr : strdup(str.c_str()) ;
1931 }
1932
1933
1934 inline uint64_t U::Now()
1935 {
1936
1937 using Clock = std::chrono::system_clock;
1938 using Unit = std::chrono::microseconds ;
1939 std::chrono::time_point<Clock> t0 = Clock::now();
1940 return std::chrono::duration_cast<Unit>(t0.time_since_epoch()).count() ;
1941 }
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963 inline bool U::LooksLikeStampInt(const char* str)
1964 {
1965 int length = strlen(str) ;
1966 int digits = 0 ;
1967 for(int i=0 ; i < length ; i++) if(str[i] >= '0' && str[i] <= '9') digits += 1 ;
1968 return length == 16 && digits == length ;
1969 }
1970
1971
1972 template<typename T>
1973 inline bool U::LooksLikeTimestamp( T value )
1974 {
1975 return sizeof(T) == 8 && value > 1700000000000000 ;
1976 }
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991 inline bool U::LooksLikeProfileTriplet(const char* str)
1992 {
1993 int len = str ? int(strlen(str)) : 0 ;
1994 int count_delim = 0 ;
1995 int count_non_digit = 0 ;
1996 int first_field_digits = 0 ;
1997
1998 for(int i=0 ; i < len ; i++ )
1999 {
2000 char c = str[i] ;
2001 bool is_digit = c >= '0' && c <= '9' ;
2002 bool is_delim = c == ',' ;
2003 if(!is_digit) count_non_digit += 1 ;
2004 if(count_delim == 0 && is_digit ) first_field_digits += 1 ;
2005 if(is_delim) count_delim += 1 ;
2006 }
2007 bool heuristic = count_delim == 2 && count_non_digit == count_delim && first_field_digits == 16 ;
2008 return heuristic ;
2009 }
2010
2011
2012 inline std::string U::FormatLog(const char* msg)
2013 {
2014 std::string line = U::Format(0, LOG_FMT, 3);
2015 if(msg)
2016 {
2017 line += " " ;
2018 line += msg ;
2019 }
2020 return line ;
2021 }
2022
2023 inline std::string U::Log(const char* msg)
2024 {
2025 std::string line = U::Format(0, LOG_FMT, 3);
2026 if(msg)
2027 {
2028 line += " " ;
2029 line += msg ;
2030 }
2031 return line ;
2032 }
2033
2034
2035
2036 inline std::string U::Format(uint64_t t, const char* fmt, int _wsubsec)
2037 {
2038
2039 if(t == 0) t = Now() ;
2040 using Clock = std::chrono::system_clock;
2041 using Unit = std::chrono::microseconds ;
2042 std::chrono::time_point<Clock> tp{Unit{t}} ;
2043
2044 std::time_t tt = Clock::to_time_t(tp);
2045
2046 std::stringstream ss ;
2047 ss << std::put_time(std::localtime(&tt), fmt ) ;
2048
2049 if(_wsubsec == 3 || _wsubsec == 6)
2050 {
2051
2052 auto subsec = std::chrono::duration_cast<Unit>(tp.time_since_epoch()) % std::chrono::seconds{1};
2053 auto count = subsec.count() ;
2054 if( _wsubsec == 3 ) count /= 1000 ;
2055 ss << "." << std::setfill('0') << std::setw(_wsubsec) << count ;
2056 }
2057
2058 std::string str = ss.str();
2059 return str ;
2060 }
2061
2062 inline std::string U::FormatInt(int64_t t, int wid )
2063 {
2064 std::stringstream ss ;
2065 ss.imbue(std::locale("")) ;
2066
2067 if( t > -1 ) ss << std::setw(wid) << t ;
2068 else ss << std::setw(wid) << "" ;
2069 std::string str = ss.str();
2070 return str ;
2071 }
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086 inline char* U::LastDigit(const char* str)
2087 {
2088 if(str == nullptr) return nullptr ;
2089 char* s = const_cast<char*>(str);
2090 bool first_char_is_digit = *s >= '0' && *s <= '9' ;
2091 char* p = s+strlen(s)-1 ;
2092 while( p > s )
2093 {
2094 if( *p >= '0' && *p <= '9' ) break ;
2095 p-- ;
2096 }
2097
2098 return p == s && first_char_is_digit == false ? nullptr : p ;
2099 }
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115 inline char* U::FirstDigit(const char* str)
2116 {
2117 if(str == nullptr) return nullptr ;
2118 char* s = const_cast<char*>(str);
2119 char* p = s ;
2120 while( *p )
2121 {
2122 if( *p >= '0' && *p <= '9' ) break ;
2123 p++ ;
2124 }
2125 return *p == '\0' ? nullptr : p ;
2126 }
2127
2128 inline char* U::FirstToLastDigit(const char* str)
2129 {
2130 const char* s = strdup(str);
2131 char* f = FirstDigit(s);
2132 char* l = LastDigit(s);
2133
2134 bool no_f = f == nullptr ;
2135 bool no_l = l == nullptr ;
2136
2137 if( no_f && no_l ) return nullptr ;
2138 if( no_f && !no_l ) assert(0) ;
2139 if( !no_f && no_l ) assert(0) ;
2140
2141 char* r = nullptr ;
2142 if( l + 1 > f)
2143 {
2144 if(*(l+1) != '\0') *(l+1) = '\0' ;
2145 r = f ;
2146 }
2147 return r ;
2148 }
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166 inline void U::GetMetaKVS_(
2167 const char* metadata,
2168 std::vector<std::string>* keys,
2169 std::vector<std::string>* vals,
2170 std::vector<int64_t>* stamps,
2171 bool only_with_stamp )
2172 {
2173 if(metadata == nullptr) return ;
2174 std::stringstream ss;
2175 ss.str(metadata);
2176 std::string s;
2177 char delim = ':' ;
2178
2179 while (std::getline(ss, s))
2180 {
2181 size_t pos = s.find(delim);
2182 if( pos != std::string::npos )
2183 {
2184 std::string _k = s.substr(0, pos);
2185 std::string _v = s.substr(pos+1);
2186 const char* k = _k.c_str();
2187 const char* v = _v.c_str();
2188 bool disqualify_key = strlen(k) > 0 && k[0] == '_' ;
2189 bool looks_like_stamp = U::LooksLikeStampInt(v);
2190 bool looks_like_prof = U::LooksLikeProfileTriplet(v);
2191 int64_t t = 0 ;
2192 if(looks_like_stamp) t = U::To<int64_t>(v) ;
2193 if(looks_like_prof) t = strtoll(v, nullptr, 10);
2194 bool select = only_with_stamp ? ( t > 0 && !disqualify_key ) : true ;
2195 if(!select) continue ;
2196
2197 if(keys) keys->push_back(k);
2198 if(vals) vals->push_back(v);
2199 if(stamps) stamps->push_back(t);
2200 }
2201 }
2202 }
2203
2204
2205
2206
2207
2208
2209
2210
2211 inline void U::GetMetaKVS( const std::string& meta, std::vector<std::string>* keys, std::vector<std::string>* vals, std::vector<int64_t>* stamps, bool only_with_stamp )
2212 {
2213 const char* metadata = meta.empty() ? nullptr : meta.c_str() ;
2214 return GetMetaKVS_( metadata, keys, vals, stamps, only_with_stamp );
2215 }
2216
2217
2218
2219 inline void U::KeyIndices( std::vector<int>& indices, const std::vector<std::string>& keys, const char* key )
2220 {
2221 for(int i=0 ; i < int(keys.size()) ; i++) if(strcmp(keys[i].c_str(), key) == 0) indices.push_back(i);
2222 }
2223
2224 inline int U::KeyIndex( const std::vector<std::string>& keys, const char* key )
2225 {
2226 int ikey = std::distance( keys.begin(), std::find(keys.begin(), keys.end(), key )) ;
2227 return ikey == int(keys.size()) ? -1 : ikey ;
2228 }
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241 inline int U::FormattedKeyIndex( std::string& fkey, const std::vector<std::string>& keys, const char* key, int idx0, int idx1 )
2242 {
2243 int k = -1 ;
2244 if( strchr(key,'%') == nullptr )
2245 {
2246 fkey = key ;
2247 k = KeyIndex(keys, key ) ;
2248 }
2249 else
2250 {
2251 const int N = 100 ;
2252 char keybuf[N] ;
2253 for( int idx=idx0 ; idx < idx1 ; idx++)
2254 {
2255 int n = snprintf(keybuf, N, key, idx ) ;
2256 if(!(n < N)) std::cerr << "U::FormattedKeyIndex ERR n " << n << std::endl ;
2257 assert( n < N );
2258 k = KeyIndex(keys, keybuf ) ;
2259 if( k > -1 )
2260 {
2261 fkey = keybuf ;
2262 break ;
2263 }
2264 }
2265 }
2266 return k ;
2267 }
2268
2269
2270 inline void U::SplitTuple( std::vector<std::string>& keys, std::vector<int64_t>& tt, const std::vector<std::tuple<std::string, int64_t>>& kt )
2271 {
2272 for(int i=0 ; i < int(kt.size()) ; i++)
2273 {
2274 keys.push_back(std::get<0>(kt[i]));
2275 tt.push_back(std::get<1>(kt[i]));
2276 }
2277 }
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303 struct NPU
2304 {
2305 typedef std::int64_t INT ;
2306
2307 static constexpr char* MAGIC = (char*)"\x93NUMPY" ;
2308 static constexpr bool FORTRAN_ORDER = false ;
2309
2310 template<typename T>
2311 static std::string make_header(const std::vector<INT>& shape );
2312
2313 template<typename T>
2314 static std::string make_jsonhdr(const std::vector<INT>& shape );
2315
2316 static void parse_header(std::vector<INT>& shape, std::string& descr, char& uifc, INT& ebyte, const std::string& hdr );
2317 static int _parse_header_length(const std::string& hdr );
2318 static void _parse_tuple(std::vector<INT>& shape, const std::string& sh );
2319 static void _parse_dict(bool& little_endian, char& uifc, INT& width, std::string& descr, bool& fortran_order, const char* dict);
2320 static void _parse_dict(std::string& descr, bool& fortran_order, const char* dict);
2321 static void _parse_descr(bool& little_endian, char& uifc, INT& width, const char* descr);
2322
2323 static NPU::INT _dtype_ebyte(const char* dtype);
2324 static char _dtype_uifc(const char* dtype);
2325
2326 static std::string _make_descr(bool little_endian, char uifc, INT width );
2327 static std::string _make_narrow(const char* descr);
2328 static std::string _make_wide(const char* descr);
2329 static std::string _make_other(const char* descr, char other);
2330
2331 static std::string _make_preamble( INT major=1, INT minor=0 );
2332 static std::string _make_header(const std::vector<INT>& shape, const char* descr="<f4" );
2333 static std::string _make_jsonhdr(const std::vector<INT>& shape, const char* descr="<f4" );
2334 static std::string _little_endian_short_string( uint16_t dlen ) ;
2335 static std::string _make_tuple(const std::vector<INT>& shape, bool json );
2336 static std::string _make_dict(const std::vector<INT>& shape, const char* descr );
2337 static std::string _make_json(const std::vector<INT>& shape, const char* descr );
2338 static std::string _make_header(const std::string& dict);
2339 static std::string _make_jsonhdr(const std::string& json);
2340
2341 static std::string xxdisplay(const std::string& hdr, INT width, char non_printable );
2342 static std::string _check(const char* path);
2343 static int check(const char* path);
2344 static bool is_readable(const char* path);
2345 };
2346
2347 template<typename T>
2348 inline std::string NPU::make_header(const std::vector<INT>& shape )
2349 {
2350
2351 std::string descr = descr_<T>::dtype() ;
2352
2353 return _make_header( shape, descr.c_str() ) ;
2354 }
2355
2356 template<typename T>
2357 inline std::string NPU::make_jsonhdr(const std::vector<INT>& shape )
2358 {
2359
2360 std::string descr = descr_<T>::dtype() ;
2361 return _make_jsonhdr( shape, descr.c_str() ) ;
2362 }
2363
2364 inline std::string NPU::xxdisplay(const std::string& hdr, INT width, char non_printable)
2365 {
2366 std::stringstream ss ;
2367 for(unsigned i=0 ; i < hdr.size() ; i++)
2368 {
2369 char c = hdr[i] ;
2370 bool printable = c >= ' ' && c <= '~' ;
2371 ss << ( printable ? c : non_printable ) ;
2372 if((i+1) % width == 0 ) ss << "\n" ;
2373 }
2374 return ss.str();
2375 }
2376
2377 inline int NPU::_parse_header_length(const std::string& hdr )
2378 {
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446 std::string preamble = hdr.substr(0,8) ;
2447 std::string PREAMBLE = _make_preamble();
2448 assert( preamble.compare(PREAMBLE) == 0 );
2449
2450
2451
2452
2453
2454
2455
2456 unsigned char hlen_lsb = hdr[8] ;
2457 unsigned char hlen_msb = hdr[9] ;
2458 int hlen = hlen_msb << 8 | hlen_lsb ;
2459
2460 #ifdef NPU_DEBUG
2461 std::cout
2462 << " _parse_header_length " << std::endl
2463 << " hdr " << std::endl << xxdisplay(hdr, 16, '.' ) << std::endl
2464 << " preamble " << preamble << std::endl
2465 << " hlen_lsb(hex) " << std::hex << int(hlen_lsb) << std::endl
2466 << " hlen_msb(hex) " << std::hex << int(hlen_msb) << std::endl
2467 << " hlen(hex) " << std::hex << hlen << std::endl
2468 << " hlen_lsb(dec) " << std::dec << int(hlen_lsb) << std::endl
2469 << " hlen_msb(dec) " << std::dec << int(hlen_msb) << std::endl
2470 << " hlen(dec) " << std::dec << hlen << std::endl
2471 << " hlen+10(dec) " << std::dec << hlen+10 << std::endl
2472 << " (hlen+10)%16(dec) " << (hlen+10)%16 << std::endl
2473 << " hdr.size() (dec) " << std::dec << hdr.size() << std::endl
2474 << " preamble.size() " << std::dec << preamble.size() << std::endl
2475 << std::endl
2476 ;
2477
2478 #endif
2479 assert( hlen > 0 );
2480 assert( (hlen+10) % 16 == 0 ) ;
2481 assert( hlen+10 == int(hdr.size()) ) ;
2482
2483 return hlen ;
2484 }
2485
2486
2487 inline void NPU::parse_header(std::vector<INT>& shape, std::string& descr, char& uifc, INT& ebyte, const std::string& hdr )
2488 {
2489 int hlen = _parse_header_length( hdr ) ;
2490
2491 std::string dict = hdr.substr(10,10+hlen) ;
2492
2493 char last = dict[dict.size()-1] ;
2494 bool ends_with_newline = last == '\n' ;
2495 if(!ends_with_newline) std::cerr << "NPU::parse_header UNEXPECTED ends_with_newline " << std::endl ;
2496 assert(ends_with_newline) ;
2497 dict[dict.size()-1] = '\0' ;
2498
2499 std::string::size_type p0 = dict.find("(") + 1;
2500 std::string::size_type p1 = dict.find(")");
2501 assert( p0 != std::string::npos );
2502 assert( p1 != std::string::npos );
2503
2504 std::string sh = dict.substr( p0, p1 - p0 ) ;
2505
2506 _parse_tuple( shape, sh );
2507
2508
2509 bool little_endian ;
2510 bool fortran_order ;
2511
2512 _parse_dict(little_endian, uifc, ebyte, descr, fortran_order, dict.c_str());
2513
2514
2515 assert( fortran_order == FORTRAN_ORDER );
2516 assert( little_endian == true );
2517
2518 #ifdef NPU_DEBUG
2519 std::cout
2520 << " parse_header " << std::endl
2521 << " hdr " << std::endl << xxdisplay(hdr, 16, '.' ) << std::endl
2522 << " hlen(hex) " << std::hex << hlen << std::endl
2523 << " hlen(dec) " << std::dec << hlen << std::endl
2524 << " hlen+10(dec) " << std::dec << hlen+10 << std::endl
2525 << " (hlen+10)%16(dec) " << (hlen+10)%16 << std::endl
2526 << " dict [" << xxdisplay(dict,200,'.') << "]"<< std::endl
2527 << " p0( " << p0 << std::endl
2528 << " p1) " << p1 << std::endl
2529 << " shape " << sh << std::endl
2530 << " last(dec) " << std::dec << int(last) << std::endl
2531 << " newline(dec) " << std::dec << int('\n') << std::endl
2532 << " hdr.size() (dec) " << std::dec << hdr.size() << std::endl
2533 << " dict.size() (dec) " << std::dec << dict.size() << std::endl
2534 << " descr " << descr
2535 << " uifc " << uifc
2536 << " ebyte " << ebyte
2537 << std::endl
2538 ;
2539
2540 #endif
2541
2542 }
2543
2544 inline void NPU::_parse_tuple(std::vector<INT>& shape, const std::string& sh )
2545 {
2546 std::istringstream f(sh);
2547 std::string s;
2548
2549 char delim = ',' ;
2550 const char* trim = " " ;
2551
2552 INT ival(0) ;
2553
2554 while (getline(f, s, delim))
2555 {
2556 s.erase(0, s.find_first_not_of(trim));
2557 s.erase(s.find_last_not_of(trim) + 1);
2558 if( s.size() == 0 ) continue ;
2559
2560 std::istringstream ic(s) ;
2561 ic >> ival ;
2562
2563 shape.push_back(ival) ;
2564
2565 #ifdef NPU_DEBUG
2566 std::cout << "[" << s << "] -> " << ival << std::endl ;
2567 #endif
2568
2569 }
2570
2571 #ifdef NPU_DEBUG
2572 std::cout << " parse_tuple "
2573 << " sh [" << sh << "]"
2574 << " shape " << shape.size()
2575 << std::endl
2576 ;
2577
2578 #endif
2579 }
2580
2581
2582 inline void NPU::_parse_dict(bool& little_endian, char& uifc, INT& ebyte, std::string& descr, bool& fortran_order, const char* dict)
2583 {
2584 _parse_dict(descr, fortran_order, dict);
2585 _parse_descr(little_endian, uifc, ebyte, descr.c_str() );
2586 }
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601 inline void NPU::_parse_dict(std::string& descr, bool& fortran_order, const char* dict)
2602 {
2603 char q = '\'' ;
2604 char x = '\0' ;
2605
2606 std::vector<std::string> elem ;
2607 std::stringstream ss ;
2608 unsigned nq = 0 ;
2609 for(unsigned i=0 ; i < strlen(dict) ; i++)
2610 {
2611 if(dict[i] == q || dict[i] == x)
2612 {
2613 nq += 1 ;
2614 if(nq == 6 ) x = ' ' ;
2615 if(nq == 7 ) x = ',' ;
2616 if(nq == 8 ) x = '\0' ;
2617
2618 if( nq % 2 == 0 )
2619 {
2620 elem.push_back(ss.str());
2621 ss.str("");
2622 }
2623 }
2624 else
2625 {
2626 if(nq % 2 == 1 ) ss << dict[i] ;
2627 }
2628 }
2629
2630 assert( elem[0].compare("descr") == 0 );
2631 assert( elem[2].compare("fortran_order") == 0 );
2632 assert( elem[3].compare("False") == 0 || elem[3].compare("True") == 0);
2633 assert( elem[4].compare("shape") == 0 );
2634
2635 descr = elem[1];
2636 assert( descr.length() == 3 );
2637
2638 fortran_order = elem[3].compare("False") == 0 ? false : true ;
2639 }
2640
2641 inline void NPU::_parse_descr(bool& little_endian, char& uifc, INT& ebyte, const char* descr)
2642 {
2643 assert( strlen(descr) == 3 );
2644
2645 char c_endian = descr[0] ;
2646 char c_uifc = descr[1] ;
2647 char c_ebyte = descr[2] ;
2648
2649 bool expect_endian = c_endian == '<' || c_endian == '>' || c_endian == '|' ;
2650 if(!expect_endian)
2651 {
2652 std::cerr
2653 << "unexpected endian "
2654 << " c_endian " << c_endian
2655 << " descr [" << descr << "]"
2656 << std::endl
2657 ;
2658 }
2659 assert( expect_endian );
2660 little_endian = c_endian == '<' || c_endian == '|' ;
2661
2662 assert( c_uifc == 'u' || c_uifc == 'i' || c_uifc == 'f' || c_uifc == 'c' );
2663 uifc = c_uifc ;
2664
2665 ebyte = c_ebyte - '0' ;
2666 assert( ebyte == 1 || ebyte == 2 || ebyte == 4 || ebyte == 8 );
2667 }
2668
2669 inline NPU::INT NPU::_dtype_ebyte(const char* dtype)
2670 {
2671 unsigned len = strlen(dtype) ;
2672 assert( len == 2 || len == 3 );
2673
2674 char c_ebyte = dtype[len-1] ;
2675 INT ebyte = c_ebyte - '0' ;
2676
2677 assert( ebyte == 1 || ebyte == 2 || ebyte == 4 || ebyte == 8 );
2678 return ebyte ;
2679 }
2680 inline char NPU::_dtype_uifc(const char* dtype)
2681 {
2682 unsigned len = strlen(dtype) ;
2683 assert( len == 2 || len == 3 );
2684 char c_uifc = dtype[len-2] ;
2685 assert( c_uifc == 'u' || c_uifc == 'i' || c_uifc == 'f' );
2686 return c_uifc ;
2687 }
2688
2689 inline std::string NPU::_make_descr(bool little_endian, char uifc, INT width )
2690 {
2691 std::stringstream ss ;
2692 ss << ( little_endian ? '<' : '>' ) << uifc << width ;
2693 return ss.str();
2694 }
2695
2696 inline std::string NPU::_make_narrow(const char* descr)
2697 {
2698 bool little_endian ;
2699 char uifc ;
2700 INT ebyte ;
2701 _parse_descr( little_endian, uifc, ebyte, descr );
2702 return _make_descr(little_endian, uifc, ebyte/2 );
2703 }
2704
2705 inline std::string NPU::_make_wide(const char* descr)
2706 {
2707 bool little_endian ;
2708 char uifc ;
2709 INT ebyte ;
2710 _parse_descr( little_endian, uifc, ebyte, descr );
2711 return _make_descr(little_endian, uifc, ebyte*2 );
2712 }
2713
2714
2715 inline std::string NPU::_make_other(const char* descr, char other)
2716 {
2717 bool little_endian ;
2718 char uifc ;
2719 INT ebyte ;
2720 _parse_descr( little_endian, uifc, ebyte, descr );
2721 return _make_descr(little_endian, other, ebyte );
2722 }
2723
2724
2725
2726
2727 inline bool NPU::is_readable(const char* path)
2728 {
2729 std::ifstream fp(path, std::ios::in|std::ios::binary);
2730 bool readable = !fp.fail();
2731 fp.close();
2732 return readable ;
2733 }
2734
2735
2736 inline std::string NPU::_check(const char* path)
2737 {
2738 char* py = getenv("PYTHON");
2739 std::stringstream ss ;
2740 ss << ( py ? py : "python" )
2741 << " -c \"import numpy as np ; print(np.load('"
2742 << path
2743 << "')) \" && xxd "
2744 << path
2745 ;
2746 return ss.str();
2747 }
2748
2749 inline int NPU::check(const char* path)
2750 {
2751 std::string cmd = _check(path);
2752 return system(cmd.c_str());
2753 }
2754
2755
2756
2757 inline std::string NPU::_make_header(const std::vector<INT>& shape, const char* descr )
2758 {
2759 std::string dict = _make_dict( shape, descr );
2760 std::string header = _make_header( dict );
2761 return header ;
2762 }
2763
2764 inline std::string NPU::_make_jsonhdr(const std::vector<INT>& shape, const char* descr )
2765 {
2766 std::string json = _make_json( shape, descr );
2767 return json ;
2768 }
2769
2770
2771
2772 inline std::string NPU::_make_dict(const std::vector<INT>& shape, const char* descr )
2773 {
2774 std::stringstream ss ;
2775 ss << "{" ;
2776 ss << "'descr': '" << descr << "', " ;
2777 ss << "'fortran_order': " << ( FORTRAN_ORDER ? "True" : "False" ) << ", " ;
2778 ss << "'shape': " ;
2779 bool json = false ;
2780 ss << _make_tuple( shape, json ) ;
2781 ss << "}" ;
2782 return ss.str();
2783 }
2784
2785 inline std::string NPU::_make_json(const std::vector<INT>& shape, const char* descr )
2786 {
2787 std::stringstream ss ;
2788 ss << "{" ;
2789 ss << "\"descr\": \"" << descr << "\", " ;
2790 ss << "\"fortran_order\": " << ( FORTRAN_ORDER ? "true" : "false" ) << ", " ;
2791 ss << "\"shape\": " ;
2792 bool json = true ;
2793 ss << _make_tuple( shape, json) ;
2794 ss << "}" ;
2795 return ss.str();
2796 }
2797
2798
2799
2800
2801 inline std::string NPU::_make_tuple( const std::vector<INT>& shape, bool json )
2802 {
2803 INT ndim = shape.size() ;
2804 std::stringstream ss ;
2805 ss << ( json ? "[" : "(" ) ;
2806
2807 if( ndim == 1)
2808 {
2809 ss << shape[0] << "," ;
2810 }
2811 else
2812 {
2813 for(INT i=0 ; i < ndim ; i++ ) ss << shape[i] << ( i == ndim - 1 ? "" : ", " ) ;
2814 }
2815 ss << ( json ? "] " : "), " ) ;
2816 return ss.str();
2817 }
2818
2819
2820 inline std::string NPU::_little_endian_short_string( uint16_t dlen )
2821 {
2822
2823
2824
2825 union u16c2_t {
2826 uint16_t u16 ;
2827 char c[2] ;
2828 };
2829
2830 u16c2_t len ;
2831 len.u16 = dlen ;
2832
2833 char e = endian::detect() ;
2834 std::string hlen(2, ' ') ;
2835 hlen[0] = e == endian::LITTLE ? len.c[0] : len.c[1] ;
2836 hlen[1] = e == endian::LITTLE ? len.c[1] : len.c[0] ;
2837
2838 #ifdef NPU_DEBUG
2839 std::cout << " dlen " << dlen << std::endl ;
2840 std::cout << " len.c[0] " << len.c[0] << std::endl ;
2841 std::cout << " len.c[1] " << len.c[1] << std::endl ;
2842 std::cout << ( e == endian::LITTLE ? "little_endian" : "big_endian" ) << std::endl ;
2843 #endif
2844
2845 return hlen ;
2846 }
2847
2848
2849 inline std::string NPU::_make_preamble( INT major, INT minor )
2850 {
2851 std::string preamble(MAGIC) ;
2852 preamble.push_back((char)major);
2853 preamble.push_back((char)minor);
2854 return preamble ;
2855 }
2856
2857 inline std::string NPU::_make_header(const std::string& dict)
2858 {
2859 uint16_t dlen = dict.size() ;
2860 uint16_t padding = 16 - ((10 + dlen ) % 16 ) - 1 ;
2861 padding += 3*16 ;
2862 uint16_t hlen = dlen + padding + 1 ;
2863
2864 #ifdef NPU_DEBUG
2865 std::cout
2866 << " dlen " << dlen
2867 << " padding " << padding
2868 << " hlen " << hlen
2869 << std::endl
2870 ;
2871 #endif
2872
2873 assert( (hlen + 10) % 16 == 0 );
2874 std::stringstream ss ;
2875 ss << _make_preamble() ;
2876 ss << _little_endian_short_string( hlen ) ;
2877 ss << dict ;
2878
2879 for(INT i=0 ; i < padding ; i++ ) ss << " " ;
2880 ss << "\n" ;
2881
2882 return ss.str();
2883 }
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935 #if defined(__CUDACC__) || defined(__CUDABE__)
2936 # define NVIEW_METHOD __host__ __device__ __forceinline__
2937 #else
2938 # define NVIEW_METHOD inline
2939 #endif
2940
2941 struct nview
2942 {
2943 union UIF32
2944 {
2945 unsigned u ;
2946 int i ;
2947 float f ;
2948 };
2949
2950 struct uint2 { unsigned x, y ; };
2951 struct int2 { unsigned x, y ; };
2952
2953 union UIF64
2954 {
2955 uint2 uu ;
2956 int2 ii ;
2957 double f ;
2958 };
2959
2960 template<typename T> static T int_as( int i );
2961 template<typename T> static int int_from( T v );
2962
2963 template<typename T> static T uint_as( unsigned u );
2964 template<typename T> static unsigned uint_from( T v );
2965 };
2966
2967 template<> NVIEW_METHOD float nview::int_as<float>( int i )
2968 {
2969 UIF32 u32 ;
2970 u32.i = i ;
2971 return u32.f ;
2972 }
2973 template<> NVIEW_METHOD double nview::int_as<double>( int i )
2974 {
2975 UIF64 u64 ;
2976 u64.ii.x = i ;
2977 return u64.f ;
2978 }
2979
2980
2981 template<> NVIEW_METHOD int nview::int_from<float>( float f )
2982 {
2983 UIF32 u32 ;
2984 u32.f = f ;
2985 return u32.i ;
2986 }
2987 template<> NVIEW_METHOD int nview::int_from<double>( double f )
2988 {
2989 UIF64 u64 ;
2990 u64.f = f ;
2991 return u64.ii.x ;
2992 }
2993
2994 template<> NVIEW_METHOD float nview::uint_as<float>( unsigned u )
2995 {
2996 UIF32 u32 ;
2997 u32.u = u ;
2998 return u32.f ;
2999 }
3000 template<> NVIEW_METHOD double nview::uint_as<double>( unsigned v )
3001 {
3002 UIF64 u64 ;
3003 u64.uu.x = v ;
3004 return u64.f ;
3005 }
3006
3007 template<> NVIEW_METHOD unsigned nview::uint_from<float>( float f )
3008 {
3009 UIF32 u32 ;
3010 u32.f = f ;
3011 return u32.u ;
3012 }
3013 template<> NVIEW_METHOD unsigned nview::uint_from<double>( double f )
3014 {
3015 UIF64 u64 ;
3016 u64.f = f ;
3017 return u64.uu.x ;
3018 }
3019
3020
3021
3022
3023
3024
3025 struct UName
3026 {
3027 static constexpr const char* UNSET = "UNSET" ;
3028 std::vector<std::string> names ;
3029 int count ;
3030
3031 UName();
3032 int get(const char* name) ;
3033 int add(const char* name, bool dump=false) ;
3034 std::string desc() const ;
3035 std::string as_str() const ;
3036 };
3037
3038
3039 inline UName::UName()
3040 :
3041 count(0)
3042 {
3043 names.push_back(UNSET);
3044 }
3045
3046 inline int UName::add(const char* name, bool dump)
3047 {
3048 if(std::find(names.begin(), names.end(), name) == names.end()) names.push_back(name) ;
3049 int idx = get(name) ;
3050 if(dump) std::cerr
3051 << "UName::add"
3052 << " idx " << std::setw(4) << idx
3053 << " name " << name
3054 << " count " << std::setw(5) << count
3055 << " size " << std::setw(5) << names.size()
3056 << std::endl
3057 ;
3058
3059
3060 count += 1 ;
3061 return idx ;
3062 }
3063 inline int UName::get(const char* name)
3064 {
3065 size_t idx = std::distance( names.begin(), std::find(names.begin(), names.end(), name) ) ;
3066 size_t num = names.size() ;
3067 std::cout << "UName::get " << ( name ? name : "-" ) << " num " << num << " idx " << idx << std::endl ;
3068 return idx == num ? -1 : int(idx) ;
3069 }
3070 inline std::string UName::desc() const
3071 {
3072 std::stringstream ss ;
3073 ss << "UName::desc"
3074 << " count " << std::setw(5) << count
3075 << " size " << std::setw(5) << names.size()
3076 << std::endl
3077 ;
3078
3079 for(int i=0 ; i < int(names.size()) ; i++ ) ss << std::setw(5) << i << " : " << names[i] << std::endl ;
3080 std::string str = ss.str();
3081 return str ;
3082 }
3083 inline std::string UName::as_str() const
3084 {
3085 int num_names = names.size();
3086 std::stringstream ss ;
3087 for(int i=0 ; i < num_names ; i++ )
3088 {
3089 ss << names[i] ;
3090 if( i < num_names - 1 ) ss << std::endl ;
3091 }
3092 std::string str = ss.str();
3093 return str ;
3094 }
3095
3096
3097
3098
3099
3100 union uc4
3101 {
3102 char c[4] ;
3103 unsigned u ;
3104
3105 void set(const char* s4) ;
3106 std::string get() const ;
3107 std::string desc() const ;
3108 };
3109
3110 inline void uc4::set(const char* s4)
3111 {
3112 for(unsigned i=0 ; i < 4 ; i++) c[i] = i < strlen(s4) ? s4[i] : '\0' ;
3113 }
3114 inline std::string uc4::get() const
3115 {
3116 const char* p = &c[0] ;
3117 std::string str(p, p+4) ;
3118 return str ;
3119 }
3120 inline std::string uc4::desc() const
3121 {
3122 std::stringstream ss ;
3123 ss << get() << " " << u ;
3124 std::string str = ss.str();
3125 return str ;
3126 }
3127
3128
3129
3130
3131
3132
3133 union uc8
3134 {
3135 char c[8] ;
3136 uint64_t u ;
3137
3138 void set(const char* s8) ;
3139 std::string get() const ;
3140 std::string desc() const ;
3141 };
3142 inline void uc8::set(const char* s8)
3143 {
3144 for(unsigned i=0 ; i < 8 ; i++) c[i] = i < strlen(s8) ? s8[i] : '\0' ;
3145 }
3146 inline std::string uc8::get() const
3147 {
3148 const char* p = &c[0] ;
3149 std::string str(p, p+8) ;
3150 return str ;
3151 }
3152 inline std::string uc8::desc() const
3153 {
3154 std::stringstream ss ;
3155 ss << get() << " " << u ;
3156 std::string str = ss.str();
3157 return str ;
3158 }
3159
3160 #endif