// SPDX-License-Identifier: Apache-2.0 // // Copyright 2008-2016 Conrad Sanderson (http://conradsanderson.id.au) // Copyright 2008-2016 National ICT Australia (NICTA) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ------------------------------------------------------------------------ //! \addtogroup arma_str //! @{ namespace arma_str { class char_buffer { public: static constexpr uword n_chars_prealloc = 1024; char* mem = nullptr; uword n_chars = 0; char local_mem[n_chars_prealloc]; inline ~char_buffer() { if(n_chars > n_chars_prealloc) { std::free(mem); } mem = nullptr; n_chars = 0; } inline char_buffer() { mem = &(local_mem[0]); n_chars = n_chars_prealloc; if(n_chars > 0) { mem[0] = char(0); } } inline void set_size(const uword new_n_chars) { if(n_chars > n_chars_prealloc) { std::free(mem); } mem = (new_n_chars <= n_chars_prealloc) ? &(local_mem[0]) : (char*)std::malloc(new_n_chars); n_chars = (new_n_chars <= n_chars_prealloc) ? n_chars_prealloc : new_n_chars; if(n_chars > 0) { mem[0] = char(0); } } }; class format { public: const std::string fmt; inline format(const char* in_fmt) : fmt(in_fmt) { } inline format(const std::string& in_fmt) : fmt(in_fmt) { } private: format(); }; template class basic_format { public: const T1& A; const T2& B; inline basic_format(const T1& in_A, const T2& in_B) : A(in_A) , B(in_B) { } private: basic_format(); }; template inline basic_format< format, T2 > operator% (const format& X, const T2& arg) { return basic_format< format, T2 >(X, arg); } template inline basic_format< basic_format, T3 > operator% (const basic_format& X, const T3& arg) { return basic_format< basic_format, T3 >(X, arg); } template inline std::string str(const basic_format< format, T2>& X) { std::string out; char_buffer buf; bool status = false; while(status == false) { int required_size = (std::snprintf)(buf.mem, size_t(buf.n_chars), X.A.fmt.c_str(), X.B); if(required_size < 0) { break; } if(uword(required_size) >= buf.n_chars) { if(buf.n_chars > char_buffer::n_chars_prealloc) { break; } buf.set_size(1 + uword(required_size)); } else { status = true; } if(status) { out = buf.mem; } } return out; } template inline std::string str(const basic_format< basic_format< format, T2>, T3>& X) { char_buffer buf; std::string out; bool status = false; while(status == false) { int required_size = (std::snprintf)(buf.mem, size_t(buf.n_chars), X.A.A.fmt.c_str(), X.A.B, X.B); if(required_size < 0) { break; } if(uword(required_size) >= buf.n_chars) { if(buf.n_chars > char_buffer::n_chars_prealloc) { break; } buf.set_size(1 + uword(required_size)); } else { status = true; } if(status) { out = buf.mem; } } return out; } template inline std::string str(const basic_format< basic_format< basic_format< format, T2>, T3>, T4>& X) { char_buffer buf; std::string out; bool status = false; while(status == false) { int required_size = (std::snprintf)(buf.mem, size_t(buf.n_chars), X.A.A.A.fmt.c_str(), X.A.A.B, X.A.B, X.B); if(required_size < 0) { break; } if(uword(required_size) >= buf.n_chars) { if(buf.n_chars > char_buffer::n_chars_prealloc) { break; } buf.set_size(1 + uword(required_size)); } else { status = true; } if(status) { out = buf.mem; } } return out; } template inline std::string str(const basic_format< basic_format< basic_format< basic_format< format, T2>, T3>, T4>, T5>& X) { char_buffer buf; std::string out; bool status = false; while(status == false) { int required_size = (std::snprintf)(buf.mem, size_t(buf.n_chars), X.A.A.A.A.fmt.c_str(), X.A.A.A.B, X.A.A.B, X.A.B, X.B); if(required_size < 0) { break; } if(uword(required_size) >= buf.n_chars) { if(buf.n_chars > char_buffer::n_chars_prealloc) { break; } buf.set_size(1 + uword(required_size)); } else { status = true; } if(status) { out = buf.mem; } } return out; } template inline std::string str(const basic_format< basic_format< basic_format< basic_format< basic_format< format, T2>, T3>, T4>, T5>, T6>& X) { char_buffer buf; std::string out; bool status = false; while(status == false) { int required_size = (std::snprintf)(buf.mem, size_t(buf.n_chars), X.A.A.A.A.A.fmt.c_str(), X.A.A.A.A.B, X.A.A.A.B, X.A.A.B, X.A.B, X.B); if(required_size < 0) { break; } if(uword(required_size) >= buf.n_chars) { if(buf.n_chars > char_buffer::n_chars_prealloc) { break; } buf.set_size(1 + uword(required_size)); } else { status = true; } if(status) { out = buf.mem; } } return out; } template inline std::string str(const basic_format< basic_format< basic_format< basic_format< basic_format< basic_format< format, T2>, T3>, T4>, T5>, T6>, T7>& X) { char_buffer buf; std::string out; bool status = false; while(status == false) { int required_size = (std::snprintf)(buf.mem, size_t(buf.n_chars), X.A.A.A.A.A.A.fmt.c_str(), X.A.A.A.A.A.B, X.A.A.A.A.B, X.A.A.A.B, X.A.A.B, X.A.B, X.B); if(required_size < 0) { break; } if(uword(required_size) >= buf.n_chars) { if(buf.n_chars > char_buffer::n_chars_prealloc) { break; } buf.set_size(1 + uword(required_size)); } else { status = true; } if(status) { out = buf.mem; } } return out; } template struct format_metaprog { static constexpr uword depth = 0; inline static const std::string& get_fmt(const T1& X) { return X.A; } }; //template<> template struct format_metaprog< basic_format > { static constexpr uword depth = 1 + format_metaprog::depth; inline static const std::string& get_fmt(const T1& X) { return format_metaprog::get_fmt(X.A); } }; template inline std::string str(const basic_format& X) { return format_metaprog< basic_format >::get_fmt(X.A); } template inline std::ostream& operator<< (std::ostream& o, const basic_format& X) { o << str(X); return o; } template struct string_only { }; template<> struct string_only { typedef std::string result; }; template struct char_only { }; template<> struct char_only { typedef char result; }; template struct basic_format_only { }; template struct basic_format_only< basic_format > { typedef basic_format result; }; template inline static const T1& str_wrapper(const T1& x, const typename string_only::result* junk = nullptr) { arma_ignore(junk); return x; } template inline static const T1* str_wrapper(const T1* x, const typename char_only::result* junk = nullptr) { arma_ignore(junk); return x; } template inline static std::string str_wrapper(const T1& x, const typename basic_format_only::result* junk = nullptr) { arma_ignore(junk); return str(x); } } //! @}